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("")
4697 * Returns an HTML fragment of this template with the specified values applied.
4698 * @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'})
4699 * @return {String} The HTML fragment
4701 applyTemplate : function(values){
4702 //Roo.log(["applyTemplate", values]);
4706 return this.compiled(values);
4708 var useF = this.disableFormats !== true;
4709 var fm = Roo.util.Format, tpl = this;
4710 var fn = function(m, name, format, args){
4712 if(format.substr(0, 5) == "this."){
4713 return tpl.call(format.substr(5), values[name], values);
4716 // quoted values are required for strings in compiled templates,
4717 // but for non compiled we need to strip them
4718 // quoted reversed for jsmin
4719 var re = /^\s*['"](.*)["']\s*$/;
4720 args = args.split(',');
4721 for(var i = 0, len = args.length; i < len; i++){
4722 args[i] = args[i].replace(re, "$1");
4724 args = [values[name]].concat(args);
4726 args = [values[name]];
4728 return fm[format].apply(fm, args);
4731 return values[name] !== undefined ? values[name] : "";
4734 return this.html.replace(this.re, fn);
4752 this.loading = true;
4753 this.compiled = false;
4755 var cx = new Roo.data.Connection();
4759 success : function (response) {
4761 _t.html = response.responseText;
4768 failure : function(response) {
4769 Roo.log("Template failed to load from " + _t.url);
4776 * Sets the HTML used as the template and optionally compiles it.
4777 * @param {String} html
4778 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4779 * @return {Roo.Template} this
4781 set : function(html, compile){
4783 this.compiled = null;
4791 * True to disable format functions (defaults to false)
4794 disableFormats : false,
4797 * The regular expression used to match template variables
4801 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4804 * Compiles the template into an internal function, eliminating the RegEx overhead.
4805 * @return {Roo.Template} this
4807 compile : function(){
4808 var fm = Roo.util.Format;
4809 var useF = this.disableFormats !== true;
4810 var sep = Roo.isGecko ? "+" : ",";
4811 var fn = function(m, name, format, args){
4813 args = args ? ',' + args : "";
4814 if(format.substr(0, 5) != "this."){
4815 format = "fm." + format + '(';
4817 format = 'this.call("'+ format.substr(5) + '", ';
4821 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4823 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4826 // branched to use + in gecko and [].join() in others
4828 body = "this.compiled = function(values){ return '" +
4829 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4832 body = ["this.compiled = function(values){ return ['"];
4833 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4834 body.push("'].join('');};");
4835 body = body.join('');
4845 // private function used to call members
4846 call : function(fnName, value, allValues){
4847 return this[fnName](value, allValues);
4851 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4852 * @param {String/HTMLElement/Roo.Element} el The context element
4853 * @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'})
4854 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4855 * @return {HTMLElement/Roo.Element} The new node or Element
4857 insertFirst: function(el, values, returnElement){
4858 return this.doInsert('afterBegin', el, values, returnElement);
4862 * Applies the supplied values to the template and inserts the new node(s) before el.
4863 * @param {String/HTMLElement/Roo.Element} el The context element
4864 * @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'})
4865 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4866 * @return {HTMLElement/Roo.Element} The new node or Element
4868 insertBefore: function(el, values, returnElement){
4869 return this.doInsert('beforeBegin', el, values, returnElement);
4873 * Applies the supplied values to the template and inserts the new node(s) after el.
4874 * @param {String/HTMLElement/Roo.Element} el The context element
4875 * @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'})
4876 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4877 * @return {HTMLElement/Roo.Element} The new node or Element
4879 insertAfter : function(el, values, returnElement){
4880 return this.doInsert('afterEnd', el, values, returnElement);
4884 * Applies the supplied values to the template and appends the new node(s) to el.
4885 * @param {String/HTMLElement/Roo.Element} el The context element
4886 * @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'})
4887 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4888 * @return {HTMLElement/Roo.Element} The new node or Element
4890 append : function(el, values, returnElement){
4891 return this.doInsert('beforeEnd', el, values, returnElement);
4894 doInsert : function(where, el, values, returnEl){
4895 el = Roo.getDom(el);
4896 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4897 return returnEl ? Roo.get(newNode, true) : newNode;
4901 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4902 * @param {String/HTMLElement/Roo.Element} el The context element
4903 * @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'})
4904 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4905 * @return {HTMLElement/Roo.Element} The new node or Element
4907 overwrite : function(el, values, returnElement){
4908 el = Roo.getDom(el);
4909 el.innerHTML = this.applyTemplate(values);
4910 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4914 * Alias for {@link #applyTemplate}
4917 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4920 Roo.DomHelper.Template = Roo.Template;
4923 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4924 * @param {String/HTMLElement} el A DOM element or its id
4925 * @returns {Roo.Template} The created template
4928 Roo.Template.from = function(el){
4929 el = Roo.getDom(el);
4930 return new Roo.Template(el.value || el.innerHTML);
4933 * Ext JS Library 1.1.1
4934 * Copyright(c) 2006-2007, Ext JS, LLC.
4936 * Originally Released Under LGPL - original licence link has changed is not relivant.
4939 * <script type="text/javascript">
4944 * This is code is also distributed under MIT license for use
4945 * with jQuery and prototype JavaScript libraries.
4948 * @class Roo.DomQuery
4949 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).
4951 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>
4954 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.
4956 <h4>Element Selectors:</h4>
4958 <li> <b>*</b> any element</li>
4959 <li> <b>E</b> an element with the tag E</li>
4960 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4961 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4962 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4963 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4965 <h4>Attribute Selectors:</h4>
4966 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4968 <li> <b>E[foo]</b> has an attribute "foo"</li>
4969 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4970 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4971 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4972 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4973 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4974 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4976 <h4>Pseudo Classes:</h4>
4978 <li> <b>E:first-child</b> E is the first child of its parent</li>
4979 <li> <b>E:last-child</b> E is the last child of its parent</li>
4980 <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>
4981 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4982 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4983 <li> <b>E:only-child</b> E is the only child of its parent</li>
4984 <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>
4985 <li> <b>E:first</b> the first E in the resultset</li>
4986 <li> <b>E:last</b> the last E in the resultset</li>
4987 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4988 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4989 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4990 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4991 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4992 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4993 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4994 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4995 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4997 <h4>CSS Value Selectors:</h4>
4999 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5000 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5001 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5002 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5003 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5004 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5008 Roo.DomQuery = function(){
5009 var cache = {}, simpleCache = {}, valueCache = {};
5010 var nonSpace = /\S/;
5011 var trimRe = /^\s+|\s+$/g;
5012 var tplRe = /\{(\d+)\}/g;
5013 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5014 var tagTokenRe = /^(#)?([\w-\*]+)/;
5015 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5017 function child(p, index){
5019 var n = p.firstChild;
5021 if(n.nodeType == 1){
5032 while((n = n.nextSibling) && n.nodeType != 1);
5037 while((n = n.previousSibling) && n.nodeType != 1);
5041 function children(d){
5042 var n = d.firstChild, ni = -1;
5044 var nx = n.nextSibling;
5045 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5055 function byClassName(c, a, v){
5059 var r = [], ri = -1, cn;
5060 for(var i = 0, ci; ci = c[i]; i++){
5061 if((' '+ci.className+' ').indexOf(v) != -1){
5068 function attrValue(n, attr){
5069 if(!n.tagName && typeof n.length != "undefined"){
5078 if(attr == "class" || attr == "className"){
5081 return n.getAttribute(attr) || n[attr];
5085 function getNodes(ns, mode, tagName){
5086 var result = [], ri = -1, cs;
5090 tagName = tagName || "*";
5091 if(typeof ns.getElementsByTagName != "undefined"){
5095 for(var i = 0, ni; ni = ns[i]; i++){
5096 cs = ni.getElementsByTagName(tagName);
5097 for(var j = 0, ci; ci = cs[j]; j++){
5101 }else if(mode == "/" || mode == ">"){
5102 var utag = tagName.toUpperCase();
5103 for(var i = 0, ni, cn; ni = ns[i]; i++){
5104 cn = ni.children || ni.childNodes;
5105 for(var j = 0, cj; cj = cn[j]; j++){
5106 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5111 }else if(mode == "+"){
5112 var utag = tagName.toUpperCase();
5113 for(var i = 0, n; n = ns[i]; i++){
5114 while((n = n.nextSibling) && n.nodeType != 1);
5115 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5119 }else if(mode == "~"){
5120 for(var i = 0, n; n = ns[i]; i++){
5121 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5130 function concat(a, b){
5134 for(var i = 0, l = b.length; i < l; i++){
5140 function byTag(cs, tagName){
5141 if(cs.tagName || cs == document){
5147 var r = [], ri = -1;
5148 tagName = tagName.toLowerCase();
5149 for(var i = 0, ci; ci = cs[i]; i++){
5150 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5157 function byId(cs, attr, id){
5158 if(cs.tagName || cs == document){
5164 var r = [], ri = -1;
5165 for(var i = 0,ci; ci = cs[i]; i++){
5166 if(ci && ci.id == id){
5174 function byAttribute(cs, attr, value, op, custom){
5175 var r = [], ri = -1, st = custom=="{";
5176 var f = Roo.DomQuery.operators[op];
5177 for(var i = 0, ci; ci = cs[i]; i++){
5180 a = Roo.DomQuery.getStyle(ci, attr);
5182 else if(attr == "class" || attr == "className"){
5184 }else if(attr == "for"){
5186 }else if(attr == "href"){
5187 a = ci.getAttribute("href", 2);
5189 a = ci.getAttribute(attr);
5191 if((f && f(a, value)) || (!f && a)){
5198 function byPseudo(cs, name, value){
5199 return Roo.DomQuery.pseudos[name](cs, value);
5202 // This is for IE MSXML which does not support expandos.
5203 // IE runs the same speed using setAttribute, however FF slows way down
5204 // and Safari completely fails so they need to continue to use expandos.
5205 var isIE = window.ActiveXObject ? true : false;
5207 // this eval is stop the compressor from
5208 // renaming the variable to something shorter
5210 /** eval:var:batch */
5215 function nodupIEXml(cs){
5217 cs[0].setAttribute("_nodup", d);
5219 for(var i = 1, len = cs.length; i < len; i++){
5221 if(!c.getAttribute("_nodup") != d){
5222 c.setAttribute("_nodup", d);
5226 for(var i = 0, len = cs.length; i < len; i++){
5227 cs[i].removeAttribute("_nodup");
5236 var len = cs.length, c, i, r = cs, cj, ri = -1;
5237 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5240 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5241 return nodupIEXml(cs);
5245 for(i = 1; c = cs[i]; i++){
5250 for(var j = 0; j < i; j++){
5253 for(j = i+1; cj = cs[j]; j++){
5265 function quickDiffIEXml(c1, c2){
5267 for(var i = 0, len = c1.length; i < len; i++){
5268 c1[i].setAttribute("_qdiff", d);
5271 for(var i = 0, len = c2.length; i < len; i++){
5272 if(c2[i].getAttribute("_qdiff") != d){
5273 r[r.length] = c2[i];
5276 for(var i = 0, len = c1.length; i < len; i++){
5277 c1[i].removeAttribute("_qdiff");
5282 function quickDiff(c1, c2){
5283 var len1 = c1.length;
5287 if(isIE && c1[0].selectSingleNode){
5288 return quickDiffIEXml(c1, c2);
5291 for(var i = 0; i < len1; i++){
5295 for(var i = 0, len = c2.length; i < len; i++){
5296 if(c2[i]._qdiff != d){
5297 r[r.length] = c2[i];
5303 function quickId(ns, mode, root, id){
5305 var d = root.ownerDocument || root;
5306 return d.getElementById(id);
5308 ns = getNodes(ns, mode, "*");
5309 return byId(ns, null, id);
5313 getStyle : function(el, name){
5314 return Roo.fly(el).getStyle(name);
5317 * Compiles a selector/xpath query into a reusable function. The returned function
5318 * takes one parameter "root" (optional), which is the context node from where the query should start.
5319 * @param {String} selector The selector/xpath query
5320 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5321 * @return {Function}
5323 compile : function(path, type){
5324 type = type || "select";
5326 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5327 var q = path, mode, lq;
5328 var tk = Roo.DomQuery.matchers;
5329 var tklen = tk.length;
5332 // accept leading mode switch
5333 var lmode = q.match(modeRe);
5334 if(lmode && lmode[1]){
5335 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5336 q = q.replace(lmode[1], "");
5338 // strip leading slashes
5339 while(path.substr(0, 1)=="/"){
5340 path = path.substr(1);
5343 while(q && lq != q){
5345 var tm = q.match(tagTokenRe);
5346 if(type == "select"){
5349 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5351 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5353 q = q.replace(tm[0], "");
5354 }else if(q.substr(0, 1) != '@'){
5355 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5360 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5362 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5364 q = q.replace(tm[0], "");
5367 while(!(mm = q.match(modeRe))){
5368 var matched = false;
5369 for(var j = 0; j < tklen; j++){
5371 var m = q.match(t.re);
5373 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5376 q = q.replace(m[0], "");
5381 // prevent infinite loop on bad selector
5383 throw 'Error parsing selector, parsing failed at "' + q + '"';
5387 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5388 q = q.replace(mm[1], "");
5391 fn[fn.length] = "return nodup(n);\n}";
5394 * list of variables that need from compression as they are used by eval.
5404 * eval:var:byClassName
5406 * eval:var:byAttribute
5407 * eval:var:attrValue
5415 * Selects a group of elements.
5416 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5417 * @param {Node} root (optional) The start of the query (defaults to document).
5420 select : function(path, root, type){
5421 if(!root || root == document){
5424 if(typeof root == "string"){
5425 root = document.getElementById(root);
5427 var paths = path.split(",");
5429 for(var i = 0, len = paths.length; i < len; i++){
5430 var p = paths[i].replace(trimRe, "");
5432 cache[p] = Roo.DomQuery.compile(p);
5434 throw p + " is not a valid selector";
5437 var result = cache[p](root);
5438 if(result && result != document){
5439 results = results.concat(result);
5442 if(paths.length > 1){
5443 return nodup(results);
5449 * Selects a single element.
5450 * @param {String} selector The selector/xpath query
5451 * @param {Node} root (optional) The start of the query (defaults to document).
5454 selectNode : function(path, root){
5455 return Roo.DomQuery.select(path, root)[0];
5459 * Selects the value of a node, optionally replacing null with the defaultValue.
5460 * @param {String} selector The selector/xpath query
5461 * @param {Node} root (optional) The start of the query (defaults to document).
5462 * @param {String} defaultValue
5464 selectValue : function(path, root, defaultValue){
5465 path = path.replace(trimRe, "");
5466 if(!valueCache[path]){
5467 valueCache[path] = Roo.DomQuery.compile(path, "select");
5469 var n = valueCache[path](root);
5470 n = n[0] ? n[0] : n;
5471 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5472 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5476 * Selects the value of a node, parsing integers and floats.
5477 * @param {String} selector The selector/xpath query
5478 * @param {Node} root (optional) The start of the query (defaults to document).
5479 * @param {Number} defaultValue
5482 selectNumber : function(path, root, defaultValue){
5483 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5484 return parseFloat(v);
5488 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5489 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5490 * @param {String} selector The simple selector to test
5493 is : function(el, ss){
5494 if(typeof el == "string"){
5495 el = document.getElementById(el);
5497 var isArray = (el instanceof Array);
5498 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5499 return isArray ? (result.length == el.length) : (result.length > 0);
5503 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5504 * @param {Array} el An array of elements to filter
5505 * @param {String} selector The simple selector to test
5506 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5507 * the selector instead of the ones that match
5510 filter : function(els, ss, nonMatches){
5511 ss = ss.replace(trimRe, "");
5512 if(!simpleCache[ss]){
5513 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5515 var result = simpleCache[ss](els);
5516 return nonMatches ? quickDiff(result, els) : result;
5520 * Collection of matching regular expressions and code snippets.
5524 select: 'n = byClassName(n, null, " {1} ");'
5526 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5527 select: 'n = byPseudo(n, "{1}", "{2}");'
5529 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5530 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5533 select: 'n = byId(n, null, "{1}");'
5536 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5541 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5542 * 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, > <.
5545 "=" : function(a, v){
5548 "!=" : function(a, v){
5551 "^=" : function(a, v){
5552 return a && a.substr(0, v.length) == v;
5554 "$=" : function(a, v){
5555 return a && a.substr(a.length-v.length) == v;
5557 "*=" : function(a, v){
5558 return a && a.indexOf(v) !== -1;
5560 "%=" : function(a, v){
5561 return (a % v) == 0;
5563 "|=" : function(a, v){
5564 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5566 "~=" : function(a, v){
5567 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5572 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5573 * and the argument (if any) supplied in the selector.
5576 "first-child" : function(c){
5577 var r = [], ri = -1, n;
5578 for(var i = 0, ci; ci = n = c[i]; i++){
5579 while((n = n.previousSibling) && n.nodeType != 1);
5587 "last-child" : function(c){
5588 var r = [], ri = -1, n;
5589 for(var i = 0, ci; ci = n = c[i]; i++){
5590 while((n = n.nextSibling) && n.nodeType != 1);
5598 "nth-child" : function(c, a) {
5599 var r = [], ri = -1;
5600 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5601 var f = (m[1] || 1) - 0, l = m[2] - 0;
5602 for(var i = 0, n; n = c[i]; i++){
5603 var pn = n.parentNode;
5604 if (batch != pn._batch) {
5606 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5607 if(cn.nodeType == 1){
5614 if (l == 0 || n.nodeIndex == l){
5617 } else if ((n.nodeIndex + l) % f == 0){
5625 "only-child" : function(c){
5626 var r = [], ri = -1;;
5627 for(var i = 0, ci; ci = c[i]; i++){
5628 if(!prev(ci) && !next(ci)){
5635 "empty" : function(c){
5636 var r = [], ri = -1;
5637 for(var i = 0, ci; ci = c[i]; i++){
5638 var cns = ci.childNodes, j = 0, cn, empty = true;
5641 if(cn.nodeType == 1 || cn.nodeType == 3){
5653 "contains" : function(c, v){
5654 var r = [], ri = -1;
5655 for(var i = 0, ci; ci = c[i]; i++){
5656 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5663 "nodeValue" : function(c, v){
5664 var r = [], ri = -1;
5665 for(var i = 0, ci; ci = c[i]; i++){
5666 if(ci.firstChild && ci.firstChild.nodeValue == v){
5673 "checked" : function(c){
5674 var r = [], ri = -1;
5675 for(var i = 0, ci; ci = c[i]; i++){
5676 if(ci.checked == true){
5683 "not" : function(c, ss){
5684 return Roo.DomQuery.filter(c, ss, true);
5687 "odd" : function(c){
5688 return this["nth-child"](c, "odd");
5691 "even" : function(c){
5692 return this["nth-child"](c, "even");
5695 "nth" : function(c, a){
5696 return c[a-1] || [];
5699 "first" : function(c){
5703 "last" : function(c){
5704 return c[c.length-1] || [];
5707 "has" : function(c, ss){
5708 var s = Roo.DomQuery.select;
5709 var r = [], ri = -1;
5710 for(var i = 0, ci; ci = c[i]; i++){
5711 if(s(ss, ci).length > 0){
5718 "next" : function(c, ss){
5719 var is = Roo.DomQuery.is;
5720 var r = [], ri = -1;
5721 for(var i = 0, ci; ci = c[i]; i++){
5730 "prev" : function(c, ss){
5731 var is = Roo.DomQuery.is;
5732 var r = [], ri = -1;
5733 for(var i = 0, ci; ci = c[i]; i++){
5746 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5747 * @param {String} path The selector/xpath query
5748 * @param {Node} root (optional) The start of the query (defaults to document).
5753 Roo.query = Roo.DomQuery.select;
5756 * Ext JS Library 1.1.1
5757 * Copyright(c) 2006-2007, Ext JS, LLC.
5759 * Originally Released Under LGPL - original licence link has changed is not relivant.
5762 * <script type="text/javascript">
5766 * @class Roo.util.Observable
5767 * Base class that provides a common interface for publishing events. Subclasses are expected to
5768 * to have a property "events" with all the events defined.<br>
5771 Employee = function(name){
5778 Roo.extend(Employee, Roo.util.Observable);
5780 * @param {Object} config properties to use (incuding events / listeners)
5783 Roo.util.Observable = function(cfg){
5786 this.addEvents(cfg.events || {});
5788 delete cfg.events; // make sure
5791 Roo.apply(this, cfg);
5794 this.on(this.listeners);
5795 delete this.listeners;
5798 Roo.util.Observable.prototype = {
5800 * @cfg {Object} listeners list of events and functions to call for this object,
5804 'click' : function(e) {
5814 * Fires the specified event with the passed parameters (minus the event name).
5815 * @param {String} eventName
5816 * @param {Object...} args Variable number of parameters are passed to handlers
5817 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5819 fireEvent : function(){
5820 var ce = this.events[arguments[0].toLowerCase()];
5821 if(typeof ce == "object"){
5822 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5829 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5832 * Appends an event handler to this component
5833 * @param {String} eventName The type of event to listen for
5834 * @param {Function} handler The method the event invokes
5835 * @param {Object} scope (optional) The scope in which to execute the handler
5836 * function. The handler function's "this" context.
5837 * @param {Object} options (optional) An object containing handler configuration
5838 * properties. This may contain any of the following properties:<ul>
5839 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5840 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5841 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5842 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5843 * by the specified number of milliseconds. If the event fires again within that time, the original
5844 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5847 * <b>Combining Options</b><br>
5848 * Using the options argument, it is possible to combine different types of listeners:<br>
5850 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5852 el.on('click', this.onClick, this, {
5859 * <b>Attaching multiple handlers in 1 call</b><br>
5860 * The method also allows for a single argument to be passed which is a config object containing properties
5861 * which specify multiple handlers.
5870 fn: this.onMouseOver,
5874 fn: this.onMouseOut,
5880 * Or a shorthand syntax which passes the same scope object to all handlers:
5883 'click': this.onClick,
5884 'mouseover': this.onMouseOver,
5885 'mouseout': this.onMouseOut,
5890 addListener : function(eventName, fn, scope, o){
5891 if(typeof eventName == "object"){
5894 if(this.filterOptRe.test(e)){
5897 if(typeof o[e] == "function"){
5899 this.addListener(e, o[e], o.scope, o);
5901 // individual options
5902 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5907 o = (!o || typeof o == "boolean") ? {} : o;
5908 eventName = eventName.toLowerCase();
5909 var ce = this.events[eventName] || true;
5910 if(typeof ce == "boolean"){
5911 ce = new Roo.util.Event(this, eventName);
5912 this.events[eventName] = ce;
5914 ce.addListener(fn, scope, o);
5918 * Removes a listener
5919 * @param {String} eventName The type of event to listen for
5920 * @param {Function} handler The handler to remove
5921 * @param {Object} scope (optional) The scope (this object) for the handler
5923 removeListener : function(eventName, fn, scope){
5924 var ce = this.events[eventName.toLowerCase()];
5925 if(typeof ce == "object"){
5926 ce.removeListener(fn, scope);
5931 * Removes all listeners for this object
5933 purgeListeners : function(){
5934 for(var evt in this.events){
5935 if(typeof this.events[evt] == "object"){
5936 this.events[evt].clearListeners();
5941 relayEvents : function(o, events){
5942 var createHandler = function(ename){
5944 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5947 for(var i = 0, len = events.length; i < len; i++){
5948 var ename = events[i];
5949 if(!this.events[ename]){ this.events[ename] = true; };
5950 o.on(ename, createHandler(ename), this);
5955 * Used to define events on this Observable
5956 * @param {Object} object The object with the events defined
5958 addEvents : function(o){
5962 Roo.applyIf(this.events, o);
5966 * Checks to see if this object has any listeners for a specified event
5967 * @param {String} eventName The name of the event to check for
5968 * @return {Boolean} True if the event is being listened for, else false
5970 hasListener : function(eventName){
5971 var e = this.events[eventName];
5972 return typeof e == "object" && e.listeners.length > 0;
5976 * Appends an event handler to this element (shorthand for addListener)
5977 * @param {String} eventName The type of event to listen for
5978 * @param {Function} handler The method the event invokes
5979 * @param {Object} scope (optional) The scope in which to execute the handler
5980 * function. The handler function's "this" context.
5981 * @param {Object} options (optional)
5984 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5986 * Removes a listener (shorthand for removeListener)
5987 * @param {String} eventName The type of event to listen for
5988 * @param {Function} handler The handler to remove
5989 * @param {Object} scope (optional) The scope (this object) for the handler
5992 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5995 * Starts capture on the specified Observable. All events will be passed
5996 * to the supplied function with the event name + standard signature of the event
5997 * <b>before</b> the event is fired. If the supplied function returns false,
5998 * the event will not fire.
5999 * @param {Observable} o The Observable to capture
6000 * @param {Function} fn The function to call
6001 * @param {Object} scope (optional) The scope (this object) for the fn
6004 Roo.util.Observable.capture = function(o, fn, scope){
6005 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6009 * Removes <b>all</b> added captures from the Observable.
6010 * @param {Observable} o The Observable to release
6013 Roo.util.Observable.releaseCapture = function(o){
6014 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6019 var createBuffered = function(h, o, scope){
6020 var task = new Roo.util.DelayedTask();
6022 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6026 var createSingle = function(h, e, fn, scope){
6028 e.removeListener(fn, scope);
6029 return h.apply(scope, arguments);
6033 var createDelayed = function(h, o, scope){
6035 var args = Array.prototype.slice.call(arguments, 0);
6036 setTimeout(function(){
6037 h.apply(scope, args);
6042 Roo.util.Event = function(obj, name){
6045 this.listeners = [];
6048 Roo.util.Event.prototype = {
6049 addListener : function(fn, scope, options){
6050 var o = options || {};
6051 scope = scope || this.obj;
6052 if(!this.isListening(fn, scope)){
6053 var l = {fn: fn, scope: scope, options: o};
6056 h = createDelayed(h, o, scope);
6059 h = createSingle(h, this, fn, scope);
6062 h = createBuffered(h, o, scope);
6065 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6066 this.listeners.push(l);
6068 this.listeners = this.listeners.slice(0);
6069 this.listeners.push(l);
6074 findListener : function(fn, scope){
6075 scope = scope || this.obj;
6076 var ls = this.listeners;
6077 for(var i = 0, len = ls.length; i < len; i++){
6079 if(l.fn == fn && l.scope == scope){
6086 isListening : function(fn, scope){
6087 return this.findListener(fn, scope) != -1;
6090 removeListener : function(fn, scope){
6092 if((index = this.findListener(fn, scope)) != -1){
6094 this.listeners.splice(index, 1);
6096 this.listeners = this.listeners.slice(0);
6097 this.listeners.splice(index, 1);
6104 clearListeners : function(){
6105 this.listeners = [];
6109 var ls = this.listeners, scope, len = ls.length;
6112 var args = Array.prototype.slice.call(arguments, 0);
6113 for(var i = 0; i < len; i++){
6115 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6116 this.firing = false;
6120 this.firing = false;
6127 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6134 * @class Roo.Document
6135 * @extends Roo.util.Observable
6136 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6138 * @param {Object} config the methods and properties of the 'base' class for the application.
6140 * Generic Page handler - implement this to start your app..
6143 * MyProject = new Roo.Document({
6145 'load' : true // your events..
6148 'ready' : function() {
6149 // fired on Roo.onReady()
6154 Roo.Document = function(cfg) {
6159 Roo.util.Observable.call(this,cfg);
6163 Roo.onReady(function() {
6164 _this.fireEvent('ready');
6170 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6172 * Ext JS Library 1.1.1
6173 * Copyright(c) 2006-2007, Ext JS, LLC.
6175 * Originally Released Under LGPL - original licence link has changed is not relivant.
6178 * <script type="text/javascript">
6182 * @class Roo.EventManager
6183 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6184 * several useful events directly.
6185 * See {@link Roo.EventObject} for more details on normalized event objects.
6188 Roo.EventManager = function(){
6189 var docReadyEvent, docReadyProcId, docReadyState = false;
6190 var resizeEvent, resizeTask, textEvent, textSize;
6191 var E = Roo.lib.Event;
6192 var D = Roo.lib.Dom;
6197 var fireDocReady = function(){
6199 docReadyState = true;
6202 clearInterval(docReadyProcId);
6204 if(Roo.isGecko || Roo.isOpera) {
6205 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6208 var defer = document.getElementById("ie-deferred-loader");
6210 defer.onreadystatechange = null;
6211 defer.parentNode.removeChild(defer);
6215 docReadyEvent.fire();
6216 docReadyEvent.clearListeners();
6221 var initDocReady = function(){
6222 docReadyEvent = new Roo.util.Event();
6223 if(Roo.isGecko || Roo.isOpera) {
6224 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6226 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6227 var defer = document.getElementById("ie-deferred-loader");
6228 defer.onreadystatechange = function(){
6229 if(this.readyState == "complete"){
6233 }else if(Roo.isSafari){
6234 docReadyProcId = setInterval(function(){
6235 var rs = document.readyState;
6236 if(rs == "complete") {
6241 // no matter what, make sure it fires on load
6242 E.on(window, "load", fireDocReady);
6245 var createBuffered = function(h, o){
6246 var task = new Roo.util.DelayedTask(h);
6248 // create new event object impl so new events don't wipe out properties
6249 e = new Roo.EventObjectImpl(e);
6250 task.delay(o.buffer, h, null, [e]);
6254 var createSingle = function(h, el, ename, fn){
6256 Roo.EventManager.removeListener(el, ename, fn);
6261 var createDelayed = function(h, o){
6263 // create new event object impl so new events don't wipe out properties
6264 e = new Roo.EventObjectImpl(e);
6265 setTimeout(function(){
6270 var transitionEndVal = false;
6272 var transitionEnd = function()
6274 if (transitionEndVal) {
6275 return transitionEndVal;
6277 var el = document.createElement('div');
6279 var transEndEventNames = {
6280 WebkitTransition : 'webkitTransitionEnd',
6281 MozTransition : 'transitionend',
6282 OTransition : 'oTransitionEnd otransitionend',
6283 transition : 'transitionend'
6286 for (var name in transEndEventNames) {
6287 if (el.style[name] !== undefined) {
6288 transitionEndVal = transEndEventNames[name];
6289 return transitionEndVal ;
6295 var listen = function(element, ename, opt, fn, scope){
6296 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6297 fn = fn || o.fn; scope = scope || o.scope;
6298 var el = Roo.getDom(element);
6302 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6305 if (ename == 'transitionend') {
6306 ename = transitionEnd();
6308 var h = function(e){
6309 e = Roo.EventObject.setEvent(e);
6312 t = e.getTarget(o.delegate, el);
6319 if(o.stopEvent === true){
6322 if(o.preventDefault === true){
6325 if(o.stopPropagation === true){
6326 e.stopPropagation();
6329 if(o.normalized === false){
6333 fn.call(scope || el, e, t, o);
6336 h = createDelayed(h, o);
6339 h = createSingle(h, el, ename, fn);
6342 h = createBuffered(h, o);
6345 fn._handlers = fn._handlers || [];
6348 fn._handlers.push([Roo.id(el), ename, h]);
6353 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6354 el.addEventListener("DOMMouseScroll", h, false);
6355 E.on(window, 'unload', function(){
6356 el.removeEventListener("DOMMouseScroll", h, false);
6359 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6360 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6365 var stopListening = function(el, ename, fn){
6366 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6368 for(var i = 0, len = hds.length; i < len; i++){
6370 if(h[0] == id && h[1] == ename){
6377 E.un(el, ename, hd);
6378 el = Roo.getDom(el);
6379 if(ename == "mousewheel" && el.addEventListener){
6380 el.removeEventListener("DOMMouseScroll", hd, false);
6382 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6383 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6387 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6394 * @scope Roo.EventManager
6399 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6400 * object with a Roo.EventObject
6401 * @param {Function} fn The method the event invokes
6402 * @param {Object} scope An object that becomes the scope of the handler
6403 * @param {boolean} override If true, the obj passed in becomes
6404 * the execution scope of the listener
6405 * @return {Function} The wrapped function
6408 wrap : function(fn, scope, override){
6410 Roo.EventObject.setEvent(e);
6411 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6416 * Appends an event handler to an element (shorthand for addListener)
6417 * @param {String/HTMLElement} element The html element or id to assign the
6418 * @param {String} eventName The type of event to listen for
6419 * @param {Function} handler The method the event invokes
6420 * @param {Object} scope (optional) The scope in which to execute the handler
6421 * function. The handler function's "this" context.
6422 * @param {Object} options (optional) An object containing handler configuration
6423 * properties. This may contain any of the following properties:<ul>
6424 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6425 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6426 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6427 * <li>preventDefault {Boolean} True to prevent the default action</li>
6428 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6429 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6430 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6431 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6432 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6433 * by the specified number of milliseconds. If the event fires again within that time, the original
6434 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6437 * <b>Combining Options</b><br>
6438 * Using the options argument, it is possible to combine different types of listeners:<br>
6440 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6442 el.on('click', this.onClick, this, {
6449 * <b>Attaching multiple handlers in 1 call</b><br>
6450 * The method also allows for a single argument to be passed which is a config object containing properties
6451 * which specify multiple handlers.
6461 fn: this.onMouseOver
6470 * Or a shorthand syntax:<br>
6473 'click' : this.onClick,
6474 'mouseover' : this.onMouseOver,
6475 'mouseout' : this.onMouseOut
6479 addListener : function(element, eventName, fn, scope, options){
6480 if(typeof eventName == "object"){
6486 if(typeof o[e] == "function"){
6488 listen(element, e, o, o[e], o.scope);
6490 // individual options
6491 listen(element, e, o[e]);
6496 return listen(element, eventName, options, fn, scope);
6500 * Removes an event handler
6502 * @param {String/HTMLElement} element The id or html element to remove the
6504 * @param {String} eventName The type of event
6505 * @param {Function} fn
6506 * @return {Boolean} True if a listener was actually removed
6508 removeListener : function(element, eventName, fn){
6509 return stopListening(element, eventName, fn);
6513 * Fires when the document is ready (before onload and before images are loaded). Can be
6514 * accessed shorthanded Roo.onReady().
6515 * @param {Function} fn The method the event invokes
6516 * @param {Object} scope An object that becomes the scope of the handler
6517 * @param {boolean} options
6519 onDocumentReady : function(fn, scope, options){
6520 if(docReadyState){ // if it already fired
6521 docReadyEvent.addListener(fn, scope, options);
6522 docReadyEvent.fire();
6523 docReadyEvent.clearListeners();
6529 docReadyEvent.addListener(fn, scope, options);
6533 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6534 * @param {Function} fn The method the event invokes
6535 * @param {Object} scope An object that becomes the scope of the handler
6536 * @param {boolean} options
6538 onWindowResize : function(fn, scope, options){
6540 resizeEvent = new Roo.util.Event();
6541 resizeTask = new Roo.util.DelayedTask(function(){
6542 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6544 E.on(window, "resize", function(){
6546 resizeTask.delay(50);
6548 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6552 resizeEvent.addListener(fn, scope, options);
6556 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6557 * @param {Function} fn The method the event invokes
6558 * @param {Object} scope An object that becomes the scope of the handler
6559 * @param {boolean} options
6561 onTextResize : function(fn, scope, options){
6563 textEvent = new Roo.util.Event();
6564 var textEl = new Roo.Element(document.createElement('div'));
6565 textEl.dom.className = 'x-text-resize';
6566 textEl.dom.innerHTML = 'X';
6567 textEl.appendTo(document.body);
6568 textSize = textEl.dom.offsetHeight;
6569 setInterval(function(){
6570 if(textEl.dom.offsetHeight != textSize){
6571 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6573 }, this.textResizeInterval);
6575 textEvent.addListener(fn, scope, options);
6579 * Removes the passed window resize listener.
6580 * @param {Function} fn The method the event invokes
6581 * @param {Object} scope The scope of handler
6583 removeResizeListener : function(fn, scope){
6585 resizeEvent.removeListener(fn, scope);
6590 fireResize : function(){
6592 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6596 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6600 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6602 textResizeInterval : 50
6607 * @scopeAlias pub=Roo.EventManager
6611 * Appends an event handler to an element (shorthand for addListener)
6612 * @param {String/HTMLElement} element The html element or id to assign the
6613 * @param {String} eventName The type of event to listen for
6614 * @param {Function} handler The method the event invokes
6615 * @param {Object} scope (optional) The scope in which to execute the handler
6616 * function. The handler function's "this" context.
6617 * @param {Object} options (optional) An object containing handler configuration
6618 * properties. This may contain any of the following properties:<ul>
6619 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6620 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6621 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6622 * <li>preventDefault {Boolean} True to prevent the default action</li>
6623 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6624 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6625 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6626 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6627 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6628 * by the specified number of milliseconds. If the event fires again within that time, the original
6629 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6632 * <b>Combining Options</b><br>
6633 * Using the options argument, it is possible to combine different types of listeners:<br>
6635 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6637 el.on('click', this.onClick, this, {
6644 * <b>Attaching multiple handlers in 1 call</b><br>
6645 * The method also allows for a single argument to be passed which is a config object containing properties
6646 * which specify multiple handlers.
6656 fn: this.onMouseOver
6665 * Or a shorthand syntax:<br>
6668 'click' : this.onClick,
6669 'mouseover' : this.onMouseOver,
6670 'mouseout' : this.onMouseOut
6674 pub.on = pub.addListener;
6675 pub.un = pub.removeListener;
6677 pub.stoppedMouseDownEvent = new Roo.util.Event();
6681 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6682 * @param {Function} fn The method the event invokes
6683 * @param {Object} scope An object that becomes the scope of the handler
6684 * @param {boolean} override If true, the obj passed in becomes
6685 * the execution scope of the listener
6689 Roo.onReady = Roo.EventManager.onDocumentReady;
6691 Roo.onReady(function(){
6692 var bd = Roo.get(document.body);
6697 : Roo.isIE11 ? "roo-ie11"
6698 : Roo.isEdge ? "roo-edge"
6699 : Roo.isGecko ? "roo-gecko"
6700 : Roo.isOpera ? "roo-opera"
6701 : Roo.isSafari ? "roo-safari" : ""];
6704 cls.push("roo-mac");
6707 cls.push("roo-linux");
6710 cls.push("roo-ios");
6713 cls.push("roo-touch");
6715 if(Roo.isBorderBox){
6716 cls.push('roo-border-box');
6718 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6719 var p = bd.dom.parentNode;
6721 p.className += ' roo-strict';
6724 bd.addClass(cls.join(' '));
6728 * @class Roo.EventObject
6729 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6730 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6733 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6735 var target = e.getTarget();
6738 var myDiv = Roo.get("myDiv");
6739 myDiv.on("click", handleClick);
6741 Roo.EventManager.on("myDiv", 'click', handleClick);
6742 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6746 Roo.EventObject = function(){
6748 var E = Roo.lib.Event;
6750 // safari keypress events for special keys return bad keycodes
6753 63235 : 39, // right
6756 63276 : 33, // page up
6757 63277 : 34, // page down
6758 63272 : 46, // delete
6763 // normalize button clicks
6764 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6765 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6767 Roo.EventObjectImpl = function(e){
6769 this.setEvent(e.browserEvent || e);
6772 Roo.EventObjectImpl.prototype = {
6774 * Used to fix doc tools.
6775 * @scope Roo.EventObject.prototype
6781 /** The normal browser event */
6782 browserEvent : null,
6783 /** The button pressed in a mouse event */
6785 /** True if the shift key was down during the event */
6787 /** True if the control key was down during the event */
6789 /** True if the alt key was down during the event */
6848 setEvent : function(e){
6849 if(e == this || (e && e.browserEvent)){ // already wrapped
6852 this.browserEvent = e;
6854 // normalize buttons
6855 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6856 if(e.type == 'click' && this.button == -1){
6860 this.shiftKey = e.shiftKey;
6861 // mac metaKey behaves like ctrlKey
6862 this.ctrlKey = e.ctrlKey || e.metaKey;
6863 this.altKey = e.altKey;
6864 // in getKey these will be normalized for the mac
6865 this.keyCode = e.keyCode;
6866 // keyup warnings on firefox.
6867 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6868 // cache the target for the delayed and or buffered events
6869 this.target = E.getTarget(e);
6871 this.xy = E.getXY(e);
6874 this.shiftKey = false;
6875 this.ctrlKey = false;
6876 this.altKey = false;
6886 * Stop the event (preventDefault and stopPropagation)
6888 stopEvent : function(){
6889 if(this.browserEvent){
6890 if(this.browserEvent.type == 'mousedown'){
6891 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6893 E.stopEvent(this.browserEvent);
6898 * Prevents the browsers default handling of the event.
6900 preventDefault : function(){
6901 if(this.browserEvent){
6902 E.preventDefault(this.browserEvent);
6907 isNavKeyPress : function(){
6908 var k = this.keyCode;
6909 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6910 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6913 isSpecialKey : function(){
6914 var k = this.keyCode;
6915 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6916 (k == 16) || (k == 17) ||
6917 (k >= 18 && k <= 20) ||
6918 (k >= 33 && k <= 35) ||
6919 (k >= 36 && k <= 39) ||
6920 (k >= 44 && k <= 45);
6923 * Cancels bubbling of the event.
6925 stopPropagation : function(){
6926 if(this.browserEvent){
6927 if(this.type == 'mousedown'){
6928 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6930 E.stopPropagation(this.browserEvent);
6935 * Gets the key code for the event.
6938 getCharCode : function(){
6939 return this.charCode || this.keyCode;
6943 * Returns a normalized keyCode for the event.
6944 * @return {Number} The key code
6946 getKey : function(){
6947 var k = this.keyCode || this.charCode;
6948 return Roo.isSafari ? (safariKeys[k] || k) : k;
6952 * Gets the x coordinate of the event.
6955 getPageX : function(){
6960 * Gets the y coordinate of the event.
6963 getPageY : function(){
6968 * Gets the time of the event.
6971 getTime : function(){
6972 if(this.browserEvent){
6973 return E.getTime(this.browserEvent);
6979 * Gets the page coordinates of the event.
6980 * @return {Array} The xy values like [x, y]
6987 * Gets the target for the event.
6988 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6989 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6990 search as a number or element (defaults to 10 || document.body)
6991 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6992 * @return {HTMLelement}
6994 getTarget : function(selector, maxDepth, returnEl){
6995 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6998 * Gets the related target.
6999 * @return {HTMLElement}
7001 getRelatedTarget : function(){
7002 if(this.browserEvent){
7003 return E.getRelatedTarget(this.browserEvent);
7009 * Normalizes mouse wheel delta across browsers
7010 * @return {Number} The delta
7012 getWheelDelta : function(){
7013 var e = this.browserEvent;
7015 if(e.wheelDelta){ /* IE/Opera. */
7016 delta = e.wheelDelta/120;
7017 }else if(e.detail){ /* Mozilla case. */
7018 delta = -e.detail/3;
7024 * Returns true if the control, meta, shift or alt key was pressed during this event.
7027 hasModifier : function(){
7028 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7032 * Returns true if the target of this event equals el or is a child of el
7033 * @param {String/HTMLElement/Element} el
7034 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7037 within : function(el, related){
7038 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7039 return t && Roo.fly(el).contains(t);
7042 getPoint : function(){
7043 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7047 return new Roo.EventObjectImpl();
7052 * Ext JS Library 1.1.1
7053 * Copyright(c) 2006-2007, Ext JS, LLC.
7055 * Originally Released Under LGPL - original licence link has changed is not relivant.
7058 * <script type="text/javascript">
7062 // was in Composite Element!??!?!
7065 var D = Roo.lib.Dom;
7066 var E = Roo.lib.Event;
7067 var A = Roo.lib.Anim;
7069 // local style camelizing for speed
7071 var camelRe = /(-[a-z])/gi;
7072 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7073 var view = document.defaultView;
7076 * @class Roo.Element
7077 * Represents an Element in the DOM.<br><br>
7080 var el = Roo.get("my-div");
7083 var el = getEl("my-div");
7085 // or with a DOM element
7086 var el = Roo.get(myDivElement);
7088 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7089 * each call instead of constructing a new one.<br><br>
7090 * <b>Animations</b><br />
7091 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7092 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7094 Option Default Description
7095 --------- -------- ---------------------------------------------
7096 duration .35 The duration of the animation in seconds
7097 easing easeOut The YUI easing method
7098 callback none A function to execute when the anim completes
7099 scope this The scope (this) of the callback function
7101 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7102 * manipulate the animation. Here's an example:
7104 var el = Roo.get("my-div");
7109 // default animation
7110 el.setWidth(100, true);
7112 // animation with some options set
7119 // using the "anim" property to get the Anim object
7125 el.setWidth(100, opt);
7127 if(opt.anim.isAnimated()){
7131 * <b> Composite (Collections of) Elements</b><br />
7132 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7133 * @constructor Create a new Element directly.
7134 * @param {String/HTMLElement} element
7135 * @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).
7137 Roo.Element = function(element, forceNew){
7138 var dom = typeof element == "string" ?
7139 document.getElementById(element) : element;
7140 if(!dom){ // invalid id/element
7144 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7145 return Roo.Element.cache[id];
7155 * The DOM element ID
7158 this.id = id || Roo.id(dom);
7161 var El = Roo.Element;
7165 * The element's default display mode (defaults to "")
7168 originalDisplay : "",
7171 // note this is overridden in BS version..
7174 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7180 * Sets the element's visibility mode. When setVisible() is called it
7181 * will use this to determine whether to set the visibility or the display property.
7182 * @param visMode Element.VISIBILITY or Element.DISPLAY
7183 * @return {Roo.Element} this
7185 setVisibilityMode : function(visMode){
7186 this.visibilityMode = visMode;
7190 * Convenience method for setVisibilityMode(Element.DISPLAY)
7191 * @param {String} display (optional) What to set display to when visible
7192 * @return {Roo.Element} this
7194 enableDisplayMode : function(display){
7195 this.setVisibilityMode(El.DISPLAY);
7196 if(typeof display != "undefined") { this.originalDisplay = display; }
7201 * 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)
7202 * @param {String} selector The simple selector to test
7203 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7204 search as a number or element (defaults to 10 || document.body)
7205 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7206 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7208 findParent : function(simpleSelector, maxDepth, returnEl){
7209 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7210 maxDepth = maxDepth || 50;
7211 if(typeof maxDepth != "number"){
7212 stopEl = Roo.getDom(maxDepth);
7215 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7216 if(dq.is(p, simpleSelector)){
7217 return returnEl ? Roo.get(p) : p;
7227 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7228 * @param {String} selector The simple selector to test
7229 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7230 search as a number or element (defaults to 10 || document.body)
7231 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7232 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7234 findParentNode : function(simpleSelector, maxDepth, returnEl){
7235 var p = Roo.fly(this.dom.parentNode, '_internal');
7236 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7240 * Looks at the scrollable parent element
7242 findScrollableParent : function()
7244 var overflowRegex = /(auto|scroll)/;
7246 if(this.getStyle('position') === 'fixed'){
7247 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7250 var excludeStaticParent = this.getStyle('position') === "absolute";
7252 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7254 if (excludeStaticParent && parent.getStyle('position') === "static") {
7258 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7262 if(parent.dom.nodeName.toLowerCase() == 'body'){
7263 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7267 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7271 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7272 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7273 * @param {String} selector The simple selector to test
7274 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7275 search as a number or element (defaults to 10 || document.body)
7276 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7278 up : function(simpleSelector, maxDepth){
7279 return this.findParentNode(simpleSelector, maxDepth, true);
7285 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7286 * @param {String} selector The simple selector to test
7287 * @return {Boolean} True if this element matches the selector, else false
7289 is : function(simpleSelector){
7290 return Roo.DomQuery.is(this.dom, simpleSelector);
7294 * Perform animation on this element.
7295 * @param {Object} args The YUI animation control args
7296 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7297 * @param {Function} onComplete (optional) Function to call when animation completes
7298 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7299 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7300 * @return {Roo.Element} this
7302 animate : function(args, duration, onComplete, easing, animType){
7303 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7308 * @private Internal animation call
7310 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7311 animType = animType || 'run';
7313 var anim = Roo.lib.Anim[animType](
7315 (opt.duration || defaultDur) || .35,
7316 (opt.easing || defaultEase) || 'easeOut',
7318 Roo.callback(cb, this);
7319 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7327 // private legacy anim prep
7328 preanim : function(a, i){
7329 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7333 * Removes worthless text nodes
7334 * @param {Boolean} forceReclean (optional) By default the element
7335 * keeps track if it has been cleaned already so
7336 * you can call this over and over. However, if you update the element and
7337 * need to force a reclean, you can pass true.
7339 clean : function(forceReclean){
7340 if(this.isCleaned && forceReclean !== true){
7344 var d = this.dom, n = d.firstChild, ni = -1;
7346 var nx = n.nextSibling;
7347 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7354 this.isCleaned = true;
7359 calcOffsetsTo : function(el){
7362 var restorePos = false;
7363 if(el.getStyle('position') == 'static'){
7364 el.position('relative');
7369 while(op && op != d && op.tagName != 'HTML'){
7372 op = op.offsetParent;
7375 el.position('static');
7381 * Scrolls this element into view within the passed container.
7382 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7383 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7384 * @return {Roo.Element} this
7386 scrollIntoView : function(container, hscroll){
7387 var c = Roo.getDom(container) || document.body;
7390 var o = this.calcOffsetsTo(c),
7393 b = t+el.offsetHeight,
7394 r = l+el.offsetWidth;
7396 var ch = c.clientHeight;
7397 var ct = parseInt(c.scrollTop, 10);
7398 var cl = parseInt(c.scrollLeft, 10);
7400 var cr = cl + c.clientWidth;
7408 if(hscroll !== false){
7412 c.scrollLeft = r-c.clientWidth;
7419 scrollChildIntoView : function(child, hscroll){
7420 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7424 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7425 * the new height may not be available immediately.
7426 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7427 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7428 * @param {Function} onComplete (optional) Function to call when animation completes
7429 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7430 * @return {Roo.Element} this
7432 autoHeight : function(animate, duration, onComplete, easing){
7433 var oldHeight = this.getHeight();
7435 this.setHeight(1); // force clipping
7436 setTimeout(function(){
7437 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7439 this.setHeight(height);
7441 if(typeof onComplete == "function"){
7445 this.setHeight(oldHeight); // restore original height
7446 this.setHeight(height, animate, duration, function(){
7448 if(typeof onComplete == "function") { onComplete(); }
7449 }.createDelegate(this), easing);
7451 }.createDelegate(this), 0);
7456 * Returns true if this element is an ancestor of the passed element
7457 * @param {HTMLElement/String} el The element to check
7458 * @return {Boolean} True if this element is an ancestor of el, else false
7460 contains : function(el){
7461 if(!el){return false;}
7462 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7466 * Checks whether the element is currently visible using both visibility and display properties.
7467 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7468 * @return {Boolean} True if the element is currently visible, else false
7470 isVisible : function(deep) {
7471 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7472 if(deep !== true || !vis){
7475 var p = this.dom.parentNode;
7476 while(p && p.tagName.toLowerCase() != "body"){
7477 if(!Roo.fly(p, '_isVisible').isVisible()){
7486 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7487 * @param {String} selector The CSS selector
7488 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7489 * @return {CompositeElement/CompositeElementLite} The composite element
7491 select : function(selector, unique){
7492 return El.select(selector, unique, this.dom);
7496 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7497 * @param {String} selector The CSS selector
7498 * @return {Array} An array of the matched nodes
7500 query : function(selector, unique){
7501 return Roo.DomQuery.select(selector, this.dom);
7505 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7506 * @param {String} selector The CSS selector
7507 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7508 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7510 child : function(selector, returnDom){
7511 var n = Roo.DomQuery.selectNode(selector, this.dom);
7512 return returnDom ? n : Roo.get(n);
7516 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7517 * @param {String} selector The CSS selector
7518 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7519 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7521 down : function(selector, returnDom){
7522 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7523 return returnDom ? n : Roo.get(n);
7527 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7528 * @param {String} group The group the DD object is member of
7529 * @param {Object} config The DD config object
7530 * @param {Object} overrides An object containing methods to override/implement on the DD object
7531 * @return {Roo.dd.DD} The DD object
7533 initDD : function(group, config, overrides){
7534 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7535 return Roo.apply(dd, overrides);
7539 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7540 * @param {String} group The group the DDProxy object is member of
7541 * @param {Object} config The DDProxy config object
7542 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7543 * @return {Roo.dd.DDProxy} The DDProxy object
7545 initDDProxy : function(group, config, overrides){
7546 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7547 return Roo.apply(dd, overrides);
7551 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7552 * @param {String} group The group the DDTarget object is member of
7553 * @param {Object} config The DDTarget config object
7554 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7555 * @return {Roo.dd.DDTarget} The DDTarget object
7557 initDDTarget : function(group, config, overrides){
7558 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7559 return Roo.apply(dd, overrides);
7563 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7564 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7565 * @param {Boolean} visible Whether the element is visible
7566 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7567 * @return {Roo.Element} this
7569 setVisible : function(visible, animate){
7571 if(this.visibilityMode == El.DISPLAY){
7572 this.setDisplayed(visible);
7575 this.dom.style.visibility = visible ? "visible" : "hidden";
7578 // closure for composites
7580 var visMode = this.visibilityMode;
7582 this.setOpacity(.01);
7583 this.setVisible(true);
7585 this.anim({opacity: { to: (visible?1:0) }},
7586 this.preanim(arguments, 1),
7587 null, .35, 'easeIn', function(){
7589 if(visMode == El.DISPLAY){
7590 dom.style.display = "none";
7592 dom.style.visibility = "hidden";
7594 Roo.get(dom).setOpacity(1);
7602 * Returns true if display is not "none"
7605 isDisplayed : function() {
7606 return this.getStyle("display") != "none";
7610 * Toggles the element's visibility or display, depending on visibility mode.
7611 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7612 * @return {Roo.Element} this
7614 toggle : function(animate){
7615 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7620 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7621 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7622 * @return {Roo.Element} this
7624 setDisplayed : function(value) {
7625 if(typeof value == "boolean"){
7626 value = value ? this.originalDisplay : "none";
7628 this.setStyle("display", value);
7633 * Tries to focus the element. Any exceptions are caught and ignored.
7634 * @return {Roo.Element} this
7636 focus : function() {
7644 * Tries to blur the element. Any exceptions are caught and ignored.
7645 * @return {Roo.Element} this
7655 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7656 * @param {String/Array} className The CSS class to add, or an array of classes
7657 * @return {Roo.Element} this
7659 addClass : function(className){
7660 if(className instanceof Array){
7661 for(var i = 0, len = className.length; i < len; i++) {
7662 this.addClass(className[i]);
7665 if(className && !this.hasClass(className)){
7666 this.dom.className = this.dom.className + " " + className;
7673 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7674 * @param {String/Array} className The CSS class to add, or an array of classes
7675 * @return {Roo.Element} this
7677 radioClass : function(className){
7678 var siblings = this.dom.parentNode.childNodes;
7679 for(var i = 0; i < siblings.length; i++) {
7680 var s = siblings[i];
7681 if(s.nodeType == 1){
7682 Roo.get(s).removeClass(className);
7685 this.addClass(className);
7690 * Removes one or more CSS classes from the element.
7691 * @param {String/Array} className The CSS class to remove, or an array of classes
7692 * @return {Roo.Element} this
7694 removeClass : function(className){
7695 if(!className || !this.dom.className){
7698 if(className instanceof Array){
7699 for(var i = 0, len = className.length; i < len; i++) {
7700 this.removeClass(className[i]);
7703 if(this.hasClass(className)){
7704 var re = this.classReCache[className];
7706 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7707 this.classReCache[className] = re;
7709 this.dom.className =
7710 this.dom.className.replace(re, " ");
7720 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7721 * @param {String} className The CSS class to toggle
7722 * @return {Roo.Element} this
7724 toggleClass : function(className){
7725 if(this.hasClass(className)){
7726 this.removeClass(className);
7728 this.addClass(className);
7734 * Checks if the specified CSS class exists on this element's DOM node.
7735 * @param {String} className The CSS class to check for
7736 * @return {Boolean} True if the class exists, else false
7738 hasClass : function(className){
7739 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7743 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7744 * @param {String} oldClassName The CSS class to replace
7745 * @param {String} newClassName The replacement CSS class
7746 * @return {Roo.Element} this
7748 replaceClass : function(oldClassName, newClassName){
7749 this.removeClass(oldClassName);
7750 this.addClass(newClassName);
7755 * Returns an object with properties matching the styles requested.
7756 * For example, el.getStyles('color', 'font-size', 'width') might return
7757 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7758 * @param {String} style1 A style name
7759 * @param {String} style2 A style name
7760 * @param {String} etc.
7761 * @return {Object} The style object
7763 getStyles : function(){
7764 var a = arguments, len = a.length, r = {};
7765 for(var i = 0; i < len; i++){
7766 r[a[i]] = this.getStyle(a[i]);
7772 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7773 * @param {String} property The style property whose value is returned.
7774 * @return {String} The current value of the style property for this element.
7776 getStyle : function(){
7777 return view && view.getComputedStyle ?
7779 var el = this.dom, v, cs, camel;
7780 if(prop == 'float'){
7783 if(el.style && (v = el.style[prop])){
7786 if(cs = view.getComputedStyle(el, "")){
7787 if(!(camel = propCache[prop])){
7788 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7795 var el = this.dom, v, cs, camel;
7796 if(prop == 'opacity'){
7797 if(typeof el.style.filter == 'string'){
7798 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7800 var fv = parseFloat(m[1]);
7802 return fv ? fv / 100 : 0;
7807 }else if(prop == 'float'){
7808 prop = "styleFloat";
7810 if(!(camel = propCache[prop])){
7811 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7813 if(v = el.style[camel]){
7816 if(cs = el.currentStyle){
7824 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7825 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7826 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7827 * @return {Roo.Element} this
7829 setStyle : function(prop, value){
7830 if(typeof prop == "string"){
7832 if (prop == 'float') {
7833 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7838 if(!(camel = propCache[prop])){
7839 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7842 if(camel == 'opacity') {
7843 this.setOpacity(value);
7845 this.dom.style[camel] = value;
7848 for(var style in prop){
7849 if(typeof prop[style] != "function"){
7850 this.setStyle(style, prop[style]);
7858 * More flexible version of {@link #setStyle} for setting style properties.
7859 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7860 * a function which returns such a specification.
7861 * @return {Roo.Element} this
7863 applyStyles : function(style){
7864 Roo.DomHelper.applyStyles(this.dom, style);
7869 * 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).
7870 * @return {Number} The X position of the element
7873 return D.getX(this.dom);
7877 * 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).
7878 * @return {Number} The Y position of the element
7881 return D.getY(this.dom);
7885 * 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).
7886 * @return {Array} The XY position of the element
7889 return D.getXY(this.dom);
7893 * 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).
7894 * @param {Number} The X position of the element
7895 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7896 * @return {Roo.Element} this
7898 setX : function(x, animate){
7900 D.setX(this.dom, x);
7902 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7908 * 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).
7909 * @param {Number} The Y position of the element
7910 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7911 * @return {Roo.Element} this
7913 setY : function(y, animate){
7915 D.setY(this.dom, y);
7917 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7923 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7924 * @param {String} left The left CSS property value
7925 * @return {Roo.Element} this
7927 setLeft : function(left){
7928 this.setStyle("left", this.addUnits(left));
7933 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7934 * @param {String} top The top CSS property value
7935 * @return {Roo.Element} this
7937 setTop : function(top){
7938 this.setStyle("top", this.addUnits(top));
7943 * Sets the element's CSS right style.
7944 * @param {String} right The right CSS property value
7945 * @return {Roo.Element} this
7947 setRight : function(right){
7948 this.setStyle("right", this.addUnits(right));
7953 * Sets the element's CSS bottom style.
7954 * @param {String} bottom The bottom CSS property value
7955 * @return {Roo.Element} this
7957 setBottom : function(bottom){
7958 this.setStyle("bottom", this.addUnits(bottom));
7963 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7964 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7965 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7966 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7967 * @return {Roo.Element} this
7969 setXY : function(pos, animate){
7971 D.setXY(this.dom, pos);
7973 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7979 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7980 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7981 * @param {Number} x X value for new position (coordinates are page-based)
7982 * @param {Number} y Y value for new position (coordinates are page-based)
7983 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7984 * @return {Roo.Element} this
7986 setLocation : function(x, y, animate){
7987 this.setXY([x, y], this.preanim(arguments, 2));
7992 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7993 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7994 * @param {Number} x X value for new position (coordinates are page-based)
7995 * @param {Number} y Y value for new position (coordinates are page-based)
7996 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7997 * @return {Roo.Element} this
7999 moveTo : function(x, y, animate){
8000 this.setXY([x, y], this.preanim(arguments, 2));
8005 * Returns the region of the given element.
8006 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8007 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8009 getRegion : function(){
8010 return D.getRegion(this.dom);
8014 * Returns the offset height of the element
8015 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8016 * @return {Number} The element's height
8018 getHeight : function(contentHeight){
8019 var h = this.dom.offsetHeight || 0;
8020 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8024 * Returns the offset width of the element
8025 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8026 * @return {Number} The element's width
8028 getWidth : function(contentWidth){
8029 var w = this.dom.offsetWidth || 0;
8030 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8034 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8035 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8036 * if a height has not been set using CSS.
8039 getComputedHeight : function(){
8040 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8042 h = parseInt(this.getStyle('height'), 10) || 0;
8043 if(!this.isBorderBox()){
8044 h += this.getFrameWidth('tb');
8051 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8052 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8053 * if a width has not been set using CSS.
8056 getComputedWidth : function(){
8057 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8059 w = parseInt(this.getStyle('width'), 10) || 0;
8060 if(!this.isBorderBox()){
8061 w += this.getFrameWidth('lr');
8068 * Returns the size of the element.
8069 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8070 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8072 getSize : function(contentSize){
8073 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8077 * Returns the width and height of the viewport.
8078 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8080 getViewSize : function(){
8081 var d = this.dom, doc = document, aw = 0, ah = 0;
8082 if(d == doc || d == doc.body){
8083 return {width : D.getViewWidth(), height: D.getViewHeight()};
8086 width : d.clientWidth,
8087 height: d.clientHeight
8093 * Returns the value of the "value" attribute
8094 * @param {Boolean} asNumber true to parse the value as a number
8095 * @return {String/Number}
8097 getValue : function(asNumber){
8098 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8102 adjustWidth : function(width){
8103 if(typeof width == "number"){
8104 if(this.autoBoxAdjust && !this.isBorderBox()){
8105 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8115 adjustHeight : function(height){
8116 if(typeof height == "number"){
8117 if(this.autoBoxAdjust && !this.isBorderBox()){
8118 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8128 * Set the width of the element
8129 * @param {Number} width The new width
8130 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8131 * @return {Roo.Element} this
8133 setWidth : function(width, animate){
8134 width = this.adjustWidth(width);
8136 this.dom.style.width = this.addUnits(width);
8138 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8144 * Set the height of the element
8145 * @param {Number} height The new height
8146 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8147 * @return {Roo.Element} this
8149 setHeight : function(height, animate){
8150 height = this.adjustHeight(height);
8152 this.dom.style.height = this.addUnits(height);
8154 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8160 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8161 * @param {Number} width The new width
8162 * @param {Number} height The new height
8163 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8164 * @return {Roo.Element} this
8166 setSize : function(width, height, animate){
8167 if(typeof width == "object"){ // in case of object from getSize()
8168 height = width.height; width = width.width;
8170 width = this.adjustWidth(width); height = this.adjustHeight(height);
8172 this.dom.style.width = this.addUnits(width);
8173 this.dom.style.height = this.addUnits(height);
8175 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8181 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8182 * @param {Number} x X value for new position (coordinates are page-based)
8183 * @param {Number} y Y value for new position (coordinates are page-based)
8184 * @param {Number} width The new width
8185 * @param {Number} height The new height
8186 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8187 * @return {Roo.Element} this
8189 setBounds : function(x, y, width, height, animate){
8191 this.setSize(width, height);
8192 this.setLocation(x, y);
8194 width = this.adjustWidth(width); height = this.adjustHeight(height);
8195 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8196 this.preanim(arguments, 4), 'motion');
8202 * 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.
8203 * @param {Roo.lib.Region} region The region to fill
8204 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8205 * @return {Roo.Element} this
8207 setRegion : function(region, animate){
8208 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8213 * Appends an event handler
8215 * @param {String} eventName The type of event to append
8216 * @param {Function} fn The method the event invokes
8217 * @param {Object} scope (optional) The scope (this object) of the fn
8218 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8220 addListener : function(eventName, fn, scope, options){
8222 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8227 * Removes an event handler from this element
8228 * @param {String} eventName the type of event to remove
8229 * @param {Function} fn the method the event invokes
8230 * @return {Roo.Element} this
8232 removeListener : function(eventName, fn){
8233 Roo.EventManager.removeListener(this.dom, eventName, fn);
8238 * Removes all previous added listeners from this element
8239 * @return {Roo.Element} this
8241 removeAllListeners : function(){
8242 E.purgeElement(this.dom);
8246 relayEvent : function(eventName, observable){
8247 this.on(eventName, function(e){
8248 observable.fireEvent(eventName, e);
8253 * Set the opacity of the element
8254 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8255 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8256 * @return {Roo.Element} this
8258 setOpacity : function(opacity, animate){
8260 var s = this.dom.style;
8263 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8264 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8266 s.opacity = opacity;
8269 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8275 * Gets the left X coordinate
8276 * @param {Boolean} local True to get the local css position instead of page coordinate
8279 getLeft : function(local){
8283 return parseInt(this.getStyle("left"), 10) || 0;
8288 * Gets the right X coordinate of the element (element X position + element width)
8289 * @param {Boolean} local True to get the local css position instead of page coordinate
8292 getRight : function(local){
8294 return this.getX() + this.getWidth();
8296 return (this.getLeft(true) + this.getWidth()) || 0;
8301 * Gets the top Y coordinate
8302 * @param {Boolean} local True to get the local css position instead of page coordinate
8305 getTop : function(local) {
8309 return parseInt(this.getStyle("top"), 10) || 0;
8314 * Gets the bottom Y coordinate of the element (element Y position + element height)
8315 * @param {Boolean} local True to get the local css position instead of page coordinate
8318 getBottom : function(local){
8320 return this.getY() + this.getHeight();
8322 return (this.getTop(true) + this.getHeight()) || 0;
8327 * Initializes positioning on this element. If a desired position is not passed, it will make the
8328 * the element positioned relative IF it is not already positioned.
8329 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8330 * @param {Number} zIndex (optional) The zIndex to apply
8331 * @param {Number} x (optional) Set the page X position
8332 * @param {Number} y (optional) Set the page Y position
8334 position : function(pos, zIndex, x, y){
8336 if(this.getStyle('position') == 'static'){
8337 this.setStyle('position', 'relative');
8340 this.setStyle("position", pos);
8343 this.setStyle("z-index", zIndex);
8345 if(x !== undefined && y !== undefined){
8347 }else if(x !== undefined){
8349 }else if(y !== undefined){
8355 * Clear positioning back to the default when the document was loaded
8356 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8357 * @return {Roo.Element} this
8359 clearPositioning : function(value){
8367 "position" : "static"
8373 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8374 * snapshot before performing an update and then restoring the element.
8377 getPositioning : function(){
8378 var l = this.getStyle("left");
8379 var t = this.getStyle("top");
8381 "position" : this.getStyle("position"),
8383 "right" : l ? "" : this.getStyle("right"),
8385 "bottom" : t ? "" : this.getStyle("bottom"),
8386 "z-index" : this.getStyle("z-index")
8391 * Gets the width of the border(s) for the specified side(s)
8392 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8393 * passing lr would get the border (l)eft width + the border (r)ight width.
8394 * @return {Number} The width of the sides passed added together
8396 getBorderWidth : function(side){
8397 return this.addStyles(side, El.borders);
8401 * Gets the width of the padding(s) for the specified side(s)
8402 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8403 * passing lr would get the padding (l)eft + the padding (r)ight.
8404 * @return {Number} The padding of the sides passed added together
8406 getPadding : function(side){
8407 return this.addStyles(side, El.paddings);
8411 * Set positioning with an object returned by getPositioning().
8412 * @param {Object} posCfg
8413 * @return {Roo.Element} this
8415 setPositioning : function(pc){
8416 this.applyStyles(pc);
8417 if(pc.right == "auto"){
8418 this.dom.style.right = "";
8420 if(pc.bottom == "auto"){
8421 this.dom.style.bottom = "";
8427 fixDisplay : function(){
8428 if(this.getStyle("display") == "none"){
8429 this.setStyle("visibility", "hidden");
8430 this.setStyle("display", this.originalDisplay); // first try reverting to default
8431 if(this.getStyle("display") == "none"){ // if that fails, default to block
8432 this.setStyle("display", "block");
8438 * Quick set left and top adding default units
8439 * @param {String} left The left CSS property value
8440 * @param {String} top The top CSS property value
8441 * @return {Roo.Element} this
8443 setLeftTop : function(left, top){
8444 this.dom.style.left = this.addUnits(left);
8445 this.dom.style.top = this.addUnits(top);
8450 * Move this element relative to its current position.
8451 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8452 * @param {Number} distance How far to move the element in pixels
8453 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8454 * @return {Roo.Element} this
8456 move : function(direction, distance, animate){
8457 var xy = this.getXY();
8458 direction = direction.toLowerCase();
8462 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8466 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8471 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8476 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8483 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8484 * @return {Roo.Element} this
8487 if(!this.isClipped){
8488 this.isClipped = true;
8489 this.originalClip = {
8490 "o": this.getStyle("overflow"),
8491 "x": this.getStyle("overflow-x"),
8492 "y": this.getStyle("overflow-y")
8494 this.setStyle("overflow", "hidden");
8495 this.setStyle("overflow-x", "hidden");
8496 this.setStyle("overflow-y", "hidden");
8502 * Return clipping (overflow) to original clipping before clip() was called
8503 * @return {Roo.Element} this
8505 unclip : function(){
8507 this.isClipped = false;
8508 var o = this.originalClip;
8509 if(o.o){this.setStyle("overflow", o.o);}
8510 if(o.x){this.setStyle("overflow-x", o.x);}
8511 if(o.y){this.setStyle("overflow-y", o.y);}
8518 * Gets the x,y coordinates specified by the anchor position on the element.
8519 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8520 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8521 * {width: (target width), height: (target height)} (defaults to the element's current size)
8522 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8523 * @return {Array} [x, y] An array containing the element's x and y coordinates
8525 getAnchorXY : function(anchor, local, s){
8526 //Passing a different size is useful for pre-calculating anchors,
8527 //especially for anchored animations that change the el size.
8529 var w, h, vp = false;
8532 if(d == document.body || d == document){
8534 w = D.getViewWidth(); h = D.getViewHeight();
8536 w = this.getWidth(); h = this.getHeight();
8539 w = s.width; h = s.height;
8541 var x = 0, y = 0, r = Math.round;
8542 switch((anchor || "tl").toLowerCase()){
8584 var sc = this.getScroll();
8585 return [x + sc.left, y + sc.top];
8587 //Add the element's offset xy
8588 var o = this.getXY();
8589 return [x+o[0], y+o[1]];
8593 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8594 * supported position values.
8595 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8596 * @param {String} position The position to align to.
8597 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8598 * @return {Array} [x, y]
8600 getAlignToXY : function(el, p, o)
8605 throw "Element.alignTo with an element that doesn't exist";
8607 var c = false; //constrain to viewport
8608 var p1 = "", p2 = "";
8615 }else if(p.indexOf("-") == -1){
8618 p = p.toLowerCase();
8619 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8621 throw "Element.alignTo with an invalid alignment " + p;
8623 p1 = m[1]; p2 = m[2]; c = !!m[3];
8625 //Subtract the aligned el's internal xy from the target's offset xy
8626 //plus custom offset to get the aligned el's new offset xy
8627 var a1 = this.getAnchorXY(p1, true);
8628 var a2 = el.getAnchorXY(p2, false);
8629 var x = a2[0] - a1[0] + o[0];
8630 var y = a2[1] - a1[1] + o[1];
8632 //constrain the aligned el to viewport if necessary
8633 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8634 // 5px of margin for ie
8635 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8637 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8638 //perpendicular to the vp border, allow the aligned el to slide on that border,
8639 //otherwise swap the aligned el to the opposite border of the target.
8640 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8641 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8642 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8643 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8646 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8647 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8649 if((x+w) > dw + scrollX){
8650 x = swapX ? r.left-w : dw+scrollX-w;
8653 x = swapX ? r.right : scrollX;
8655 if((y+h) > dh + scrollY){
8656 y = swapY ? r.top-h : dh+scrollY-h;
8659 y = swapY ? r.bottom : scrollY;
8666 getConstrainToXY : function(){
8667 var os = {top:0, left:0, bottom:0, right: 0};
8669 return function(el, local, offsets, proposedXY){
8671 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8673 var vw, vh, vx = 0, vy = 0;
8674 if(el.dom == document.body || el.dom == document){
8675 vw = Roo.lib.Dom.getViewWidth();
8676 vh = Roo.lib.Dom.getViewHeight();
8678 vw = el.dom.clientWidth;
8679 vh = el.dom.clientHeight;
8681 var vxy = el.getXY();
8687 var s = el.getScroll();
8689 vx += offsets.left + s.left;
8690 vy += offsets.top + s.top;
8692 vw -= offsets.right;
8693 vh -= offsets.bottom;
8698 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8699 var x = xy[0], y = xy[1];
8700 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8702 // only move it if it needs it
8705 // first validate right/bottom
8714 // then make sure top/left isn't negative
8723 return moved ? [x, y] : false;
8728 adjustForConstraints : function(xy, parent, offsets){
8729 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8733 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8734 * document it aligns it to the viewport.
8735 * The position parameter is optional, and can be specified in any one of the following formats:
8737 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8738 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8739 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8740 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8741 * <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
8742 * element's anchor point, and the second value is used as the target's anchor point.</li>
8744 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8745 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8746 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8747 * that specified in order to enforce the viewport constraints.
8748 * Following are all of the supported anchor positions:
8751 ----- -----------------------------
8752 tl The top left corner (default)
8753 t The center of the top edge
8754 tr The top right corner
8755 l The center of the left edge
8756 c In the center of the element
8757 r The center of the right edge
8758 bl The bottom left corner
8759 b The center of the bottom edge
8760 br The bottom right corner
8764 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8765 el.alignTo("other-el");
8767 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8768 el.alignTo("other-el", "tr?");
8770 // align the bottom right corner of el with the center left edge of other-el
8771 el.alignTo("other-el", "br-l?");
8773 // align the center of el with the bottom left corner of other-el and
8774 // adjust the x position by -6 pixels (and the y position by 0)
8775 el.alignTo("other-el", "c-bl", [-6, 0]);
8777 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8778 * @param {String} position The position to align to.
8779 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8780 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8781 * @return {Roo.Element} this
8783 alignTo : function(element, position, offsets, animate){
8784 var xy = this.getAlignToXY(element, position, offsets);
8785 this.setXY(xy, this.preanim(arguments, 3));
8790 * Anchors an element to another element and realigns it when the window is resized.
8791 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8792 * @param {String} position The position to align to.
8793 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8794 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8795 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8796 * is a number, it is used as the buffer delay (defaults to 50ms).
8797 * @param {Function} callback The function to call after the animation finishes
8798 * @return {Roo.Element} this
8800 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8801 var action = function(){
8802 this.alignTo(el, alignment, offsets, animate);
8803 Roo.callback(callback, this);
8805 Roo.EventManager.onWindowResize(action, this);
8806 var tm = typeof monitorScroll;
8807 if(tm != 'undefined'){
8808 Roo.EventManager.on(window, 'scroll', action, this,
8809 {buffer: tm == 'number' ? monitorScroll : 50});
8811 action.call(this); // align immediately
8815 * Clears any opacity settings from this element. Required in some cases for IE.
8816 * @return {Roo.Element} this
8818 clearOpacity : function(){
8819 if (window.ActiveXObject) {
8820 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8821 this.dom.style.filter = "";
8824 this.dom.style.opacity = "";
8825 this.dom.style["-moz-opacity"] = "";
8826 this.dom.style["-khtml-opacity"] = "";
8832 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8833 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8834 * @return {Roo.Element} this
8836 hide : function(animate){
8837 this.setVisible(false, this.preanim(arguments, 0));
8842 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8843 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8844 * @return {Roo.Element} this
8846 show : function(animate){
8847 this.setVisible(true, this.preanim(arguments, 0));
8852 * @private Test if size has a unit, otherwise appends the default
8854 addUnits : function(size){
8855 return Roo.Element.addUnits(size, this.defaultUnit);
8859 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8860 * @return {Roo.Element} this
8862 beginMeasure : function(){
8864 if(el.offsetWidth || el.offsetHeight){
8865 return this; // offsets work already
8868 var p = this.dom, b = document.body; // start with this element
8869 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8870 var pe = Roo.get(p);
8871 if(pe.getStyle('display') == 'none'){
8872 changed.push({el: p, visibility: pe.getStyle("visibility")});
8873 p.style.visibility = "hidden";
8874 p.style.display = "block";
8878 this._measureChanged = changed;
8884 * Restores displays to before beginMeasure was called
8885 * @return {Roo.Element} this
8887 endMeasure : function(){
8888 var changed = this._measureChanged;
8890 for(var i = 0, len = changed.length; i < len; i++) {
8892 r.el.style.visibility = r.visibility;
8893 r.el.style.display = "none";
8895 this._measureChanged = null;
8901 * Update the innerHTML of this element, optionally searching for and processing scripts
8902 * @param {String} html The new HTML
8903 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8904 * @param {Function} callback For async script loading you can be noticed when the update completes
8905 * @return {Roo.Element} this
8907 update : function(html, loadScripts, callback){
8908 if(typeof html == "undefined"){
8911 if(loadScripts !== true){
8912 this.dom.innerHTML = html;
8913 if(typeof callback == "function"){
8921 html += '<span id="' + id + '"></span>';
8923 E.onAvailable(id, function(){
8924 var hd = document.getElementsByTagName("head")[0];
8925 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8926 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8927 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8930 while(match = re.exec(html)){
8931 var attrs = match[1];
8932 var srcMatch = attrs ? attrs.match(srcRe) : false;
8933 if(srcMatch && srcMatch[2]){
8934 var s = document.createElement("script");
8935 s.src = srcMatch[2];
8936 var typeMatch = attrs.match(typeRe);
8937 if(typeMatch && typeMatch[2]){
8938 s.type = typeMatch[2];
8941 }else if(match[2] && match[2].length > 0){
8942 if(window.execScript) {
8943 window.execScript(match[2]);
8951 window.eval(match[2]);
8955 var el = document.getElementById(id);
8956 if(el){el.parentNode.removeChild(el);}
8957 if(typeof callback == "function"){
8961 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8966 * Direct access to the UpdateManager update() method (takes the same parameters).
8967 * @param {String/Function} url The url for this request or a function to call to get the url
8968 * @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}
8969 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8970 * @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.
8971 * @return {Roo.Element} this
8974 var um = this.getUpdateManager();
8975 um.update.apply(um, arguments);
8980 * Gets this element's UpdateManager
8981 * @return {Roo.UpdateManager} The UpdateManager
8983 getUpdateManager : function(){
8984 if(!this.updateManager){
8985 this.updateManager = new Roo.UpdateManager(this);
8987 return this.updateManager;
8991 * Disables text selection for this element (normalized across browsers)
8992 * @return {Roo.Element} this
8994 unselectable : function(){
8995 this.dom.unselectable = "on";
8996 this.swallowEvent("selectstart", true);
8997 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8998 this.addClass("x-unselectable");
9003 * Calculates the x, y to center this element on the screen
9004 * @return {Array} The x, y values [x, y]
9006 getCenterXY : function(){
9007 return this.getAlignToXY(document, 'c-c');
9011 * Centers the Element in either the viewport, or another Element.
9012 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9014 center : function(centerIn){
9015 this.alignTo(centerIn || document, 'c-c');
9020 * Tests various css rules/browsers to determine if this element uses a border box
9023 isBorderBox : function(){
9024 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9028 * Return a box {x, y, width, height} that can be used to set another elements
9029 * size/location to match this element.
9030 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9031 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9032 * @return {Object} box An object in the format {x, y, width, height}
9034 getBox : function(contentBox, local){
9039 var left = parseInt(this.getStyle("left"), 10) || 0;
9040 var top = parseInt(this.getStyle("top"), 10) || 0;
9043 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9045 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9047 var l = this.getBorderWidth("l")+this.getPadding("l");
9048 var r = this.getBorderWidth("r")+this.getPadding("r");
9049 var t = this.getBorderWidth("t")+this.getPadding("t");
9050 var b = this.getBorderWidth("b")+this.getPadding("b");
9051 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)};
9053 bx.right = bx.x + bx.width;
9054 bx.bottom = bx.y + bx.height;
9059 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9060 for more information about the sides.
9061 * @param {String} sides
9064 getFrameWidth : function(sides, onlyContentBox){
9065 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9069 * 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.
9070 * @param {Object} box The box to fill {x, y, width, height}
9071 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9072 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9073 * @return {Roo.Element} this
9075 setBox : function(box, adjust, animate){
9076 var w = box.width, h = box.height;
9077 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9078 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9079 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9081 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9086 * Forces the browser to repaint this element
9087 * @return {Roo.Element} this
9089 repaint : function(){
9091 this.addClass("x-repaint");
9092 setTimeout(function(){
9093 Roo.get(dom).removeClass("x-repaint");
9099 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9100 * then it returns the calculated width of the sides (see getPadding)
9101 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9102 * @return {Object/Number}
9104 getMargins : function(side){
9107 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9108 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9109 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9110 right: parseInt(this.getStyle("margin-right"), 10) || 0
9113 return this.addStyles(side, El.margins);
9118 addStyles : function(sides, styles){
9120 for(var i = 0, len = sides.length; i < len; i++){
9121 v = this.getStyle(styles[sides.charAt(i)]);
9123 w = parseInt(v, 10);
9131 * Creates a proxy element of this element
9132 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9133 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9134 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9135 * @return {Roo.Element} The new proxy element
9137 createProxy : function(config, renderTo, matchBox){
9139 renderTo = Roo.getDom(renderTo);
9141 renderTo = document.body;
9143 config = typeof config == "object" ?
9144 config : {tag : "div", cls: config};
9145 var proxy = Roo.DomHelper.append(renderTo, config, true);
9147 proxy.setBox(this.getBox());
9153 * Puts a mask over this element to disable user interaction. Requires core.css.
9154 * This method can only be applied to elements which accept child nodes.
9155 * @param {String} msg (optional) A message to display in the mask
9156 * @param {String} msgCls (optional) A css class to apply to the msg element
9157 * @return {Element} The mask element
9159 mask : function(msg, msgCls)
9161 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9162 this.setStyle("position", "relative");
9165 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9168 this.addClass("x-masked");
9169 this._mask.setDisplayed(true);
9174 while (dom && dom.style) {
9175 if (!isNaN(parseInt(dom.style.zIndex))) {
9176 z = Math.max(z, parseInt(dom.style.zIndex));
9178 dom = dom.parentNode;
9180 // if we are masking the body - then it hides everything..
9181 if (this.dom == document.body) {
9183 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9184 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9187 if(typeof msg == 'string'){
9189 this._maskMsg = Roo.DomHelper.append(this.dom, {
9190 cls: "roo-el-mask-msg",
9194 cls: 'fa fa-spinner fa-spin'
9202 var mm = this._maskMsg;
9203 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9204 if (mm.dom.lastChild) { // weird IE issue?
9205 mm.dom.lastChild.innerHTML = msg;
9207 mm.setDisplayed(true);
9209 mm.setStyle('z-index', z + 102);
9211 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9212 this._mask.setHeight(this.getHeight());
9214 this._mask.setStyle('z-index', z + 100);
9220 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9221 * it is cached for reuse.
9223 unmask : function(removeEl){
9225 if(removeEl === true){
9226 this._mask.remove();
9229 this._maskMsg.remove();
9230 delete this._maskMsg;
9233 this._mask.setDisplayed(false);
9235 this._maskMsg.setDisplayed(false);
9239 this.removeClass("x-masked");
9243 * Returns true if this element is masked
9246 isMasked : function(){
9247 return this._mask && this._mask.isVisible();
9251 * Creates an iframe shim for this element to keep selects and other windowed objects from
9253 * @return {Roo.Element} The new shim element
9255 createShim : function(){
9256 var el = document.createElement('iframe');
9257 el.frameBorder = 'no';
9258 el.className = 'roo-shim';
9259 if(Roo.isIE && Roo.isSecure){
9260 el.src = Roo.SSL_SECURE_URL;
9262 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9263 shim.autoBoxAdjust = false;
9268 * Removes this element from the DOM and deletes it from the cache
9270 remove : function(){
9271 if(this.dom.parentNode){
9272 this.dom.parentNode.removeChild(this.dom);
9274 delete El.cache[this.dom.id];
9278 * Sets up event handlers to add and remove a css class when the mouse is over this element
9279 * @param {String} className
9280 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9281 * mouseout events for children elements
9282 * @return {Roo.Element} this
9284 addClassOnOver : function(className, preventFlicker){
9285 this.on("mouseover", function(){
9286 Roo.fly(this, '_internal').addClass(className);
9288 var removeFn = function(e){
9289 if(preventFlicker !== true || !e.within(this, true)){
9290 Roo.fly(this, '_internal').removeClass(className);
9293 this.on("mouseout", removeFn, this.dom);
9298 * Sets up event handlers to add and remove a css class when this element has the focus
9299 * @param {String} className
9300 * @return {Roo.Element} this
9302 addClassOnFocus : function(className){
9303 this.on("focus", function(){
9304 Roo.fly(this, '_internal').addClass(className);
9306 this.on("blur", function(){
9307 Roo.fly(this, '_internal').removeClass(className);
9312 * 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)
9313 * @param {String} className
9314 * @return {Roo.Element} this
9316 addClassOnClick : function(className){
9318 this.on("mousedown", function(){
9319 Roo.fly(dom, '_internal').addClass(className);
9320 var d = Roo.get(document);
9321 var fn = function(){
9322 Roo.fly(dom, '_internal').removeClass(className);
9323 d.removeListener("mouseup", fn);
9325 d.on("mouseup", fn);
9331 * Stops the specified event from bubbling and optionally prevents the default action
9332 * @param {String} eventName
9333 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9334 * @return {Roo.Element} this
9336 swallowEvent : function(eventName, preventDefault){
9337 var fn = function(e){
9338 e.stopPropagation();
9343 if(eventName instanceof Array){
9344 for(var i = 0, len = eventName.length; i < len; i++){
9345 this.on(eventName[i], fn);
9349 this.on(eventName, fn);
9356 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9359 * Sizes this element to its parent element's dimensions performing
9360 * neccessary box adjustments.
9361 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9362 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9363 * @return {Roo.Element} this
9365 fitToParent : function(monitorResize, targetParent) {
9366 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9367 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9368 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9371 var p = Roo.get(targetParent || this.dom.parentNode);
9372 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9373 if (monitorResize === true) {
9374 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9375 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9381 * Gets the next sibling, skipping text nodes
9382 * @return {HTMLElement} The next sibling or null
9384 getNextSibling : function(){
9385 var n = this.dom.nextSibling;
9386 while(n && n.nodeType != 1){
9393 * Gets the previous sibling, skipping text nodes
9394 * @return {HTMLElement} The previous sibling or null
9396 getPrevSibling : function(){
9397 var n = this.dom.previousSibling;
9398 while(n && n.nodeType != 1){
9399 n = n.previousSibling;
9406 * Appends the passed element(s) to this element
9407 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9408 * @return {Roo.Element} this
9410 appendChild: function(el){
9417 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9418 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9419 * automatically generated with the specified attributes.
9420 * @param {HTMLElement} insertBefore (optional) a child element of this element
9421 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9422 * @return {Roo.Element} The new child element
9424 createChild: function(config, insertBefore, returnDom){
9425 config = config || {tag:'div'};
9427 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9429 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9433 * Appends this element to the passed element
9434 * @param {String/HTMLElement/Element} el The new parent element
9435 * @return {Roo.Element} this
9437 appendTo: function(el){
9438 el = Roo.getDom(el);
9439 el.appendChild(this.dom);
9444 * Inserts this element before the passed element in the DOM
9445 * @param {String/HTMLElement/Element} el The element to insert before
9446 * @return {Roo.Element} this
9448 insertBefore: function(el){
9449 el = Roo.getDom(el);
9450 el.parentNode.insertBefore(this.dom, el);
9455 * Inserts this element after the passed element in the DOM
9456 * @param {String/HTMLElement/Element} el The element to insert after
9457 * @return {Roo.Element} this
9459 insertAfter: function(el){
9460 el = Roo.getDom(el);
9461 el.parentNode.insertBefore(this.dom, el.nextSibling);
9466 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9467 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9468 * @return {Roo.Element} The new child
9470 insertFirst: function(el, returnDom){
9472 if(typeof el == 'object' && !el.nodeType){ // dh config
9473 return this.createChild(el, this.dom.firstChild, returnDom);
9475 el = Roo.getDom(el);
9476 this.dom.insertBefore(el, this.dom.firstChild);
9477 return !returnDom ? Roo.get(el) : el;
9482 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9483 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9484 * @param {String} where (optional) 'before' or 'after' defaults to before
9485 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9486 * @return {Roo.Element} the inserted Element
9488 insertSibling: function(el, where, returnDom){
9489 where = where ? where.toLowerCase() : 'before';
9491 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9493 if(typeof el == 'object' && !el.nodeType){ // dh config
9494 if(where == 'after' && !this.dom.nextSibling){
9495 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9497 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9501 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9502 where == 'before' ? this.dom : this.dom.nextSibling);
9511 * Creates and wraps this element with another element
9512 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9513 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9514 * @return {HTMLElement/Element} The newly created wrapper element
9516 wrap: function(config, returnDom){
9518 config = {tag: "div"};
9520 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9521 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9526 * Replaces the passed element with this element
9527 * @param {String/HTMLElement/Element} el The element to replace
9528 * @return {Roo.Element} this
9530 replace: function(el){
9532 this.insertBefore(el);
9538 * Inserts an html fragment into this element
9539 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9540 * @param {String} html The HTML fragment
9541 * @param {Boolean} returnEl True to return an Roo.Element
9542 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9544 insertHtml : function(where, html, returnEl){
9545 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9546 return returnEl ? Roo.get(el) : el;
9550 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9551 * @param {Object} o The object with the attributes
9552 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9553 * @return {Roo.Element} this
9555 set : function(o, useSet){
9557 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9559 if(attr == "style" || typeof o[attr] == "function") { continue; }
9561 el.className = o["cls"];
9564 el.setAttribute(attr, o[attr]);
9571 Roo.DomHelper.applyStyles(el, o.style);
9577 * Convenience method for constructing a KeyMap
9578 * @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:
9579 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9580 * @param {Function} fn The function to call
9581 * @param {Object} scope (optional) The scope of the function
9582 * @return {Roo.KeyMap} The KeyMap created
9584 addKeyListener : function(key, fn, scope){
9586 if(typeof key != "object" || key instanceof Array){
9602 return new Roo.KeyMap(this, config);
9606 * Creates a KeyMap for this element
9607 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9608 * @return {Roo.KeyMap} The KeyMap created
9610 addKeyMap : function(config){
9611 return new Roo.KeyMap(this, config);
9615 * Returns true if this element is scrollable.
9618 isScrollable : function(){
9620 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9624 * 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().
9625 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9626 * @param {Number} value The new scroll value
9627 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9628 * @return {Element} this
9631 scrollTo : function(side, value, animate){
9632 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9634 this.dom[prop] = value;
9636 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9637 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9643 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9644 * within this element's scrollable range.
9645 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9646 * @param {Number} distance How far to scroll the element in pixels
9647 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9648 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9649 * was scrolled as far as it could go.
9651 scroll : function(direction, distance, animate){
9652 if(!this.isScrollable()){
9656 var l = el.scrollLeft, t = el.scrollTop;
9657 var w = el.scrollWidth, h = el.scrollHeight;
9658 var cw = el.clientWidth, ch = el.clientHeight;
9659 direction = direction.toLowerCase();
9660 var scrolled = false;
9661 var a = this.preanim(arguments, 2);
9666 var v = Math.min(l + distance, w-cw);
9667 this.scrollTo("left", v, a);
9674 var v = Math.max(l - distance, 0);
9675 this.scrollTo("left", v, a);
9683 var v = Math.max(t - distance, 0);
9684 this.scrollTo("top", v, a);
9692 var v = Math.min(t + distance, h-ch);
9693 this.scrollTo("top", v, a);
9702 * Translates the passed page coordinates into left/top css values for this element
9703 * @param {Number/Array} x The page x or an array containing [x, y]
9704 * @param {Number} y The page y
9705 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9707 translatePoints : function(x, y){
9708 if(typeof x == 'object' || x instanceof Array){
9711 var p = this.getStyle('position');
9712 var o = this.getXY();
9714 var l = parseInt(this.getStyle('left'), 10);
9715 var t = parseInt(this.getStyle('top'), 10);
9718 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9721 t = (p == "relative") ? 0 : this.dom.offsetTop;
9724 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9728 * Returns the current scroll position of the element.
9729 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9731 getScroll : function(){
9732 var d = this.dom, doc = document;
9733 if(d == doc || d == doc.body){
9734 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9735 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9736 return {left: l, top: t};
9738 return {left: d.scrollLeft, top: d.scrollTop};
9743 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9744 * are convert to standard 6 digit hex color.
9745 * @param {String} attr The css attribute
9746 * @param {String} defaultValue The default value to use when a valid color isn't found
9747 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9750 getColor : function(attr, defaultValue, prefix){
9751 var v = this.getStyle(attr);
9752 if(!v || v == "transparent" || v == "inherit") {
9753 return defaultValue;
9755 var color = typeof prefix == "undefined" ? "#" : prefix;
9756 if(v.substr(0, 4) == "rgb("){
9757 var rvs = v.slice(4, v.length -1).split(",");
9758 for(var i = 0; i < 3; i++){
9759 var h = parseInt(rvs[i]).toString(16);
9766 if(v.substr(0, 1) == "#"){
9768 for(var i = 1; i < 4; i++){
9769 var c = v.charAt(i);
9772 }else if(v.length == 7){
9773 color += v.substr(1);
9777 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9781 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9782 * gradient background, rounded corners and a 4-way shadow.
9783 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9784 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9785 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9786 * @return {Roo.Element} this
9788 boxWrap : function(cls){
9789 cls = cls || 'x-box';
9790 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9791 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9796 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9797 * @param {String} namespace The namespace in which to look for the attribute
9798 * @param {String} name The attribute name
9799 * @return {String} The attribute value
9801 getAttributeNS : Roo.isIE ? function(ns, name){
9803 var type = typeof d[ns+":"+name];
9804 if(type != 'undefined' && type != 'unknown'){
9805 return d[ns+":"+name];
9808 } : function(ns, name){
9810 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9815 * Sets or Returns the value the dom attribute value
9816 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9817 * @param {String} value (optional) The value to set the attribute to
9818 * @return {String} The attribute value
9820 attr : function(name){
9821 if (arguments.length > 1) {
9822 this.dom.setAttribute(name, arguments[1]);
9823 return arguments[1];
9825 if (typeof(name) == 'object') {
9826 for(var i in name) {
9827 this.attr(i, name[i]);
9833 if (!this.dom.hasAttribute(name)) {
9836 return this.dom.getAttribute(name);
9843 var ep = El.prototype;
9846 * Appends an event handler (Shorthand for addListener)
9847 * @param {String} eventName The type of event to append
9848 * @param {Function} fn The method the event invokes
9849 * @param {Object} scope (optional) The scope (this object) of the fn
9850 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9853 ep.on = ep.addListener;
9855 ep.mon = ep.addListener;
9858 * Removes an event handler from this element (shorthand for removeListener)
9859 * @param {String} eventName the type of event to remove
9860 * @param {Function} fn the method the event invokes
9861 * @return {Roo.Element} this
9864 ep.un = ep.removeListener;
9867 * true to automatically adjust width and height settings for box-model issues (default to true)
9869 ep.autoBoxAdjust = true;
9872 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9875 El.addUnits = function(v, defaultUnit){
9876 if(v === "" || v == "auto"){
9879 if(v === undefined){
9882 if(typeof v == "number" || !El.unitPattern.test(v)){
9883 return v + (defaultUnit || 'px');
9888 // special markup used throughout Roo when box wrapping elements
9889 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>';
9891 * Visibility mode constant - Use visibility to hide element
9897 * Visibility mode constant - Use display to hide element
9903 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9904 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9905 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9917 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9918 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9919 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9920 * @return {Element} The Element object
9923 El.get = function(el){
9925 if(!el){ return null; }
9926 if(typeof el == "string"){ // element id
9927 if(!(elm = document.getElementById(el))){
9930 if(ex = El.cache[el]){
9933 ex = El.cache[el] = new El(elm);
9936 }else if(el.tagName){ // dom element
9940 if(ex = El.cache[id]){
9943 ex = El.cache[id] = new El(el);
9946 }else if(el instanceof El){
9948 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9949 // catch case where it hasn't been appended
9950 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9953 }else if(el.isComposite){
9955 }else if(el instanceof Array){
9956 return El.select(el);
9957 }else if(el == document){
9958 // create a bogus element object representing the document object
9960 var f = function(){};
9961 f.prototype = El.prototype;
9963 docEl.dom = document;
9971 El.uncache = function(el){
9972 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9974 delete El.cache[a[i].id || a[i]];
9980 // Garbage collection - uncache elements/purge listeners on orphaned elements
9981 // so we don't hold a reference and cause the browser to retain them
9982 El.garbageCollect = function(){
9983 if(!Roo.enableGarbageCollector){
9984 clearInterval(El.collectorThread);
9987 for(var eid in El.cache){
9988 var el = El.cache[eid], d = el.dom;
9989 // -------------------------------------------------------
9990 // Determining what is garbage:
9991 // -------------------------------------------------------
9993 // dom node is null, definitely garbage
9994 // -------------------------------------------------------
9996 // no parentNode == direct orphan, definitely garbage
9997 // -------------------------------------------------------
9998 // !d.offsetParent && !document.getElementById(eid)
9999 // display none elements have no offsetParent so we will
10000 // also try to look it up by it's id. However, check
10001 // offsetParent first so we don't do unneeded lookups.
10002 // This enables collection of elements that are not orphans
10003 // directly, but somewhere up the line they have an orphan
10005 // -------------------------------------------------------
10006 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10007 delete El.cache[eid];
10008 if(d && Roo.enableListenerCollection){
10014 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10018 El.Flyweight = function(dom){
10021 El.Flyweight.prototype = El.prototype;
10023 El._flyweights = {};
10025 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10026 * the dom node can be overwritten by other code.
10027 * @param {String/HTMLElement} el The dom node or id
10028 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10029 * prevent conflicts (e.g. internally Roo uses "_internal")
10031 * @return {Element} The shared Element object
10033 El.fly = function(el, named){
10034 named = named || '_global';
10035 el = Roo.getDom(el);
10039 if(!El._flyweights[named]){
10040 El._flyweights[named] = new El.Flyweight();
10042 El._flyweights[named].dom = el;
10043 return El._flyweights[named];
10047 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10048 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10049 * Shorthand of {@link Roo.Element#get}
10050 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10051 * @return {Element} The Element object
10057 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10058 * the dom node can be overwritten by other code.
10059 * Shorthand of {@link Roo.Element#fly}
10060 * @param {String/HTMLElement} el The dom node or id
10061 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10062 * prevent conflicts (e.g. internally Roo uses "_internal")
10064 * @return {Element} The shared Element object
10070 // speedy lookup for elements never to box adjust
10071 var noBoxAdjust = Roo.isStrict ? {
10074 input:1, select:1, textarea:1
10076 if(Roo.isIE || Roo.isGecko){
10077 noBoxAdjust['button'] = 1;
10081 Roo.EventManager.on(window, 'unload', function(){
10083 delete El._flyweights;
10091 Roo.Element.selectorFunction = Roo.DomQuery.select;
10094 Roo.Element.select = function(selector, unique, root){
10096 if(typeof selector == "string"){
10097 els = Roo.Element.selectorFunction(selector, root);
10098 }else if(selector.length !== undefined){
10101 throw "Invalid selector";
10103 if(unique === true){
10104 return new Roo.CompositeElement(els);
10106 return new Roo.CompositeElementLite(els);
10110 * Selects elements based on the passed CSS selector to enable working on them as 1.
10111 * @param {String/Array} selector The CSS selector or an array of elements
10112 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10113 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10114 * @return {CompositeElementLite/CompositeElement}
10118 Roo.select = Roo.Element.select;
10135 * Ext JS Library 1.1.1
10136 * Copyright(c) 2006-2007, Ext JS, LLC.
10138 * Originally Released Under LGPL - original licence link has changed is not relivant.
10141 * <script type="text/javascript">
10146 //Notifies Element that fx methods are available
10147 Roo.enableFx = true;
10151 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10152 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10153 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10154 * Element effects to work.</p><br/>
10156 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10157 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10158 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10159 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10160 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10161 * expected results and should be done with care.</p><br/>
10163 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10164 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10167 ----- -----------------------------
10168 tl The top left corner
10169 t The center of the top edge
10170 tr The top right corner
10171 l The center of the left edge
10172 r The center of the right edge
10173 bl The bottom left corner
10174 b The center of the bottom edge
10175 br The bottom right corner
10177 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10178 * below are common options that can be passed to any Fx method.</b>
10179 * @cfg {Function} callback A function called when the effect is finished
10180 * @cfg {Object} scope The scope of the effect function
10181 * @cfg {String} easing A valid Easing value for the effect
10182 * @cfg {String} afterCls A css class to apply after the effect
10183 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10184 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10185 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10186 * effects that end with the element being visually hidden, ignored otherwise)
10187 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10188 * a function which returns such a specification that will be applied to the Element after the effect finishes
10189 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10190 * @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
10191 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10195 * Slides the element into view. An anchor point can be optionally passed to set the point of
10196 * origin for the slide effect. This function automatically handles wrapping the element with
10197 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10200 // default: slide the element in from the top
10203 // custom: slide the element in from the right with a 2-second duration
10204 el.slideIn('r', { duration: 2 });
10206 // common config options shown with default values
10212 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10213 * @param {Object} options (optional) Object literal with any of the Fx config options
10214 * @return {Roo.Element} The Element
10216 slideIn : function(anchor, o){
10217 var el = this.getFxEl();
10220 el.queueFx(o, function(){
10222 anchor = anchor || "t";
10224 // fix display to visibility
10227 // restore values after effect
10228 var r = this.getFxRestore();
10229 var b = this.getBox();
10230 // fixed size for slide
10234 var wrap = this.fxWrap(r.pos, o, "hidden");
10236 var st = this.dom.style;
10237 st.visibility = "visible";
10238 st.position = "absolute";
10240 // clear out temp styles after slide and unwrap
10241 var after = function(){
10242 el.fxUnwrap(wrap, r.pos, o);
10243 st.width = r.width;
10244 st.height = r.height;
10247 // time to calc the positions
10248 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10250 switch(anchor.toLowerCase()){
10252 wrap.setSize(b.width, 0);
10253 st.left = st.bottom = "0";
10257 wrap.setSize(0, b.height);
10258 st.right = st.top = "0";
10262 wrap.setSize(0, b.height);
10263 wrap.setX(b.right);
10264 st.left = st.top = "0";
10265 a = {width: bw, points: pt};
10268 wrap.setSize(b.width, 0);
10269 wrap.setY(b.bottom);
10270 st.left = st.top = "0";
10271 a = {height: bh, points: pt};
10274 wrap.setSize(0, 0);
10275 st.right = st.bottom = "0";
10276 a = {width: bw, height: bh};
10279 wrap.setSize(0, 0);
10280 wrap.setY(b.y+b.height);
10281 st.right = st.top = "0";
10282 a = {width: bw, height: bh, points: pt};
10285 wrap.setSize(0, 0);
10286 wrap.setXY([b.right, b.bottom]);
10287 st.left = st.top = "0";
10288 a = {width: bw, height: bh, points: pt};
10291 wrap.setSize(0, 0);
10292 wrap.setX(b.x+b.width);
10293 st.left = st.bottom = "0";
10294 a = {width: bw, height: bh, points: pt};
10297 this.dom.style.visibility = "visible";
10300 arguments.callee.anim = wrap.fxanim(a,
10310 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10311 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10312 * 'hidden') but block elements will still take up space in the document. The element must be removed
10313 * from the DOM using the 'remove' config option if desired. This function automatically handles
10314 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10317 // default: slide the element out to the top
10320 // custom: slide the element out to the right with a 2-second duration
10321 el.slideOut('r', { duration: 2 });
10323 // common config options shown with default values
10331 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10332 * @param {Object} options (optional) Object literal with any of the Fx config options
10333 * @return {Roo.Element} The Element
10335 slideOut : function(anchor, o){
10336 var el = this.getFxEl();
10339 el.queueFx(o, function(){
10341 anchor = anchor || "t";
10343 // restore values after effect
10344 var r = this.getFxRestore();
10346 var b = this.getBox();
10347 // fixed size for slide
10351 var wrap = this.fxWrap(r.pos, o, "visible");
10353 var st = this.dom.style;
10354 st.visibility = "visible";
10355 st.position = "absolute";
10359 var after = function(){
10361 el.setDisplayed(false);
10366 el.fxUnwrap(wrap, r.pos, o);
10368 st.width = r.width;
10369 st.height = r.height;
10374 var a, zero = {to: 0};
10375 switch(anchor.toLowerCase()){
10377 st.left = st.bottom = "0";
10378 a = {height: zero};
10381 st.right = st.top = "0";
10385 st.left = st.top = "0";
10386 a = {width: zero, points: {to:[b.right, b.y]}};
10389 st.left = st.top = "0";
10390 a = {height: zero, points: {to:[b.x, b.bottom]}};
10393 st.right = st.bottom = "0";
10394 a = {width: zero, height: zero};
10397 st.right = st.top = "0";
10398 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10401 st.left = st.top = "0";
10402 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10405 st.left = st.bottom = "0";
10406 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10410 arguments.callee.anim = wrap.fxanim(a,
10420 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10421 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10422 * The element must be removed from the DOM using the 'remove' config option if desired.
10428 // common config options shown with default values
10436 * @param {Object} options (optional) Object literal with any of the Fx config options
10437 * @return {Roo.Element} The Element
10439 puff : function(o){
10440 var el = this.getFxEl();
10443 el.queueFx(o, function(){
10444 this.clearOpacity();
10447 // restore values after effect
10448 var r = this.getFxRestore();
10449 var st = this.dom.style;
10451 var after = function(){
10453 el.setDisplayed(false);
10460 el.setPositioning(r.pos);
10461 st.width = r.width;
10462 st.height = r.height;
10467 var width = this.getWidth();
10468 var height = this.getHeight();
10470 arguments.callee.anim = this.fxanim({
10471 width : {to: this.adjustWidth(width * 2)},
10472 height : {to: this.adjustHeight(height * 2)},
10473 points : {by: [-(width * .5), -(height * .5)]},
10475 fontSize: {to:200, unit: "%"}
10486 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10487 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10488 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10494 // all config options shown with default values
10502 * @param {Object} options (optional) Object literal with any of the Fx config options
10503 * @return {Roo.Element} The Element
10505 switchOff : function(o){
10506 var el = this.getFxEl();
10509 el.queueFx(o, function(){
10510 this.clearOpacity();
10513 // restore values after effect
10514 var r = this.getFxRestore();
10515 var st = this.dom.style;
10517 var after = function(){
10519 el.setDisplayed(false);
10525 el.setPositioning(r.pos);
10526 st.width = r.width;
10527 st.height = r.height;
10532 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10533 this.clearOpacity();
10537 points:{by:[0, this.getHeight() * .5]}
10538 }, o, 'motion', 0.3, 'easeIn', after);
10539 }).defer(100, this);
10546 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10547 * changed using the "attr" config option) and then fading back to the original color. If no original
10548 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10551 // default: highlight background to yellow
10554 // custom: highlight foreground text to blue for 2 seconds
10555 el.highlight("0000ff", { attr: 'color', duration: 2 });
10557 // common config options shown with default values
10558 el.highlight("ffff9c", {
10559 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10560 endColor: (current color) or "ffffff",
10565 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10566 * @param {Object} options (optional) Object literal with any of the Fx config options
10567 * @return {Roo.Element} The Element
10569 highlight : function(color, o){
10570 var el = this.getFxEl();
10573 el.queueFx(o, function(){
10574 color = color || "ffff9c";
10575 attr = o.attr || "backgroundColor";
10577 this.clearOpacity();
10580 var origColor = this.getColor(attr);
10581 var restoreColor = this.dom.style[attr];
10582 endColor = (o.endColor || origColor) || "ffffff";
10584 var after = function(){
10585 el.dom.style[attr] = restoreColor;
10590 a[attr] = {from: color, to: endColor};
10591 arguments.callee.anim = this.fxanim(a,
10601 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10604 // default: a single light blue ripple
10607 // custom: 3 red ripples lasting 3 seconds total
10608 el.frame("ff0000", 3, { duration: 3 });
10610 // common config options shown with default values
10611 el.frame("C3DAF9", 1, {
10612 duration: 1 //duration of entire animation (not each individual ripple)
10613 // Note: Easing is not configurable and will be ignored if included
10616 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10617 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10618 * @param {Object} options (optional) Object literal with any of the Fx config options
10619 * @return {Roo.Element} The Element
10621 frame : function(color, count, o){
10622 var el = this.getFxEl();
10625 el.queueFx(o, function(){
10626 color = color || "#C3DAF9";
10627 if(color.length == 6){
10628 color = "#" + color;
10630 count = count || 1;
10631 duration = o.duration || 1;
10634 var b = this.getBox();
10635 var animFn = function(){
10636 var proxy = this.createProxy({
10639 visbility:"hidden",
10640 position:"absolute",
10641 "z-index":"35000", // yee haw
10642 border:"0px solid " + color
10645 var scale = Roo.isBorderBox ? 2 : 1;
10647 top:{from:b.y, to:b.y - 20},
10648 left:{from:b.x, to:b.x - 20},
10649 borderWidth:{from:0, to:10},
10650 opacity:{from:1, to:0},
10651 height:{from:b.height, to:(b.height + (20*scale))},
10652 width:{from:b.width, to:(b.width + (20*scale))}
10653 }, duration, function(){
10657 animFn.defer((duration/2)*1000, this);
10668 * Creates a pause before any subsequent queued effects begin. If there are
10669 * no effects queued after the pause it will have no effect.
10674 * @param {Number} seconds The length of time to pause (in seconds)
10675 * @return {Roo.Element} The Element
10677 pause : function(seconds){
10678 var el = this.getFxEl();
10681 el.queueFx(o, function(){
10682 setTimeout(function(){
10684 }, seconds * 1000);
10690 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10691 * using the "endOpacity" config option.
10694 // default: fade in from opacity 0 to 100%
10697 // custom: fade in from opacity 0 to 75% over 2 seconds
10698 el.fadeIn({ endOpacity: .75, duration: 2});
10700 // common config options shown with default values
10702 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10707 * @param {Object} options (optional) Object literal with any of the Fx config options
10708 * @return {Roo.Element} The Element
10710 fadeIn : function(o){
10711 var el = this.getFxEl();
10713 el.queueFx(o, function(){
10714 this.setOpacity(0);
10716 this.dom.style.visibility = 'visible';
10717 var to = o.endOpacity || 1;
10718 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10719 o, null, .5, "easeOut", function(){
10721 this.clearOpacity();
10730 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10731 * using the "endOpacity" config option.
10734 // default: fade out from the element's current opacity to 0
10737 // custom: fade out from the element's current opacity to 25% over 2 seconds
10738 el.fadeOut({ endOpacity: .25, duration: 2});
10740 // common config options shown with default values
10742 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10749 * @param {Object} options (optional) Object literal with any of the Fx config options
10750 * @return {Roo.Element} The Element
10752 fadeOut : function(o){
10753 var el = this.getFxEl();
10755 el.queueFx(o, function(){
10756 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10757 o, null, .5, "easeOut", function(){
10758 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10759 this.dom.style.display = "none";
10761 this.dom.style.visibility = "hidden";
10763 this.clearOpacity();
10771 * Animates the transition of an element's dimensions from a starting height/width
10772 * to an ending height/width.
10775 // change height and width to 100x100 pixels
10776 el.scale(100, 100);
10778 // common config options shown with default values. The height and width will default to
10779 // the element's existing values if passed as null.
10782 [element's height], {
10787 * @param {Number} width The new width (pass undefined to keep the original width)
10788 * @param {Number} height The new height (pass undefined to keep the original height)
10789 * @param {Object} options (optional) Object literal with any of the Fx config options
10790 * @return {Roo.Element} The Element
10792 scale : function(w, h, o){
10793 this.shift(Roo.apply({}, o, {
10801 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10802 * Any of these properties not specified in the config object will not be changed. This effect
10803 * requires that at least one new dimension, position or opacity setting must be passed in on
10804 * the config object in order for the function to have any effect.
10807 // slide the element horizontally to x position 200 while changing the height and opacity
10808 el.shift({ x: 200, height: 50, opacity: .8 });
10810 // common config options shown with default values.
10812 width: [element's width],
10813 height: [element's height],
10814 x: [element's x position],
10815 y: [element's y position],
10816 opacity: [element's opacity],
10821 * @param {Object} options Object literal with any of the Fx config options
10822 * @return {Roo.Element} The Element
10824 shift : function(o){
10825 var el = this.getFxEl();
10827 el.queueFx(o, function(){
10828 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10829 if(w !== undefined){
10830 a.width = {to: this.adjustWidth(w)};
10832 if(h !== undefined){
10833 a.height = {to: this.adjustHeight(h)};
10835 if(x !== undefined || y !== undefined){
10837 x !== undefined ? x : this.getX(),
10838 y !== undefined ? y : this.getY()
10841 if(op !== undefined){
10842 a.opacity = {to: op};
10844 if(o.xy !== undefined){
10845 a.points = {to: o.xy};
10847 arguments.callee.anim = this.fxanim(a,
10848 o, 'motion', .35, "easeOut", function(){
10856 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10857 * ending point of the effect.
10860 // default: slide the element downward while fading out
10863 // custom: slide the element out to the right with a 2-second duration
10864 el.ghost('r', { duration: 2 });
10866 // common config options shown with default values
10874 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10875 * @param {Object} options (optional) Object literal with any of the Fx config options
10876 * @return {Roo.Element} The Element
10878 ghost : function(anchor, o){
10879 var el = this.getFxEl();
10882 el.queueFx(o, function(){
10883 anchor = anchor || "b";
10885 // restore values after effect
10886 var r = this.getFxRestore();
10887 var w = this.getWidth(),
10888 h = this.getHeight();
10890 var st = this.dom.style;
10892 var after = function(){
10894 el.setDisplayed(false);
10900 el.setPositioning(r.pos);
10901 st.width = r.width;
10902 st.height = r.height;
10907 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10908 switch(anchor.toLowerCase()){
10935 arguments.callee.anim = this.fxanim(a,
10945 * Ensures that all effects queued after syncFx is called on the element are
10946 * run concurrently. This is the opposite of {@link #sequenceFx}.
10947 * @return {Roo.Element} The Element
10949 syncFx : function(){
10950 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10959 * Ensures that all effects queued after sequenceFx is called on the element are
10960 * run in sequence. This is the opposite of {@link #syncFx}.
10961 * @return {Roo.Element} The Element
10963 sequenceFx : function(){
10964 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10966 concurrent : false,
10973 nextFx : function(){
10974 var ef = this.fxQueue[0];
10981 * Returns true if the element has any effects actively running or queued, else returns false.
10982 * @return {Boolean} True if element has active effects, else false
10984 hasActiveFx : function(){
10985 return this.fxQueue && this.fxQueue[0];
10989 * Stops any running effects and clears the element's internal effects queue if it contains
10990 * any additional effects that haven't started yet.
10991 * @return {Roo.Element} The Element
10993 stopFx : function(){
10994 if(this.hasActiveFx()){
10995 var cur = this.fxQueue[0];
10996 if(cur && cur.anim && cur.anim.isAnimated()){
10997 this.fxQueue = [cur]; // clear out others
10998 cur.anim.stop(true);
11005 beforeFx : function(o){
11006 if(this.hasActiveFx() && !o.concurrent){
11017 * Returns true if the element is currently blocking so that no other effect can be queued
11018 * until this effect is finished, else returns false if blocking is not set. This is commonly
11019 * used to ensure that an effect initiated by a user action runs to completion prior to the
11020 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11021 * @return {Boolean} True if blocking, else false
11023 hasFxBlock : function(){
11024 var q = this.fxQueue;
11025 return q && q[0] && q[0].block;
11029 queueFx : function(o, fn){
11033 if(!this.hasFxBlock()){
11034 Roo.applyIf(o, this.fxDefaults);
11036 var run = this.beforeFx(o);
11037 fn.block = o.block;
11038 this.fxQueue.push(fn);
11050 fxWrap : function(pos, o, vis){
11052 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11055 wrapXY = this.getXY();
11057 var div = document.createElement("div");
11058 div.style.visibility = vis;
11059 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11060 wrap.setPositioning(pos);
11061 if(wrap.getStyle("position") == "static"){
11062 wrap.position("relative");
11064 this.clearPositioning('auto');
11066 wrap.dom.appendChild(this.dom);
11068 wrap.setXY(wrapXY);
11075 fxUnwrap : function(wrap, pos, o){
11076 this.clearPositioning();
11077 this.setPositioning(pos);
11079 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11085 getFxRestore : function(){
11086 var st = this.dom.style;
11087 return {pos: this.getPositioning(), width: st.width, height : st.height};
11091 afterFx : function(o){
11093 this.applyStyles(o.afterStyle);
11096 this.addClass(o.afterCls);
11098 if(o.remove === true){
11101 Roo.callback(o.callback, o.scope, [this]);
11103 this.fxQueue.shift();
11109 getFxEl : function(){ // support for composite element fx
11110 return Roo.get(this.dom);
11114 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11115 animType = animType || 'run';
11117 var anim = Roo.lib.Anim[animType](
11119 (opt.duration || defaultDur) || .35,
11120 (opt.easing || defaultEase) || 'easeOut',
11122 Roo.callback(cb, this);
11131 // backwords compat
11132 Roo.Fx.resize = Roo.Fx.scale;
11134 //When included, Roo.Fx is automatically applied to Element so that all basic
11135 //effects are available directly via the Element API
11136 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11138 * Ext JS Library 1.1.1
11139 * Copyright(c) 2006-2007, Ext JS, LLC.
11141 * Originally Released Under LGPL - original licence link has changed is not relivant.
11144 * <script type="text/javascript">
11149 * @class Roo.CompositeElement
11150 * Standard composite class. Creates a Roo.Element for every element in the collection.
11152 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11153 * actions will be performed on all the elements in this collection.</b>
11155 * All methods return <i>this</i> and can be chained.
11157 var els = Roo.select("#some-el div.some-class", true);
11158 // or select directly from an existing element
11159 var el = Roo.get('some-el');
11160 el.select('div.some-class', true);
11162 els.setWidth(100); // all elements become 100 width
11163 els.hide(true); // all elements fade out and hide
11165 els.setWidth(100).hide(true);
11168 Roo.CompositeElement = function(els){
11169 this.elements = [];
11170 this.addElements(els);
11172 Roo.CompositeElement.prototype = {
11174 addElements : function(els){
11178 if(typeof els == "string"){
11179 els = Roo.Element.selectorFunction(els);
11181 var yels = this.elements;
11182 var index = yels.length-1;
11183 for(var i = 0, len = els.length; i < len; i++) {
11184 yels[++index] = Roo.get(els[i]);
11190 * Clears this composite and adds the elements returned by the passed selector.
11191 * @param {String/Array} els A string CSS selector, an array of elements or an element
11192 * @return {CompositeElement} this
11194 fill : function(els){
11195 this.elements = [];
11201 * Filters this composite to only elements that match the passed selector.
11202 * @param {String} selector A string CSS selector
11203 * @param {Boolean} inverse return inverse filter (not matches)
11204 * @return {CompositeElement} this
11206 filter : function(selector, inverse){
11208 inverse = inverse || false;
11209 this.each(function(el){
11210 var match = inverse ? !el.is(selector) : el.is(selector);
11212 els[els.length] = el.dom;
11219 invoke : function(fn, args){
11220 var els = this.elements;
11221 for(var i = 0, len = els.length; i < len; i++) {
11222 Roo.Element.prototype[fn].apply(els[i], args);
11227 * Adds elements to this composite.
11228 * @param {String/Array} els A string CSS selector, an array of elements or an element
11229 * @return {CompositeElement} this
11231 add : function(els){
11232 if(typeof els == "string"){
11233 this.addElements(Roo.Element.selectorFunction(els));
11234 }else if(els.length !== undefined){
11235 this.addElements(els);
11237 this.addElements([els]);
11242 * Calls the passed function passing (el, this, index) for each element in this composite.
11243 * @param {Function} fn The function to call
11244 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11245 * @return {CompositeElement} this
11247 each : function(fn, scope){
11248 var els = this.elements;
11249 for(var i = 0, len = els.length; i < len; i++){
11250 if(fn.call(scope || els[i], els[i], this, i) === false) {
11258 * Returns the Element object at the specified index
11259 * @param {Number} index
11260 * @return {Roo.Element}
11262 item : function(index){
11263 return this.elements[index] || null;
11267 * Returns the first Element
11268 * @return {Roo.Element}
11270 first : function(){
11271 return this.item(0);
11275 * Returns the last Element
11276 * @return {Roo.Element}
11279 return this.item(this.elements.length-1);
11283 * Returns the number of elements in this composite
11286 getCount : function(){
11287 return this.elements.length;
11291 * Returns true if this composite contains the passed element
11294 contains : function(el){
11295 return this.indexOf(el) !== -1;
11299 * Returns true if this composite contains the passed element
11302 indexOf : function(el){
11303 return this.elements.indexOf(Roo.get(el));
11308 * Removes the specified element(s).
11309 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11310 * or an array of any of those.
11311 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11312 * @return {CompositeElement} this
11314 removeElement : function(el, removeDom){
11315 if(el instanceof Array){
11316 for(var i = 0, len = el.length; i < len; i++){
11317 this.removeElement(el[i]);
11321 var index = typeof el == 'number' ? el : this.indexOf(el);
11324 var d = this.elements[index];
11328 d.parentNode.removeChild(d);
11331 this.elements.splice(index, 1);
11337 * Replaces the specified element with the passed element.
11338 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11340 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11341 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11342 * @return {CompositeElement} this
11344 replaceElement : function(el, replacement, domReplace){
11345 var index = typeof el == 'number' ? el : this.indexOf(el);
11348 this.elements[index].replaceWith(replacement);
11350 this.elements.splice(index, 1, Roo.get(replacement))
11357 * Removes all elements.
11359 clear : function(){
11360 this.elements = [];
11364 Roo.CompositeElement.createCall = function(proto, fnName){
11365 if(!proto[fnName]){
11366 proto[fnName] = function(){
11367 return this.invoke(fnName, arguments);
11371 for(var fnName in Roo.Element.prototype){
11372 if(typeof Roo.Element.prototype[fnName] == "function"){
11373 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11379 * Ext JS Library 1.1.1
11380 * Copyright(c) 2006-2007, Ext JS, LLC.
11382 * Originally Released Under LGPL - original licence link has changed is not relivant.
11385 * <script type="text/javascript">
11389 * @class Roo.CompositeElementLite
11390 * @extends Roo.CompositeElement
11391 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11393 var els = Roo.select("#some-el div.some-class");
11394 // or select directly from an existing element
11395 var el = Roo.get('some-el');
11396 el.select('div.some-class');
11398 els.setWidth(100); // all elements become 100 width
11399 els.hide(true); // all elements fade out and hide
11401 els.setWidth(100).hide(true);
11402 </code></pre><br><br>
11403 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11404 * actions will be performed on all the elements in this collection.</b>
11406 Roo.CompositeElementLite = function(els){
11407 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11408 this.el = new Roo.Element.Flyweight();
11410 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11411 addElements : function(els){
11413 if(els instanceof Array){
11414 this.elements = this.elements.concat(els);
11416 var yels = this.elements;
11417 var index = yels.length-1;
11418 for(var i = 0, len = els.length; i < len; i++) {
11419 yels[++index] = els[i];
11425 invoke : function(fn, args){
11426 var els = this.elements;
11428 for(var i = 0, len = els.length; i < len; i++) {
11430 Roo.Element.prototype[fn].apply(el, args);
11435 * Returns a flyweight Element of the dom element object at the specified index
11436 * @param {Number} index
11437 * @return {Roo.Element}
11439 item : function(index){
11440 if(!this.elements[index]){
11443 this.el.dom = this.elements[index];
11447 // fixes scope with flyweight
11448 addListener : function(eventName, handler, scope, opt){
11449 var els = this.elements;
11450 for(var i = 0, len = els.length; i < len; i++) {
11451 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11457 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11458 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11459 * a reference to the dom node, use el.dom.</b>
11460 * @param {Function} fn The function to call
11461 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11462 * @return {CompositeElement} this
11464 each : function(fn, scope){
11465 var els = this.elements;
11467 for(var i = 0, len = els.length; i < len; i++){
11469 if(fn.call(scope || el, el, this, i) === false){
11476 indexOf : function(el){
11477 return this.elements.indexOf(Roo.getDom(el));
11480 replaceElement : function(el, replacement, domReplace){
11481 var index = typeof el == 'number' ? el : this.indexOf(el);
11483 replacement = Roo.getDom(replacement);
11485 var d = this.elements[index];
11486 d.parentNode.insertBefore(replacement, d);
11487 d.parentNode.removeChild(d);
11489 this.elements.splice(index, 1, replacement);
11494 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11498 * Ext JS Library 1.1.1
11499 * Copyright(c) 2006-2007, Ext JS, LLC.
11501 * Originally Released Under LGPL - original licence link has changed is not relivant.
11504 * <script type="text/javascript">
11510 * @class Roo.data.Connection
11511 * @extends Roo.util.Observable
11512 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11513 * either to a configured URL, or to a URL specified at request time.
11515 * Requests made by this class are asynchronous, and will return immediately. No data from
11516 * the server will be available to the statement immediately following the {@link #request} call.
11517 * To process returned data, use a callback in the request options object, or an event listener.
11519 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11520 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11521 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11522 * property and, if present, the IFRAME's XML document as the responseXML property.
11524 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11525 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11526 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11527 * standard DOM methods.
11529 * @param {Object} config a configuration object.
11531 Roo.data.Connection = function(config){
11532 Roo.apply(this, config);
11535 * @event beforerequest
11536 * Fires before a network request is made to retrieve a data object.
11537 * @param {Connection} conn This Connection object.
11538 * @param {Object} options The options config object passed to the {@link #request} method.
11540 "beforerequest" : true,
11542 * @event requestcomplete
11543 * Fires if the request was successfully completed.
11544 * @param {Connection} conn This Connection object.
11545 * @param {Object} response The XHR object containing the response data.
11546 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11547 * @param {Object} options The options config object passed to the {@link #request} method.
11549 "requestcomplete" : true,
11551 * @event requestexception
11552 * Fires if an error HTTP status was returned from the server.
11553 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11554 * @param {Connection} conn This Connection object.
11555 * @param {Object} response The XHR object containing the response data.
11556 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11557 * @param {Object} options The options config object passed to the {@link #request} method.
11559 "requestexception" : true
11561 Roo.data.Connection.superclass.constructor.call(this);
11564 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11566 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11569 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11570 * extra parameters to each request made by this object. (defaults to undefined)
11573 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11574 * to each request made by this object. (defaults to undefined)
11577 * @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)
11580 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11584 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11590 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11593 disableCaching: true,
11596 * Sends an HTTP request to a remote server.
11597 * @param {Object} options An object which may contain the following properties:<ul>
11598 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11599 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11600 * request, a url encoded string or a function to call to get either.</li>
11601 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11602 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11603 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11604 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11605 * <li>options {Object} The parameter to the request call.</li>
11606 * <li>success {Boolean} True if the request succeeded.</li>
11607 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11609 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11610 * The callback is passed the following parameters:<ul>
11611 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11612 * <li>options {Object} The parameter to the request call.</li>
11614 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11615 * The callback is passed the following parameters:<ul>
11616 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11617 * <li>options {Object} The parameter to the request call.</li>
11619 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11620 * for the callback function. Defaults to the browser window.</li>
11621 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11622 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11623 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11624 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11625 * params for the post data. Any params will be appended to the URL.</li>
11626 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11628 * @return {Number} transactionId
11630 request : function(o){
11631 if(this.fireEvent("beforerequest", this, o) !== false){
11634 if(typeof p == "function"){
11635 p = p.call(o.scope||window, o);
11637 if(typeof p == "object"){
11638 p = Roo.urlEncode(o.params);
11640 if(this.extraParams){
11641 var extras = Roo.urlEncode(this.extraParams);
11642 p = p ? (p + '&' + extras) : extras;
11645 var url = o.url || this.url;
11646 if(typeof url == 'function'){
11647 url = url.call(o.scope||window, o);
11651 var form = Roo.getDom(o.form);
11652 url = url || form.action;
11654 var enctype = form.getAttribute("enctype");
11657 return this.doFormDataUpload(o, url);
11660 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11661 return this.doFormUpload(o, p, url);
11663 var f = Roo.lib.Ajax.serializeForm(form);
11664 p = p ? (p + '&' + f) : f;
11667 if (!o.form && o.formData) {
11668 o.formData = o.formData === true ? new FormData() : o.formData;
11669 for (var k in o.params) {
11670 o.formData.append(k,o.params[k]);
11673 return this.doFormDataUpload(o, url);
11677 var hs = o.headers;
11678 if(this.defaultHeaders){
11679 hs = Roo.apply(hs || {}, this.defaultHeaders);
11686 success: this.handleResponse,
11687 failure: this.handleFailure,
11689 argument: {options: o},
11690 timeout : o.timeout || this.timeout
11693 var method = o.method||this.method||(p ? "POST" : "GET");
11695 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11696 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11699 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11703 }else if(this.autoAbort !== false){
11707 if((method == 'GET' && p) || o.xmlData){
11708 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11711 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11712 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11713 Roo.lib.Ajax.useDefaultHeader == true;
11714 return this.transId;
11716 Roo.callback(o.callback, o.scope, [o, null, null]);
11722 * Determine whether this object has a request outstanding.
11723 * @param {Number} transactionId (Optional) defaults to the last transaction
11724 * @return {Boolean} True if there is an outstanding request.
11726 isLoading : function(transId){
11728 return Roo.lib.Ajax.isCallInProgress(transId);
11730 return this.transId ? true : false;
11735 * Aborts any outstanding request.
11736 * @param {Number} transactionId (Optional) defaults to the last transaction
11738 abort : function(transId){
11739 if(transId || this.isLoading()){
11740 Roo.lib.Ajax.abort(transId || this.transId);
11745 handleResponse : function(response){
11746 this.transId = false;
11747 var options = response.argument.options;
11748 response.argument = options ? options.argument : null;
11749 this.fireEvent("requestcomplete", this, response, options);
11750 Roo.callback(options.success, options.scope, [response, options]);
11751 Roo.callback(options.callback, options.scope, [options, true, response]);
11755 handleFailure : function(response, e){
11756 this.transId = false;
11757 var options = response.argument.options;
11758 response.argument = options ? options.argument : null;
11759 this.fireEvent("requestexception", this, response, options, e);
11760 Roo.callback(options.failure, options.scope, [response, options]);
11761 Roo.callback(options.callback, options.scope, [options, false, response]);
11765 doFormUpload : function(o, ps, url){
11767 var frame = document.createElement('iframe');
11770 frame.className = 'x-hidden';
11772 frame.src = Roo.SSL_SECURE_URL;
11774 document.body.appendChild(frame);
11777 document.frames[id].name = id;
11780 var form = Roo.getDom(o.form);
11782 form.method = 'POST';
11783 form.enctype = form.encoding = 'multipart/form-data';
11789 if(ps){ // add dynamic params
11791 ps = Roo.urlDecode(ps, false);
11793 if(ps.hasOwnProperty(k)){
11794 hd = document.createElement('input');
11795 hd.type = 'hidden';
11798 form.appendChild(hd);
11805 var r = { // bogus response object
11810 r.argument = o ? o.argument : null;
11815 doc = frame.contentWindow.document;
11817 doc = (frame.contentDocument || window.frames[id].document);
11819 if(doc && doc.body){
11820 r.responseText = doc.body.innerHTML;
11822 if(doc && doc.XMLDocument){
11823 r.responseXML = doc.XMLDocument;
11825 r.responseXML = doc;
11832 Roo.EventManager.removeListener(frame, 'load', cb, this);
11834 this.fireEvent("requestcomplete", this, r, o);
11835 Roo.callback(o.success, o.scope, [r, o]);
11836 Roo.callback(o.callback, o.scope, [o, true, r]);
11838 setTimeout(function(){document.body.removeChild(frame);}, 100);
11841 Roo.EventManager.on(frame, 'load', cb, this);
11844 if(hiddens){ // remove dynamic params
11845 for(var i = 0, len = hiddens.length; i < len; i++){
11846 form.removeChild(hiddens[i]);
11850 // this is a 'formdata version???'
11853 doFormDataUpload : function(o, url)
11857 var form = Roo.getDom(o.form);
11858 form.enctype = form.encoding = 'multipart/form-data';
11859 formData = o.formData === true ? new FormData(form) : o.formData;
11861 formData = o.formData === true ? new FormData() : o.formData;
11866 success: this.handleResponse,
11867 failure: this.handleFailure,
11869 argument: {options: o},
11870 timeout : o.timeout || this.timeout
11873 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11877 }else if(this.autoAbort !== false){
11881 //Roo.lib.Ajax.defaultPostHeader = null;
11882 Roo.lib.Ajax.useDefaultHeader = false;
11883 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11884 Roo.lib.Ajax.useDefaultHeader = true;
11892 * Ext JS Library 1.1.1
11893 * Copyright(c) 2006-2007, Ext JS, LLC.
11895 * Originally Released Under LGPL - original licence link has changed is not relivant.
11898 * <script type="text/javascript">
11902 * Global Ajax request class.
11905 * @extends Roo.data.Connection
11908 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11909 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11910 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11911 * @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)
11912 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11913 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11914 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11916 Roo.Ajax = new Roo.data.Connection({
11925 * Serialize the passed form into a url encoded string
11927 * @param {String/HTMLElement} form
11930 serializeForm : function(form){
11931 return Roo.lib.Ajax.serializeForm(form);
11935 * Ext JS Library 1.1.1
11936 * Copyright(c) 2006-2007, Ext JS, LLC.
11938 * Originally Released Under LGPL - original licence link has changed is not relivant.
11941 * <script type="text/javascript">
11946 * @class Roo.UpdateManager
11947 * @extends Roo.util.Observable
11948 * Provides AJAX-style update for Element object.<br><br>
11951 * // Get it from a Roo.Element object
11952 * var el = Roo.get("foo");
11953 * var mgr = el.getUpdateManager();
11954 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11956 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11958 * // or directly (returns the same UpdateManager instance)
11959 * var mgr = new Roo.UpdateManager("myElementId");
11960 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11961 * mgr.on("update", myFcnNeedsToKnow);
11963 // short handed call directly from the element object
11964 Roo.get("foo").load({
11968 text: "Loading Foo..."
11972 * Create new UpdateManager directly.
11973 * @param {String/HTMLElement/Roo.Element} el The element to update
11974 * @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).
11976 Roo.UpdateManager = function(el, forceNew){
11978 if(!forceNew && el.updateManager){
11979 return el.updateManager;
11982 * The Element object
11983 * @type Roo.Element
11987 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11990 this.defaultUrl = null;
11994 * @event beforeupdate
11995 * Fired before an update is made, return false from your handler and the update is cancelled.
11996 * @param {Roo.Element} el
11997 * @param {String/Object/Function} url
11998 * @param {String/Object} params
12000 "beforeupdate": true,
12003 * Fired after successful update is made.
12004 * @param {Roo.Element} el
12005 * @param {Object} oResponseObject The response Object
12010 * Fired on update failure.
12011 * @param {Roo.Element} el
12012 * @param {Object} oResponseObject The response Object
12016 var d = Roo.UpdateManager.defaults;
12018 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12021 this.sslBlankUrl = d.sslBlankUrl;
12023 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12026 this.disableCaching = d.disableCaching;
12028 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12031 this.indicatorText = d.indicatorText;
12033 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12036 this.showLoadIndicator = d.showLoadIndicator;
12038 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12041 this.timeout = d.timeout;
12044 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12047 this.loadScripts = d.loadScripts;
12050 * Transaction object of current executing transaction
12052 this.transaction = null;
12057 this.autoRefreshProcId = null;
12059 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12062 this.refreshDelegate = this.refresh.createDelegate(this);
12064 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12067 this.updateDelegate = this.update.createDelegate(this);
12069 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12072 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12076 this.successDelegate = this.processSuccess.createDelegate(this);
12080 this.failureDelegate = this.processFailure.createDelegate(this);
12082 if(!this.renderer){
12084 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12086 this.renderer = new Roo.UpdateManager.BasicRenderer();
12089 Roo.UpdateManager.superclass.constructor.call(this);
12092 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12094 * Get the Element this UpdateManager is bound to
12095 * @return {Roo.Element} The element
12097 getEl : function(){
12101 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12102 * @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:
12105 url: "your-url.php",<br/>
12106 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12107 callback: yourFunction,<br/>
12108 scope: yourObject, //(optional scope) <br/>
12109 discardUrl: false, <br/>
12110 nocache: false,<br/>
12111 text: "Loading...",<br/>
12113 scripts: false<br/>
12116 * The only required property is url. The optional properties nocache, text and scripts
12117 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12118 * @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}
12119 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12120 * @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.
12122 update : function(url, params, callback, discardUrl){
12123 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12124 var method = this.method,
12126 if(typeof url == "object"){ // must be config object
12129 params = params || cfg.params;
12130 callback = callback || cfg.callback;
12131 discardUrl = discardUrl || cfg.discardUrl;
12132 if(callback && cfg.scope){
12133 callback = callback.createDelegate(cfg.scope);
12135 if(typeof cfg.method != "undefined"){method = cfg.method;};
12136 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12137 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12138 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12139 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12141 this.showLoading();
12143 this.defaultUrl = url;
12145 if(typeof url == "function"){
12146 url = url.call(this);
12149 method = method || (params ? "POST" : "GET");
12150 if(method == "GET"){
12151 url = this.prepareUrl(url);
12154 var o = Roo.apply(cfg ||{}, {
12157 success: this.successDelegate,
12158 failure: this.failureDelegate,
12159 callback: undefined,
12160 timeout: (this.timeout*1000),
12161 argument: {"url": url, "form": null, "callback": callback, "params": params}
12163 Roo.log("updated manager called with timeout of " + o.timeout);
12164 this.transaction = Roo.Ajax.request(o);
12169 * 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.
12170 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12171 * @param {String/HTMLElement} form The form Id or form element
12172 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12173 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12174 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12176 formUpdate : function(form, url, reset, callback){
12177 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12178 if(typeof url == "function"){
12179 url = url.call(this);
12181 form = Roo.getDom(form);
12182 this.transaction = Roo.Ajax.request({
12185 success: this.successDelegate,
12186 failure: this.failureDelegate,
12187 timeout: (this.timeout*1000),
12188 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12190 this.showLoading.defer(1, this);
12195 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12196 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12198 refresh : function(callback){
12199 if(this.defaultUrl == null){
12202 this.update(this.defaultUrl, null, callback, true);
12206 * Set this element to auto refresh.
12207 * @param {Number} interval How often to update (in seconds).
12208 * @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)
12209 * @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}
12210 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12211 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12213 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12215 this.update(url || this.defaultUrl, params, callback, true);
12217 if(this.autoRefreshProcId){
12218 clearInterval(this.autoRefreshProcId);
12220 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12224 * Stop auto refresh on this element.
12226 stopAutoRefresh : function(){
12227 if(this.autoRefreshProcId){
12228 clearInterval(this.autoRefreshProcId);
12229 delete this.autoRefreshProcId;
12233 isAutoRefreshing : function(){
12234 return this.autoRefreshProcId ? true : false;
12237 * Called to update the element to "Loading" state. Override to perform custom action.
12239 showLoading : function(){
12240 if(this.showLoadIndicator){
12241 this.el.update(this.indicatorText);
12246 * Adds unique parameter to query string if disableCaching = true
12249 prepareUrl : function(url){
12250 if(this.disableCaching){
12251 var append = "_dc=" + (new Date().getTime());
12252 if(url.indexOf("?") !== -1){
12253 url += "&" + append;
12255 url += "?" + append;
12264 processSuccess : function(response){
12265 this.transaction = null;
12266 if(response.argument.form && response.argument.reset){
12267 try{ // put in try/catch since some older FF releases had problems with this
12268 response.argument.form.reset();
12271 if(this.loadScripts){
12272 this.renderer.render(this.el, response, this,
12273 this.updateComplete.createDelegate(this, [response]));
12275 this.renderer.render(this.el, response, this);
12276 this.updateComplete(response);
12280 updateComplete : function(response){
12281 this.fireEvent("update", this.el, response);
12282 if(typeof response.argument.callback == "function"){
12283 response.argument.callback(this.el, true, response);
12290 processFailure : function(response){
12291 this.transaction = null;
12292 this.fireEvent("failure", this.el, response);
12293 if(typeof response.argument.callback == "function"){
12294 response.argument.callback(this.el, false, response);
12299 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12300 * @param {Object} renderer The object implementing the render() method
12302 setRenderer : function(renderer){
12303 this.renderer = renderer;
12306 getRenderer : function(){
12307 return this.renderer;
12311 * Set the defaultUrl used for updates
12312 * @param {String/Function} defaultUrl The url or a function to call to get the url
12314 setDefaultUrl : function(defaultUrl){
12315 this.defaultUrl = defaultUrl;
12319 * Aborts the executing transaction
12321 abort : function(){
12322 if(this.transaction){
12323 Roo.Ajax.abort(this.transaction);
12328 * Returns true if an update is in progress
12329 * @return {Boolean}
12331 isUpdating : function(){
12332 if(this.transaction){
12333 return Roo.Ajax.isLoading(this.transaction);
12340 * @class Roo.UpdateManager.defaults
12341 * @static (not really - but it helps the doc tool)
12342 * The defaults collection enables customizing the default properties of UpdateManager
12344 Roo.UpdateManager.defaults = {
12346 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12352 * True to process scripts by default (Defaults to false).
12355 loadScripts : false,
12358 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12361 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12363 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12366 disableCaching : false,
12368 * Whether to show indicatorText when loading (Defaults to true).
12371 showLoadIndicator : true,
12373 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12376 indicatorText : '<div class="loading-indicator">Loading...</div>'
12380 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12382 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12383 * @param {String/HTMLElement/Roo.Element} el The element to update
12384 * @param {String} url The url
12385 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12386 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12389 * @member Roo.UpdateManager
12391 Roo.UpdateManager.updateElement = function(el, url, params, options){
12392 var um = Roo.get(el, true).getUpdateManager();
12393 Roo.apply(um, options);
12394 um.update(url, params, options ? options.callback : null);
12396 // alias for backwards compat
12397 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12399 * @class Roo.UpdateManager.BasicRenderer
12400 * Default Content renderer. Updates the elements innerHTML with the responseText.
12402 Roo.UpdateManager.BasicRenderer = function(){};
12404 Roo.UpdateManager.BasicRenderer.prototype = {
12406 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12407 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12408 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12409 * @param {Roo.Element} el The element being rendered
12410 * @param {Object} response The YUI Connect response object
12411 * @param {UpdateManager} updateManager The calling update manager
12412 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12414 render : function(el, response, updateManager, callback){
12415 el.update(response.responseText, updateManager.loadScripts, callback);
12421 * (c)) Alan Knowles
12427 * @class Roo.DomTemplate
12428 * @extends Roo.Template
12429 * An effort at a dom based template engine..
12431 * Similar to XTemplate, except it uses dom parsing to create the template..
12433 * Supported features:
12438 {a_variable} - output encoded.
12439 {a_variable.format:("Y-m-d")} - call a method on the variable
12440 {a_variable:raw} - unencoded output
12441 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12442 {a_variable:this.method_on_template(...)} - call a method on the template object.
12447 <div roo-for="a_variable or condition.."></div>
12448 <div roo-if="a_variable or condition"></div>
12449 <div roo-exec="some javascript"></div>
12450 <div roo-name="named_template"></div>
12455 Roo.DomTemplate = function()
12457 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12464 Roo.extend(Roo.DomTemplate, Roo.Template, {
12466 * id counter for sub templates.
12470 * flag to indicate if dom parser is inside a pre,
12471 * it will strip whitespace if not.
12476 * The various sub templates
12484 * basic tag replacing syntax
12487 * // you can fake an object call by doing this
12491 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12492 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12494 iterChild : function (node, method) {
12496 var oldPre = this.inPre;
12497 if (node.tagName == 'PRE') {
12500 for( var i = 0; i < node.childNodes.length; i++) {
12501 method.call(this, node.childNodes[i]);
12503 this.inPre = oldPre;
12509 * compile the template
12511 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12514 compile: function()
12518 // covert the html into DOM...
12522 doc = document.implementation.createHTMLDocument("");
12523 doc.documentElement.innerHTML = this.html ;
12524 div = doc.documentElement;
12526 // old IE... - nasty -- it causes all sorts of issues.. with
12527 // images getting pulled from server..
12528 div = document.createElement('div');
12529 div.innerHTML = this.html;
12531 //doc.documentElement.innerHTML = htmlBody
12537 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12539 var tpls = this.tpls;
12541 // create a top level template from the snippet..
12543 //Roo.log(div.innerHTML);
12550 body : div.innerHTML,
12563 Roo.each(tpls, function(tp){
12564 this.compileTpl(tp);
12565 this.tpls[tp.id] = tp;
12568 this.master = tpls[0];
12574 compileNode : function(node, istop) {
12579 // skip anything not a tag..
12580 if (node.nodeType != 1) {
12581 if (node.nodeType == 3 && !this.inPre) {
12582 // reduce white space..
12583 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12606 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12607 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12608 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12609 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12615 // just itterate children..
12616 this.iterChild(node,this.compileNode);
12619 tpl.uid = this.id++;
12620 tpl.value = node.getAttribute('roo-' + tpl.attr);
12621 node.removeAttribute('roo-'+ tpl.attr);
12622 if (tpl.attr != 'name') {
12623 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12624 node.parentNode.replaceChild(placeholder, node);
12627 var placeholder = document.createElement('span');
12628 placeholder.className = 'roo-tpl-' + tpl.value;
12629 node.parentNode.replaceChild(placeholder, node);
12632 // parent now sees '{domtplXXXX}
12633 this.iterChild(node,this.compileNode);
12635 // we should now have node body...
12636 var div = document.createElement('div');
12637 div.appendChild(node);
12639 // this has the unfortunate side effect of converting tagged attributes
12640 // eg. href="{...}" into %7C...%7D
12641 // this has been fixed by searching for those combo's although it's a bit hacky..
12644 tpl.body = div.innerHTML;
12651 switch (tpl.value) {
12652 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12653 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12654 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12659 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12663 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12667 tpl.id = tpl.value; // replace non characters???
12673 this.tpls.push(tpl);
12683 * Compile a segment of the template into a 'sub-template'
12689 compileTpl : function(tpl)
12691 var fm = Roo.util.Format;
12692 var useF = this.disableFormats !== true;
12694 var sep = Roo.isGecko ? "+\n" : ",\n";
12696 var undef = function(str) {
12697 Roo.debug && Roo.log("Property not found :" + str);
12701 //Roo.log(tpl.body);
12705 var fn = function(m, lbrace, name, format, args)
12708 //Roo.log(arguments);
12709 args = args ? args.replace(/\\'/g,"'") : args;
12710 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12711 if (typeof(format) == 'undefined') {
12712 format = 'htmlEncode';
12714 if (format == 'raw' ) {
12718 if(name.substr(0, 6) == 'domtpl'){
12719 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12722 // build an array of options to determine if value is undefined..
12724 // basically get 'xxxx.yyyy' then do
12725 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12726 // (function () { Roo.log("Property not found"); return ''; })() :
12731 Roo.each(name.split('.'), function(st) {
12732 lookfor += (lookfor.length ? '.': '') + st;
12733 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12736 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12739 if(format && useF){
12741 args = args ? ',' + args : "";
12743 if(format.substr(0, 5) != "this."){
12744 format = "fm." + format + '(';
12746 format = 'this.call("'+ format.substr(5) + '", ';
12750 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12753 if (args && args.length) {
12754 // called with xxyx.yuu:(test,test)
12756 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12758 // raw.. - :raw modifier..
12759 return "'"+ sep + udef_st + name + ")"+sep+"'";
12763 // branched to use + in gecko and [].join() in others
12765 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12766 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12769 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12770 body.push(tpl.body.replace(/(\r\n|\n)/g,
12771 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12772 body.push("'].join('');};};");
12773 body = body.join('');
12776 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12778 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12785 * same as applyTemplate, except it's done to one of the subTemplates
12786 * when using named templates, you can do:
12788 * var str = pl.applySubTemplate('your-name', values);
12791 * @param {Number} id of the template
12792 * @param {Object} values to apply to template
12793 * @param {Object} parent (normaly the instance of this object)
12795 applySubTemplate : function(id, values, parent)
12799 var t = this.tpls[id];
12803 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12804 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12808 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12815 if(t.execCall && t.execCall.call(this, values, parent)){
12819 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12825 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12826 parent = t.target ? values : parent;
12827 if(t.forCall && vs instanceof Array){
12829 for(var i = 0, len = vs.length; i < len; i++){
12831 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12833 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12835 //Roo.log(t.compiled);
12839 return buf.join('');
12842 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12847 return t.compiled.call(this, vs, parent);
12849 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12851 //Roo.log(t.compiled);
12859 applyTemplate : function(values){
12860 return this.master.compiled.call(this, values, {});
12861 //var s = this.subs;
12864 apply : function(){
12865 return this.applyTemplate.apply(this, arguments);
12870 Roo.DomTemplate.from = function(el){
12871 el = Roo.getDom(el);
12872 return new Roo.Domtemplate(el.value || el.innerHTML);
12875 * Ext JS Library 1.1.1
12876 * Copyright(c) 2006-2007, Ext JS, LLC.
12878 * Originally Released Under LGPL - original licence link has changed is not relivant.
12881 * <script type="text/javascript">
12885 * @class Roo.util.DelayedTask
12886 * Provides a convenient method of performing setTimeout where a new
12887 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12888 * You can use this class to buffer
12889 * the keypress events for a certain number of milliseconds, and perform only if they stop
12890 * for that amount of time.
12891 * @constructor The parameters to this constructor serve as defaults and are not required.
12892 * @param {Function} fn (optional) The default function to timeout
12893 * @param {Object} scope (optional) The default scope of that timeout
12894 * @param {Array} args (optional) The default Array of arguments
12896 Roo.util.DelayedTask = function(fn, scope, args){
12897 var id = null, d, t;
12899 var call = function(){
12900 var now = new Date().getTime();
12904 fn.apply(scope, args || []);
12908 * Cancels any pending timeout and queues a new one
12909 * @param {Number} delay The milliseconds to delay
12910 * @param {Function} newFn (optional) Overrides function passed to constructor
12911 * @param {Object} newScope (optional) Overrides scope passed to constructor
12912 * @param {Array} newArgs (optional) Overrides args passed to constructor
12914 this.delay = function(delay, newFn, newScope, newArgs){
12915 if(id && delay != d){
12919 t = new Date().getTime();
12921 scope = newScope || scope;
12922 args = newArgs || args;
12924 id = setInterval(call, d);
12929 * Cancel the last queued timeout
12931 this.cancel = function(){
12939 * Ext JS Library 1.1.1
12940 * Copyright(c) 2006-2007, Ext JS, LLC.
12942 * Originally Released Under LGPL - original licence link has changed is not relivant.
12945 * <script type="text/javascript">
12949 Roo.util.TaskRunner = function(interval){
12950 interval = interval || 10;
12951 var tasks = [], removeQueue = [];
12953 var running = false;
12955 var stopThread = function(){
12961 var startThread = function(){
12964 id = setInterval(runTasks, interval);
12968 var removeTask = function(task){
12969 removeQueue.push(task);
12975 var runTasks = function(){
12976 if(removeQueue.length > 0){
12977 for(var i = 0, len = removeQueue.length; i < len; i++){
12978 tasks.remove(removeQueue[i]);
12981 if(tasks.length < 1){
12986 var now = new Date().getTime();
12987 for(var i = 0, len = tasks.length; i < len; ++i){
12989 var itime = now - t.taskRunTime;
12990 if(t.interval <= itime){
12991 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12992 t.taskRunTime = now;
12993 if(rt === false || t.taskRunCount === t.repeat){
12998 if(t.duration && t.duration <= (now - t.taskStartTime)){
13005 * Queues a new task.
13006 * @param {Object} task
13008 this.start = function(task){
13010 task.taskStartTime = new Date().getTime();
13011 task.taskRunTime = 0;
13012 task.taskRunCount = 0;
13017 this.stop = function(task){
13022 this.stopAll = function(){
13024 for(var i = 0, len = tasks.length; i < len; i++){
13025 if(tasks[i].onStop){
13034 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13036 * Ext JS Library 1.1.1
13037 * Copyright(c) 2006-2007, Ext JS, LLC.
13039 * Originally Released Under LGPL - original licence link has changed is not relivant.
13042 * <script type="text/javascript">
13047 * @class Roo.util.MixedCollection
13048 * @extends Roo.util.Observable
13049 * A Collection class that maintains both numeric indexes and keys and exposes events.
13051 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13052 * collection (defaults to false)
13053 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13054 * and return the key value for that item. This is used when available to look up the key on items that
13055 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13056 * equivalent to providing an implementation for the {@link #getKey} method.
13058 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13066 * Fires when the collection is cleared.
13071 * Fires when an item is added to the collection.
13072 * @param {Number} index The index at which the item was added.
13073 * @param {Object} o The item added.
13074 * @param {String} key The key associated with the added item.
13079 * Fires when an item is replaced in the collection.
13080 * @param {String} key he key associated with the new added.
13081 * @param {Object} old The item being replaced.
13082 * @param {Object} new The new item.
13087 * Fires when an item is removed from the collection.
13088 * @param {Object} o The item being removed.
13089 * @param {String} key (optional) The key associated with the removed item.
13094 this.allowFunctions = allowFunctions === true;
13096 this.getKey = keyFn;
13098 Roo.util.MixedCollection.superclass.constructor.call(this);
13101 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13102 allowFunctions : false,
13105 * Adds an item to the collection.
13106 * @param {String} key The key to associate with the item
13107 * @param {Object} o The item to add.
13108 * @return {Object} The item added.
13110 add : function(key, o){
13111 if(arguments.length == 1){
13113 key = this.getKey(o);
13115 if(typeof key == "undefined" || key === null){
13117 this.items.push(o);
13118 this.keys.push(null);
13120 var old = this.map[key];
13122 return this.replace(key, o);
13125 this.items.push(o);
13127 this.keys.push(key);
13129 this.fireEvent("add", this.length-1, o, key);
13134 * MixedCollection has a generic way to fetch keys if you implement getKey.
13137 var mc = new Roo.util.MixedCollection();
13138 mc.add(someEl.dom.id, someEl);
13139 mc.add(otherEl.dom.id, otherEl);
13143 var mc = new Roo.util.MixedCollection();
13144 mc.getKey = function(el){
13150 // or via the constructor
13151 var mc = new Roo.util.MixedCollection(false, function(el){
13157 * @param o {Object} The item for which to find the key.
13158 * @return {Object} The key for the passed item.
13160 getKey : function(o){
13165 * Replaces an item in the collection.
13166 * @param {String} key The key associated with the item to replace, or the item to replace.
13167 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13168 * @return {Object} The new item.
13170 replace : function(key, o){
13171 if(arguments.length == 1){
13173 key = this.getKey(o);
13175 var old = this.item(key);
13176 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13177 return this.add(key, o);
13179 var index = this.indexOfKey(key);
13180 this.items[index] = o;
13182 this.fireEvent("replace", key, old, o);
13187 * Adds all elements of an Array or an Object to the collection.
13188 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13189 * an Array of values, each of which are added to the collection.
13191 addAll : function(objs){
13192 if(arguments.length > 1 || objs instanceof Array){
13193 var args = arguments.length > 1 ? arguments : objs;
13194 for(var i = 0, len = args.length; i < len; i++){
13198 for(var key in objs){
13199 if(this.allowFunctions || typeof objs[key] != "function"){
13200 this.add(key, objs[key]);
13207 * Executes the specified function once for every item in the collection, passing each
13208 * item as the first and only parameter. returning false from the function will stop the iteration.
13209 * @param {Function} fn The function to execute for each item.
13210 * @param {Object} scope (optional) The scope in which to execute the function.
13212 each : function(fn, scope){
13213 var items = [].concat(this.items); // each safe for removal
13214 for(var i = 0, len = items.length; i < len; i++){
13215 if(fn.call(scope || items[i], items[i], i, len) === false){
13222 * Executes the specified function once for every key in the collection, passing each
13223 * key, and its associated item as the first two parameters.
13224 * @param {Function} fn The function to execute for each item.
13225 * @param {Object} scope (optional) The scope in which to execute the function.
13227 eachKey : function(fn, scope){
13228 for(var i = 0, len = this.keys.length; i < len; i++){
13229 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13234 * Returns the first item in the collection which elicits a true return value from the
13235 * passed selection function.
13236 * @param {Function} fn The selection function to execute for each item.
13237 * @param {Object} scope (optional) The scope in which to execute the function.
13238 * @return {Object} The first item in the collection which returned true from the selection function.
13240 find : function(fn, scope){
13241 for(var i = 0, len = this.items.length; i < len; i++){
13242 if(fn.call(scope || window, this.items[i], this.keys[i])){
13243 return this.items[i];
13250 * Inserts an item at the specified index in the collection.
13251 * @param {Number} index The index to insert the item at.
13252 * @param {String} key The key to associate with the new item, or the item itself.
13253 * @param {Object} o (optional) If the second parameter was a key, the new item.
13254 * @return {Object} The item inserted.
13256 insert : function(index, key, o){
13257 if(arguments.length == 2){
13259 key = this.getKey(o);
13261 if(index >= this.length){
13262 return this.add(key, o);
13265 this.items.splice(index, 0, o);
13266 if(typeof key != "undefined" && key != null){
13269 this.keys.splice(index, 0, key);
13270 this.fireEvent("add", index, o, key);
13275 * Removed an item from the collection.
13276 * @param {Object} o The item to remove.
13277 * @return {Object} The item removed.
13279 remove : function(o){
13280 return this.removeAt(this.indexOf(o));
13284 * Remove an item from a specified index in the collection.
13285 * @param {Number} index The index within the collection of the item to remove.
13287 removeAt : function(index){
13288 if(index < this.length && index >= 0){
13290 var o = this.items[index];
13291 this.items.splice(index, 1);
13292 var key = this.keys[index];
13293 if(typeof key != "undefined"){
13294 delete this.map[key];
13296 this.keys.splice(index, 1);
13297 this.fireEvent("remove", o, key);
13302 * Removed an item associated with the passed key fom the collection.
13303 * @param {String} key The key of the item to remove.
13305 removeKey : function(key){
13306 return this.removeAt(this.indexOfKey(key));
13310 * Returns the number of items in the collection.
13311 * @return {Number} the number of items in the collection.
13313 getCount : function(){
13314 return this.length;
13318 * Returns index within the collection of the passed Object.
13319 * @param {Object} o The item to find the index of.
13320 * @return {Number} index of the item.
13322 indexOf : function(o){
13323 if(!this.items.indexOf){
13324 for(var i = 0, len = this.items.length; i < len; i++){
13325 if(this.items[i] == o) {
13331 return this.items.indexOf(o);
13336 * Returns index within the collection of the passed key.
13337 * @param {String} key The key to find the index of.
13338 * @return {Number} index of the key.
13340 indexOfKey : function(key){
13341 if(!this.keys.indexOf){
13342 for(var i = 0, len = this.keys.length; i < len; i++){
13343 if(this.keys[i] == key) {
13349 return this.keys.indexOf(key);
13354 * Returns the item associated with the passed key OR index. Key has priority over index.
13355 * @param {String/Number} key The key or index of the item.
13356 * @return {Object} The item associated with the passed key.
13358 item : function(key){
13359 if (key === 'length') {
13362 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13363 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13367 * Returns the item at the specified index.
13368 * @param {Number} index The index of the item.
13371 itemAt : function(index){
13372 return this.items[index];
13376 * Returns the item associated with the passed key.
13377 * @param {String/Number} key The key of the item.
13378 * @return {Object} The item associated with the passed key.
13380 key : function(key){
13381 return this.map[key];
13385 * Returns true if the collection contains the passed Object as an item.
13386 * @param {Object} o The Object to look for in the collection.
13387 * @return {Boolean} True if the collection contains the Object as an item.
13389 contains : function(o){
13390 return this.indexOf(o) != -1;
13394 * Returns true if the collection contains the passed Object as a key.
13395 * @param {String} key The key to look for in the collection.
13396 * @return {Boolean} True if the collection contains the Object as a key.
13398 containsKey : function(key){
13399 return typeof this.map[key] != "undefined";
13403 * Removes all items from the collection.
13405 clear : function(){
13410 this.fireEvent("clear");
13414 * Returns the first item in the collection.
13415 * @return {Object} the first item in the collection..
13417 first : function(){
13418 return this.items[0];
13422 * Returns the last item in the collection.
13423 * @return {Object} the last item in the collection..
13426 return this.items[this.length-1];
13429 _sort : function(property, dir, fn){
13430 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13431 fn = fn || function(a, b){
13434 var c = [], k = this.keys, items = this.items;
13435 for(var i = 0, len = items.length; i < len; i++){
13436 c[c.length] = {key: k[i], value: items[i], index: i};
13438 c.sort(function(a, b){
13439 var v = fn(a[property], b[property]) * dsc;
13441 v = (a.index < b.index ? -1 : 1);
13445 for(var i = 0, len = c.length; i < len; i++){
13446 items[i] = c[i].value;
13449 this.fireEvent("sort", this);
13453 * Sorts this collection with the passed comparison function
13454 * @param {String} direction (optional) "ASC" or "DESC"
13455 * @param {Function} fn (optional) comparison function
13457 sort : function(dir, fn){
13458 this._sort("value", dir, fn);
13462 * Sorts this collection by keys
13463 * @param {String} direction (optional) "ASC" or "DESC"
13464 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13466 keySort : function(dir, fn){
13467 this._sort("key", dir, fn || function(a, b){
13468 return String(a).toUpperCase()-String(b).toUpperCase();
13473 * Returns a range of items in this collection
13474 * @param {Number} startIndex (optional) defaults to 0
13475 * @param {Number} endIndex (optional) default to the last item
13476 * @return {Array} An array of items
13478 getRange : function(start, end){
13479 var items = this.items;
13480 if(items.length < 1){
13483 start = start || 0;
13484 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13487 for(var i = start; i <= end; i++) {
13488 r[r.length] = items[i];
13491 for(var i = start; i >= end; i--) {
13492 r[r.length] = items[i];
13499 * Filter the <i>objects</i> in this collection by a specific property.
13500 * Returns a new collection that has been filtered.
13501 * @param {String} property A property on your objects
13502 * @param {String/RegExp} value Either string that the property values
13503 * should start with or a RegExp to test against the property
13504 * @return {MixedCollection} The new filtered collection
13506 filter : function(property, value){
13507 if(!value.exec){ // not a regex
13508 value = String(value);
13509 if(value.length == 0){
13510 return this.clone();
13512 value = new RegExp("^" + Roo.escapeRe(value), "i");
13514 return this.filterBy(function(o){
13515 return o && value.test(o[property]);
13520 * Filter by a function. * Returns a new collection that has been filtered.
13521 * The passed function will be called with each
13522 * object in the collection. If the function returns true, the value is included
13523 * otherwise it is filtered.
13524 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13525 * @param {Object} scope (optional) The scope of the function (defaults to this)
13526 * @return {MixedCollection} The new filtered collection
13528 filterBy : function(fn, scope){
13529 var r = new Roo.util.MixedCollection();
13530 r.getKey = this.getKey;
13531 var k = this.keys, it = this.items;
13532 for(var i = 0, len = it.length; i < len; i++){
13533 if(fn.call(scope||this, it[i], k[i])){
13534 r.add(k[i], it[i]);
13541 * Creates a duplicate of this collection
13542 * @return {MixedCollection}
13544 clone : function(){
13545 var r = new Roo.util.MixedCollection();
13546 var k = this.keys, it = this.items;
13547 for(var i = 0, len = it.length; i < len; i++){
13548 r.add(k[i], it[i]);
13550 r.getKey = this.getKey;
13555 * Returns the item associated with the passed key or index.
13557 * @param {String/Number} key The key or index of the item.
13558 * @return {Object} The item associated with the passed key.
13560 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13562 * Ext JS Library 1.1.1
13563 * Copyright(c) 2006-2007, Ext JS, LLC.
13565 * Originally Released Under LGPL - original licence link has changed is not relivant.
13568 * <script type="text/javascript">
13571 * @class Roo.util.JSON
13572 * Modified version of Douglas Crockford"s json.js that doesn"t
13573 * mess with the Object prototype
13574 * http://www.json.org/js.html
13577 Roo.util.JSON = new (function(){
13578 var useHasOwn = {}.hasOwnProperty ? true : false;
13580 // crashes Safari in some instances
13581 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13583 var pad = function(n) {
13584 return n < 10 ? "0" + n : n;
13597 var encodeString = function(s){
13598 if (/["\\\x00-\x1f]/.test(s)) {
13599 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13604 c = b.charCodeAt();
13606 Math.floor(c / 16).toString(16) +
13607 (c % 16).toString(16);
13610 return '"' + s + '"';
13613 var encodeArray = function(o){
13614 var a = ["["], b, i, l = o.length, v;
13615 for (i = 0; i < l; i += 1) {
13617 switch (typeof v) {
13626 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13634 var encodeDate = function(o){
13635 return '"' + o.getFullYear() + "-" +
13636 pad(o.getMonth() + 1) + "-" +
13637 pad(o.getDate()) + "T" +
13638 pad(o.getHours()) + ":" +
13639 pad(o.getMinutes()) + ":" +
13640 pad(o.getSeconds()) + '"';
13644 * Encodes an Object, Array or other value
13645 * @param {Mixed} o The variable to encode
13646 * @return {String} The JSON string
13648 this.encode = function(o)
13650 // should this be extended to fully wrap stringify..
13652 if(typeof o == "undefined" || o === null){
13654 }else if(o instanceof Array){
13655 return encodeArray(o);
13656 }else if(o instanceof Date){
13657 return encodeDate(o);
13658 }else if(typeof o == "string"){
13659 return encodeString(o);
13660 }else if(typeof o == "number"){
13661 return isFinite(o) ? String(o) : "null";
13662 }else if(typeof o == "boolean"){
13665 var a = ["{"], b, i, v;
13667 if(!useHasOwn || o.hasOwnProperty(i)) {
13669 switch (typeof v) {
13678 a.push(this.encode(i), ":",
13679 v === null ? "null" : this.encode(v));
13690 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13691 * @param {String} json The JSON string
13692 * @return {Object} The resulting object
13694 this.decode = function(json){
13696 return /** eval:var:json */ eval("(" + json + ')');
13700 * Shorthand for {@link Roo.util.JSON#encode}
13701 * @member Roo encode
13703 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13705 * Shorthand for {@link Roo.util.JSON#decode}
13706 * @member Roo decode
13708 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13711 * Ext JS Library 1.1.1
13712 * Copyright(c) 2006-2007, Ext JS, LLC.
13714 * Originally Released Under LGPL - original licence link has changed is not relivant.
13717 * <script type="text/javascript">
13721 * @class Roo.util.Format
13722 * Reusable data formatting functions
13725 Roo.util.Format = function(){
13726 var trimRe = /^\s+|\s+$/g;
13729 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13730 * @param {String} value The string to truncate
13731 * @param {Number} length The maximum length to allow before truncating
13732 * @return {String} The converted text
13734 ellipsis : function(value, len){
13735 if(value && value.length > len){
13736 return value.substr(0, len-3)+"...";
13742 * Checks a reference and converts it to empty string if it is undefined
13743 * @param {Mixed} value Reference to check
13744 * @return {Mixed} Empty string if converted, otherwise the original value
13746 undef : function(value){
13747 return typeof value != "undefined" ? value : "";
13751 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13752 * @param {String} value The string to encode
13753 * @return {String} The encoded text
13755 htmlEncode : function(value){
13756 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13760 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13761 * @param {String} value The string to decode
13762 * @return {String} The decoded text
13764 htmlDecode : function(value){
13765 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13769 * Trims any whitespace from either side of a string
13770 * @param {String} value The text to trim
13771 * @return {String} The trimmed text
13773 trim : function(value){
13774 return String(value).replace(trimRe, "");
13778 * Returns a substring from within an original string
13779 * @param {String} value The original text
13780 * @param {Number} start The start index of the substring
13781 * @param {Number} length The length of the substring
13782 * @return {String} The substring
13784 substr : function(value, start, length){
13785 return String(value).substr(start, length);
13789 * Converts a string to all lower case letters
13790 * @param {String} value The text to convert
13791 * @return {String} The converted text
13793 lowercase : function(value){
13794 return String(value).toLowerCase();
13798 * Converts a string to all upper case letters
13799 * @param {String} value The text to convert
13800 * @return {String} The converted text
13802 uppercase : function(value){
13803 return String(value).toUpperCase();
13807 * Converts the first character only of a string to upper case
13808 * @param {String} value The text to convert
13809 * @return {String} The converted text
13811 capitalize : function(value){
13812 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13816 call : function(value, fn){
13817 if(arguments.length > 2){
13818 var args = Array.prototype.slice.call(arguments, 2);
13819 args.unshift(value);
13821 return /** eval:var:value */ eval(fn).apply(window, args);
13823 /** eval:var:value */
13824 return /** eval:var:value */ eval(fn).call(window, value);
13830 * safer version of Math.toFixed..??/
13831 * @param {Number/String} value The numeric value to format
13832 * @param {Number/String} value Decimal places
13833 * @return {String} The formatted currency string
13835 toFixed : function(v, n)
13837 // why not use to fixed - precision is buggered???
13839 return Math.round(v-0);
13841 var fact = Math.pow(10,n+1);
13842 v = (Math.round((v-0)*fact))/fact;
13843 var z = (''+fact).substring(2);
13844 if (v == Math.floor(v)) {
13845 return Math.floor(v) + '.' + z;
13848 // now just padd decimals..
13849 var ps = String(v).split('.');
13850 var fd = (ps[1] + z);
13851 var r = fd.substring(0,n);
13852 var rm = fd.substring(n);
13854 return ps[0] + '.' + r;
13856 r*=1; // turn it into a number;
13858 if (String(r).length != n) {
13861 r = String(r).substring(1); // chop the end off.
13864 return ps[0] + '.' + r;
13869 * Format a number as US currency
13870 * @param {Number/String} value The numeric value to format
13871 * @return {String} The formatted currency string
13873 usMoney : function(v){
13874 return '$' + Roo.util.Format.number(v);
13879 * eventually this should probably emulate php's number_format
13880 * @param {Number/String} value The numeric value to format
13881 * @param {Number} decimals number of decimal places
13882 * @param {String} delimiter for thousands (default comma)
13883 * @return {String} The formatted currency string
13885 number : function(v, decimals, thousandsDelimiter)
13887 // multiply and round.
13888 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13889 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13891 var mul = Math.pow(10, decimals);
13892 var zero = String(mul).substring(1);
13893 v = (Math.round((v-0)*mul))/mul;
13895 // if it's '0' number.. then
13897 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13899 var ps = v.split('.');
13902 var r = /(\d+)(\d{3})/;
13905 if(thousandsDelimiter.length != 0) {
13906 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13911 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13912 // does not have decimals
13913 (decimals ? ('.' + zero) : '');
13916 return whole + sub ;
13920 * Parse a value into a formatted date using the specified format pattern.
13921 * @param {Mixed} value The value to format
13922 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13923 * @return {String} The formatted date string
13925 date : function(v, format){
13929 if(!(v instanceof Date)){
13930 v = new Date(Date.parse(v));
13932 return v.dateFormat(format || Roo.util.Format.defaults.date);
13936 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13937 * @param {String} format Any valid date format string
13938 * @return {Function} The date formatting function
13940 dateRenderer : function(format){
13941 return function(v){
13942 return Roo.util.Format.date(v, format);
13947 stripTagsRE : /<\/?[^>]+>/gi,
13950 * Strips all HTML tags
13951 * @param {Mixed} value The text from which to strip tags
13952 * @return {String} The stripped text
13954 stripTags : function(v){
13955 return !v ? v : String(v).replace(this.stripTagsRE, "");
13959 Roo.util.Format.defaults = {
13963 * Ext JS Library 1.1.1
13964 * Copyright(c) 2006-2007, Ext JS, LLC.
13966 * Originally Released Under LGPL - original licence link has changed is not relivant.
13969 * <script type="text/javascript">
13976 * @class Roo.MasterTemplate
13977 * @extends Roo.Template
13978 * Provides a template that can have child templates. The syntax is:
13980 var t = new Roo.MasterTemplate(
13981 '<select name="{name}">',
13982 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13985 t.add('options', {value: 'foo', text: 'bar'});
13986 // or you can add multiple child elements in one shot
13987 t.addAll('options', [
13988 {value: 'foo', text: 'bar'},
13989 {value: 'foo2', text: 'bar2'},
13990 {value: 'foo3', text: 'bar3'}
13992 // then append, applying the master template values
13993 t.append('my-form', {name: 'my-select'});
13995 * A name attribute for the child template is not required if you have only one child
13996 * template or you want to refer to them by index.
13998 Roo.MasterTemplate = function(){
13999 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14000 this.originalHtml = this.html;
14002 var m, re = this.subTemplateRe;
14005 while(m = re.exec(this.html)){
14006 var name = m[1], content = m[2];
14011 tpl : new Roo.Template(content)
14014 st[name] = st[subIndex];
14016 st[subIndex].tpl.compile();
14017 st[subIndex].tpl.call = this.call.createDelegate(this);
14020 this.subCount = subIndex;
14023 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14025 * The regular expression used to match sub templates
14029 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14032 * Applies the passed values to a child template.
14033 * @param {String/Number} name (optional) The name or index of the child template
14034 * @param {Array/Object} values The values to be applied to the template
14035 * @return {MasterTemplate} this
14037 add : function(name, values){
14038 if(arguments.length == 1){
14039 values = arguments[0];
14042 var s = this.subs[name];
14043 s.buffer[s.buffer.length] = s.tpl.apply(values);
14048 * Applies all the passed values to a child template.
14049 * @param {String/Number} name (optional) The name or index of the child template
14050 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14051 * @param {Boolean} reset (optional) True to reset the template first
14052 * @return {MasterTemplate} this
14054 fill : function(name, values, reset){
14056 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14064 for(var i = 0, len = values.length; i < len; i++){
14065 this.add(name, values[i]);
14071 * Resets the template for reuse
14072 * @return {MasterTemplate} this
14074 reset : function(){
14076 for(var i = 0; i < this.subCount; i++){
14082 applyTemplate : function(values){
14084 var replaceIndex = -1;
14085 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14086 return s[++replaceIndex].buffer.join("");
14088 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14091 apply : function(){
14092 return this.applyTemplate.apply(this, arguments);
14095 compile : function(){return this;}
14099 * Alias for fill().
14102 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14104 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14105 * var tpl = Roo.MasterTemplate.from('element-id');
14106 * @param {String/HTMLElement} el
14107 * @param {Object} config
14110 Roo.MasterTemplate.from = function(el, config){
14111 el = Roo.getDom(el);
14112 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14115 * Ext JS Library 1.1.1
14116 * Copyright(c) 2006-2007, Ext JS, LLC.
14118 * Originally Released Under LGPL - original licence link has changed is not relivant.
14121 * <script type="text/javascript">
14126 * @class Roo.util.CSS
14127 * Utility class for manipulating CSS rules
14130 Roo.util.CSS = function(){
14132 var doc = document;
14134 var camelRe = /(-[a-z])/gi;
14135 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14139 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14140 * tag and appended to the HEAD of the document.
14141 * @param {String|Object} cssText The text containing the css rules
14142 * @param {String} id An id to add to the stylesheet for later removal
14143 * @return {StyleSheet}
14145 createStyleSheet : function(cssText, id){
14147 var head = doc.getElementsByTagName("head")[0];
14148 var nrules = doc.createElement("style");
14149 nrules.setAttribute("type", "text/css");
14151 nrules.setAttribute("id", id);
14153 if (typeof(cssText) != 'string') {
14154 // support object maps..
14155 // not sure if this a good idea..
14156 // perhaps it should be merged with the general css handling
14157 // and handle js style props.
14158 var cssTextNew = [];
14159 for(var n in cssText) {
14161 for(var k in cssText[n]) {
14162 citems.push( k + ' : ' +cssText[n][k] + ';' );
14164 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14167 cssText = cssTextNew.join("\n");
14173 head.appendChild(nrules);
14174 ss = nrules.styleSheet;
14175 ss.cssText = cssText;
14178 nrules.appendChild(doc.createTextNode(cssText));
14180 nrules.cssText = cssText;
14182 head.appendChild(nrules);
14183 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14185 this.cacheStyleSheet(ss);
14190 * Removes a style or link tag by id
14191 * @param {String} id The id of the tag
14193 removeStyleSheet : function(id){
14194 var existing = doc.getElementById(id);
14196 existing.parentNode.removeChild(existing);
14201 * Dynamically swaps an existing stylesheet reference for a new one
14202 * @param {String} id The id of an existing link tag to remove
14203 * @param {String} url The href of the new stylesheet to include
14205 swapStyleSheet : function(id, url){
14206 this.removeStyleSheet(id);
14207 var ss = doc.createElement("link");
14208 ss.setAttribute("rel", "stylesheet");
14209 ss.setAttribute("type", "text/css");
14210 ss.setAttribute("id", id);
14211 ss.setAttribute("href", url);
14212 doc.getElementsByTagName("head")[0].appendChild(ss);
14216 * Refresh the rule cache if you have dynamically added stylesheets
14217 * @return {Object} An object (hash) of rules indexed by selector
14219 refreshCache : function(){
14220 return this.getRules(true);
14224 cacheStyleSheet : function(stylesheet){
14228 try{// try catch for cross domain access issue
14229 var ssRules = stylesheet.cssRules || stylesheet.rules;
14230 for(var j = ssRules.length-1; j >= 0; --j){
14231 rules[ssRules[j].selectorText] = ssRules[j];
14237 * Gets all css rules for the document
14238 * @param {Boolean} refreshCache true to refresh the internal cache
14239 * @return {Object} An object (hash) of rules indexed by selector
14241 getRules : function(refreshCache){
14242 if(rules == null || refreshCache){
14244 var ds = doc.styleSheets;
14245 for(var i =0, len = ds.length; i < len; i++){
14247 this.cacheStyleSheet(ds[i]);
14255 * Gets an an individual CSS rule by selector(s)
14256 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14257 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14258 * @return {CSSRule} The CSS rule or null if one is not found
14260 getRule : function(selector, refreshCache){
14261 var rs = this.getRules(refreshCache);
14262 if(!(selector instanceof Array)){
14263 return rs[selector];
14265 for(var i = 0; i < selector.length; i++){
14266 if(rs[selector[i]]){
14267 return rs[selector[i]];
14275 * Updates a rule property
14276 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14277 * @param {String} property The css property
14278 * @param {String} value The new value for the property
14279 * @return {Boolean} true If a rule was found and updated
14281 updateRule : function(selector, property, value){
14282 if(!(selector instanceof Array)){
14283 var rule = this.getRule(selector);
14285 rule.style[property.replace(camelRe, camelFn)] = value;
14289 for(var i = 0; i < selector.length; i++){
14290 if(this.updateRule(selector[i], property, value)){
14300 * Ext JS Library 1.1.1
14301 * Copyright(c) 2006-2007, Ext JS, LLC.
14303 * Originally Released Under LGPL - original licence link has changed is not relivant.
14306 * <script type="text/javascript">
14312 * @class Roo.util.ClickRepeater
14313 * @extends Roo.util.Observable
14315 * A wrapper class which can be applied to any element. Fires a "click" event while the
14316 * mouse is pressed. The interval between firings may be specified in the config but
14317 * defaults to 10 milliseconds.
14319 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14321 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14322 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14323 * Similar to an autorepeat key delay.
14324 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14325 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14326 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14327 * "interval" and "delay" are ignored. "immediate" is honored.
14328 * @cfg {Boolean} preventDefault True to prevent the default click event
14329 * @cfg {Boolean} stopDefault True to stop the default click event
14332 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14333 * 2007-02-02 jvs Renamed to ClickRepeater
14334 * 2007-02-03 jvs Modifications for FF Mac and Safari
14337 * @param {String/HTMLElement/Element} el The element to listen on
14338 * @param {Object} config
14340 Roo.util.ClickRepeater = function(el, config)
14342 this.el = Roo.get(el);
14343 this.el.unselectable();
14345 Roo.apply(this, config);
14350 * Fires when the mouse button is depressed.
14351 * @param {Roo.util.ClickRepeater} this
14353 "mousedown" : true,
14356 * Fires on a specified interval during the time the element is pressed.
14357 * @param {Roo.util.ClickRepeater} this
14362 * Fires when the mouse key is released.
14363 * @param {Roo.util.ClickRepeater} this
14368 this.el.on("mousedown", this.handleMouseDown, this);
14369 if(this.preventDefault || this.stopDefault){
14370 this.el.on("click", function(e){
14371 if(this.preventDefault){
14372 e.preventDefault();
14374 if(this.stopDefault){
14380 // allow inline handler
14382 this.on("click", this.handler, this.scope || this);
14385 Roo.util.ClickRepeater.superclass.constructor.call(this);
14388 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14391 preventDefault : true,
14392 stopDefault : false,
14396 handleMouseDown : function(){
14397 clearTimeout(this.timer);
14399 if(this.pressClass){
14400 this.el.addClass(this.pressClass);
14402 this.mousedownTime = new Date();
14404 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14405 this.el.on("mouseout", this.handleMouseOut, this);
14407 this.fireEvent("mousedown", this);
14408 this.fireEvent("click", this);
14410 this.timer = this.click.defer(this.delay || this.interval, this);
14414 click : function(){
14415 this.fireEvent("click", this);
14416 this.timer = this.click.defer(this.getInterval(), this);
14420 getInterval: function(){
14421 if(!this.accelerate){
14422 return this.interval;
14424 var pressTime = this.mousedownTime.getElapsed();
14425 if(pressTime < 500){
14427 }else if(pressTime < 1700){
14429 }else if(pressTime < 2600){
14431 }else if(pressTime < 3500){
14433 }else if(pressTime < 4400){
14435 }else if(pressTime < 5300){
14437 }else if(pressTime < 6200){
14445 handleMouseOut : function(){
14446 clearTimeout(this.timer);
14447 if(this.pressClass){
14448 this.el.removeClass(this.pressClass);
14450 this.el.on("mouseover", this.handleMouseReturn, this);
14454 handleMouseReturn : function(){
14455 this.el.un("mouseover", this.handleMouseReturn);
14456 if(this.pressClass){
14457 this.el.addClass(this.pressClass);
14463 handleMouseUp : function(){
14464 clearTimeout(this.timer);
14465 this.el.un("mouseover", this.handleMouseReturn);
14466 this.el.un("mouseout", this.handleMouseOut);
14467 Roo.get(document).un("mouseup", this.handleMouseUp);
14468 this.el.removeClass(this.pressClass);
14469 this.fireEvent("mouseup", this);
14473 * Ext JS Library 1.1.1
14474 * Copyright(c) 2006-2007, Ext JS, LLC.
14476 * Originally Released Under LGPL - original licence link has changed is not relivant.
14479 * <script type="text/javascript">
14484 * @class Roo.KeyNav
14485 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14486 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14487 * way to implement custom navigation schemes for any UI component.</p>
14488 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14489 * pageUp, pageDown, del, home, end. Usage:</p>
14491 var nav = new Roo.KeyNav("my-element", {
14492 "left" : function(e){
14493 this.moveLeft(e.ctrlKey);
14495 "right" : function(e){
14496 this.moveRight(e.ctrlKey);
14498 "enter" : function(e){
14505 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14506 * @param {Object} config The config
14508 Roo.KeyNav = function(el, config){
14509 this.el = Roo.get(el);
14510 Roo.apply(this, config);
14511 if(!this.disabled){
14512 this.disabled = true;
14517 Roo.KeyNav.prototype = {
14519 * @cfg {Boolean} disabled
14520 * True to disable this KeyNav instance (defaults to false)
14524 * @cfg {String} defaultEventAction
14525 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14526 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14527 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14529 defaultEventAction: "stopEvent",
14531 * @cfg {Boolean} forceKeyDown
14532 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14533 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14534 * handle keydown instead of keypress.
14536 forceKeyDown : false,
14539 prepareEvent : function(e){
14540 var k = e.getKey();
14541 var h = this.keyToHandler[k];
14542 //if(h && this[h]){
14543 // e.stopPropagation();
14545 if(Roo.isSafari && h && k >= 37 && k <= 40){
14551 relay : function(e){
14552 var k = e.getKey();
14553 var h = this.keyToHandler[k];
14555 if(this.doRelay(e, this[h], h) !== true){
14556 e[this.defaultEventAction]();
14562 doRelay : function(e, h, hname){
14563 return h.call(this.scope || this, e);
14566 // possible handlers
14580 // quick lookup hash
14597 * Enable this KeyNav
14599 enable: function(){
14601 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14602 // the EventObject will normalize Safari automatically
14603 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14604 this.el.on("keydown", this.relay, this);
14606 this.el.on("keydown", this.prepareEvent, this);
14607 this.el.on("keypress", this.relay, this);
14609 this.disabled = false;
14614 * Disable this KeyNav
14616 disable: function(){
14617 if(!this.disabled){
14618 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14619 this.el.un("keydown", this.relay);
14621 this.el.un("keydown", this.prepareEvent);
14622 this.el.un("keypress", this.relay);
14624 this.disabled = true;
14629 * Ext JS Library 1.1.1
14630 * Copyright(c) 2006-2007, Ext JS, LLC.
14632 * Originally Released Under LGPL - original licence link has changed is not relivant.
14635 * <script type="text/javascript">
14640 * @class Roo.KeyMap
14641 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14642 * The constructor accepts the same config object as defined by {@link #addBinding}.
14643 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14644 * combination it will call the function with this signature (if the match is a multi-key
14645 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14646 * A KeyMap can also handle a string representation of keys.<br />
14649 // map one key by key code
14650 var map = new Roo.KeyMap("my-element", {
14651 key: 13, // or Roo.EventObject.ENTER
14656 // map multiple keys to one action by string
14657 var map = new Roo.KeyMap("my-element", {
14663 // map multiple keys to multiple actions by strings and array of codes
14664 var map = new Roo.KeyMap("my-element", [
14667 fn: function(){ alert("Return was pressed"); }
14670 fn: function(){ alert('a, b or c was pressed'); }
14675 fn: function(){ alert('Control + shift + tab was pressed.'); }
14679 * <b>Note: A KeyMap starts enabled</b>
14681 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14682 * @param {Object} config The config (see {@link #addBinding})
14683 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14685 Roo.KeyMap = function(el, config, eventName){
14686 this.el = Roo.get(el);
14687 this.eventName = eventName || "keydown";
14688 this.bindings = [];
14690 this.addBinding(config);
14695 Roo.KeyMap.prototype = {
14697 * True to stop the event from bubbling and prevent the default browser action if the
14698 * key was handled by the KeyMap (defaults to false)
14704 * Add a new binding to this KeyMap. The following config object properties are supported:
14706 Property Type Description
14707 ---------- --------------- ----------------------------------------------------------------------
14708 key String/Array A single keycode or an array of keycodes to handle
14709 shift Boolean True to handle key only when shift is pressed (defaults to false)
14710 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14711 alt Boolean True to handle key only when alt is pressed (defaults to false)
14712 fn Function The function to call when KeyMap finds the expected key combination
14713 scope Object The scope of the callback function
14719 var map = new Roo.KeyMap(document, {
14720 key: Roo.EventObject.ENTER,
14725 //Add a new binding to the existing KeyMap later
14733 * @param {Object/Array} config A single KeyMap config or an array of configs
14735 addBinding : function(config){
14736 if(config instanceof Array){
14737 for(var i = 0, len = config.length; i < len; i++){
14738 this.addBinding(config[i]);
14742 var keyCode = config.key,
14743 shift = config.shift,
14744 ctrl = config.ctrl,
14747 scope = config.scope;
14748 if(typeof keyCode == "string"){
14750 var keyString = keyCode.toUpperCase();
14751 for(var j = 0, len = keyString.length; j < len; j++){
14752 ks.push(keyString.charCodeAt(j));
14756 var keyArray = keyCode instanceof Array;
14757 var handler = function(e){
14758 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14759 var k = e.getKey();
14761 for(var i = 0, len = keyCode.length; i < len; i++){
14762 if(keyCode[i] == k){
14763 if(this.stopEvent){
14766 fn.call(scope || window, k, e);
14772 if(this.stopEvent){
14775 fn.call(scope || window, k, e);
14780 this.bindings.push(handler);
14784 * Shorthand for adding a single key listener
14785 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14786 * following options:
14787 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14788 * @param {Function} fn The function to call
14789 * @param {Object} scope (optional) The scope of the function
14791 on : function(key, fn, scope){
14792 var keyCode, shift, ctrl, alt;
14793 if(typeof key == "object" && !(key instanceof Array)){
14812 handleKeyDown : function(e){
14813 if(this.enabled){ //just in case
14814 var b = this.bindings;
14815 for(var i = 0, len = b.length; i < len; i++){
14816 b[i].call(this, e);
14822 * Returns true if this KeyMap is enabled
14823 * @return {Boolean}
14825 isEnabled : function(){
14826 return this.enabled;
14830 * Enables this KeyMap
14832 enable: function(){
14834 this.el.on(this.eventName, this.handleKeyDown, this);
14835 this.enabled = true;
14840 * Disable this KeyMap
14842 disable: function(){
14844 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14845 this.enabled = false;
14850 * Ext JS Library 1.1.1
14851 * Copyright(c) 2006-2007, Ext JS, LLC.
14853 * Originally Released Under LGPL - original licence link has changed is not relivant.
14856 * <script type="text/javascript">
14861 * @class Roo.util.TextMetrics
14862 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14863 * wide, in pixels, a given block of text will be.
14866 Roo.util.TextMetrics = function(){
14870 * Measures the size of the specified text
14871 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14872 * that can affect the size of the rendered text
14873 * @param {String} text The text to measure
14874 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14875 * in order to accurately measure the text height
14876 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14878 measure : function(el, text, fixedWidth){
14880 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14883 shared.setFixedWidth(fixedWidth || 'auto');
14884 return shared.getSize(text);
14888 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14889 * the overhead of multiple calls to initialize the style properties on each measurement.
14890 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14891 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14892 * in order to accurately measure the text height
14893 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14895 createInstance : function(el, fixedWidth){
14896 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14903 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14904 var ml = new Roo.Element(document.createElement('div'));
14905 document.body.appendChild(ml.dom);
14906 ml.position('absolute');
14907 ml.setLeftTop(-1000, -1000);
14911 ml.setWidth(fixedWidth);
14916 * Returns the size of the specified text based on the internal element's style and width properties
14917 * @memberOf Roo.util.TextMetrics.Instance#
14918 * @param {String} text The text to measure
14919 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14921 getSize : function(text){
14923 var s = ml.getSize();
14929 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14930 * that can affect the size of the rendered text
14931 * @memberOf Roo.util.TextMetrics.Instance#
14932 * @param {String/HTMLElement} el The element, dom node or id
14934 bind : function(el){
14936 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14941 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14942 * to set a fixed width in order to accurately measure the text height.
14943 * @memberOf Roo.util.TextMetrics.Instance#
14944 * @param {Number} width The width to set on the element
14946 setFixedWidth : function(width){
14947 ml.setWidth(width);
14951 * Returns the measured width of the specified text
14952 * @memberOf Roo.util.TextMetrics.Instance#
14953 * @param {String} text The text to measure
14954 * @return {Number} width The width in pixels
14956 getWidth : function(text){
14957 ml.dom.style.width = 'auto';
14958 return this.getSize(text).width;
14962 * Returns the measured height of the specified text. For multiline text, be sure to call
14963 * {@link #setFixedWidth} if necessary.
14964 * @memberOf Roo.util.TextMetrics.Instance#
14965 * @param {String} text The text to measure
14966 * @return {Number} height The height in pixels
14968 getHeight : function(text){
14969 return this.getSize(text).height;
14973 instance.bind(bindTo);
14978 // backwards compat
14979 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14981 * Ext JS Library 1.1.1
14982 * Copyright(c) 2006-2007, Ext JS, LLC.
14984 * Originally Released Under LGPL - original licence link has changed is not relivant.
14987 * <script type="text/javascript">
14991 * @class Roo.state.Provider
14992 * Abstract base class for state provider implementations. This class provides methods
14993 * for encoding and decoding <b>typed</b> variables including dates and defines the
14994 * Provider interface.
14996 Roo.state.Provider = function(){
14998 * @event statechange
14999 * Fires when a state change occurs.
15000 * @param {Provider} this This state provider
15001 * @param {String} key The state key which was changed
15002 * @param {String} value The encoded value for the state
15005 "statechange": true
15008 Roo.state.Provider.superclass.constructor.call(this);
15010 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15012 * Returns the current value for a key
15013 * @param {String} name The key name
15014 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15015 * @return {Mixed} The state data
15017 get : function(name, defaultValue){
15018 return typeof this.state[name] == "undefined" ?
15019 defaultValue : this.state[name];
15023 * Clears a value from the state
15024 * @param {String} name The key name
15026 clear : function(name){
15027 delete this.state[name];
15028 this.fireEvent("statechange", this, name, null);
15032 * Sets the value for a key
15033 * @param {String} name The key name
15034 * @param {Mixed} value The value to set
15036 set : function(name, value){
15037 this.state[name] = value;
15038 this.fireEvent("statechange", this, name, value);
15042 * Decodes a string previously encoded with {@link #encodeValue}.
15043 * @param {String} value The value to decode
15044 * @return {Mixed} The decoded value
15046 decodeValue : function(cookie){
15047 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15048 var matches = re.exec(unescape(cookie));
15049 if(!matches || !matches[1]) {
15050 return; // non state cookie
15052 var type = matches[1];
15053 var v = matches[2];
15056 return parseFloat(v);
15058 return new Date(Date.parse(v));
15063 var values = v.split("^");
15064 for(var i = 0, len = values.length; i < len; i++){
15065 all.push(this.decodeValue(values[i]));
15070 var values = v.split("^");
15071 for(var i = 0, len = values.length; i < len; i++){
15072 var kv = values[i].split("=");
15073 all[kv[0]] = this.decodeValue(kv[1]);
15082 * Encodes a value including type information. Decode with {@link #decodeValue}.
15083 * @param {Mixed} value The value to encode
15084 * @return {String} The encoded value
15086 encodeValue : function(v){
15088 if(typeof v == "number"){
15090 }else if(typeof v == "boolean"){
15091 enc = "b:" + (v ? "1" : "0");
15092 }else if(v instanceof Date){
15093 enc = "d:" + v.toGMTString();
15094 }else if(v instanceof Array){
15096 for(var i = 0, len = v.length; i < len; i++){
15097 flat += this.encodeValue(v[i]);
15103 }else if(typeof v == "object"){
15106 if(typeof v[key] != "function"){
15107 flat += key + "=" + this.encodeValue(v[key]) + "^";
15110 enc = "o:" + flat.substring(0, flat.length-1);
15114 return escape(enc);
15120 * Ext JS Library 1.1.1
15121 * Copyright(c) 2006-2007, Ext JS, LLC.
15123 * Originally Released Under LGPL - original licence link has changed is not relivant.
15126 * <script type="text/javascript">
15129 * @class Roo.state.Manager
15130 * This is the global state manager. By default all components that are "state aware" check this class
15131 * for state information if you don't pass them a custom state provider. In order for this class
15132 * to be useful, it must be initialized with a provider when your application initializes.
15134 // in your initialization function
15136 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15138 // supposed you have a {@link Roo.BorderLayout}
15139 var layout = new Roo.BorderLayout(...);
15140 layout.restoreState();
15141 // or a {Roo.BasicDialog}
15142 var dialog = new Roo.BasicDialog(...);
15143 dialog.restoreState();
15147 Roo.state.Manager = function(){
15148 var provider = new Roo.state.Provider();
15152 * Configures the default state provider for your application
15153 * @param {Provider} stateProvider The state provider to set
15155 setProvider : function(stateProvider){
15156 provider = stateProvider;
15160 * Returns the current value for a key
15161 * @param {String} name The key name
15162 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15163 * @return {Mixed} The state data
15165 get : function(key, defaultValue){
15166 return provider.get(key, defaultValue);
15170 * Sets the value for a key
15171 * @param {String} name The key name
15172 * @param {Mixed} value The state data
15174 set : function(key, value){
15175 provider.set(key, value);
15179 * Clears a value from the state
15180 * @param {String} name The key name
15182 clear : function(key){
15183 provider.clear(key);
15187 * Gets the currently configured state provider
15188 * @return {Provider} The state provider
15190 getProvider : function(){
15197 * Ext JS Library 1.1.1
15198 * Copyright(c) 2006-2007, Ext JS, LLC.
15200 * Originally Released Under LGPL - original licence link has changed is not relivant.
15203 * <script type="text/javascript">
15206 * @class Roo.state.CookieProvider
15207 * @extends Roo.state.Provider
15208 * The default Provider implementation which saves state via cookies.
15211 var cp = new Roo.state.CookieProvider({
15213 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15214 domain: "roojs.com"
15216 Roo.state.Manager.setProvider(cp);
15218 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15219 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15220 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15221 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15222 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15223 * domain the page is running on including the 'www' like 'www.roojs.com')
15224 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15226 * Create a new CookieProvider
15227 * @param {Object} config The configuration object
15229 Roo.state.CookieProvider = function(config){
15230 Roo.state.CookieProvider.superclass.constructor.call(this);
15232 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15233 this.domain = null;
15234 this.secure = false;
15235 Roo.apply(this, config);
15236 this.state = this.readCookies();
15239 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15241 set : function(name, value){
15242 if(typeof value == "undefined" || value === null){
15246 this.setCookie(name, value);
15247 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15251 clear : function(name){
15252 this.clearCookie(name);
15253 Roo.state.CookieProvider.superclass.clear.call(this, name);
15257 readCookies : function(){
15259 var c = document.cookie + ";";
15260 var re = /\s?(.*?)=(.*?);/g;
15262 while((matches = re.exec(c)) != null){
15263 var name = matches[1];
15264 var value = matches[2];
15265 if(name && name.substring(0,3) == "ys-"){
15266 cookies[name.substr(3)] = this.decodeValue(value);
15273 setCookie : function(name, value){
15274 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15275 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15276 ((this.path == null) ? "" : ("; path=" + this.path)) +
15277 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15278 ((this.secure == true) ? "; secure" : "");
15282 clearCookie : function(name){
15283 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15284 ((this.path == null) ? "" : ("; path=" + this.path)) +
15285 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15286 ((this.secure == true) ? "; secure" : "");
15290 * Ext JS Library 1.1.1
15291 * Copyright(c) 2006-2007, Ext JS, LLC.
15293 * Originally Released Under LGPL - original licence link has changed is not relivant.
15296 * <script type="text/javascript">
15301 * @class Roo.ComponentMgr
15302 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15305 Roo.ComponentMgr = function(){
15306 var all = new Roo.util.MixedCollection();
15310 * Registers a component.
15311 * @param {Roo.Component} c The component
15313 register : function(c){
15318 * Unregisters a component.
15319 * @param {Roo.Component} c The component
15321 unregister : function(c){
15326 * Returns a component by id
15327 * @param {String} id The component id
15329 get : function(id){
15330 return all.get(id);
15334 * Registers a function that will be called when a specified component is added to ComponentMgr
15335 * @param {String} id The component id
15336 * @param {Funtction} fn The callback function
15337 * @param {Object} scope The scope of the callback
15339 onAvailable : function(id, fn, scope){
15340 all.on("add", function(index, o){
15342 fn.call(scope || o, o);
15343 all.un("add", fn, scope);
15350 * Ext JS Library 1.1.1
15351 * Copyright(c) 2006-2007, Ext JS, LLC.
15353 * Originally Released Under LGPL - original licence link has changed is not relivant.
15356 * <script type="text/javascript">
15360 * @class Roo.Component
15361 * @extends Roo.util.Observable
15362 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15363 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15364 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15365 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15366 * All visual components (widgets) that require rendering into a layout should subclass Component.
15368 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15369 * 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
15370 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15372 Roo.Component = function(config){
15373 config = config || {};
15374 if(config.tagName || config.dom || typeof config == "string"){ // element object
15375 config = {el: config, id: config.id || config};
15377 this.initialConfig = config;
15379 Roo.apply(this, config);
15383 * Fires after the component is disabled.
15384 * @param {Roo.Component} this
15389 * Fires after the component is enabled.
15390 * @param {Roo.Component} this
15394 * @event beforeshow
15395 * Fires before the component is shown. Return false to stop the show.
15396 * @param {Roo.Component} this
15401 * Fires after the component is shown.
15402 * @param {Roo.Component} this
15406 * @event beforehide
15407 * Fires before the component is hidden. Return false to stop the hide.
15408 * @param {Roo.Component} this
15413 * Fires after the component is hidden.
15414 * @param {Roo.Component} this
15418 * @event beforerender
15419 * Fires before the component is rendered. Return false to stop the render.
15420 * @param {Roo.Component} this
15422 beforerender : true,
15425 * Fires after the component is rendered.
15426 * @param {Roo.Component} this
15430 * @event beforedestroy
15431 * Fires before the component is destroyed. Return false to stop the destroy.
15432 * @param {Roo.Component} this
15434 beforedestroy : true,
15437 * Fires after the component is destroyed.
15438 * @param {Roo.Component} this
15443 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15445 Roo.ComponentMgr.register(this);
15446 Roo.Component.superclass.constructor.call(this);
15447 this.initComponent();
15448 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15449 this.render(this.renderTo);
15450 delete this.renderTo;
15455 Roo.Component.AUTO_ID = 1000;
15457 Roo.extend(Roo.Component, Roo.util.Observable, {
15459 * @scope Roo.Component.prototype
15461 * true if this component is hidden. Read-only.
15466 * true if this component is disabled. Read-only.
15471 * true if this component has been rendered. Read-only.
15475 /** @cfg {String} disableClass
15476 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15478 disabledClass : "x-item-disabled",
15479 /** @cfg {Boolean} allowDomMove
15480 * Whether the component can move the Dom node when rendering (defaults to true).
15482 allowDomMove : true,
15483 /** @cfg {String} hideMode (display|visibility)
15484 * How this component should hidden. Supported values are
15485 * "visibility" (css visibility), "offsets" (negative offset position) and
15486 * "display" (css display) - defaults to "display".
15488 hideMode: 'display',
15491 ctype : "Roo.Component",
15494 * @cfg {String} actionMode
15495 * which property holds the element that used for hide() / show() / disable() / enable()
15496 * default is 'el' for forms you probably want to set this to fieldEl
15501 getActionEl : function(){
15502 return this[this.actionMode];
15505 initComponent : Roo.emptyFn,
15507 * If this is a lazy rendering component, render it to its container element.
15508 * @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.
15510 render : function(container, position){
15516 if(this.fireEvent("beforerender", this) === false){
15520 if(!container && this.el){
15521 this.el = Roo.get(this.el);
15522 container = this.el.dom.parentNode;
15523 this.allowDomMove = false;
15525 this.container = Roo.get(container);
15526 this.rendered = true;
15527 if(position !== undefined){
15528 if(typeof position == 'number'){
15529 position = this.container.dom.childNodes[position];
15531 position = Roo.getDom(position);
15534 this.onRender(this.container, position || null);
15536 this.el.addClass(this.cls);
15540 this.el.applyStyles(this.style);
15543 this.fireEvent("render", this);
15544 this.afterRender(this.container);
15557 // default function is not really useful
15558 onRender : function(ct, position){
15560 this.el = Roo.get(this.el);
15561 if(this.allowDomMove !== false){
15562 ct.dom.insertBefore(this.el.dom, position);
15568 getAutoCreate : function(){
15569 var cfg = typeof this.autoCreate == "object" ?
15570 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15571 if(this.id && !cfg.id){
15578 afterRender : Roo.emptyFn,
15581 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15582 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15584 destroy : function(){
15585 if(this.fireEvent("beforedestroy", this) !== false){
15586 this.purgeListeners();
15587 this.beforeDestroy();
15589 this.el.removeAllListeners();
15591 if(this.actionMode == "container"){
15592 this.container.remove();
15596 Roo.ComponentMgr.unregister(this);
15597 this.fireEvent("destroy", this);
15602 beforeDestroy : function(){
15607 onDestroy : function(){
15612 * Returns the underlying {@link Roo.Element}.
15613 * @return {Roo.Element} The element
15615 getEl : function(){
15620 * Returns the id of this component.
15623 getId : function(){
15628 * Try to focus this component.
15629 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15630 * @return {Roo.Component} this
15632 focus : function(selectText){
15635 if(selectText === true){
15636 this.el.dom.select();
15651 * Disable this component.
15652 * @return {Roo.Component} this
15654 disable : function(){
15658 this.disabled = true;
15659 this.fireEvent("disable", this);
15664 onDisable : function(){
15665 this.getActionEl().addClass(this.disabledClass);
15666 this.el.dom.disabled = true;
15670 * Enable this component.
15671 * @return {Roo.Component} this
15673 enable : function(){
15677 this.disabled = false;
15678 this.fireEvent("enable", this);
15683 onEnable : function(){
15684 this.getActionEl().removeClass(this.disabledClass);
15685 this.el.dom.disabled = false;
15689 * Convenience function for setting disabled/enabled by boolean.
15690 * @param {Boolean} disabled
15692 setDisabled : function(disabled){
15693 this[disabled ? "disable" : "enable"]();
15697 * Show this component.
15698 * @return {Roo.Component} this
15701 if(this.fireEvent("beforeshow", this) !== false){
15702 this.hidden = false;
15706 this.fireEvent("show", this);
15712 onShow : function(){
15713 var ae = this.getActionEl();
15714 if(this.hideMode == 'visibility'){
15715 ae.dom.style.visibility = "visible";
15716 }else if(this.hideMode == 'offsets'){
15717 ae.removeClass('x-hidden');
15719 ae.dom.style.display = "";
15724 * Hide this component.
15725 * @return {Roo.Component} this
15728 if(this.fireEvent("beforehide", this) !== false){
15729 this.hidden = true;
15733 this.fireEvent("hide", this);
15739 onHide : function(){
15740 var ae = this.getActionEl();
15741 if(this.hideMode == 'visibility'){
15742 ae.dom.style.visibility = "hidden";
15743 }else if(this.hideMode == 'offsets'){
15744 ae.addClass('x-hidden');
15746 ae.dom.style.display = "none";
15751 * Convenience function to hide or show this component by boolean.
15752 * @param {Boolean} visible True to show, false to hide
15753 * @return {Roo.Component} this
15755 setVisible: function(visible){
15765 * Returns true if this component is visible.
15767 isVisible : function(){
15768 return this.getActionEl().isVisible();
15771 cloneConfig : function(overrides){
15772 overrides = overrides || {};
15773 var id = overrides.id || Roo.id();
15774 var cfg = Roo.applyIf(overrides, this.initialConfig);
15775 cfg.id = id; // prevent dup id
15776 return new this.constructor(cfg);
15780 * Ext JS Library 1.1.1
15781 * Copyright(c) 2006-2007, Ext JS, LLC.
15783 * Originally Released Under LGPL - original licence link has changed is not relivant.
15786 * <script type="text/javascript">
15790 * @class Roo.BoxComponent
15791 * @extends Roo.Component
15792 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15793 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15794 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15795 * layout containers.
15797 * @param {Roo.Element/String/Object} config The configuration options.
15799 Roo.BoxComponent = function(config){
15800 Roo.Component.call(this, config);
15804 * Fires after the component is resized.
15805 * @param {Roo.Component} this
15806 * @param {Number} adjWidth The box-adjusted width that was set
15807 * @param {Number} adjHeight The box-adjusted height that was set
15808 * @param {Number} rawWidth The width that was originally specified
15809 * @param {Number} rawHeight The height that was originally specified
15814 * Fires after the component is moved.
15815 * @param {Roo.Component} this
15816 * @param {Number} x The new x position
15817 * @param {Number} y The new y position
15823 Roo.extend(Roo.BoxComponent, Roo.Component, {
15824 // private, set in afterRender to signify that the component has been rendered
15826 // private, used to defer height settings to subclasses
15827 deferHeight: false,
15828 /** @cfg {Number} width
15829 * width (optional) size of component
15831 /** @cfg {Number} height
15832 * height (optional) size of component
15836 * Sets the width and height of the component. This method fires the resize event. This method can accept
15837 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15838 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15839 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15840 * @return {Roo.BoxComponent} this
15842 setSize : function(w, h){
15843 // support for standard size objects
15844 if(typeof w == 'object'){
15849 if(!this.boxReady){
15855 // prevent recalcs when not needed
15856 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15859 this.lastSize = {width: w, height: h};
15861 var adj = this.adjustSize(w, h);
15862 var aw = adj.width, ah = adj.height;
15863 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15864 var rz = this.getResizeEl();
15865 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15866 rz.setSize(aw, ah);
15867 }else if(!this.deferHeight && ah !== undefined){
15869 }else if(aw !== undefined){
15872 this.onResize(aw, ah, w, h);
15873 this.fireEvent('resize', this, aw, ah, w, h);
15879 * Gets the current size of the component's underlying element.
15880 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15882 getSize : function(){
15883 return this.el.getSize();
15887 * Gets the current XY position of the component's underlying element.
15888 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15889 * @return {Array} The XY position of the element (e.g., [100, 200])
15891 getPosition : function(local){
15892 if(local === true){
15893 return [this.el.getLeft(true), this.el.getTop(true)];
15895 return this.xy || this.el.getXY();
15899 * Gets the current box measurements of the component's underlying element.
15900 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15901 * @returns {Object} box An object in the format {x, y, width, height}
15903 getBox : function(local){
15904 var s = this.el.getSize();
15906 s.x = this.el.getLeft(true);
15907 s.y = this.el.getTop(true);
15909 var xy = this.xy || this.el.getXY();
15917 * Sets the current box measurements of the component's underlying element.
15918 * @param {Object} box An object in the format {x, y, width, height}
15919 * @returns {Roo.BoxComponent} this
15921 updateBox : function(box){
15922 this.setSize(box.width, box.height);
15923 this.setPagePosition(box.x, box.y);
15928 getResizeEl : function(){
15929 return this.resizeEl || this.el;
15933 getPositionEl : function(){
15934 return this.positionEl || this.el;
15938 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15939 * This method fires the move event.
15940 * @param {Number} left The new left
15941 * @param {Number} top The new top
15942 * @returns {Roo.BoxComponent} this
15944 setPosition : function(x, y){
15947 if(!this.boxReady){
15950 var adj = this.adjustPosition(x, y);
15951 var ax = adj.x, ay = adj.y;
15953 var el = this.getPositionEl();
15954 if(ax !== undefined || ay !== undefined){
15955 if(ax !== undefined && ay !== undefined){
15956 el.setLeftTop(ax, ay);
15957 }else if(ax !== undefined){
15959 }else if(ay !== undefined){
15962 this.onPosition(ax, ay);
15963 this.fireEvent('move', this, ax, ay);
15969 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15970 * This method fires the move event.
15971 * @param {Number} x The new x position
15972 * @param {Number} y The new y position
15973 * @returns {Roo.BoxComponent} this
15975 setPagePosition : function(x, y){
15978 if(!this.boxReady){
15981 if(x === undefined || y === undefined){ // cannot translate undefined points
15984 var p = this.el.translatePoints(x, y);
15985 this.setPosition(p.left, p.top);
15990 onRender : function(ct, position){
15991 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15993 this.resizeEl = Roo.get(this.resizeEl);
15995 if(this.positionEl){
15996 this.positionEl = Roo.get(this.positionEl);
16001 afterRender : function(){
16002 Roo.BoxComponent.superclass.afterRender.call(this);
16003 this.boxReady = true;
16004 this.setSize(this.width, this.height);
16005 if(this.x || this.y){
16006 this.setPosition(this.x, this.y);
16008 if(this.pageX || this.pageY){
16009 this.setPagePosition(this.pageX, this.pageY);
16014 * Force the component's size to recalculate based on the underlying element's current height and width.
16015 * @returns {Roo.BoxComponent} this
16017 syncSize : function(){
16018 delete this.lastSize;
16019 this.setSize(this.el.getWidth(), this.el.getHeight());
16024 * Called after the component is resized, this method is empty by default but can be implemented by any
16025 * subclass that needs to perform custom logic after a resize occurs.
16026 * @param {Number} adjWidth The box-adjusted width that was set
16027 * @param {Number} adjHeight The box-adjusted height that was set
16028 * @param {Number} rawWidth The width that was originally specified
16029 * @param {Number} rawHeight The height that was originally specified
16031 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16036 * Called after the component is moved, this method is empty by default but can be implemented by any
16037 * subclass that needs to perform custom logic after a move occurs.
16038 * @param {Number} x The new x position
16039 * @param {Number} y The new y position
16041 onPosition : function(x, y){
16046 adjustSize : function(w, h){
16047 if(this.autoWidth){
16050 if(this.autoHeight){
16053 return {width : w, height: h};
16057 adjustPosition : function(x, y){
16058 return {x : x, y: y};
16062 * Ext JS Library 1.1.1
16063 * Copyright(c) 2006-2007, Ext JS, LLC.
16065 * Originally Released Under LGPL - original licence link has changed is not relivant.
16068 * <script type="text/javascript">
16073 * @extends Roo.Element
16074 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16075 * automatic maintaining of shadow/shim positions.
16076 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16077 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16078 * you can pass a string with a CSS class name. False turns off the shadow.
16079 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16080 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16081 * @cfg {String} cls CSS class to add to the element
16082 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16083 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16085 * @param {Object} config An object with config options.
16086 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16089 Roo.Layer = function(config, existingEl){
16090 config = config || {};
16091 var dh = Roo.DomHelper;
16092 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16094 this.dom = Roo.getDom(existingEl);
16097 var o = config.dh || {tag: "div", cls: "x-layer"};
16098 this.dom = dh.append(pel, o);
16101 this.addClass(config.cls);
16103 this.constrain = config.constrain !== false;
16104 this.visibilityMode = Roo.Element.VISIBILITY;
16106 this.id = this.dom.id = config.id;
16108 this.id = Roo.id(this.dom);
16110 this.zindex = config.zindex || this.getZIndex();
16111 this.position("absolute", this.zindex);
16113 this.shadowOffset = config.shadowOffset || 4;
16114 this.shadow = new Roo.Shadow({
16115 offset : this.shadowOffset,
16116 mode : config.shadow
16119 this.shadowOffset = 0;
16121 this.useShim = config.shim !== false && Roo.useShims;
16122 this.useDisplay = config.useDisplay;
16126 var supr = Roo.Element.prototype;
16128 // shims are shared among layer to keep from having 100 iframes
16131 Roo.extend(Roo.Layer, Roo.Element, {
16133 getZIndex : function(){
16134 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16137 getShim : function(){
16144 var shim = shims.shift();
16146 shim = this.createShim();
16147 shim.enableDisplayMode('block');
16148 shim.dom.style.display = 'none';
16149 shim.dom.style.visibility = 'visible';
16151 var pn = this.dom.parentNode;
16152 if(shim.dom.parentNode != pn){
16153 pn.insertBefore(shim.dom, this.dom);
16155 shim.setStyle('z-index', this.getZIndex()-2);
16160 hideShim : function(){
16162 this.shim.setDisplayed(false);
16163 shims.push(this.shim);
16168 disableShadow : function(){
16170 this.shadowDisabled = true;
16171 this.shadow.hide();
16172 this.lastShadowOffset = this.shadowOffset;
16173 this.shadowOffset = 0;
16177 enableShadow : function(show){
16179 this.shadowDisabled = false;
16180 this.shadowOffset = this.lastShadowOffset;
16181 delete this.lastShadowOffset;
16189 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16190 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16191 sync : function(doShow){
16192 var sw = this.shadow;
16193 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16194 var sh = this.getShim();
16196 var w = this.getWidth(),
16197 h = this.getHeight();
16199 var l = this.getLeft(true),
16200 t = this.getTop(true);
16202 if(sw && !this.shadowDisabled){
16203 if(doShow && !sw.isVisible()){
16206 sw.realign(l, t, w, h);
16212 // fit the shim behind the shadow, so it is shimmed too
16213 var a = sw.adjusts, s = sh.dom.style;
16214 s.left = (Math.min(l, l+a.l))+"px";
16215 s.top = (Math.min(t, t+a.t))+"px";
16216 s.width = (w+a.w)+"px";
16217 s.height = (h+a.h)+"px";
16224 sh.setLeftTop(l, t);
16231 destroy : function(){
16234 this.shadow.hide();
16236 this.removeAllListeners();
16237 var pn = this.dom.parentNode;
16239 pn.removeChild(this.dom);
16241 Roo.Element.uncache(this.id);
16244 remove : function(){
16249 beginUpdate : function(){
16250 this.updating = true;
16254 endUpdate : function(){
16255 this.updating = false;
16260 hideUnders : function(negOffset){
16262 this.shadow.hide();
16268 constrainXY : function(){
16269 if(this.constrain){
16270 var vw = Roo.lib.Dom.getViewWidth(),
16271 vh = Roo.lib.Dom.getViewHeight();
16272 var s = Roo.get(document).getScroll();
16274 var xy = this.getXY();
16275 var x = xy[0], y = xy[1];
16276 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16277 // only move it if it needs it
16279 // first validate right/bottom
16280 if((x + w) > vw+s.left){
16281 x = vw - w - this.shadowOffset;
16284 if((y + h) > vh+s.top){
16285 y = vh - h - this.shadowOffset;
16288 // then make sure top/left isn't negative
16299 var ay = this.avoidY;
16300 if(y <= ay && (y+h) >= ay){
16306 supr.setXY.call(this, xy);
16312 isVisible : function(){
16313 return this.visible;
16317 showAction : function(){
16318 this.visible = true; // track visibility to prevent getStyle calls
16319 if(this.useDisplay === true){
16320 this.setDisplayed("");
16321 }else if(this.lastXY){
16322 supr.setXY.call(this, this.lastXY);
16323 }else if(this.lastLT){
16324 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16329 hideAction : function(){
16330 this.visible = false;
16331 if(this.useDisplay === true){
16332 this.setDisplayed(false);
16334 this.setLeftTop(-10000,-10000);
16338 // overridden Element method
16339 setVisible : function(v, a, d, c, e){
16344 var cb = function(){
16349 }.createDelegate(this);
16350 supr.setVisible.call(this, true, true, d, cb, e);
16353 this.hideUnders(true);
16362 }.createDelegate(this);
16364 supr.setVisible.call(this, v, a, d, cb, e);
16373 storeXY : function(xy){
16374 delete this.lastLT;
16378 storeLeftTop : function(left, top){
16379 delete this.lastXY;
16380 this.lastLT = [left, top];
16384 beforeFx : function(){
16385 this.beforeAction();
16386 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16390 afterFx : function(){
16391 Roo.Layer.superclass.afterFx.apply(this, arguments);
16392 this.sync(this.isVisible());
16396 beforeAction : function(){
16397 if(!this.updating && this.shadow){
16398 this.shadow.hide();
16402 // overridden Element method
16403 setLeft : function(left){
16404 this.storeLeftTop(left, this.getTop(true));
16405 supr.setLeft.apply(this, arguments);
16409 setTop : function(top){
16410 this.storeLeftTop(this.getLeft(true), top);
16411 supr.setTop.apply(this, arguments);
16415 setLeftTop : function(left, top){
16416 this.storeLeftTop(left, top);
16417 supr.setLeftTop.apply(this, arguments);
16421 setXY : function(xy, a, d, c, e){
16423 this.beforeAction();
16425 var cb = this.createCB(c);
16426 supr.setXY.call(this, xy, a, d, cb, e);
16433 createCB : function(c){
16444 // overridden Element method
16445 setX : function(x, a, d, c, e){
16446 this.setXY([x, this.getY()], a, d, c, e);
16449 // overridden Element method
16450 setY : function(y, a, d, c, e){
16451 this.setXY([this.getX(), y], a, d, c, e);
16454 // overridden Element method
16455 setSize : function(w, h, a, d, c, e){
16456 this.beforeAction();
16457 var cb = this.createCB(c);
16458 supr.setSize.call(this, w, h, a, d, cb, e);
16464 // overridden Element method
16465 setWidth : function(w, a, d, c, e){
16466 this.beforeAction();
16467 var cb = this.createCB(c);
16468 supr.setWidth.call(this, w, a, d, cb, e);
16474 // overridden Element method
16475 setHeight : function(h, a, d, c, e){
16476 this.beforeAction();
16477 var cb = this.createCB(c);
16478 supr.setHeight.call(this, h, a, d, cb, e);
16484 // overridden Element method
16485 setBounds : function(x, y, w, h, a, d, c, e){
16486 this.beforeAction();
16487 var cb = this.createCB(c);
16489 this.storeXY([x, y]);
16490 supr.setXY.call(this, [x, y]);
16491 supr.setSize.call(this, w, h, a, d, cb, e);
16494 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16500 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16501 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16502 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16503 * @param {Number} zindex The new z-index to set
16504 * @return {this} The Layer
16506 setZIndex : function(zindex){
16507 this.zindex = zindex;
16508 this.setStyle("z-index", zindex + 2);
16510 this.shadow.setZIndex(zindex + 1);
16513 this.shim.setStyle("z-index", zindex);
16518 * Original code for Roojs - LGPL
16519 * <script type="text/javascript">
16523 * @class Roo.XComponent
16524 * A delayed Element creator...
16525 * Or a way to group chunks of interface together.
16526 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16527 * used in conjunction with XComponent.build() it will create an instance of each element,
16528 * then call addxtype() to build the User interface.
16530 * Mypart.xyx = new Roo.XComponent({
16532 parent : 'Mypart.xyz', // empty == document.element.!!
16536 disabled : function() {}
16538 tree : function() { // return an tree of xtype declared components
16542 xtype : 'NestedLayoutPanel',
16549 * It can be used to build a big heiracy, with parent etc.
16550 * or you can just use this to render a single compoent to a dom element
16551 * MYPART.render(Roo.Element | String(id) | dom_element )
16558 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16559 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16561 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16563 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16564 * - if mulitple topModules exist, the last one is defined as the top module.
16568 * When the top level or multiple modules are to embedded into a existing HTML page,
16569 * the parent element can container '#id' of the element where the module will be drawn.
16573 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16574 * it relies more on a include mechanism, where sub modules are included into an outer page.
16575 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16577 * Bootstrap Roo Included elements
16579 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16580 * hence confusing the component builder as it thinks there are multiple top level elements.
16582 * String Over-ride & Translations
16584 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16585 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16586 * are needed. @see Roo.XComponent.overlayString
16590 * @extends Roo.util.Observable
16592 * @param cfg {Object} configuration of component
16595 Roo.XComponent = function(cfg) {
16596 Roo.apply(this, cfg);
16600 * Fires when this the componnt is built
16601 * @param {Roo.XComponent} c the component
16606 this.region = this.region || 'center'; // default..
16607 Roo.XComponent.register(this);
16608 this.modules = false;
16609 this.el = false; // where the layout goes..
16613 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16616 * The created element (with Roo.factory())
16617 * @type {Roo.Layout}
16623 * for BC - use el in new code
16624 * @type {Roo.Layout}
16630 * for BC - use el in new code
16631 * @type {Roo.Layout}
16636 * @cfg {Function|boolean} disabled
16637 * If this module is disabled by some rule, return true from the funtion
16642 * @cfg {String} parent
16643 * Name of parent element which it get xtype added to..
16648 * @cfg {String} order
16649 * Used to set the order in which elements are created (usefull for multiple tabs)
16654 * @cfg {String} name
16655 * String to display while loading.
16659 * @cfg {String} region
16660 * Region to render component to (defaults to center)
16665 * @cfg {Array} items
16666 * A single item array - the first element is the root of the tree..
16667 * It's done this way to stay compatible with the Xtype system...
16673 * The method that retuns the tree of parts that make up this compoennt
16680 * render element to dom or tree
16681 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16684 render : function(el)
16688 var hp = this.parent ? 1 : 0;
16689 Roo.debug && Roo.log(this);
16691 var tree = this._tree ? this._tree() : this.tree();
16694 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16695 // if parent is a '#.....' string, then let's use that..
16696 var ename = this.parent.substr(1);
16697 this.parent = false;
16698 Roo.debug && Roo.log(ename);
16700 case 'bootstrap-body':
16701 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16702 // this is the BorderLayout standard?
16703 this.parent = { el : true };
16706 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16707 // need to insert stuff...
16709 el : new Roo.bootstrap.layout.Border({
16710 el : document.body,
16716 tabPosition: 'top',
16717 //resizeTabs: true,
16718 alwaysShowTabs: true,
16728 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16729 this.parent = { el : new Roo.bootstrap.Body() };
16730 Roo.debug && Roo.log("setting el to doc body");
16733 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16737 this.parent = { el : true};
16740 el = Roo.get(ename);
16741 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16742 this.parent = { el : true};
16749 if (!el && !this.parent) {
16750 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16755 Roo.debug && Roo.log("EL:");
16756 Roo.debug && Roo.log(el);
16757 Roo.debug && Roo.log("this.parent.el:");
16758 Roo.debug && Roo.log(this.parent.el);
16761 // altertive root elements ??? - we need a better way to indicate these.
16762 var is_alt = Roo.XComponent.is_alt ||
16763 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16764 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16765 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16769 if (!this.parent && is_alt) {
16770 //el = Roo.get(document.body);
16771 this.parent = { el : true };
16776 if (!this.parent) {
16778 Roo.debug && Roo.log("no parent - creating one");
16780 el = el ? Roo.get(el) : false;
16782 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16785 el : new Roo.bootstrap.layout.Border({
16786 el: el || document.body,
16792 tabPosition: 'top',
16793 //resizeTabs: true,
16794 alwaysShowTabs: false,
16797 overflow: 'visible'
16803 // it's a top level one..
16805 el : new Roo.BorderLayout(el || document.body, {
16810 tabPosition: 'top',
16811 //resizeTabs: true,
16812 alwaysShowTabs: el && hp? false : true,
16813 hideTabs: el || !hp ? true : false,
16821 if (!this.parent.el) {
16822 // probably an old style ctor, which has been disabled.
16826 // The 'tree' method is '_tree now'
16828 tree.region = tree.region || this.region;
16829 var is_body = false;
16830 if (this.parent.el === true) {
16831 // bootstrap... - body..
16835 this.parent.el = Roo.factory(tree);
16839 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16840 this.fireEvent('built', this);
16842 this.panel = this.el;
16843 this.layout = this.panel.layout;
16844 this.parentLayout = this.parent.layout || false;
16850 Roo.apply(Roo.XComponent, {
16852 * @property hideProgress
16853 * true to disable the building progress bar.. usefull on single page renders.
16856 hideProgress : false,
16858 * @property buildCompleted
16859 * True when the builder has completed building the interface.
16862 buildCompleted : false,
16865 * @property topModule
16866 * the upper most module - uses document.element as it's constructor.
16873 * @property modules
16874 * array of modules to be created by registration system.
16875 * @type {Array} of Roo.XComponent
16880 * @property elmodules
16881 * array of modules to be created by which use #ID
16882 * @type {Array} of Roo.XComponent
16889 * Is an alternative Root - normally used by bootstrap or other systems,
16890 * where the top element in the tree can wrap 'body'
16891 * @type {boolean} (default false)
16896 * @property build_from_html
16897 * Build elements from html - used by bootstrap HTML stuff
16898 * - this is cleared after build is completed
16899 * @type {boolean} (default false)
16902 build_from_html : false,
16904 * Register components to be built later.
16906 * This solves the following issues
16907 * - Building is not done on page load, but after an authentication process has occured.
16908 * - Interface elements are registered on page load
16909 * - Parent Interface elements may not be loaded before child, so this handles that..
16916 module : 'Pman.Tab.projectMgr',
16918 parent : 'Pman.layout',
16919 disabled : false, // or use a function..
16922 * * @param {Object} details about module
16924 register : function(obj) {
16926 Roo.XComponent.event.fireEvent('register', obj);
16927 switch(typeof(obj.disabled) ) {
16933 if ( obj.disabled() ) {
16939 if (obj.disabled || obj.region == '#disabled') {
16945 this.modules.push(obj);
16949 * convert a string to an object..
16950 * eg. 'AAA.BBB' -> finds AAA.BBB
16954 toObject : function(str)
16956 if (!str || typeof(str) == 'object') {
16959 if (str.substring(0,1) == '#') {
16963 var ar = str.split('.');
16968 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16970 throw "Module not found : " + str;
16974 throw "Module not found : " + str;
16976 Roo.each(ar, function(e) {
16977 if (typeof(o[e]) == 'undefined') {
16978 throw "Module not found : " + str;
16989 * move modules into their correct place in the tree..
16992 preBuild : function ()
16995 Roo.each(this.modules , function (obj)
16997 Roo.XComponent.event.fireEvent('beforebuild', obj);
16999 var opar = obj.parent;
17001 obj.parent = this.toObject(opar);
17003 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17008 Roo.debug && Roo.log("GOT top level module");
17009 Roo.debug && Roo.log(obj);
17010 obj.modules = new Roo.util.MixedCollection(false,
17011 function(o) { return o.order + '' }
17013 this.topModule = obj;
17016 // parent is a string (usually a dom element name..)
17017 if (typeof(obj.parent) == 'string') {
17018 this.elmodules.push(obj);
17021 if (obj.parent.constructor != Roo.XComponent) {
17022 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17024 if (!obj.parent.modules) {
17025 obj.parent.modules = new Roo.util.MixedCollection(false,
17026 function(o) { return o.order + '' }
17029 if (obj.parent.disabled) {
17030 obj.disabled = true;
17032 obj.parent.modules.add(obj);
17037 * make a list of modules to build.
17038 * @return {Array} list of modules.
17041 buildOrder : function()
17044 var cmp = function(a,b) {
17045 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17047 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17048 throw "No top level modules to build";
17051 // make a flat list in order of modules to build.
17052 var mods = this.topModule ? [ this.topModule ] : [];
17055 // elmodules (is a list of DOM based modules )
17056 Roo.each(this.elmodules, function(e) {
17058 if (!this.topModule &&
17059 typeof(e.parent) == 'string' &&
17060 e.parent.substring(0,1) == '#' &&
17061 Roo.get(e.parent.substr(1))
17064 _this.topModule = e;
17070 // add modules to their parents..
17071 var addMod = function(m) {
17072 Roo.debug && Roo.log("build Order: add: " + m.name);
17075 if (m.modules && !m.disabled) {
17076 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17077 m.modules.keySort('ASC', cmp );
17078 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17080 m.modules.each(addMod);
17082 Roo.debug && Roo.log("build Order: no child modules");
17084 // not sure if this is used any more..
17086 m.finalize.name = m.name + " (clean up) ";
17087 mods.push(m.finalize);
17091 if (this.topModule && this.topModule.modules) {
17092 this.topModule.modules.keySort('ASC', cmp );
17093 this.topModule.modules.each(addMod);
17099 * Build the registered modules.
17100 * @param {Object} parent element.
17101 * @param {Function} optional method to call after module has been added.
17105 build : function(opts)
17108 if (typeof(opts) != 'undefined') {
17109 Roo.apply(this,opts);
17113 var mods = this.buildOrder();
17115 //this.allmods = mods;
17116 //Roo.debug && Roo.log(mods);
17118 if (!mods.length) { // should not happen
17119 throw "NO modules!!!";
17123 var msg = "Building Interface...";
17124 // flash it up as modal - so we store the mask!?
17125 if (!this.hideProgress && Roo.MessageBox) {
17126 Roo.MessageBox.show({ title: 'loading' });
17127 Roo.MessageBox.show({
17128 title: "Please wait...",
17138 var total = mods.length;
17141 var progressRun = function() {
17142 if (!mods.length) {
17143 Roo.debug && Roo.log('hide?');
17144 if (!this.hideProgress && Roo.MessageBox) {
17145 Roo.MessageBox.hide();
17147 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17149 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17155 var m = mods.shift();
17158 Roo.debug && Roo.log(m);
17159 // not sure if this is supported any more.. - modules that are are just function
17160 if (typeof(m) == 'function') {
17162 return progressRun.defer(10, _this);
17166 msg = "Building Interface " + (total - mods.length) +
17168 (m.name ? (' - ' + m.name) : '');
17169 Roo.debug && Roo.log(msg);
17170 if (!_this.hideProgress && Roo.MessageBox) {
17171 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17175 // is the module disabled?
17176 var disabled = (typeof(m.disabled) == 'function') ?
17177 m.disabled.call(m.module.disabled) : m.disabled;
17181 return progressRun(); // we do not update the display!
17189 // it's 10 on top level, and 1 on others??? why...
17190 return progressRun.defer(10, _this);
17193 progressRun.defer(1, _this);
17199 * Overlay a set of modified strings onto a component
17200 * This is dependant on our builder exporting the strings and 'named strings' elements.
17202 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17203 * @param {Object} associative array of 'named' string and it's new value.
17206 overlayStrings : function( component, strings )
17208 if (typeof(component['_named_strings']) == 'undefined') {
17209 throw "ERROR: component does not have _named_strings";
17211 for ( var k in strings ) {
17212 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17213 if (md !== false) {
17214 component['_strings'][md] = strings[k];
17216 Roo.log('could not find named string: ' + k + ' in');
17217 Roo.log(component);
17232 * wrapper for event.on - aliased later..
17233 * Typically use to register a event handler for register:
17235 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17244 Roo.XComponent.event = new Roo.util.Observable({
17248 * Fires when an Component is registered,
17249 * set the disable property on the Component to stop registration.
17250 * @param {Roo.XComponent} c the component being registerd.
17255 * @event beforebuild
17256 * Fires before each Component is built
17257 * can be used to apply permissions.
17258 * @param {Roo.XComponent} c the component being registerd.
17261 'beforebuild' : true,
17263 * @event buildcomplete
17264 * Fires on the top level element when all elements have been built
17265 * @param {Roo.XComponent} the top level component.
17267 'buildcomplete' : true
17272 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17275 * marked - a markdown parser
17276 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17277 * https://github.com/chjj/marked
17283 * Roo.Markdown - is a very crude wrapper around marked..
17287 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17289 * Note: move the sample code to the bottom of this
17290 * file before uncommenting it.
17295 Roo.Markdown.toHtml = function(text) {
17297 var c = new Roo.Markdown.marked.setOptions({
17298 renderer: new Roo.Markdown.marked.Renderer(),
17309 text = text.replace(/\\\n/g,' ');
17310 return Roo.Markdown.marked(text);
17315 // Wraps all "globals" so that the only thing
17316 // exposed is makeHtml().
17322 * eval:var:unescape
17330 var escape = function (html, encode) {
17332 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17333 .replace(/</g, '<')
17334 .replace(/>/g, '>')
17335 .replace(/"/g, '"')
17336 .replace(/'/g, ''');
17339 var unescape = function (html) {
17340 // explicitly match decimal, hex, and named HTML entities
17341 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17342 n = n.toLowerCase();
17343 if (n === 'colon') { return ':'; }
17344 if (n.charAt(0) === '#') {
17345 return n.charAt(1) === 'x'
17346 ? String.fromCharCode(parseInt(n.substring(2), 16))
17347 : String.fromCharCode(+n.substring(1));
17353 var replace = function (regex, opt) {
17354 regex = regex.source;
17356 return function self(name, val) {
17357 if (!name) { return new RegExp(regex, opt); }
17358 val = val.source || val;
17359 val = val.replace(/(^|[^\[])\^/g, '$1');
17360 regex = regex.replace(name, val);
17369 var noop = function () {}
17375 var merge = function (obj) {
17380 for (; i < arguments.length; i++) {
17381 target = arguments[i];
17382 for (key in target) {
17383 if (Object.prototype.hasOwnProperty.call(target, key)) {
17384 obj[key] = target[key];
17394 * Block-Level Grammar
17402 code: /^( {4}[^\n]+\n*)+/,
17404 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17405 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17407 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17408 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17409 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17410 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17411 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17413 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17417 block.bullet = /(?:[*+-]|\d+\.)/;
17418 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17419 block.item = replace(block.item, 'gm')
17420 (/bull/g, block.bullet)
17423 block.list = replace(block.list)
17424 (/bull/g, block.bullet)
17425 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17426 ('def', '\\n+(?=' + block.def.source + ')')
17429 block.blockquote = replace(block.blockquote)
17433 block._tag = '(?!(?:'
17434 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17435 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17436 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17438 block.html = replace(block.html)
17439 ('comment', /<!--[\s\S]*?-->/)
17440 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17441 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17442 (/tag/g, block._tag)
17445 block.paragraph = replace(block.paragraph)
17447 ('heading', block.heading)
17448 ('lheading', block.lheading)
17449 ('blockquote', block.blockquote)
17450 ('tag', '<' + block._tag)
17455 * Normal Block Grammar
17458 block.normal = merge({}, block);
17461 * GFM Block Grammar
17464 block.gfm = merge({}, block.normal, {
17465 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17467 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17470 block.gfm.paragraph = replace(block.paragraph)
17472 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17473 + block.list.source.replace('\\1', '\\3') + '|')
17477 * GFM + Tables Block Grammar
17480 block.tables = merge({}, block.gfm, {
17481 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17482 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17489 var Lexer = function (options) {
17491 this.tokens.links = {};
17492 this.options = options || marked.defaults;
17493 this.rules = block.normal;
17495 if (this.options.gfm) {
17496 if (this.options.tables) {
17497 this.rules = block.tables;
17499 this.rules = block.gfm;
17505 * Expose Block Rules
17508 Lexer.rules = block;
17511 * Static Lex Method
17514 Lexer.lex = function(src, options) {
17515 var lexer = new Lexer(options);
17516 return lexer.lex(src);
17523 Lexer.prototype.lex = function(src) {
17525 .replace(/\r\n|\r/g, '\n')
17526 .replace(/\t/g, ' ')
17527 .replace(/\u00a0/g, ' ')
17528 .replace(/\u2424/g, '\n');
17530 return this.token(src, true);
17537 Lexer.prototype.token = function(src, top, bq) {
17538 var src = src.replace(/^ +$/gm, '')
17551 if (cap = this.rules.newline.exec(src)) {
17552 src = src.substring(cap[0].length);
17553 if (cap[0].length > 1) {
17561 if (cap = this.rules.code.exec(src)) {
17562 src = src.substring(cap[0].length);
17563 cap = cap[0].replace(/^ {4}/gm, '');
17566 text: !this.options.pedantic
17567 ? cap.replace(/\n+$/, '')
17574 if (cap = this.rules.fences.exec(src)) {
17575 src = src.substring(cap[0].length);
17585 if (cap = this.rules.heading.exec(src)) {
17586 src = src.substring(cap[0].length);
17589 depth: cap[1].length,
17595 // table no leading pipe (gfm)
17596 if (top && (cap = this.rules.nptable.exec(src))) {
17597 src = src.substring(cap[0].length);
17601 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17602 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17603 cells: cap[3].replace(/\n$/, '').split('\n')
17606 for (i = 0; i < item.align.length; i++) {
17607 if (/^ *-+: *$/.test(item.align[i])) {
17608 item.align[i] = 'right';
17609 } else if (/^ *:-+: *$/.test(item.align[i])) {
17610 item.align[i] = 'center';
17611 } else if (/^ *:-+ *$/.test(item.align[i])) {
17612 item.align[i] = 'left';
17614 item.align[i] = null;
17618 for (i = 0; i < item.cells.length; i++) {
17619 item.cells[i] = item.cells[i].split(/ *\| */);
17622 this.tokens.push(item);
17628 if (cap = this.rules.lheading.exec(src)) {
17629 src = src.substring(cap[0].length);
17632 depth: cap[2] === '=' ? 1 : 2,
17639 if (cap = this.rules.hr.exec(src)) {
17640 src = src.substring(cap[0].length);
17648 if (cap = this.rules.blockquote.exec(src)) {
17649 src = src.substring(cap[0].length);
17652 type: 'blockquote_start'
17655 cap = cap[0].replace(/^ *> ?/gm, '');
17657 // Pass `top` to keep the current
17658 // "toplevel" state. This is exactly
17659 // how markdown.pl works.
17660 this.token(cap, top, true);
17663 type: 'blockquote_end'
17670 if (cap = this.rules.list.exec(src)) {
17671 src = src.substring(cap[0].length);
17675 type: 'list_start',
17676 ordered: bull.length > 1
17679 // Get each top-level item.
17680 cap = cap[0].match(this.rules.item);
17686 for (; i < l; i++) {
17689 // Remove the list item's bullet
17690 // so it is seen as the next token.
17691 space = item.length;
17692 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17694 // Outdent whatever the
17695 // list item contains. Hacky.
17696 if (~item.indexOf('\n ')) {
17697 space -= item.length;
17698 item = !this.options.pedantic
17699 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17700 : item.replace(/^ {1,4}/gm, '');
17703 // Determine whether the next list item belongs here.
17704 // Backpedal if it does not belong in this list.
17705 if (this.options.smartLists && i !== l - 1) {
17706 b = block.bullet.exec(cap[i + 1])[0];
17707 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17708 src = cap.slice(i + 1).join('\n') + src;
17713 // Determine whether item is loose or not.
17714 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17715 // for discount behavior.
17716 loose = next || /\n\n(?!\s*$)/.test(item);
17718 next = item.charAt(item.length - 1) === '\n';
17719 if (!loose) { loose = next; }
17724 ? 'loose_item_start'
17725 : 'list_item_start'
17729 this.token(item, false, bq);
17732 type: 'list_item_end'
17744 if (cap = this.rules.html.exec(src)) {
17745 src = src.substring(cap[0].length);
17747 type: this.options.sanitize
17750 pre: !this.options.sanitizer
17751 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17758 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17759 src = src.substring(cap[0].length);
17760 this.tokens.links[cap[1].toLowerCase()] = {
17768 if (top && (cap = this.rules.table.exec(src))) {
17769 src = src.substring(cap[0].length);
17773 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17774 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17775 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17778 for (i = 0; i < item.align.length; i++) {
17779 if (/^ *-+: *$/.test(item.align[i])) {
17780 item.align[i] = 'right';
17781 } else if (/^ *:-+: *$/.test(item.align[i])) {
17782 item.align[i] = 'center';
17783 } else if (/^ *:-+ *$/.test(item.align[i])) {
17784 item.align[i] = 'left';
17786 item.align[i] = null;
17790 for (i = 0; i < item.cells.length; i++) {
17791 item.cells[i] = item.cells[i]
17792 .replace(/^ *\| *| *\| *$/g, '')
17796 this.tokens.push(item);
17801 // top-level paragraph
17802 if (top && (cap = this.rules.paragraph.exec(src))) {
17803 src = src.substring(cap[0].length);
17806 text: cap[1].charAt(cap[1].length - 1) === '\n'
17807 ? cap[1].slice(0, -1)
17814 if (cap = this.rules.text.exec(src)) {
17815 // Top-level should never reach here.
17816 src = src.substring(cap[0].length);
17826 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17830 return this.tokens;
17834 * Inline-Level Grammar
17838 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17839 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17841 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17842 link: /^!?\[(inside)\]\(href\)/,
17843 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17844 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17845 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17846 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17847 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17848 br: /^ {2,}\n(?!\s*$)/,
17850 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17853 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17854 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17856 inline.link = replace(inline.link)
17857 ('inside', inline._inside)
17858 ('href', inline._href)
17861 inline.reflink = replace(inline.reflink)
17862 ('inside', inline._inside)
17866 * Normal Inline Grammar
17869 inline.normal = merge({}, inline);
17872 * Pedantic Inline Grammar
17875 inline.pedantic = merge({}, inline.normal, {
17876 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17877 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17881 * GFM Inline Grammar
17884 inline.gfm = merge({}, inline.normal, {
17885 escape: replace(inline.escape)('])', '~|])')(),
17886 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17887 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17888 text: replace(inline.text)
17890 ('|', '|https?://|')
17895 * GFM + Line Breaks Inline Grammar
17898 inline.breaks = merge({}, inline.gfm, {
17899 br: replace(inline.br)('{2,}', '*')(),
17900 text: replace(inline.gfm.text)('{2,}', '*')()
17904 * Inline Lexer & Compiler
17907 var InlineLexer = function (links, options) {
17908 this.options = options || marked.defaults;
17909 this.links = links;
17910 this.rules = inline.normal;
17911 this.renderer = this.options.renderer || new Renderer;
17912 this.renderer.options = this.options;
17916 Error('Tokens array requires a `links` property.');
17919 if (this.options.gfm) {
17920 if (this.options.breaks) {
17921 this.rules = inline.breaks;
17923 this.rules = inline.gfm;
17925 } else if (this.options.pedantic) {
17926 this.rules = inline.pedantic;
17931 * Expose Inline Rules
17934 InlineLexer.rules = inline;
17937 * Static Lexing/Compiling Method
17940 InlineLexer.output = function(src, links, options) {
17941 var inline = new InlineLexer(links, options);
17942 return inline.output(src);
17949 InlineLexer.prototype.output = function(src) {
17958 if (cap = this.rules.escape.exec(src)) {
17959 src = src.substring(cap[0].length);
17965 if (cap = this.rules.autolink.exec(src)) {
17966 src = src.substring(cap[0].length);
17967 if (cap[2] === '@') {
17968 text = cap[1].charAt(6) === ':'
17969 ? this.mangle(cap[1].substring(7))
17970 : this.mangle(cap[1]);
17971 href = this.mangle('mailto:') + text;
17973 text = escape(cap[1]);
17976 out += this.renderer.link(href, null, text);
17981 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17982 src = src.substring(cap[0].length);
17983 text = escape(cap[1]);
17985 out += this.renderer.link(href, null, text);
17990 if (cap = this.rules.tag.exec(src)) {
17991 if (!this.inLink && /^<a /i.test(cap[0])) {
17992 this.inLink = true;
17993 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17994 this.inLink = false;
17996 src = src.substring(cap[0].length);
17997 out += this.options.sanitize
17998 ? this.options.sanitizer
17999 ? this.options.sanitizer(cap[0])
18006 if (cap = this.rules.link.exec(src)) {
18007 src = src.substring(cap[0].length);
18008 this.inLink = true;
18009 out += this.outputLink(cap, {
18013 this.inLink = false;
18018 if ((cap = this.rules.reflink.exec(src))
18019 || (cap = this.rules.nolink.exec(src))) {
18020 src = src.substring(cap[0].length);
18021 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18022 link = this.links[link.toLowerCase()];
18023 if (!link || !link.href) {
18024 out += cap[0].charAt(0);
18025 src = cap[0].substring(1) + src;
18028 this.inLink = true;
18029 out += this.outputLink(cap, link);
18030 this.inLink = false;
18035 if (cap = this.rules.strong.exec(src)) {
18036 src = src.substring(cap[0].length);
18037 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18042 if (cap = this.rules.em.exec(src)) {
18043 src = src.substring(cap[0].length);
18044 out += this.renderer.em(this.output(cap[2] || cap[1]));
18049 if (cap = this.rules.code.exec(src)) {
18050 src = src.substring(cap[0].length);
18051 out += this.renderer.codespan(escape(cap[2], true));
18056 if (cap = this.rules.br.exec(src)) {
18057 src = src.substring(cap[0].length);
18058 out += this.renderer.br();
18063 if (cap = this.rules.del.exec(src)) {
18064 src = src.substring(cap[0].length);
18065 out += this.renderer.del(this.output(cap[1]));
18070 if (cap = this.rules.text.exec(src)) {
18071 src = src.substring(cap[0].length);
18072 out += this.renderer.text(escape(this.smartypants(cap[0])));
18078 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18089 InlineLexer.prototype.outputLink = function(cap, link) {
18090 var href = escape(link.href)
18091 , title = link.title ? escape(link.title) : null;
18093 return cap[0].charAt(0) !== '!'
18094 ? this.renderer.link(href, title, this.output(cap[1]))
18095 : this.renderer.image(href, title, escape(cap[1]));
18099 * Smartypants Transformations
18102 InlineLexer.prototype.smartypants = function(text) {
18103 if (!this.options.smartypants) { return text; }
18106 .replace(/---/g, '\u2014')
18108 .replace(/--/g, '\u2013')
18110 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18111 // closing singles & apostrophes
18112 .replace(/'/g, '\u2019')
18114 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18116 .replace(/"/g, '\u201d')
18118 .replace(/\.{3}/g, '\u2026');
18125 InlineLexer.prototype.mangle = function(text) {
18126 if (!this.options.mangle) { return text; }
18132 for (; i < l; i++) {
18133 ch = text.charCodeAt(i);
18134 if (Math.random() > 0.5) {
18135 ch = 'x' + ch.toString(16);
18137 out += '&#' + ch + ';';
18148 * eval:var:Renderer
18151 var Renderer = function (options) {
18152 this.options = options || {};
18155 Renderer.prototype.code = function(code, lang, escaped) {
18156 if (this.options.highlight) {
18157 var out = this.options.highlight(code, lang);
18158 if (out != null && out !== code) {
18163 // hack!!! - it's already escapeD?
18168 return '<pre><code>'
18169 + (escaped ? code : escape(code, true))
18170 + '\n</code></pre>';
18173 return '<pre><code class="'
18174 + this.options.langPrefix
18175 + escape(lang, true)
18177 + (escaped ? code : escape(code, true))
18178 + '\n</code></pre>\n';
18181 Renderer.prototype.blockquote = function(quote) {
18182 return '<blockquote>\n' + quote + '</blockquote>\n';
18185 Renderer.prototype.html = function(html) {
18189 Renderer.prototype.heading = function(text, level, raw) {
18193 + this.options.headerPrefix
18194 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18202 Renderer.prototype.hr = function() {
18203 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18206 Renderer.prototype.list = function(body, ordered) {
18207 var type = ordered ? 'ol' : 'ul';
18208 return '<' + type + '>\n' + body + '</' + type + '>\n';
18211 Renderer.prototype.listitem = function(text) {
18212 return '<li>' + text + '</li>\n';
18215 Renderer.prototype.paragraph = function(text) {
18216 return '<p>' + text + '</p>\n';
18219 Renderer.prototype.table = function(header, body) {
18220 return '<table class="table table-striped">\n'
18230 Renderer.prototype.tablerow = function(content) {
18231 return '<tr>\n' + content + '</tr>\n';
18234 Renderer.prototype.tablecell = function(content, flags) {
18235 var type = flags.header ? 'th' : 'td';
18236 var tag = flags.align
18237 ? '<' + type + ' style="text-align:' + flags.align + '">'
18238 : '<' + type + '>';
18239 return tag + content + '</' + type + '>\n';
18242 // span level renderer
18243 Renderer.prototype.strong = function(text) {
18244 return '<strong>' + text + '</strong>';
18247 Renderer.prototype.em = function(text) {
18248 return '<em>' + text + '</em>';
18251 Renderer.prototype.codespan = function(text) {
18252 return '<code>' + text + '</code>';
18255 Renderer.prototype.br = function() {
18256 return this.options.xhtml ? '<br/>' : '<br>';
18259 Renderer.prototype.del = function(text) {
18260 return '<del>' + text + '</del>';
18263 Renderer.prototype.link = function(href, title, text) {
18264 if (this.options.sanitize) {
18266 var prot = decodeURIComponent(unescape(href))
18267 .replace(/[^\w:]/g, '')
18272 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18276 var out = '<a href="' + href + '"';
18278 out += ' title="' + title + '"';
18280 out += '>' + text + '</a>';
18284 Renderer.prototype.image = function(href, title, text) {
18285 var out = '<img src="' + href + '" alt="' + text + '"';
18287 out += ' title="' + title + '"';
18289 out += this.options.xhtml ? '/>' : '>';
18293 Renderer.prototype.text = function(text) {
18298 * Parsing & Compiling
18304 var Parser= function (options) {
18307 this.options = options || marked.defaults;
18308 this.options.renderer = this.options.renderer || new Renderer;
18309 this.renderer = this.options.renderer;
18310 this.renderer.options = this.options;
18314 * Static Parse Method
18317 Parser.parse = function(src, options, renderer) {
18318 var parser = new Parser(options, renderer);
18319 return parser.parse(src);
18326 Parser.prototype.parse = function(src) {
18327 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18328 this.tokens = src.reverse();
18331 while (this.next()) {
18342 Parser.prototype.next = function() {
18343 return this.token = this.tokens.pop();
18347 * Preview Next Token
18350 Parser.prototype.peek = function() {
18351 return this.tokens[this.tokens.length - 1] || 0;
18355 * Parse Text Tokens
18358 Parser.prototype.parseText = function() {
18359 var body = this.token.text;
18361 while (this.peek().type === 'text') {
18362 body += '\n' + this.next().text;
18365 return this.inline.output(body);
18369 * Parse Current Token
18372 Parser.prototype.tok = function() {
18373 switch (this.token.type) {
18378 return this.renderer.hr();
18381 return this.renderer.heading(
18382 this.inline.output(this.token.text),
18387 return this.renderer.code(this.token.text,
18389 this.token.escaped);
18402 for (i = 0; i < this.token.header.length; i++) {
18403 flags = { header: true, align: this.token.align[i] };
18404 cell += this.renderer.tablecell(
18405 this.inline.output(this.token.header[i]),
18406 { header: true, align: this.token.align[i] }
18409 header += this.renderer.tablerow(cell);
18411 for (i = 0; i < this.token.cells.length; i++) {
18412 row = this.token.cells[i];
18415 for (j = 0; j < row.length; j++) {
18416 cell += this.renderer.tablecell(
18417 this.inline.output(row[j]),
18418 { header: false, align: this.token.align[j] }
18422 body += this.renderer.tablerow(cell);
18424 return this.renderer.table(header, body);
18426 case 'blockquote_start': {
18429 while (this.next().type !== 'blockquote_end') {
18430 body += this.tok();
18433 return this.renderer.blockquote(body);
18435 case 'list_start': {
18437 , ordered = this.token.ordered;
18439 while (this.next().type !== 'list_end') {
18440 body += this.tok();
18443 return this.renderer.list(body, ordered);
18445 case 'list_item_start': {
18448 while (this.next().type !== 'list_item_end') {
18449 body += this.token.type === 'text'
18454 return this.renderer.listitem(body);
18456 case 'loose_item_start': {
18459 while (this.next().type !== 'list_item_end') {
18460 body += this.tok();
18463 return this.renderer.listitem(body);
18466 var html = !this.token.pre && !this.options.pedantic
18467 ? this.inline.output(this.token.text)
18469 return this.renderer.html(html);
18471 case 'paragraph': {
18472 return this.renderer.paragraph(this.inline.output(this.token.text));
18475 return this.renderer.paragraph(this.parseText());
18487 var marked = function (src, opt, callback) {
18488 if (callback || typeof opt === 'function') {
18494 opt = merge({}, marked.defaults, opt || {});
18496 var highlight = opt.highlight
18502 tokens = Lexer.lex(src, opt)
18504 return callback(e);
18507 pending = tokens.length;
18511 var done = function(err) {
18513 opt.highlight = highlight;
18514 return callback(err);
18520 out = Parser.parse(tokens, opt);
18525 opt.highlight = highlight;
18529 : callback(null, out);
18532 if (!highlight || highlight.length < 3) {
18536 delete opt.highlight;
18538 if (!pending) { return done(); }
18540 for (; i < tokens.length; i++) {
18542 if (token.type !== 'code') {
18543 return --pending || done();
18545 return highlight(token.text, token.lang, function(err, code) {
18546 if (err) { return done(err); }
18547 if (code == null || code === token.text) {
18548 return --pending || done();
18551 token.escaped = true;
18552 --pending || done();
18560 if (opt) { opt = merge({}, marked.defaults, opt); }
18561 return Parser.parse(Lexer.lex(src, opt), opt);
18563 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18564 if ((opt || marked.defaults).silent) {
18565 return '<p>An error occured:</p><pre>'
18566 + escape(e.message + '', true)
18578 marked.setOptions = function(opt) {
18579 merge(marked.defaults, opt);
18583 marked.defaults = {
18594 langPrefix: 'lang-',
18595 smartypants: false,
18597 renderer: new Renderer,
18605 marked.Parser = Parser;
18606 marked.parser = Parser.parse;
18608 marked.Renderer = Renderer;
18610 marked.Lexer = Lexer;
18611 marked.lexer = Lexer.lex;
18613 marked.InlineLexer = InlineLexer;
18614 marked.inlineLexer = InlineLexer.output;
18616 marked.parse = marked;
18618 Roo.Markdown.marked = marked;
18622 * Ext JS Library 1.1.1
18623 * Copyright(c) 2006-2007, Ext JS, LLC.
18625 * Originally Released Under LGPL - original licence link has changed is not relivant.
18628 * <script type="text/javascript">
18634 * These classes are derivatives of the similarly named classes in the YUI Library.
18635 * The original license:
18636 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18637 * Code licensed under the BSD License:
18638 * http://developer.yahoo.net/yui/license.txt
18643 var Event=Roo.EventManager;
18644 var Dom=Roo.lib.Dom;
18647 * @class Roo.dd.DragDrop
18648 * @extends Roo.util.Observable
18649 * Defines the interface and base operation of items that that can be
18650 * dragged or can be drop targets. It was designed to be extended, overriding
18651 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18652 * Up to three html elements can be associated with a DragDrop instance:
18654 * <li>linked element: the element that is passed into the constructor.
18655 * This is the element which defines the boundaries for interaction with
18656 * other DragDrop objects.</li>
18657 * <li>handle element(s): The drag operation only occurs if the element that
18658 * was clicked matches a handle element. By default this is the linked
18659 * element, but there are times that you will want only a portion of the
18660 * linked element to initiate the drag operation, and the setHandleElId()
18661 * method provides a way to define this.</li>
18662 * <li>drag element: this represents the element that would be moved along
18663 * with the cursor during a drag operation. By default, this is the linked
18664 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18665 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18668 * This class should not be instantiated until the onload event to ensure that
18669 * the associated elements are available.
18670 * The following would define a DragDrop obj that would interact with any
18671 * other DragDrop obj in the "group1" group:
18673 * dd = new Roo.dd.DragDrop("div1", "group1");
18675 * Since none of the event handlers have been implemented, nothing would
18676 * actually happen if you were to run the code above. Normally you would
18677 * override this class or one of the default implementations, but you can
18678 * also override the methods you want on an instance of the class...
18680 * dd.onDragDrop = function(e, id) {
18681 * alert("dd was dropped on " + id);
18685 * @param {String} id of the element that is linked to this instance
18686 * @param {String} sGroup the group of related DragDrop objects
18687 * @param {object} config an object containing configurable attributes
18688 * Valid properties for DragDrop:
18689 * padding, isTarget, maintainOffset, primaryButtonOnly
18691 Roo.dd.DragDrop = function(id, sGroup, config) {
18693 this.init(id, sGroup, config);
18698 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18701 * The id of the element associated with this object. This is what we
18702 * refer to as the "linked element" because the size and position of
18703 * this element is used to determine when the drag and drop objects have
18711 * Configuration attributes passed into the constructor
18718 * The id of the element that will be dragged. By default this is same
18719 * as the linked element , but could be changed to another element. Ex:
18721 * @property dragElId
18728 * the id of the element that initiates the drag operation. By default
18729 * this is the linked element, but could be changed to be a child of this
18730 * element. This lets us do things like only starting the drag when the
18731 * header element within the linked html element is clicked.
18732 * @property handleElId
18739 * An associative array of HTML tags that will be ignored if clicked.
18740 * @property invalidHandleTypes
18741 * @type {string: string}
18743 invalidHandleTypes: null,
18746 * An associative array of ids for elements that will be ignored if clicked
18747 * @property invalidHandleIds
18748 * @type {string: string}
18750 invalidHandleIds: null,
18753 * An indexted array of css class names for elements that will be ignored
18755 * @property invalidHandleClasses
18758 invalidHandleClasses: null,
18761 * The linked element's absolute X position at the time the drag was
18763 * @property startPageX
18770 * The linked element's absolute X position at the time the drag was
18772 * @property startPageY
18779 * The group defines a logical collection of DragDrop objects that are
18780 * related. Instances only get events when interacting with other
18781 * DragDrop object in the same group. This lets us define multiple
18782 * groups using a single DragDrop subclass if we want.
18784 * @type {string: string}
18789 * Individual drag/drop instances can be locked. This will prevent
18790 * onmousedown start drag.
18798 * Lock this instance
18801 lock: function() { this.locked = true; },
18804 * Unlock this instace
18807 unlock: function() { this.locked = false; },
18810 * By default, all insances can be a drop target. This can be disabled by
18811 * setting isTarget to false.
18818 * The padding configured for this drag and drop object for calculating
18819 * the drop zone intersection with this object.
18826 * Cached reference to the linked element
18827 * @property _domRef
18833 * Internal typeof flag
18834 * @property __ygDragDrop
18837 __ygDragDrop: true,
18840 * Set to true when horizontal contraints are applied
18841 * @property constrainX
18848 * Set to true when vertical contraints are applied
18849 * @property constrainY
18856 * The left constraint
18864 * The right constraint
18872 * The up constraint
18881 * The down constraint
18889 * Maintain offsets when we resetconstraints. Set to true when you want
18890 * the position of the element relative to its parent to stay the same
18891 * when the page changes
18893 * @property maintainOffset
18896 maintainOffset: false,
18899 * Array of pixel locations the element will snap to if we specified a
18900 * horizontal graduation/interval. This array is generated automatically
18901 * when you define a tick interval.
18908 * Array of pixel locations the element will snap to if we specified a
18909 * vertical graduation/interval. This array is generated automatically
18910 * when you define a tick interval.
18917 * By default the drag and drop instance will only respond to the primary
18918 * button click (left button for a right-handed mouse). Set to true to
18919 * allow drag and drop to start with any mouse click that is propogated
18921 * @property primaryButtonOnly
18924 primaryButtonOnly: true,
18927 * The availabe property is false until the linked dom element is accessible.
18928 * @property available
18934 * By default, drags can only be initiated if the mousedown occurs in the
18935 * region the linked element is. This is done in part to work around a
18936 * bug in some browsers that mis-report the mousedown if the previous
18937 * mouseup happened outside of the window. This property is set to true
18938 * if outer handles are defined.
18940 * @property hasOuterHandles
18944 hasOuterHandles: false,
18947 * Code that executes immediately before the startDrag event
18948 * @method b4StartDrag
18951 b4StartDrag: function(x, y) { },
18954 * Abstract method called after a drag/drop object is clicked
18955 * and the drag or mousedown time thresholds have beeen met.
18956 * @method startDrag
18957 * @param {int} X click location
18958 * @param {int} Y click location
18960 startDrag: function(x, y) { /* override this */ },
18963 * Code that executes immediately before the onDrag event
18967 b4Drag: function(e) { },
18970 * Abstract method called during the onMouseMove event while dragging an
18973 * @param {Event} e the mousemove event
18975 onDrag: function(e) { /* override this */ },
18978 * Abstract method called when this element fist begins hovering over
18979 * another DragDrop obj
18980 * @method onDragEnter
18981 * @param {Event} e the mousemove event
18982 * @param {String|DragDrop[]} id In POINT mode, the element
18983 * id this is hovering over. In INTERSECT mode, an array of one or more
18984 * dragdrop items being hovered over.
18986 onDragEnter: function(e, id) { /* override this */ },
18989 * Code that executes immediately before the onDragOver event
18990 * @method b4DragOver
18993 b4DragOver: function(e) { },
18996 * Abstract method called when this element is hovering over another
18998 * @method onDragOver
18999 * @param {Event} e the mousemove event
19000 * @param {String|DragDrop[]} id In POINT mode, the element
19001 * id this is hovering over. In INTERSECT mode, an array of dd items
19002 * being hovered over.
19004 onDragOver: function(e, id) { /* override this */ },
19007 * Code that executes immediately before the onDragOut event
19008 * @method b4DragOut
19011 b4DragOut: function(e) { },
19014 * Abstract method called when we are no longer hovering over an element
19015 * @method onDragOut
19016 * @param {Event} e the mousemove event
19017 * @param {String|DragDrop[]} id In POINT mode, the element
19018 * id this was hovering over. In INTERSECT mode, an array of dd items
19019 * that the mouse is no longer over.
19021 onDragOut: function(e, id) { /* override this */ },
19024 * Code that executes immediately before the onDragDrop event
19025 * @method b4DragDrop
19028 b4DragDrop: function(e) { },
19031 * Abstract method called when this item is dropped on another DragDrop
19033 * @method onDragDrop
19034 * @param {Event} e the mouseup event
19035 * @param {String|DragDrop[]} id In POINT mode, the element
19036 * id this was dropped on. In INTERSECT mode, an array of dd items this
19039 onDragDrop: function(e, id) { /* override this */ },
19042 * Abstract method called when this item is dropped on an area with no
19044 * @method onInvalidDrop
19045 * @param {Event} e the mouseup event
19047 onInvalidDrop: function(e) { /* override this */ },
19050 * Code that executes immediately before the endDrag event
19051 * @method b4EndDrag
19054 b4EndDrag: function(e) { },
19057 * Fired when we are done dragging the object
19059 * @param {Event} e the mouseup event
19061 endDrag: function(e) { /* override this */ },
19064 * Code executed immediately before the onMouseDown event
19065 * @method b4MouseDown
19066 * @param {Event} e the mousedown event
19069 b4MouseDown: function(e) { },
19072 * Event handler that fires when a drag/drop obj gets a mousedown
19073 * @method onMouseDown
19074 * @param {Event} e the mousedown event
19076 onMouseDown: function(e) { /* override this */ },
19079 * Event handler that fires when a drag/drop obj gets a mouseup
19080 * @method onMouseUp
19081 * @param {Event} e the mouseup event
19083 onMouseUp: function(e) { /* override this */ },
19086 * Override the onAvailable method to do what is needed after the initial
19087 * position was determined.
19088 * @method onAvailable
19090 onAvailable: function () {
19094 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19097 defaultPadding : {left:0, right:0, top:0, bottom:0},
19100 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19104 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19105 { dragElId: "existingProxyDiv" });
19106 dd.startDrag = function(){
19107 this.constrainTo("parent-id");
19110 * Or you can initalize it using the {@link Roo.Element} object:
19112 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19113 startDrag : function(){
19114 this.constrainTo("parent-id");
19118 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19119 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19120 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19121 * an object containing the sides to pad. For example: {right:10, bottom:10}
19122 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19124 constrainTo : function(constrainTo, pad, inContent){
19125 if(typeof pad == "number"){
19126 pad = {left: pad, right:pad, top:pad, bottom:pad};
19128 pad = pad || this.defaultPadding;
19129 var b = Roo.get(this.getEl()).getBox();
19130 var ce = Roo.get(constrainTo);
19131 var s = ce.getScroll();
19132 var c, cd = ce.dom;
19133 if(cd == document.body){
19134 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19137 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19141 var topSpace = b.y - c.y;
19142 var leftSpace = b.x - c.x;
19144 this.resetConstraints();
19145 this.setXConstraint(leftSpace - (pad.left||0), // left
19146 c.width - leftSpace - b.width - (pad.right||0) //right
19148 this.setYConstraint(topSpace - (pad.top||0), //top
19149 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19154 * Returns a reference to the linked element
19156 * @return {HTMLElement} the html element
19158 getEl: function() {
19159 if (!this._domRef) {
19160 this._domRef = Roo.getDom(this.id);
19163 return this._domRef;
19167 * Returns a reference to the actual element to drag. By default this is
19168 * the same as the html element, but it can be assigned to another
19169 * element. An example of this can be found in Roo.dd.DDProxy
19170 * @method getDragEl
19171 * @return {HTMLElement} the html element
19173 getDragEl: function() {
19174 return Roo.getDom(this.dragElId);
19178 * Sets up the DragDrop object. Must be called in the constructor of any
19179 * Roo.dd.DragDrop subclass
19181 * @param id the id of the linked element
19182 * @param {String} sGroup the group of related items
19183 * @param {object} config configuration attributes
19185 init: function(id, sGroup, config) {
19186 this.initTarget(id, sGroup, config);
19187 if (!Roo.isTouch) {
19188 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19190 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19191 // Event.on(this.id, "selectstart", Event.preventDefault);
19195 * Initializes Targeting functionality only... the object does not
19196 * get a mousedown handler.
19197 * @method initTarget
19198 * @param id the id of the linked element
19199 * @param {String} sGroup the group of related items
19200 * @param {object} config configuration attributes
19202 initTarget: function(id, sGroup, config) {
19204 // configuration attributes
19205 this.config = config || {};
19207 // create a local reference to the drag and drop manager
19208 this.DDM = Roo.dd.DDM;
19209 // initialize the groups array
19212 // assume that we have an element reference instead of an id if the
19213 // parameter is not a string
19214 if (typeof id !== "string") {
19221 // add to an interaction group
19222 this.addToGroup((sGroup) ? sGroup : "default");
19224 // We don't want to register this as the handle with the manager
19225 // so we just set the id rather than calling the setter.
19226 this.handleElId = id;
19228 // the linked element is the element that gets dragged by default
19229 this.setDragElId(id);
19231 // by default, clicked anchors will not start drag operations.
19232 this.invalidHandleTypes = { A: "A" };
19233 this.invalidHandleIds = {};
19234 this.invalidHandleClasses = [];
19236 this.applyConfig();
19238 this.handleOnAvailable();
19242 * Applies the configuration parameters that were passed into the constructor.
19243 * This is supposed to happen at each level through the inheritance chain. So
19244 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19245 * DragDrop in order to get all of the parameters that are available in
19247 * @method applyConfig
19249 applyConfig: function() {
19251 // configurable properties:
19252 // padding, isTarget, maintainOffset, primaryButtonOnly
19253 this.padding = this.config.padding || [0, 0, 0, 0];
19254 this.isTarget = (this.config.isTarget !== false);
19255 this.maintainOffset = (this.config.maintainOffset);
19256 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19261 * Executed when the linked element is available
19262 * @method handleOnAvailable
19265 handleOnAvailable: function() {
19266 this.available = true;
19267 this.resetConstraints();
19268 this.onAvailable();
19272 * Configures the padding for the target zone in px. Effectively expands
19273 * (or reduces) the virtual object size for targeting calculations.
19274 * Supports css-style shorthand; if only one parameter is passed, all sides
19275 * will have that padding, and if only two are passed, the top and bottom
19276 * will have the first param, the left and right the second.
19277 * @method setPadding
19278 * @param {int} iTop Top pad
19279 * @param {int} iRight Right pad
19280 * @param {int} iBot Bot pad
19281 * @param {int} iLeft Left pad
19283 setPadding: function(iTop, iRight, iBot, iLeft) {
19284 // this.padding = [iLeft, iRight, iTop, iBot];
19285 if (!iRight && 0 !== iRight) {
19286 this.padding = [iTop, iTop, iTop, iTop];
19287 } else if (!iBot && 0 !== iBot) {
19288 this.padding = [iTop, iRight, iTop, iRight];
19290 this.padding = [iTop, iRight, iBot, iLeft];
19295 * Stores the initial placement of the linked element.
19296 * @method setInitialPosition
19297 * @param {int} diffX the X offset, default 0
19298 * @param {int} diffY the Y offset, default 0
19300 setInitPosition: function(diffX, diffY) {
19301 var el = this.getEl();
19303 if (!this.DDM.verifyEl(el)) {
19307 var dx = diffX || 0;
19308 var dy = diffY || 0;
19310 var p = Dom.getXY( el );
19312 this.initPageX = p[0] - dx;
19313 this.initPageY = p[1] - dy;
19315 this.lastPageX = p[0];
19316 this.lastPageY = p[1];
19319 this.setStartPosition(p);
19323 * Sets the start position of the element. This is set when the obj
19324 * is initialized, the reset when a drag is started.
19325 * @method setStartPosition
19326 * @param pos current position (from previous lookup)
19329 setStartPosition: function(pos) {
19330 var p = pos || Dom.getXY( this.getEl() );
19331 this.deltaSetXY = null;
19333 this.startPageX = p[0];
19334 this.startPageY = p[1];
19338 * Add this instance to a group of related drag/drop objects. All
19339 * instances belong to at least one group, and can belong to as many
19340 * groups as needed.
19341 * @method addToGroup
19342 * @param sGroup {string} the name of the group
19344 addToGroup: function(sGroup) {
19345 this.groups[sGroup] = true;
19346 this.DDM.regDragDrop(this, sGroup);
19350 * Remove's this instance from the supplied interaction group
19351 * @method removeFromGroup
19352 * @param {string} sGroup The group to drop
19354 removeFromGroup: function(sGroup) {
19355 if (this.groups[sGroup]) {
19356 delete this.groups[sGroup];
19359 this.DDM.removeDDFromGroup(this, sGroup);
19363 * Allows you to specify that an element other than the linked element
19364 * will be moved with the cursor during a drag
19365 * @method setDragElId
19366 * @param id {string} the id of the element that will be used to initiate the drag
19368 setDragElId: function(id) {
19369 this.dragElId = id;
19373 * Allows you to specify a child of the linked element that should be
19374 * used to initiate the drag operation. An example of this would be if
19375 * you have a content div with text and links. Clicking anywhere in the
19376 * content area would normally start the drag operation. Use this method
19377 * to specify that an element inside of the content div is the element
19378 * that starts the drag operation.
19379 * @method setHandleElId
19380 * @param id {string} the id of the element that will be used to
19381 * initiate the drag.
19383 setHandleElId: function(id) {
19384 if (typeof id !== "string") {
19387 this.handleElId = id;
19388 this.DDM.regHandle(this.id, id);
19392 * Allows you to set an element outside of the linked element as a drag
19394 * @method setOuterHandleElId
19395 * @param id the id of the element that will be used to initiate the drag
19397 setOuterHandleElId: function(id) {
19398 if (typeof id !== "string") {
19401 Event.on(id, "mousedown",
19402 this.handleMouseDown, this);
19403 this.setHandleElId(id);
19405 this.hasOuterHandles = true;
19409 * Remove all drag and drop hooks for this element
19412 unreg: function() {
19413 Event.un(this.id, "mousedown",
19414 this.handleMouseDown);
19415 Event.un(this.id, "touchstart",
19416 this.handleMouseDown);
19417 this._domRef = null;
19418 this.DDM._remove(this);
19421 destroy : function(){
19426 * Returns true if this instance is locked, or the drag drop mgr is locked
19427 * (meaning that all drag/drop is disabled on the page.)
19429 * @return {boolean} true if this obj or all drag/drop is locked, else
19432 isLocked: function() {
19433 return (this.DDM.isLocked() || this.locked);
19437 * Fired when this object is clicked
19438 * @method handleMouseDown
19440 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19443 handleMouseDown: function(e, oDD){
19445 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19446 //Roo.log('not touch/ button !=0');
19449 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19450 return; // double touch..
19454 if (this.isLocked()) {
19455 //Roo.log('locked');
19459 this.DDM.refreshCache(this.groups);
19460 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19461 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19462 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19463 //Roo.log('no outer handes or not over target');
19466 // Roo.log('check validator');
19467 if (this.clickValidator(e)) {
19468 // Roo.log('validate success');
19469 // set the initial element position
19470 this.setStartPosition();
19473 this.b4MouseDown(e);
19474 this.onMouseDown(e);
19476 this.DDM.handleMouseDown(e, this);
19478 this.DDM.stopEvent(e);
19486 clickValidator: function(e) {
19487 var target = e.getTarget();
19488 return ( this.isValidHandleChild(target) &&
19489 (this.id == this.handleElId ||
19490 this.DDM.handleWasClicked(target, this.id)) );
19494 * Allows you to specify a tag name that should not start a drag operation
19495 * when clicked. This is designed to facilitate embedding links within a
19496 * drag handle that do something other than start the drag.
19497 * @method addInvalidHandleType
19498 * @param {string} tagName the type of element to exclude
19500 addInvalidHandleType: function(tagName) {
19501 var type = tagName.toUpperCase();
19502 this.invalidHandleTypes[type] = type;
19506 * Lets you to specify an element id for a child of a drag handle
19507 * that should not initiate a drag
19508 * @method addInvalidHandleId
19509 * @param {string} id the element id of the element you wish to ignore
19511 addInvalidHandleId: function(id) {
19512 if (typeof id !== "string") {
19515 this.invalidHandleIds[id] = id;
19519 * Lets you specify a css class of elements that will not initiate a drag
19520 * @method addInvalidHandleClass
19521 * @param {string} cssClass the class of the elements you wish to ignore
19523 addInvalidHandleClass: function(cssClass) {
19524 this.invalidHandleClasses.push(cssClass);
19528 * Unsets an excluded tag name set by addInvalidHandleType
19529 * @method removeInvalidHandleType
19530 * @param {string} tagName the type of element to unexclude
19532 removeInvalidHandleType: function(tagName) {
19533 var type = tagName.toUpperCase();
19534 // this.invalidHandleTypes[type] = null;
19535 delete this.invalidHandleTypes[type];
19539 * Unsets an invalid handle id
19540 * @method removeInvalidHandleId
19541 * @param {string} id the id of the element to re-enable
19543 removeInvalidHandleId: function(id) {
19544 if (typeof id !== "string") {
19547 delete this.invalidHandleIds[id];
19551 * Unsets an invalid css class
19552 * @method removeInvalidHandleClass
19553 * @param {string} cssClass the class of the element(s) you wish to
19556 removeInvalidHandleClass: function(cssClass) {
19557 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19558 if (this.invalidHandleClasses[i] == cssClass) {
19559 delete this.invalidHandleClasses[i];
19565 * Checks the tag exclusion list to see if this click should be ignored
19566 * @method isValidHandleChild
19567 * @param {HTMLElement} node the HTMLElement to evaluate
19568 * @return {boolean} true if this is a valid tag type, false if not
19570 isValidHandleChild: function(node) {
19573 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19576 nodeName = node.nodeName.toUpperCase();
19578 nodeName = node.nodeName;
19580 valid = valid && !this.invalidHandleTypes[nodeName];
19581 valid = valid && !this.invalidHandleIds[node.id];
19583 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19584 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19593 * Create the array of horizontal tick marks if an interval was specified
19594 * in setXConstraint().
19595 * @method setXTicks
19598 setXTicks: function(iStartX, iTickSize) {
19600 this.xTickSize = iTickSize;
19604 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19606 this.xTicks[this.xTicks.length] = i;
19611 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19613 this.xTicks[this.xTicks.length] = i;
19618 this.xTicks.sort(this.DDM.numericSort) ;
19622 * Create the array of vertical tick marks if an interval was specified in
19623 * setYConstraint().
19624 * @method setYTicks
19627 setYTicks: function(iStartY, iTickSize) {
19629 this.yTickSize = iTickSize;
19633 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19635 this.yTicks[this.yTicks.length] = i;
19640 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19642 this.yTicks[this.yTicks.length] = i;
19647 this.yTicks.sort(this.DDM.numericSort) ;
19651 * By default, the element can be dragged any place on the screen. Use
19652 * this method to limit the horizontal travel of the element. Pass in
19653 * 0,0 for the parameters if you want to lock the drag to the y axis.
19654 * @method setXConstraint
19655 * @param {int} iLeft the number of pixels the element can move to the left
19656 * @param {int} iRight the number of pixels the element can move to the
19658 * @param {int} iTickSize optional parameter for specifying that the
19660 * should move iTickSize pixels at a time.
19662 setXConstraint: function(iLeft, iRight, iTickSize) {
19663 this.leftConstraint = iLeft;
19664 this.rightConstraint = iRight;
19666 this.minX = this.initPageX - iLeft;
19667 this.maxX = this.initPageX + iRight;
19668 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19670 this.constrainX = true;
19674 * Clears any constraints applied to this instance. Also clears ticks
19675 * since they can't exist independent of a constraint at this time.
19676 * @method clearConstraints
19678 clearConstraints: function() {
19679 this.constrainX = false;
19680 this.constrainY = false;
19685 * Clears any tick interval defined for this instance
19686 * @method clearTicks
19688 clearTicks: function() {
19689 this.xTicks = null;
19690 this.yTicks = null;
19691 this.xTickSize = 0;
19692 this.yTickSize = 0;
19696 * By default, the element can be dragged any place on the screen. Set
19697 * this to limit the vertical travel of the element. Pass in 0,0 for the
19698 * parameters if you want to lock the drag to the x axis.
19699 * @method setYConstraint
19700 * @param {int} iUp the number of pixels the element can move up
19701 * @param {int} iDown the number of pixels the element can move down
19702 * @param {int} iTickSize optional parameter for specifying that the
19703 * element should move iTickSize pixels at a time.
19705 setYConstraint: function(iUp, iDown, iTickSize) {
19706 this.topConstraint = iUp;
19707 this.bottomConstraint = iDown;
19709 this.minY = this.initPageY - iUp;
19710 this.maxY = this.initPageY + iDown;
19711 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19713 this.constrainY = true;
19718 * resetConstraints must be called if you manually reposition a dd element.
19719 * @method resetConstraints
19720 * @param {boolean} maintainOffset
19722 resetConstraints: function() {
19725 // Maintain offsets if necessary
19726 if (this.initPageX || this.initPageX === 0) {
19727 // figure out how much this thing has moved
19728 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19729 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19731 this.setInitPosition(dx, dy);
19733 // This is the first time we have detected the element's position
19735 this.setInitPosition();
19738 if (this.constrainX) {
19739 this.setXConstraint( this.leftConstraint,
19740 this.rightConstraint,
19744 if (this.constrainY) {
19745 this.setYConstraint( this.topConstraint,
19746 this.bottomConstraint,
19752 * Normally the drag element is moved pixel by pixel, but we can specify
19753 * that it move a number of pixels at a time. This method resolves the
19754 * location when we have it set up like this.
19756 * @param {int} val where we want to place the object
19757 * @param {int[]} tickArray sorted array of valid points
19758 * @return {int} the closest tick
19761 getTick: function(val, tickArray) {
19764 // If tick interval is not defined, it is effectively 1 pixel,
19765 // so we return the value passed to us.
19767 } else if (tickArray[0] >= val) {
19768 // The value is lower than the first tick, so we return the first
19770 return tickArray[0];
19772 for (var i=0, len=tickArray.length; i<len; ++i) {
19774 if (tickArray[next] && tickArray[next] >= val) {
19775 var diff1 = val - tickArray[i];
19776 var diff2 = tickArray[next] - val;
19777 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19781 // The value is larger than the last tick, so we return the last
19783 return tickArray[tickArray.length - 1];
19790 * @return {string} string representation of the dd obj
19792 toString: function() {
19793 return ("DragDrop " + this.id);
19801 * Ext JS Library 1.1.1
19802 * Copyright(c) 2006-2007, Ext JS, LLC.
19804 * Originally Released Under LGPL - original licence link has changed is not relivant.
19807 * <script type="text/javascript">
19812 * The drag and drop utility provides a framework for building drag and drop
19813 * applications. In addition to enabling drag and drop for specific elements,
19814 * the drag and drop elements are tracked by the manager class, and the
19815 * interactions between the various elements are tracked during the drag and
19816 * the implementing code is notified about these important moments.
19819 // Only load the library once. Rewriting the manager class would orphan
19820 // existing drag and drop instances.
19821 if (!Roo.dd.DragDropMgr) {
19824 * @class Roo.dd.DragDropMgr
19825 * DragDropMgr is a singleton that tracks the element interaction for
19826 * all DragDrop items in the window. Generally, you will not call
19827 * this class directly, but it does have helper methods that could
19828 * be useful in your DragDrop implementations.
19831 Roo.dd.DragDropMgr = function() {
19833 var Event = Roo.EventManager;
19838 * Two dimensional Array of registered DragDrop objects. The first
19839 * dimension is the DragDrop item group, the second the DragDrop
19842 * @type {string: string}
19849 * Array of element ids defined as drag handles. Used to determine
19850 * if the element that generated the mousedown event is actually the
19851 * handle and not the html element itself.
19852 * @property handleIds
19853 * @type {string: string}
19860 * the DragDrop object that is currently being dragged
19861 * @property dragCurrent
19869 * the DragDrop object(s) that are being hovered over
19870 * @property dragOvers
19878 * the X distance between the cursor and the object being dragged
19887 * the Y distance between the cursor and the object being dragged
19896 * Flag to determine if we should prevent the default behavior of the
19897 * events we define. By default this is true, but this can be set to
19898 * false if you need the default behavior (not recommended)
19899 * @property preventDefault
19903 preventDefault: true,
19906 * Flag to determine if we should stop the propagation of the events
19907 * we generate. This is true by default but you may want to set it to
19908 * false if the html element contains other features that require the
19910 * @property stopPropagation
19914 stopPropagation: true,
19917 * Internal flag that is set to true when drag and drop has been
19919 * @property initialized
19926 * All drag and drop can be disabled.
19934 * Called the first time an element is registered.
19940 this.initialized = true;
19944 * In point mode, drag and drop interaction is defined by the
19945 * location of the cursor during the drag/drop
19953 * In intersect mode, drag and drop interactio nis defined by the
19954 * overlap of two or more drag and drop objects.
19955 * @property INTERSECT
19962 * The current drag and drop mode. Default: POINT
19970 * Runs method on all drag and drop objects
19971 * @method _execOnAll
19975 _execOnAll: function(sMethod, args) {
19976 for (var i in this.ids) {
19977 for (var j in this.ids[i]) {
19978 var oDD = this.ids[i][j];
19979 if (! this.isTypeOfDD(oDD)) {
19982 oDD[sMethod].apply(oDD, args);
19988 * Drag and drop initialization. Sets up the global event handlers
19993 _onLoad: function() {
19997 if (!Roo.isTouch) {
19998 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19999 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20001 Event.on(document, "touchend", this.handleMouseUp, this, true);
20002 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20004 Event.on(window, "unload", this._onUnload, this, true);
20005 Event.on(window, "resize", this._onResize, this, true);
20006 // Event.on(window, "mouseout", this._test);
20011 * Reset constraints on all drag and drop objs
20012 * @method _onResize
20016 _onResize: function(e) {
20017 this._execOnAll("resetConstraints", []);
20021 * Lock all drag and drop functionality
20025 lock: function() { this.locked = true; },
20028 * Unlock all drag and drop functionality
20032 unlock: function() { this.locked = false; },
20035 * Is drag and drop locked?
20037 * @return {boolean} True if drag and drop is locked, false otherwise.
20040 isLocked: function() { return this.locked; },
20043 * Location cache that is set for all drag drop objects when a drag is
20044 * initiated, cleared when the drag is finished.
20045 * @property locationCache
20052 * Set useCache to false if you want to force object the lookup of each
20053 * drag and drop linked element constantly during a drag.
20054 * @property useCache
20061 * The number of pixels that the mouse needs to move after the
20062 * mousedown before the drag is initiated. Default=3;
20063 * @property clickPixelThresh
20067 clickPixelThresh: 3,
20070 * The number of milliseconds after the mousedown event to initiate the
20071 * drag if we don't get a mouseup event. Default=1000
20072 * @property clickTimeThresh
20076 clickTimeThresh: 350,
20079 * Flag that indicates that either the drag pixel threshold or the
20080 * mousdown time threshold has been met
20081 * @property dragThreshMet
20086 dragThreshMet: false,
20089 * Timeout used for the click time threshold
20090 * @property clickTimeout
20095 clickTimeout: null,
20098 * The X position of the mousedown event stored for later use when a
20099 * drag threshold is met.
20108 * The Y position of the mousedown event stored for later use when a
20109 * drag threshold is met.
20118 * Each DragDrop instance must be registered with the DragDropMgr.
20119 * This is executed in DragDrop.init()
20120 * @method regDragDrop
20121 * @param {DragDrop} oDD the DragDrop object to register
20122 * @param {String} sGroup the name of the group this element belongs to
20125 regDragDrop: function(oDD, sGroup) {
20126 if (!this.initialized) { this.init(); }
20128 if (!this.ids[sGroup]) {
20129 this.ids[sGroup] = {};
20131 this.ids[sGroup][oDD.id] = oDD;
20135 * Removes the supplied dd instance from the supplied group. Executed
20136 * by DragDrop.removeFromGroup, so don't call this function directly.
20137 * @method removeDDFromGroup
20141 removeDDFromGroup: function(oDD, sGroup) {
20142 if (!this.ids[sGroup]) {
20143 this.ids[sGroup] = {};
20146 var obj = this.ids[sGroup];
20147 if (obj && obj[oDD.id]) {
20148 delete obj[oDD.id];
20153 * Unregisters a drag and drop item. This is executed in
20154 * DragDrop.unreg, use that method instead of calling this directly.
20159 _remove: function(oDD) {
20160 for (var g in oDD.groups) {
20161 if (g && this.ids[g][oDD.id]) {
20162 delete this.ids[g][oDD.id];
20165 delete this.handleIds[oDD.id];
20169 * Each DragDrop handle element must be registered. This is done
20170 * automatically when executing DragDrop.setHandleElId()
20171 * @method regHandle
20172 * @param {String} sDDId the DragDrop id this element is a handle for
20173 * @param {String} sHandleId the id of the element that is the drag
20177 regHandle: function(sDDId, sHandleId) {
20178 if (!this.handleIds[sDDId]) {
20179 this.handleIds[sDDId] = {};
20181 this.handleIds[sDDId][sHandleId] = sHandleId;
20185 * Utility function to determine if a given element has been
20186 * registered as a drag drop item.
20187 * @method isDragDrop
20188 * @param {String} id the element id to check
20189 * @return {boolean} true if this element is a DragDrop item,
20193 isDragDrop: function(id) {
20194 return ( this.getDDById(id) ) ? true : false;
20198 * Returns the drag and drop instances that are in all groups the
20199 * passed in instance belongs to.
20200 * @method getRelated
20201 * @param {DragDrop} p_oDD the obj to get related data for
20202 * @param {boolean} bTargetsOnly if true, only return targetable objs
20203 * @return {DragDrop[]} the related instances
20206 getRelated: function(p_oDD, bTargetsOnly) {
20208 for (var i in p_oDD.groups) {
20209 for (j in this.ids[i]) {
20210 var dd = this.ids[i][j];
20211 if (! this.isTypeOfDD(dd)) {
20214 if (!bTargetsOnly || dd.isTarget) {
20215 oDDs[oDDs.length] = dd;
20224 * Returns true if the specified dd target is a legal target for
20225 * the specifice drag obj
20226 * @method isLegalTarget
20227 * @param {DragDrop} the drag obj
20228 * @param {DragDrop} the target
20229 * @return {boolean} true if the target is a legal target for the
20233 isLegalTarget: function (oDD, oTargetDD) {
20234 var targets = this.getRelated(oDD, true);
20235 for (var i=0, len=targets.length;i<len;++i) {
20236 if (targets[i].id == oTargetDD.id) {
20245 * My goal is to be able to transparently determine if an object is
20246 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20247 * returns "object", oDD.constructor.toString() always returns
20248 * "DragDrop" and not the name of the subclass. So for now it just
20249 * evaluates a well-known variable in DragDrop.
20250 * @method isTypeOfDD
20251 * @param {Object} the object to evaluate
20252 * @return {boolean} true if typeof oDD = DragDrop
20255 isTypeOfDD: function (oDD) {
20256 return (oDD && oDD.__ygDragDrop);
20260 * Utility function to determine if a given element has been
20261 * registered as a drag drop handle for the given Drag Drop object.
20263 * @param {String} id the element id to check
20264 * @return {boolean} true if this element is a DragDrop handle, false
20268 isHandle: function(sDDId, sHandleId) {
20269 return ( this.handleIds[sDDId] &&
20270 this.handleIds[sDDId][sHandleId] );
20274 * Returns the DragDrop instance for a given id
20275 * @method getDDById
20276 * @param {String} id the id of the DragDrop object
20277 * @return {DragDrop} the drag drop object, null if it is not found
20280 getDDById: function(id) {
20281 for (var i in this.ids) {
20282 if (this.ids[i][id]) {
20283 return this.ids[i][id];
20290 * Fired after a registered DragDrop object gets the mousedown event.
20291 * Sets up the events required to track the object being dragged
20292 * @method handleMouseDown
20293 * @param {Event} e the event
20294 * @param oDD the DragDrop object being dragged
20298 handleMouseDown: function(e, oDD) {
20300 Roo.QuickTips.disable();
20302 this.currentTarget = e.getTarget();
20304 this.dragCurrent = oDD;
20306 var el = oDD.getEl();
20308 // track start position
20309 this.startX = e.getPageX();
20310 this.startY = e.getPageY();
20312 this.deltaX = this.startX - el.offsetLeft;
20313 this.deltaY = this.startY - el.offsetTop;
20315 this.dragThreshMet = false;
20317 this.clickTimeout = setTimeout(
20319 var DDM = Roo.dd.DDM;
20320 DDM.startDrag(DDM.startX, DDM.startY);
20322 this.clickTimeThresh );
20326 * Fired when either the drag pixel threshol or the mousedown hold
20327 * time threshold has been met.
20328 * @method startDrag
20329 * @param x {int} the X position of the original mousedown
20330 * @param y {int} the Y position of the original mousedown
20333 startDrag: function(x, y) {
20334 clearTimeout(this.clickTimeout);
20335 if (this.dragCurrent) {
20336 this.dragCurrent.b4StartDrag(x, y);
20337 this.dragCurrent.startDrag(x, y);
20339 this.dragThreshMet = true;
20343 * Internal function to handle the mouseup event. Will be invoked
20344 * from the context of the document.
20345 * @method handleMouseUp
20346 * @param {Event} e the event
20350 handleMouseUp: function(e) {
20353 Roo.QuickTips.enable();
20355 if (! this.dragCurrent) {
20359 clearTimeout(this.clickTimeout);
20361 if (this.dragThreshMet) {
20362 this.fireEvents(e, true);
20372 * Utility to stop event propagation and event default, if these
20373 * features are turned on.
20374 * @method stopEvent
20375 * @param {Event} e the event as returned by this.getEvent()
20378 stopEvent: function(e){
20379 if(this.stopPropagation) {
20380 e.stopPropagation();
20383 if (this.preventDefault) {
20384 e.preventDefault();
20389 * Internal function to clean up event handlers after the drag
20390 * operation is complete
20392 * @param {Event} e the event
20396 stopDrag: function(e) {
20397 // Fire the drag end event for the item that was dragged
20398 if (this.dragCurrent) {
20399 if (this.dragThreshMet) {
20400 this.dragCurrent.b4EndDrag(e);
20401 this.dragCurrent.endDrag(e);
20404 this.dragCurrent.onMouseUp(e);
20407 this.dragCurrent = null;
20408 this.dragOvers = {};
20412 * Internal function to handle the mousemove event. Will be invoked
20413 * from the context of the html element.
20415 * @TODO figure out what we can do about mouse events lost when the
20416 * user drags objects beyond the window boundary. Currently we can
20417 * detect this in internet explorer by verifying that the mouse is
20418 * down during the mousemove event. Firefox doesn't give us the
20419 * button state on the mousemove event.
20420 * @method handleMouseMove
20421 * @param {Event} e the event
20425 handleMouseMove: function(e) {
20426 if (! this.dragCurrent) {
20430 // var button = e.which || e.button;
20432 // check for IE mouseup outside of page boundary
20433 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20435 return this.handleMouseUp(e);
20438 if (!this.dragThreshMet) {
20439 var diffX = Math.abs(this.startX - e.getPageX());
20440 var diffY = Math.abs(this.startY - e.getPageY());
20441 if (diffX > this.clickPixelThresh ||
20442 diffY > this.clickPixelThresh) {
20443 this.startDrag(this.startX, this.startY);
20447 if (this.dragThreshMet) {
20448 this.dragCurrent.b4Drag(e);
20449 this.dragCurrent.onDrag(e);
20450 if(!this.dragCurrent.moveOnly){
20451 this.fireEvents(e, false);
20461 * Iterates over all of the DragDrop elements to find ones we are
20462 * hovering over or dropping on
20463 * @method fireEvents
20464 * @param {Event} e the event
20465 * @param {boolean} isDrop is this a drop op or a mouseover op?
20469 fireEvents: function(e, isDrop) {
20470 var dc = this.dragCurrent;
20472 // If the user did the mouse up outside of the window, we could
20473 // get here even though we have ended the drag.
20474 if (!dc || dc.isLocked()) {
20478 var pt = e.getPoint();
20480 // cache the previous dragOver array
20486 var enterEvts = [];
20488 // Check to see if the object(s) we were hovering over is no longer
20489 // being hovered over so we can fire the onDragOut event
20490 for (var i in this.dragOvers) {
20492 var ddo = this.dragOvers[i];
20494 if (! this.isTypeOfDD(ddo)) {
20498 if (! this.isOverTarget(pt, ddo, this.mode)) {
20499 outEvts.push( ddo );
20502 oldOvers[i] = true;
20503 delete this.dragOvers[i];
20506 for (var sGroup in dc.groups) {
20508 if ("string" != typeof sGroup) {
20512 for (i in this.ids[sGroup]) {
20513 var oDD = this.ids[sGroup][i];
20514 if (! this.isTypeOfDD(oDD)) {
20518 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20519 if (this.isOverTarget(pt, oDD, this.mode)) {
20520 // look for drop interactions
20522 dropEvts.push( oDD );
20523 // look for drag enter and drag over interactions
20526 // initial drag over: dragEnter fires
20527 if (!oldOvers[oDD.id]) {
20528 enterEvts.push( oDD );
20529 // subsequent drag overs: dragOver fires
20531 overEvts.push( oDD );
20534 this.dragOvers[oDD.id] = oDD;
20542 if (outEvts.length) {
20543 dc.b4DragOut(e, outEvts);
20544 dc.onDragOut(e, outEvts);
20547 if (enterEvts.length) {
20548 dc.onDragEnter(e, enterEvts);
20551 if (overEvts.length) {
20552 dc.b4DragOver(e, overEvts);
20553 dc.onDragOver(e, overEvts);
20556 if (dropEvts.length) {
20557 dc.b4DragDrop(e, dropEvts);
20558 dc.onDragDrop(e, dropEvts);
20562 // fire dragout events
20564 for (i=0, len=outEvts.length; i<len; ++i) {
20565 dc.b4DragOut(e, outEvts[i].id);
20566 dc.onDragOut(e, outEvts[i].id);
20569 // fire enter events
20570 for (i=0,len=enterEvts.length; i<len; ++i) {
20571 // dc.b4DragEnter(e, oDD.id);
20572 dc.onDragEnter(e, enterEvts[i].id);
20575 // fire over events
20576 for (i=0,len=overEvts.length; i<len; ++i) {
20577 dc.b4DragOver(e, overEvts[i].id);
20578 dc.onDragOver(e, overEvts[i].id);
20581 // fire drop events
20582 for (i=0, len=dropEvts.length; i<len; ++i) {
20583 dc.b4DragDrop(e, dropEvts[i].id);
20584 dc.onDragDrop(e, dropEvts[i].id);
20589 // notify about a drop that did not find a target
20590 if (isDrop && !dropEvts.length) {
20591 dc.onInvalidDrop(e);
20597 * Helper function for getting the best match from the list of drag
20598 * and drop objects returned by the drag and drop events when we are
20599 * in INTERSECT mode. It returns either the first object that the
20600 * cursor is over, or the object that has the greatest overlap with
20601 * the dragged element.
20602 * @method getBestMatch
20603 * @param {DragDrop[]} dds The array of drag and drop objects
20605 * @return {DragDrop} The best single match
20608 getBestMatch: function(dds) {
20610 // Return null if the input is not what we expect
20611 //if (!dds || !dds.length || dds.length == 0) {
20613 // If there is only one item, it wins
20614 //} else if (dds.length == 1) {
20616 var len = dds.length;
20621 // Loop through the targeted items
20622 for (var i=0; i<len; ++i) {
20624 // If the cursor is over the object, it wins. If the
20625 // cursor is over multiple matches, the first one we come
20627 if (dd.cursorIsOver) {
20630 // Otherwise the object with the most overlap wins
20633 winner.overlap.getArea() < dd.overlap.getArea()) {
20644 * Refreshes the cache of the top-left and bottom-right points of the
20645 * drag and drop objects in the specified group(s). This is in the
20646 * format that is stored in the drag and drop instance, so typical
20649 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20653 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20655 * @TODO this really should be an indexed array. Alternatively this
20656 * method could accept both.
20657 * @method refreshCache
20658 * @param {Object} groups an associative array of groups to refresh
20661 refreshCache: function(groups) {
20662 for (var sGroup in groups) {
20663 if ("string" != typeof sGroup) {
20666 for (var i in this.ids[sGroup]) {
20667 var oDD = this.ids[sGroup][i];
20669 if (this.isTypeOfDD(oDD)) {
20670 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20671 var loc = this.getLocation(oDD);
20673 this.locationCache[oDD.id] = loc;
20675 delete this.locationCache[oDD.id];
20676 // this will unregister the drag and drop object if
20677 // the element is not in a usable state
20686 * This checks to make sure an element exists and is in the DOM. The
20687 * main purpose is to handle cases where innerHTML is used to remove
20688 * drag and drop objects from the DOM. IE provides an 'unspecified
20689 * error' when trying to access the offsetParent of such an element
20691 * @param {HTMLElement} el the element to check
20692 * @return {boolean} true if the element looks usable
20695 verifyEl: function(el) {
20700 parent = el.offsetParent;
20703 parent = el.offsetParent;
20714 * Returns a Region object containing the drag and drop element's position
20715 * and size, including the padding configured for it
20716 * @method getLocation
20717 * @param {DragDrop} oDD the drag and drop object to get the
20719 * @return {Roo.lib.Region} a Region object representing the total area
20720 * the element occupies, including any padding
20721 * the instance is configured for.
20724 getLocation: function(oDD) {
20725 if (! this.isTypeOfDD(oDD)) {
20729 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20732 pos= Roo.lib.Dom.getXY(el);
20740 x2 = x1 + el.offsetWidth;
20742 y2 = y1 + el.offsetHeight;
20744 t = y1 - oDD.padding[0];
20745 r = x2 + oDD.padding[1];
20746 b = y2 + oDD.padding[2];
20747 l = x1 - oDD.padding[3];
20749 return new Roo.lib.Region( t, r, b, l );
20753 * Checks the cursor location to see if it over the target
20754 * @method isOverTarget
20755 * @param {Roo.lib.Point} pt The point to evaluate
20756 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20757 * @return {boolean} true if the mouse is over the target
20761 isOverTarget: function(pt, oTarget, intersect) {
20762 // use cache if available
20763 var loc = this.locationCache[oTarget.id];
20764 if (!loc || !this.useCache) {
20765 loc = this.getLocation(oTarget);
20766 this.locationCache[oTarget.id] = loc;
20774 oTarget.cursorIsOver = loc.contains( pt );
20776 // DragDrop is using this as a sanity check for the initial mousedown
20777 // in this case we are done. In POINT mode, if the drag obj has no
20778 // contraints, we are also done. Otherwise we need to evaluate the
20779 // location of the target as related to the actual location of the
20780 // dragged element.
20781 var dc = this.dragCurrent;
20782 if (!dc || !dc.getTargetCoord ||
20783 (!intersect && !dc.constrainX && !dc.constrainY)) {
20784 return oTarget.cursorIsOver;
20787 oTarget.overlap = null;
20789 // Get the current location of the drag element, this is the
20790 // location of the mouse event less the delta that represents
20791 // where the original mousedown happened on the element. We
20792 // need to consider constraints and ticks as well.
20793 var pos = dc.getTargetCoord(pt.x, pt.y);
20795 var el = dc.getDragEl();
20796 var curRegion = new Roo.lib.Region( pos.y,
20797 pos.x + el.offsetWidth,
20798 pos.y + el.offsetHeight,
20801 var overlap = curRegion.intersect(loc);
20804 oTarget.overlap = overlap;
20805 return (intersect) ? true : oTarget.cursorIsOver;
20812 * unload event handler
20813 * @method _onUnload
20817 _onUnload: function(e, me) {
20818 Roo.dd.DragDropMgr.unregAll();
20822 * Cleans up the drag and drop events and objects.
20827 unregAll: function() {
20829 if (this.dragCurrent) {
20831 this.dragCurrent = null;
20834 this._execOnAll("unreg", []);
20836 for (i in this.elementCache) {
20837 delete this.elementCache[i];
20840 this.elementCache = {};
20845 * A cache of DOM elements
20846 * @property elementCache
20853 * Get the wrapper for the DOM element specified
20854 * @method getElWrapper
20855 * @param {String} id the id of the element to get
20856 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20858 * @deprecated This wrapper isn't that useful
20861 getElWrapper: function(id) {
20862 var oWrapper = this.elementCache[id];
20863 if (!oWrapper || !oWrapper.el) {
20864 oWrapper = this.elementCache[id] =
20865 new this.ElementWrapper(Roo.getDom(id));
20871 * Returns the actual DOM element
20872 * @method getElement
20873 * @param {String} id the id of the elment to get
20874 * @return {Object} The element
20875 * @deprecated use Roo.getDom instead
20878 getElement: function(id) {
20879 return Roo.getDom(id);
20883 * Returns the style property for the DOM element (i.e.,
20884 * document.getElById(id).style)
20886 * @param {String} id the id of the elment to get
20887 * @return {Object} The style property of the element
20888 * @deprecated use Roo.getDom instead
20891 getCss: function(id) {
20892 var el = Roo.getDom(id);
20893 return (el) ? el.style : null;
20897 * Inner class for cached elements
20898 * @class DragDropMgr.ElementWrapper
20903 ElementWrapper: function(el) {
20908 this.el = el || null;
20913 this.id = this.el && el.id;
20915 * A reference to the style property
20918 this.css = this.el && el.style;
20922 * Returns the X position of an html element
20924 * @param el the element for which to get the position
20925 * @return {int} the X coordinate
20927 * @deprecated use Roo.lib.Dom.getX instead
20930 getPosX: function(el) {
20931 return Roo.lib.Dom.getX(el);
20935 * Returns the Y position of an html element
20937 * @param el the element for which to get the position
20938 * @return {int} the Y coordinate
20939 * @deprecated use Roo.lib.Dom.getY instead
20942 getPosY: function(el) {
20943 return Roo.lib.Dom.getY(el);
20947 * Swap two nodes. In IE, we use the native method, for others we
20948 * emulate the IE behavior
20950 * @param n1 the first node to swap
20951 * @param n2 the other node to swap
20954 swapNode: function(n1, n2) {
20958 var p = n2.parentNode;
20959 var s = n2.nextSibling;
20962 p.insertBefore(n1, n2);
20963 } else if (n2 == n1.nextSibling) {
20964 p.insertBefore(n2, n1);
20966 n1.parentNode.replaceChild(n2, n1);
20967 p.insertBefore(n1, s);
20973 * Returns the current scroll position
20974 * @method getScroll
20978 getScroll: function () {
20979 var t, l, dde=document.documentElement, db=document.body;
20980 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20982 l = dde.scrollLeft;
20989 return { top: t, left: l };
20993 * Returns the specified element style property
20995 * @param {HTMLElement} el the element
20996 * @param {string} styleProp the style property
20997 * @return {string} The value of the style property
20998 * @deprecated use Roo.lib.Dom.getStyle
21001 getStyle: function(el, styleProp) {
21002 return Roo.fly(el).getStyle(styleProp);
21006 * Gets the scrollTop
21007 * @method getScrollTop
21008 * @return {int} the document's scrollTop
21011 getScrollTop: function () { return this.getScroll().top; },
21014 * Gets the scrollLeft
21015 * @method getScrollLeft
21016 * @return {int} the document's scrollTop
21019 getScrollLeft: function () { return this.getScroll().left; },
21022 * Sets the x/y position of an element to the location of the
21025 * @param {HTMLElement} moveEl The element to move
21026 * @param {HTMLElement} targetEl The position reference element
21029 moveToEl: function (moveEl, targetEl) {
21030 var aCoord = Roo.lib.Dom.getXY(targetEl);
21031 Roo.lib.Dom.setXY(moveEl, aCoord);
21035 * Numeric array sort function
21036 * @method numericSort
21039 numericSort: function(a, b) { return (a - b); },
21043 * @property _timeoutCount
21050 * Trying to make the load order less important. Without this we get
21051 * an error if this file is loaded before the Event Utility.
21052 * @method _addListeners
21056 _addListeners: function() {
21057 var DDM = Roo.dd.DDM;
21058 if ( Roo.lib.Event && document ) {
21061 if (DDM._timeoutCount > 2000) {
21063 setTimeout(DDM._addListeners, 10);
21064 if (document && document.body) {
21065 DDM._timeoutCount += 1;
21072 * Recursively searches the immediate parent and all child nodes for
21073 * the handle element in order to determine wheter or not it was
21075 * @method handleWasClicked
21076 * @param node the html element to inspect
21079 handleWasClicked: function(node, id) {
21080 if (this.isHandle(id, node.id)) {
21083 // check to see if this is a text node child of the one we want
21084 var p = node.parentNode;
21087 if (this.isHandle(id, p.id)) {
21102 // shorter alias, save a few bytes
21103 Roo.dd.DDM = Roo.dd.DragDropMgr;
21104 Roo.dd.DDM._addListeners();
21108 * Ext JS Library 1.1.1
21109 * Copyright(c) 2006-2007, Ext JS, LLC.
21111 * Originally Released Under LGPL - original licence link has changed is not relivant.
21114 * <script type="text/javascript">
21119 * A DragDrop implementation where the linked element follows the
21120 * mouse cursor during a drag.
21121 * @extends Roo.dd.DragDrop
21123 * @param {String} id the id of the linked element
21124 * @param {String} sGroup the group of related DragDrop items
21125 * @param {object} config an object containing configurable attributes
21126 * Valid properties for DD:
21129 Roo.dd.DD = function(id, sGroup, config) {
21131 this.init(id, sGroup, config);
21135 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21138 * When set to true, the utility automatically tries to scroll the browser
21139 * window wehn a drag and drop element is dragged near the viewport boundary.
21140 * Defaults to true.
21147 * Sets the pointer offset to the distance between the linked element's top
21148 * left corner and the location the element was clicked
21149 * @method autoOffset
21150 * @param {int} iPageX the X coordinate of the click
21151 * @param {int} iPageY the Y coordinate of the click
21153 autoOffset: function(iPageX, iPageY) {
21154 var x = iPageX - this.startPageX;
21155 var y = iPageY - this.startPageY;
21156 this.setDelta(x, y);
21160 * Sets the pointer offset. You can call this directly to force the
21161 * offset to be in a particular location (e.g., pass in 0,0 to set it
21162 * to the center of the object)
21164 * @param {int} iDeltaX the distance from the left
21165 * @param {int} iDeltaY the distance from the top
21167 setDelta: function(iDeltaX, iDeltaY) {
21168 this.deltaX = iDeltaX;
21169 this.deltaY = iDeltaY;
21173 * Sets the drag element to the location of the mousedown or click event,
21174 * maintaining the cursor location relative to the location on the element
21175 * that was clicked. Override this if you want to place the element in a
21176 * location other than where the cursor is.
21177 * @method setDragElPos
21178 * @param {int} iPageX the X coordinate of the mousedown or drag event
21179 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21181 setDragElPos: function(iPageX, iPageY) {
21182 // the first time we do this, we are going to check to make sure
21183 // the element has css positioning
21185 var el = this.getDragEl();
21186 this.alignElWithMouse(el, iPageX, iPageY);
21190 * Sets the element to the location of the mousedown or click event,
21191 * maintaining the cursor location relative to the location on the element
21192 * that was clicked. Override this if you want to place the element in a
21193 * location other than where the cursor is.
21194 * @method alignElWithMouse
21195 * @param {HTMLElement} el the element to move
21196 * @param {int} iPageX the X coordinate of the mousedown or drag event
21197 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21199 alignElWithMouse: function(el, iPageX, iPageY) {
21200 var oCoord = this.getTargetCoord(iPageX, iPageY);
21201 var fly = el.dom ? el : Roo.fly(el);
21202 if (!this.deltaSetXY) {
21203 var aCoord = [oCoord.x, oCoord.y];
21205 var newLeft = fly.getLeft(true);
21206 var newTop = fly.getTop(true);
21207 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21209 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21212 this.cachePosition(oCoord.x, oCoord.y);
21213 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21218 * Saves the most recent position so that we can reset the constraints and
21219 * tick marks on-demand. We need to know this so that we can calculate the
21220 * number of pixels the element is offset from its original position.
21221 * @method cachePosition
21222 * @param iPageX the current x position (optional, this just makes it so we
21223 * don't have to look it up again)
21224 * @param iPageY the current y position (optional, this just makes it so we
21225 * don't have to look it up again)
21227 cachePosition: function(iPageX, iPageY) {
21229 this.lastPageX = iPageX;
21230 this.lastPageY = iPageY;
21232 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21233 this.lastPageX = aCoord[0];
21234 this.lastPageY = aCoord[1];
21239 * Auto-scroll the window if the dragged object has been moved beyond the
21240 * visible window boundary.
21241 * @method autoScroll
21242 * @param {int} x the drag element's x position
21243 * @param {int} y the drag element's y position
21244 * @param {int} h the height of the drag element
21245 * @param {int} w the width of the drag element
21248 autoScroll: function(x, y, h, w) {
21251 // The client height
21252 var clientH = Roo.lib.Dom.getViewWidth();
21254 // The client width
21255 var clientW = Roo.lib.Dom.getViewHeight();
21257 // The amt scrolled down
21258 var st = this.DDM.getScrollTop();
21260 // The amt scrolled right
21261 var sl = this.DDM.getScrollLeft();
21263 // Location of the bottom of the element
21266 // Location of the right of the element
21269 // The distance from the cursor to the bottom of the visible area,
21270 // adjusted so that we don't scroll if the cursor is beyond the
21271 // element drag constraints
21272 var toBot = (clientH + st - y - this.deltaY);
21274 // The distance from the cursor to the right of the visible area
21275 var toRight = (clientW + sl - x - this.deltaX);
21278 // How close to the edge the cursor must be before we scroll
21279 // var thresh = (document.all) ? 100 : 40;
21282 // How many pixels to scroll per autoscroll op. This helps to reduce
21283 // clunky scrolling. IE is more sensitive about this ... it needs this
21284 // value to be higher.
21285 var scrAmt = (document.all) ? 80 : 30;
21287 // Scroll down if we are near the bottom of the visible page and the
21288 // obj extends below the crease
21289 if ( bot > clientH && toBot < thresh ) {
21290 window.scrollTo(sl, st + scrAmt);
21293 // Scroll up if the window is scrolled down and the top of the object
21294 // goes above the top border
21295 if ( y < st && st > 0 && y - st < thresh ) {
21296 window.scrollTo(sl, st - scrAmt);
21299 // Scroll right if the obj is beyond the right border and the cursor is
21300 // near the border.
21301 if ( right > clientW && toRight < thresh ) {
21302 window.scrollTo(sl + scrAmt, st);
21305 // Scroll left if the window has been scrolled to the right and the obj
21306 // extends past the left border
21307 if ( x < sl && sl > 0 && x - sl < thresh ) {
21308 window.scrollTo(sl - scrAmt, st);
21314 * Finds the location the element should be placed if we want to move
21315 * it to where the mouse location less the click offset would place us.
21316 * @method getTargetCoord
21317 * @param {int} iPageX the X coordinate of the click
21318 * @param {int} iPageY the Y coordinate of the click
21319 * @return an object that contains the coordinates (Object.x and Object.y)
21322 getTargetCoord: function(iPageX, iPageY) {
21325 var x = iPageX - this.deltaX;
21326 var y = iPageY - this.deltaY;
21328 if (this.constrainX) {
21329 if (x < this.minX) { x = this.minX; }
21330 if (x > this.maxX) { x = this.maxX; }
21333 if (this.constrainY) {
21334 if (y < this.minY) { y = this.minY; }
21335 if (y > this.maxY) { y = this.maxY; }
21338 x = this.getTick(x, this.xTicks);
21339 y = this.getTick(y, this.yTicks);
21346 * Sets up config options specific to this class. Overrides
21347 * Roo.dd.DragDrop, but all versions of this method through the
21348 * inheritance chain are called
21350 applyConfig: function() {
21351 Roo.dd.DD.superclass.applyConfig.call(this);
21352 this.scroll = (this.config.scroll !== false);
21356 * Event that fires prior to the onMouseDown event. Overrides
21359 b4MouseDown: function(e) {
21360 // this.resetConstraints();
21361 this.autoOffset(e.getPageX(),
21366 * Event that fires prior to the onDrag event. Overrides
21369 b4Drag: function(e) {
21370 this.setDragElPos(e.getPageX(),
21374 toString: function() {
21375 return ("DD " + this.id);
21378 //////////////////////////////////////////////////////////////////////////
21379 // Debugging ygDragDrop events that can be overridden
21380 //////////////////////////////////////////////////////////////////////////
21382 startDrag: function(x, y) {
21385 onDrag: function(e) {
21388 onDragEnter: function(e, id) {
21391 onDragOver: function(e, id) {
21394 onDragOut: function(e, id) {
21397 onDragDrop: function(e, id) {
21400 endDrag: function(e) {
21407 * Ext JS Library 1.1.1
21408 * Copyright(c) 2006-2007, Ext JS, LLC.
21410 * Originally Released Under LGPL - original licence link has changed is not relivant.
21413 * <script type="text/javascript">
21417 * @class Roo.dd.DDProxy
21418 * A DragDrop implementation that inserts an empty, bordered div into
21419 * the document that follows the cursor during drag operations. At the time of
21420 * the click, the frame div is resized to the dimensions of the linked html
21421 * element, and moved to the exact location of the linked element.
21423 * References to the "frame" element refer to the single proxy element that
21424 * was created to be dragged in place of all DDProxy elements on the
21427 * @extends Roo.dd.DD
21429 * @param {String} id the id of the linked html element
21430 * @param {String} sGroup the group of related DragDrop objects
21431 * @param {object} config an object containing configurable attributes
21432 * Valid properties for DDProxy in addition to those in DragDrop:
21433 * resizeFrame, centerFrame, dragElId
21435 Roo.dd.DDProxy = function(id, sGroup, config) {
21437 this.init(id, sGroup, config);
21443 * The default drag frame div id
21444 * @property Roo.dd.DDProxy.dragElId
21448 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21450 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21453 * By default we resize the drag frame to be the same size as the element
21454 * we want to drag (this is to get the frame effect). We can turn it off
21455 * if we want a different behavior.
21456 * @property resizeFrame
21462 * By default the frame is positioned exactly where the drag element is, so
21463 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21464 * you do not have constraints on the obj is to have the drag frame centered
21465 * around the cursor. Set centerFrame to true for this effect.
21466 * @property centerFrame
21469 centerFrame: false,
21472 * Creates the proxy element if it does not yet exist
21473 * @method createFrame
21475 createFrame: function() {
21477 var body = document.body;
21479 if (!body || !body.firstChild) {
21480 setTimeout( function() { self.createFrame(); }, 50 );
21484 var div = this.getDragEl();
21487 div = document.createElement("div");
21488 div.id = this.dragElId;
21491 s.position = "absolute";
21492 s.visibility = "hidden";
21494 s.border = "2px solid #aaa";
21497 // appendChild can blow up IE if invoked prior to the window load event
21498 // while rendering a table. It is possible there are other scenarios
21499 // that would cause this to happen as well.
21500 body.insertBefore(div, body.firstChild);
21505 * Initialization for the drag frame element. Must be called in the
21506 * constructor of all subclasses
21507 * @method initFrame
21509 initFrame: function() {
21510 this.createFrame();
21513 applyConfig: function() {
21514 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21516 this.resizeFrame = (this.config.resizeFrame !== false);
21517 this.centerFrame = (this.config.centerFrame);
21518 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21522 * Resizes the drag frame to the dimensions of the clicked object, positions
21523 * it over the object, and finally displays it
21524 * @method showFrame
21525 * @param {int} iPageX X click position
21526 * @param {int} iPageY Y click position
21529 showFrame: function(iPageX, iPageY) {
21530 var el = this.getEl();
21531 var dragEl = this.getDragEl();
21532 var s = dragEl.style;
21534 this._resizeProxy();
21536 if (this.centerFrame) {
21537 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21538 Math.round(parseInt(s.height, 10)/2) );
21541 this.setDragElPos(iPageX, iPageY);
21543 Roo.fly(dragEl).show();
21547 * The proxy is automatically resized to the dimensions of the linked
21548 * element when a drag is initiated, unless resizeFrame is set to false
21549 * @method _resizeProxy
21552 _resizeProxy: function() {
21553 if (this.resizeFrame) {
21554 var el = this.getEl();
21555 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21559 // overrides Roo.dd.DragDrop
21560 b4MouseDown: function(e) {
21561 var x = e.getPageX();
21562 var y = e.getPageY();
21563 this.autoOffset(x, y);
21564 this.setDragElPos(x, y);
21567 // overrides Roo.dd.DragDrop
21568 b4StartDrag: function(x, y) {
21569 // show the drag frame
21570 this.showFrame(x, y);
21573 // overrides Roo.dd.DragDrop
21574 b4EndDrag: function(e) {
21575 Roo.fly(this.getDragEl()).hide();
21578 // overrides Roo.dd.DragDrop
21579 // By default we try to move the element to the last location of the frame.
21580 // This is so that the default behavior mirrors that of Roo.dd.DD.
21581 endDrag: function(e) {
21583 var lel = this.getEl();
21584 var del = this.getDragEl();
21586 // Show the drag frame briefly so we can get its position
21587 del.style.visibility = "";
21590 // Hide the linked element before the move to get around a Safari
21592 lel.style.visibility = "hidden";
21593 Roo.dd.DDM.moveToEl(lel, del);
21594 del.style.visibility = "hidden";
21595 lel.style.visibility = "";
21600 beforeMove : function(){
21604 afterDrag : function(){
21608 toString: function() {
21609 return ("DDProxy " + this.id);
21615 * Ext JS Library 1.1.1
21616 * Copyright(c) 2006-2007, Ext JS, LLC.
21618 * Originally Released Under LGPL - original licence link has changed is not relivant.
21621 * <script type="text/javascript">
21625 * @class Roo.dd.DDTarget
21626 * A DragDrop implementation that does not move, but can be a drop
21627 * target. You would get the same result by simply omitting implementation
21628 * for the event callbacks, but this way we reduce the processing cost of the
21629 * event listener and the callbacks.
21630 * @extends Roo.dd.DragDrop
21632 * @param {String} id the id of the element that is a drop target
21633 * @param {String} sGroup the group of related DragDrop objects
21634 * @param {object} config an object containing configurable attributes
21635 * Valid properties for DDTarget in addition to those in
21639 Roo.dd.DDTarget = function(id, sGroup, config) {
21641 this.initTarget(id, sGroup, config);
21643 if (config && (config.listeners || config.events)) {
21644 Roo.dd.DragDrop.superclass.constructor.call(this, {
21645 listeners : config.listeners || {},
21646 events : config.events || {}
21651 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21652 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21653 toString: function() {
21654 return ("DDTarget " + this.id);
21659 * Ext JS Library 1.1.1
21660 * Copyright(c) 2006-2007, Ext JS, LLC.
21662 * Originally Released Under LGPL - original licence link has changed is not relivant.
21665 * <script type="text/javascript">
21670 * @class Roo.dd.ScrollManager
21671 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21672 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21675 Roo.dd.ScrollManager = function(){
21676 var ddm = Roo.dd.DragDropMgr;
21683 var onStop = function(e){
21688 var triggerRefresh = function(){
21689 if(ddm.dragCurrent){
21690 ddm.refreshCache(ddm.dragCurrent.groups);
21694 var doScroll = function(){
21695 if(ddm.dragCurrent){
21696 var dds = Roo.dd.ScrollManager;
21698 if(proc.el.scroll(proc.dir, dds.increment)){
21702 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21707 var clearProc = function(){
21709 clearInterval(proc.id);
21716 var startProc = function(el, dir){
21717 Roo.log('scroll startproc');
21721 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21724 var onFire = function(e, isDrop){
21726 if(isDrop || !ddm.dragCurrent){ return; }
21727 var dds = Roo.dd.ScrollManager;
21728 if(!dragEl || dragEl != ddm.dragCurrent){
21729 dragEl = ddm.dragCurrent;
21730 // refresh regions on drag start
21731 dds.refreshCache();
21734 var xy = Roo.lib.Event.getXY(e);
21735 var pt = new Roo.lib.Point(xy[0], xy[1]);
21736 for(var id in els){
21737 var el = els[id], r = el._region;
21738 if(r && r.contains(pt) && el.isScrollable()){
21739 if(r.bottom - pt.y <= dds.thresh){
21741 startProc(el, "down");
21744 }else if(r.right - pt.x <= dds.thresh){
21746 startProc(el, "left");
21749 }else if(pt.y - r.top <= dds.thresh){
21751 startProc(el, "up");
21754 }else if(pt.x - r.left <= dds.thresh){
21756 startProc(el, "right");
21765 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21766 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21770 * Registers new overflow element(s) to auto scroll
21771 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21773 register : function(el){
21774 if(el instanceof Array){
21775 for(var i = 0, len = el.length; i < len; i++) {
21776 this.register(el[i]);
21782 Roo.dd.ScrollManager.els = els;
21786 * Unregisters overflow element(s) so they are no longer scrolled
21787 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21789 unregister : function(el){
21790 if(el instanceof Array){
21791 for(var i = 0, len = el.length; i < len; i++) {
21792 this.unregister(el[i]);
21801 * The number of pixels from the edge of a container the pointer needs to be to
21802 * trigger scrolling (defaults to 25)
21808 * The number of pixels to scroll in each scroll increment (defaults to 50)
21814 * The frequency of scrolls in milliseconds (defaults to 500)
21820 * True to animate the scroll (defaults to true)
21826 * The animation duration in seconds -
21827 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21833 * Manually trigger a cache refresh.
21835 refreshCache : function(){
21836 for(var id in els){
21837 if(typeof els[id] == 'object'){ // for people extending the object prototype
21838 els[id]._region = els[id].getRegion();
21845 * Ext JS Library 1.1.1
21846 * Copyright(c) 2006-2007, Ext JS, LLC.
21848 * Originally Released Under LGPL - original licence link has changed is not relivant.
21851 * <script type="text/javascript">
21856 * @class Roo.dd.Registry
21857 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21858 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21861 Roo.dd.Registry = function(){
21864 var autoIdSeed = 0;
21866 var getId = function(el, autogen){
21867 if(typeof el == "string"){
21871 if(!id && autogen !== false){
21872 id = "roodd-" + (++autoIdSeed);
21880 * Register a drag drop element
21881 * @param {String|HTMLElement} element The id or DOM node to register
21882 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21883 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21884 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21885 * populated in the data object (if applicable):
21887 Value Description<br />
21888 --------- ------------------------------------------<br />
21889 handles Array of DOM nodes that trigger dragging<br />
21890 for the element being registered<br />
21891 isHandle True if the element passed in triggers<br />
21892 dragging itself, else false
21895 register : function(el, data){
21897 if(typeof el == "string"){
21898 el = document.getElementById(el);
21901 elements[getId(el)] = data;
21902 if(data.isHandle !== false){
21903 handles[data.ddel.id] = data;
21906 var hs = data.handles;
21907 for(var i = 0, len = hs.length; i < len; i++){
21908 handles[getId(hs[i])] = data;
21914 * Unregister a drag drop element
21915 * @param {String|HTMLElement} element The id or DOM node to unregister
21917 unregister : function(el){
21918 var id = getId(el, false);
21919 var data = elements[id];
21921 delete elements[id];
21923 var hs = data.handles;
21924 for(var i = 0, len = hs.length; i < len; i++){
21925 delete handles[getId(hs[i], false)];
21932 * Returns the handle registered for a DOM Node by id
21933 * @param {String|HTMLElement} id The DOM node or id to look up
21934 * @return {Object} handle The custom handle data
21936 getHandle : function(id){
21937 if(typeof id != "string"){ // must be element?
21940 return handles[id];
21944 * Returns the handle that is registered for the DOM node that is the target of the event
21945 * @param {Event} e The event
21946 * @return {Object} handle The custom handle data
21948 getHandleFromEvent : function(e){
21949 var t = Roo.lib.Event.getTarget(e);
21950 return t ? handles[t.id] : null;
21954 * Returns a custom data object that is registered for a DOM node by id
21955 * @param {String|HTMLElement} id The DOM node or id to look up
21956 * @return {Object} data The custom data
21958 getTarget : function(id){
21959 if(typeof id != "string"){ // must be element?
21962 return elements[id];
21966 * Returns a custom data object that is registered for the DOM node that is the target of the event
21967 * @param {Event} e The event
21968 * @return {Object} data The custom data
21970 getTargetFromEvent : function(e){
21971 var t = Roo.lib.Event.getTarget(e);
21972 return t ? elements[t.id] || handles[t.id] : null;
21977 * Ext JS Library 1.1.1
21978 * Copyright(c) 2006-2007, Ext JS, LLC.
21980 * Originally Released Under LGPL - original licence link has changed is not relivant.
21983 * <script type="text/javascript">
21988 * @class Roo.dd.StatusProxy
21989 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21990 * default drag proxy used by all Roo.dd components.
21992 * @param {Object} config
21994 Roo.dd.StatusProxy = function(config){
21995 Roo.apply(this, config);
21996 this.id = this.id || Roo.id();
21997 this.el = new Roo.Layer({
21999 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22000 {tag: "div", cls: "x-dd-drop-icon"},
22001 {tag: "div", cls: "x-dd-drag-ghost"}
22004 shadow: !config || config.shadow !== false
22006 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22007 this.dropStatus = this.dropNotAllowed;
22010 Roo.dd.StatusProxy.prototype = {
22012 * @cfg {String} dropAllowed
22013 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22015 dropAllowed : "x-dd-drop-ok",
22017 * @cfg {String} dropNotAllowed
22018 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22020 dropNotAllowed : "x-dd-drop-nodrop",
22023 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22024 * over the current target element.
22025 * @param {String} cssClass The css class for the new drop status indicator image
22027 setStatus : function(cssClass){
22028 cssClass = cssClass || this.dropNotAllowed;
22029 if(this.dropStatus != cssClass){
22030 this.el.replaceClass(this.dropStatus, cssClass);
22031 this.dropStatus = cssClass;
22036 * Resets the status indicator to the default dropNotAllowed value
22037 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22039 reset : function(clearGhost){
22040 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22041 this.dropStatus = this.dropNotAllowed;
22043 this.ghost.update("");
22048 * Updates the contents of the ghost element
22049 * @param {String} html The html that will replace the current innerHTML of the ghost element
22051 update : function(html){
22052 if(typeof html == "string"){
22053 this.ghost.update(html);
22055 this.ghost.update("");
22056 html.style.margin = "0";
22057 this.ghost.dom.appendChild(html);
22059 // ensure float = none set?? cant remember why though.
22060 var el = this.ghost.dom.firstChild;
22062 Roo.fly(el).setStyle('float', 'none');
22067 * Returns the underlying proxy {@link Roo.Layer}
22068 * @return {Roo.Layer} el
22070 getEl : function(){
22075 * Returns the ghost element
22076 * @return {Roo.Element} el
22078 getGhost : function(){
22084 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22086 hide : function(clear){
22094 * Stops the repair animation if it's currently running
22097 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22103 * Displays this proxy
22110 * Force the Layer to sync its shadow and shim positions to the element
22117 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22118 * invalid drop operation by the item being dragged.
22119 * @param {Array} xy The XY position of the element ([x, y])
22120 * @param {Function} callback The function to call after the repair is complete
22121 * @param {Object} scope The scope in which to execute the callback
22123 repair : function(xy, callback, scope){
22124 this.callback = callback;
22125 this.scope = scope;
22126 if(xy && this.animRepair !== false){
22127 this.el.addClass("x-dd-drag-repair");
22128 this.el.hideUnders(true);
22129 this.anim = this.el.shift({
22130 duration: this.repairDuration || .5,
22134 callback: this.afterRepair,
22138 this.afterRepair();
22143 afterRepair : function(){
22145 if(typeof this.callback == "function"){
22146 this.callback.call(this.scope || this);
22148 this.callback = null;
22153 * Ext JS Library 1.1.1
22154 * Copyright(c) 2006-2007, Ext JS, LLC.
22156 * Originally Released Under LGPL - original licence link has changed is not relivant.
22159 * <script type="text/javascript">
22163 * @class Roo.dd.DragSource
22164 * @extends Roo.dd.DDProxy
22165 * A simple class that provides the basic implementation needed to make any element draggable.
22167 * @param {String/HTMLElement/Element} el The container element
22168 * @param {Object} config
22170 Roo.dd.DragSource = function(el, config){
22171 this.el = Roo.get(el);
22172 this.dragData = {};
22174 Roo.apply(this, config);
22177 this.proxy = new Roo.dd.StatusProxy();
22180 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22181 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22183 this.dragging = false;
22186 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22188 * @cfg {String} dropAllowed
22189 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22191 dropAllowed : "x-dd-drop-ok",
22193 * @cfg {String} dropNotAllowed
22194 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22196 dropNotAllowed : "x-dd-drop-nodrop",
22199 * Returns the data object associated with this drag source
22200 * @return {Object} data An object containing arbitrary data
22202 getDragData : function(e){
22203 return this.dragData;
22207 onDragEnter : function(e, id){
22208 var target = Roo.dd.DragDropMgr.getDDById(id);
22209 this.cachedTarget = target;
22210 if(this.beforeDragEnter(target, e, id) !== false){
22211 if(target.isNotifyTarget){
22212 var status = target.notifyEnter(this, e, this.dragData);
22213 this.proxy.setStatus(status);
22215 this.proxy.setStatus(this.dropAllowed);
22218 if(this.afterDragEnter){
22220 * An empty function by default, but provided so that you can perform a custom action
22221 * when the dragged item enters the drop target by providing an implementation.
22222 * @param {Roo.dd.DragDrop} target The drop target
22223 * @param {Event} e The event object
22224 * @param {String} id The id of the dragged element
22225 * @method afterDragEnter
22227 this.afterDragEnter(target, e, id);
22233 * An empty function by default, but provided so that you can perform a custom action
22234 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22235 * @param {Roo.dd.DragDrop} target The drop target
22236 * @param {Event} e The event object
22237 * @param {String} id The id of the dragged element
22238 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22240 beforeDragEnter : function(target, e, id){
22245 alignElWithMouse: function() {
22246 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22251 onDragOver : function(e, id){
22252 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22253 if(this.beforeDragOver(target, e, id) !== false){
22254 if(target.isNotifyTarget){
22255 var status = target.notifyOver(this, e, this.dragData);
22256 this.proxy.setStatus(status);
22259 if(this.afterDragOver){
22261 * An empty function by default, but provided so that you can perform a custom action
22262 * while the dragged item is over the drop target by providing an implementation.
22263 * @param {Roo.dd.DragDrop} target The drop target
22264 * @param {Event} e The event object
22265 * @param {String} id The id of the dragged element
22266 * @method afterDragOver
22268 this.afterDragOver(target, e, id);
22274 * An empty function by default, but provided so that you can perform a custom action
22275 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22276 * @param {Roo.dd.DragDrop} target The drop target
22277 * @param {Event} e The event object
22278 * @param {String} id The id of the dragged element
22279 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22281 beforeDragOver : function(target, e, id){
22286 onDragOut : function(e, id){
22287 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22288 if(this.beforeDragOut(target, e, id) !== false){
22289 if(target.isNotifyTarget){
22290 target.notifyOut(this, e, this.dragData);
22292 this.proxy.reset();
22293 if(this.afterDragOut){
22295 * An empty function by default, but provided so that you can perform a custom action
22296 * after the dragged item is dragged out of the target without dropping.
22297 * @param {Roo.dd.DragDrop} target The drop target
22298 * @param {Event} e The event object
22299 * @param {String} id The id of the dragged element
22300 * @method afterDragOut
22302 this.afterDragOut(target, e, id);
22305 this.cachedTarget = null;
22309 * An empty function by default, but provided so that you can perform a custom action before the dragged
22310 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22311 * @param {Roo.dd.DragDrop} target The drop target
22312 * @param {Event} e The event object
22313 * @param {String} id The id of the dragged element
22314 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22316 beforeDragOut : function(target, e, id){
22321 onDragDrop : function(e, id){
22322 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22323 if(this.beforeDragDrop(target, e, id) !== false){
22324 if(target.isNotifyTarget){
22325 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22326 this.onValidDrop(target, e, id);
22328 this.onInvalidDrop(target, e, id);
22331 this.onValidDrop(target, e, id);
22334 if(this.afterDragDrop){
22336 * An empty function by default, but provided so that you can perform a custom action
22337 * after a valid drag drop has occurred by providing an implementation.
22338 * @param {Roo.dd.DragDrop} target The drop target
22339 * @param {Event} e The event object
22340 * @param {String} id The id of the dropped element
22341 * @method afterDragDrop
22343 this.afterDragDrop(target, e, id);
22346 delete this.cachedTarget;
22350 * An empty function by default, but provided so that you can perform a custom action before the dragged
22351 * item is dropped onto the target and optionally cancel the onDragDrop.
22352 * @param {Roo.dd.DragDrop} target The drop target
22353 * @param {Event} e The event object
22354 * @param {String} id The id of the dragged element
22355 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22357 beforeDragDrop : function(target, e, id){
22362 onValidDrop : function(target, e, id){
22364 if(this.afterValidDrop){
22366 * An empty function by default, but provided so that you can perform a custom action
22367 * after a valid drop has occurred by providing an implementation.
22368 * @param {Object} target The target DD
22369 * @param {Event} e The event object
22370 * @param {String} id The id of the dropped element
22371 * @method afterInvalidDrop
22373 this.afterValidDrop(target, e, id);
22378 getRepairXY : function(e, data){
22379 return this.el.getXY();
22383 onInvalidDrop : function(target, e, id){
22384 this.beforeInvalidDrop(target, e, id);
22385 if(this.cachedTarget){
22386 if(this.cachedTarget.isNotifyTarget){
22387 this.cachedTarget.notifyOut(this, e, this.dragData);
22389 this.cacheTarget = null;
22391 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22393 if(this.afterInvalidDrop){
22395 * An empty function by default, but provided so that you can perform a custom action
22396 * after an invalid drop has occurred by providing an implementation.
22397 * @param {Event} e The event object
22398 * @param {String} id The id of the dropped element
22399 * @method afterInvalidDrop
22401 this.afterInvalidDrop(e, id);
22406 afterRepair : function(){
22408 this.el.highlight(this.hlColor || "c3daf9");
22410 this.dragging = false;
22414 * An empty function by default, but provided so that you can perform a custom action after an invalid
22415 * drop has occurred.
22416 * @param {Roo.dd.DragDrop} target The drop target
22417 * @param {Event} e The event object
22418 * @param {String} id The id of the dragged element
22419 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22421 beforeInvalidDrop : function(target, e, id){
22426 handleMouseDown : function(e){
22427 if(this.dragging) {
22430 var data = this.getDragData(e);
22431 if(data && this.onBeforeDrag(data, e) !== false){
22432 this.dragData = data;
22434 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22439 * An empty function by default, but provided so that you can perform a custom action before the initial
22440 * drag event begins and optionally cancel it.
22441 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22442 * @param {Event} e The event object
22443 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22445 onBeforeDrag : function(data, e){
22450 * An empty function by default, but provided so that you can perform a custom action once the initial
22451 * drag event has begun. The drag cannot be canceled from this function.
22452 * @param {Number} x The x position of the click on the dragged object
22453 * @param {Number} y The y position of the click on the dragged object
22455 onStartDrag : Roo.emptyFn,
22457 // private - YUI override
22458 startDrag : function(x, y){
22459 this.proxy.reset();
22460 this.dragging = true;
22461 this.proxy.update("");
22462 this.onInitDrag(x, y);
22467 onInitDrag : function(x, y){
22468 var clone = this.el.dom.cloneNode(true);
22469 clone.id = Roo.id(); // prevent duplicate ids
22470 this.proxy.update(clone);
22471 this.onStartDrag(x, y);
22476 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22477 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22479 getProxy : function(){
22484 * Hides the drag source's {@link Roo.dd.StatusProxy}
22486 hideProxy : function(){
22488 this.proxy.reset(true);
22489 this.dragging = false;
22493 triggerCacheRefresh : function(){
22494 Roo.dd.DDM.refreshCache(this.groups);
22497 // private - override to prevent hiding
22498 b4EndDrag: function(e) {
22501 // private - override to prevent moving
22502 endDrag : function(e){
22503 this.onEndDrag(this.dragData, e);
22507 onEndDrag : function(data, e){
22510 // private - pin to cursor
22511 autoOffset : function(x, y) {
22512 this.setDelta(-12, -20);
22516 * Ext JS Library 1.1.1
22517 * Copyright(c) 2006-2007, Ext JS, LLC.
22519 * Originally Released Under LGPL - original licence link has changed is not relivant.
22522 * <script type="text/javascript">
22527 * @class Roo.dd.DropTarget
22528 * @extends Roo.dd.DDTarget
22529 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22530 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22532 * @param {String/HTMLElement/Element} el The container element
22533 * @param {Object} config
22535 Roo.dd.DropTarget = function(el, config){
22536 this.el = Roo.get(el);
22538 var listeners = false; ;
22539 if (config && config.listeners) {
22540 listeners= config.listeners;
22541 delete config.listeners;
22543 Roo.apply(this, config);
22545 if(this.containerScroll){
22546 Roo.dd.ScrollManager.register(this.el);
22550 * @scope Roo.dd.DropTarget
22555 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22556 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22557 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22559 * IMPORTANT : it should set this.overClass and this.dropAllowed
22561 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22562 * @param {Event} e The event
22563 * @param {Object} data An object containing arbitrary data supplied by the drag source
22569 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22570 * This method will be called on every mouse movement while the drag source is over the drop target.
22571 * This default implementation simply returns the dropAllowed config value.
22573 * IMPORTANT : it should set this.dropAllowed
22575 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22576 * @param {Event} e The event
22577 * @param {Object} data An object containing arbitrary data supplied by the drag source
22583 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22584 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22585 * overClass (if any) from the drop element.
22587 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22588 * @param {Event} e The event
22589 * @param {Object} data An object containing arbitrary data supplied by the drag source
22595 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22596 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22597 * implementation that does something to process the drop event and returns true so that the drag source's
22598 * repair action does not run.
22600 * IMPORTANT : it should set this.success
22602 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22603 * @param {Event} e The event
22604 * @param {Object} data An object containing arbitrary data supplied by the drag source
22610 Roo.dd.DropTarget.superclass.constructor.call( this,
22612 this.ddGroup || this.group,
22615 listeners : listeners || {}
22623 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22625 * @cfg {String} overClass
22626 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22629 * @cfg {String} ddGroup
22630 * The drag drop group to handle drop events for
22634 * @cfg {String} dropAllowed
22635 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22637 dropAllowed : "x-dd-drop-ok",
22639 * @cfg {String} dropNotAllowed
22640 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22642 dropNotAllowed : "x-dd-drop-nodrop",
22644 * @cfg {boolean} success
22645 * set this after drop listener..
22649 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22650 * if the drop point is valid for over/enter..
22657 isNotifyTarget : true,
22662 notifyEnter : function(dd, e, data)
22665 this.fireEvent('enter', dd, e, data);
22666 if(this.overClass){
22667 this.el.addClass(this.overClass);
22669 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22670 this.valid ? this.dropAllowed : this.dropNotAllowed
22677 notifyOver : function(dd, e, data)
22680 this.fireEvent('over', dd, e, data);
22681 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22682 this.valid ? this.dropAllowed : this.dropNotAllowed
22689 notifyOut : function(dd, e, data)
22691 this.fireEvent('out', dd, e, data);
22692 if(this.overClass){
22693 this.el.removeClass(this.overClass);
22700 notifyDrop : function(dd, e, data)
22702 this.success = false;
22703 this.fireEvent('drop', dd, e, data);
22704 return this.success;
22708 * Ext JS Library 1.1.1
22709 * Copyright(c) 2006-2007, Ext JS, LLC.
22711 * Originally Released Under LGPL - original licence link has changed is not relivant.
22714 * <script type="text/javascript">
22719 * @class Roo.dd.DragZone
22720 * @extends Roo.dd.DragSource
22721 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22722 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22724 * @param {String/HTMLElement/Element} el The container element
22725 * @param {Object} config
22727 Roo.dd.DragZone = function(el, config){
22728 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22729 if(this.containerScroll){
22730 Roo.dd.ScrollManager.register(this.el);
22734 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22736 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22737 * for auto scrolling during drag operations.
22740 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22741 * method after a failed drop (defaults to "c3daf9" - light blue)
22745 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22746 * for a valid target to drag based on the mouse down. Override this method
22747 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22748 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22749 * @param {EventObject} e The mouse down event
22750 * @return {Object} The dragData
22752 getDragData : function(e){
22753 return Roo.dd.Registry.getHandleFromEvent(e);
22757 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22758 * this.dragData.ddel
22759 * @param {Number} x The x position of the click on the dragged object
22760 * @param {Number} y The y position of the click on the dragged object
22761 * @return {Boolean} true to continue the drag, false to cancel
22763 onInitDrag : function(x, y){
22764 this.proxy.update(this.dragData.ddel.cloneNode(true));
22765 this.onStartDrag(x, y);
22770 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22772 afterRepair : function(){
22774 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22776 this.dragging = false;
22780 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22781 * the XY of this.dragData.ddel
22782 * @param {EventObject} e The mouse up event
22783 * @return {Array} The xy location (e.g. [100, 200])
22785 getRepairXY : function(e){
22786 return Roo.Element.fly(this.dragData.ddel).getXY();
22790 * Ext JS Library 1.1.1
22791 * Copyright(c) 2006-2007, Ext JS, LLC.
22793 * Originally Released Under LGPL - original licence link has changed is not relivant.
22796 * <script type="text/javascript">
22799 * @class Roo.dd.DropZone
22800 * @extends Roo.dd.DropTarget
22801 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22802 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22804 * @param {String/HTMLElement/Element} el The container element
22805 * @param {Object} config
22807 Roo.dd.DropZone = function(el, config){
22808 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22811 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22813 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22814 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22815 * provide your own custom lookup.
22816 * @param {Event} e The event
22817 * @return {Object} data The custom data
22819 getTargetFromEvent : function(e){
22820 return Roo.dd.Registry.getTargetFromEvent(e);
22824 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22825 * that it has registered. This method has no default implementation and should be overridden to provide
22826 * node-specific processing if necessary.
22827 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22828 * {@link #getTargetFromEvent} for this node)
22829 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22830 * @param {Event} e The event
22831 * @param {Object} data An object containing arbitrary data supplied by the drag source
22833 onNodeEnter : function(n, dd, e, data){
22838 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22839 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22840 * overridden to provide the proper feedback.
22841 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22842 * {@link #getTargetFromEvent} for this node)
22843 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22844 * @param {Event} e The event
22845 * @param {Object} data An object containing arbitrary data supplied by the drag source
22846 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22847 * underlying {@link Roo.dd.StatusProxy} can be updated
22849 onNodeOver : function(n, dd, e, data){
22850 return this.dropAllowed;
22854 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22855 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22856 * node-specific processing if necessary.
22857 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22858 * {@link #getTargetFromEvent} for this node)
22859 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22860 * @param {Event} e The event
22861 * @param {Object} data An object containing arbitrary data supplied by the drag source
22863 onNodeOut : function(n, dd, e, data){
22868 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22869 * the drop node. The default implementation returns false, so it should be overridden to provide the
22870 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22871 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22872 * {@link #getTargetFromEvent} for this node)
22873 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22874 * @param {Event} e The event
22875 * @param {Object} data An object containing arbitrary data supplied by the drag source
22876 * @return {Boolean} True if the drop was valid, else false
22878 onNodeDrop : function(n, dd, e, data){
22883 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22884 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22885 * it should be overridden to provide the proper feedback if necessary.
22886 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22887 * @param {Event} e The event
22888 * @param {Object} data An object containing arbitrary data supplied by the drag source
22889 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22890 * underlying {@link Roo.dd.StatusProxy} can be updated
22892 onContainerOver : function(dd, e, data){
22893 return this.dropNotAllowed;
22897 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22898 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22899 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22900 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22901 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22902 * @param {Event} e The event
22903 * @param {Object} data An object containing arbitrary data supplied by the drag source
22904 * @return {Boolean} True if the drop was valid, else false
22906 onContainerDrop : function(dd, e, data){
22911 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22912 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22913 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22914 * you should override this method and provide a custom implementation.
22915 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22916 * @param {Event} e The event
22917 * @param {Object} data An object containing arbitrary data supplied by the drag source
22918 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22919 * underlying {@link Roo.dd.StatusProxy} can be updated
22921 notifyEnter : function(dd, e, data){
22922 return this.dropNotAllowed;
22926 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22927 * This method will be called on every mouse movement while the drag source is over the drop zone.
22928 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22929 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22930 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22931 * registered node, it will call {@link #onContainerOver}.
22932 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22933 * @param {Event} e The event
22934 * @param {Object} data An object containing arbitrary data supplied by the drag source
22935 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22936 * underlying {@link Roo.dd.StatusProxy} can be updated
22938 notifyOver : function(dd, e, data){
22939 var n = this.getTargetFromEvent(e);
22940 if(!n){ // not over valid drop target
22941 if(this.lastOverNode){
22942 this.onNodeOut(this.lastOverNode, dd, e, data);
22943 this.lastOverNode = null;
22945 return this.onContainerOver(dd, e, data);
22947 if(this.lastOverNode != n){
22948 if(this.lastOverNode){
22949 this.onNodeOut(this.lastOverNode, dd, e, data);
22951 this.onNodeEnter(n, dd, e, data);
22952 this.lastOverNode = n;
22954 return this.onNodeOver(n, dd, e, data);
22958 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22959 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22960 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22961 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22962 * @param {Event} e The event
22963 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22965 notifyOut : function(dd, e, data){
22966 if(this.lastOverNode){
22967 this.onNodeOut(this.lastOverNode, dd, e, data);
22968 this.lastOverNode = null;
22973 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22974 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22975 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22976 * otherwise it will call {@link #onContainerDrop}.
22977 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22978 * @param {Event} e The event
22979 * @param {Object} data An object containing arbitrary data supplied by the drag source
22980 * @return {Boolean} True if the drop was valid, else false
22982 notifyDrop : function(dd, e, data){
22983 if(this.lastOverNode){
22984 this.onNodeOut(this.lastOverNode, dd, e, data);
22985 this.lastOverNode = null;
22987 var n = this.getTargetFromEvent(e);
22989 this.onNodeDrop(n, dd, e, data) :
22990 this.onContainerDrop(dd, e, data);
22994 triggerCacheRefresh : function(){
22995 Roo.dd.DDM.refreshCache(this.groups);
22999 * Ext JS Library 1.1.1
23000 * Copyright(c) 2006-2007, Ext JS, LLC.
23002 * Originally Released Under LGPL - original licence link has changed is not relivant.
23005 * <script type="text/javascript">
23010 * @class Roo.data.SortTypes
23012 * Defines the default sorting (casting?) comparison functions used when sorting data.
23014 Roo.data.SortTypes = {
23016 * Default sort that does nothing
23017 * @param {Mixed} s The value being converted
23018 * @return {Mixed} The comparison value
23020 none : function(s){
23025 * The regular expression used to strip tags
23029 stripTagsRE : /<\/?[^>]+>/gi,
23032 * Strips all HTML tags to sort on text only
23033 * @param {Mixed} s The value being converted
23034 * @return {String} The comparison value
23036 asText : function(s){
23037 return String(s).replace(this.stripTagsRE, "");
23041 * Strips all HTML tags to sort on text only - Case insensitive
23042 * @param {Mixed} s The value being converted
23043 * @return {String} The comparison value
23045 asUCText : function(s){
23046 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23050 * Case insensitive string
23051 * @param {Mixed} s The value being converted
23052 * @return {String} The comparison value
23054 asUCString : function(s) {
23055 return String(s).toUpperCase();
23060 * @param {Mixed} s The value being converted
23061 * @return {Number} The comparison value
23063 asDate : function(s) {
23067 if(s instanceof Date){
23068 return s.getTime();
23070 return Date.parse(String(s));
23075 * @param {Mixed} s The value being converted
23076 * @return {Float} The comparison value
23078 asFloat : function(s) {
23079 var val = parseFloat(String(s).replace(/,/g, ""));
23088 * @param {Mixed} s The value being converted
23089 * @return {Number} The comparison value
23091 asInt : function(s) {
23092 var val = parseInt(String(s).replace(/,/g, ""));
23100 * Ext JS Library 1.1.1
23101 * Copyright(c) 2006-2007, Ext JS, LLC.
23103 * Originally Released Under LGPL - original licence link has changed is not relivant.
23106 * <script type="text/javascript">
23110 * @class Roo.data.Record
23111 * Instances of this class encapsulate both record <em>definition</em> information, and record
23112 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
23113 * to access Records cached in an {@link Roo.data.Store} object.<br>
23115 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
23116 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
23119 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
23121 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
23122 * {@link #create}. The parameters are the same.
23123 * @param {Array} data An associative Array of data values keyed by the field name.
23124 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
23125 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
23126 * not specified an integer id is generated.
23128 Roo.data.Record = function(data, id){
23129 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
23134 * Generate a constructor for a specific record layout.
23135 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
23136 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
23137 * Each field definition object may contain the following properties: <ul>
23138 * <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,
23139 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
23140 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
23141 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
23142 * is being used, then this is a string containing the javascript expression to reference the data relative to
23143 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
23144 * to the data item relative to the record element. If the mapping expression is the same as the field name,
23145 * this may be omitted.</p></li>
23146 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
23147 * <ul><li>auto (Default, implies no conversion)</li>
23152 * <li>date</li></ul></p></li>
23153 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
23154 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
23155 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
23156 * by the Reader into an object that will be stored in the Record. It is passed the
23157 * following parameters:<ul>
23158 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
23160 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
23162 * <br>usage:<br><pre><code>
23163 var TopicRecord = Roo.data.Record.create(
23164 {name: 'title', mapping: 'topic_title'},
23165 {name: 'author', mapping: 'username'},
23166 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
23167 {name: 'lastPost', mapping: 'post_time', type: 'date'},
23168 {name: 'lastPoster', mapping: 'user2'},
23169 {name: 'excerpt', mapping: 'post_text'}
23172 var myNewRecord = new TopicRecord({
23173 title: 'Do my job please',
23176 lastPost: new Date(),
23177 lastPoster: 'Animal',
23178 excerpt: 'No way dude!'
23180 myStore.add(myNewRecord);
23185 Roo.data.Record.create = function(o){
23186 var f = function(){
23187 f.superclass.constructor.apply(this, arguments);
23189 Roo.extend(f, Roo.data.Record);
23190 var p = f.prototype;
23191 p.fields = new Roo.util.MixedCollection(false, function(field){
23194 for(var i = 0, len = o.length; i < len; i++){
23195 p.fields.add(new Roo.data.Field(o[i]));
23197 f.getField = function(name){
23198 return p.fields.get(name);
23203 Roo.data.Record.AUTO_ID = 1000;
23204 Roo.data.Record.EDIT = 'edit';
23205 Roo.data.Record.REJECT = 'reject';
23206 Roo.data.Record.COMMIT = 'commit';
23208 Roo.data.Record.prototype = {
23210 * Readonly flag - true if this record has been modified.
23219 join : function(store){
23220 this.store = store;
23224 * Set the named field to the specified value.
23225 * @param {String} name The name of the field to set.
23226 * @param {Object} value The value to set the field to.
23228 set : function(name, value){
23229 if(this.data[name] == value){
23233 if(!this.modified){
23234 this.modified = {};
23236 if(typeof this.modified[name] == 'undefined'){
23237 this.modified[name] = this.data[name];
23239 this.data[name] = value;
23240 if(!this.editing && this.store){
23241 this.store.afterEdit(this);
23246 * Get the value of the named field.
23247 * @param {String} name The name of the field to get the value of.
23248 * @return {Object} The value of the field.
23250 get : function(name){
23251 return this.data[name];
23255 beginEdit : function(){
23256 this.editing = true;
23257 this.modified = {};
23261 cancelEdit : function(){
23262 this.editing = false;
23263 delete this.modified;
23267 endEdit : function(){
23268 this.editing = false;
23269 if(this.dirty && this.store){
23270 this.store.afterEdit(this);
23275 * Usually called by the {@link Roo.data.Store} which owns the Record.
23276 * Rejects all changes made to the Record since either creation, or the last commit operation.
23277 * Modified fields are reverted to their original values.
23279 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23280 * of reject operations.
23282 reject : function(){
23283 var m = this.modified;
23285 if(typeof m[n] != "function"){
23286 this.data[n] = m[n];
23289 this.dirty = false;
23290 delete this.modified;
23291 this.editing = false;
23293 this.store.afterReject(this);
23298 * Usually called by the {@link Roo.data.Store} which owns the Record.
23299 * Commits all changes made to the Record since either creation, or the last commit operation.
23301 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23302 * of commit operations.
23304 commit : function(){
23305 this.dirty = false;
23306 delete this.modified;
23307 this.editing = false;
23309 this.store.afterCommit(this);
23314 hasError : function(){
23315 return this.error != null;
23319 clearError : function(){
23324 * Creates a copy of this record.
23325 * @param {String} id (optional) A new record id if you don't want to use this record's id
23328 copy : function(newId) {
23329 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
23333 * Ext JS Library 1.1.1
23334 * Copyright(c) 2006-2007, Ext JS, LLC.
23336 * Originally Released Under LGPL - original licence link has changed is not relivant.
23339 * <script type="text/javascript">
23345 * @class Roo.data.Store
23346 * @extends Roo.util.Observable
23347 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
23348 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
23350 * 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
23351 * has no knowledge of the format of the data returned by the Proxy.<br>
23353 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
23354 * instances from the data object. These records are cached and made available through accessor functions.
23356 * Creates a new Store.
23357 * @param {Object} config A config object containing the objects needed for the Store to access data,
23358 * and read the data into Records.
23360 Roo.data.Store = function(config){
23361 this.data = new Roo.util.MixedCollection(false);
23362 this.data.getKey = function(o){
23365 this.baseParams = {};
23367 this.paramNames = {
23372 "multisort" : "_multisort"
23375 if(config && config.data){
23376 this.inlineData = config.data;
23377 delete config.data;
23380 Roo.apply(this, config);
23382 if(this.reader){ // reader passed
23383 this.reader = Roo.factory(this.reader, Roo.data);
23384 this.reader.xmodule = this.xmodule || false;
23385 if(!this.recordType){
23386 this.recordType = this.reader.recordType;
23388 if(this.reader.onMetaChange){
23389 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
23393 if(this.recordType){
23394 this.fields = this.recordType.prototype.fields;
23396 this.modified = [];
23400 * @event datachanged
23401 * Fires when the data cache has changed, and a widget which is using this Store
23402 * as a Record cache should refresh its view.
23403 * @param {Store} this
23405 datachanged : true,
23407 * @event metachange
23408 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
23409 * @param {Store} this
23410 * @param {Object} meta The JSON metadata
23415 * Fires when Records have been added to the Store
23416 * @param {Store} this
23417 * @param {Roo.data.Record[]} records The array of Records added
23418 * @param {Number} index The index at which the record(s) were added
23423 * Fires when a Record has been removed from the Store
23424 * @param {Store} this
23425 * @param {Roo.data.Record} record The Record that was removed
23426 * @param {Number} index The index at which the record was removed
23431 * Fires when a Record has been updated
23432 * @param {Store} this
23433 * @param {Roo.data.Record} record The Record that was updated
23434 * @param {String} operation The update operation being performed. Value may be one of:
23436 Roo.data.Record.EDIT
23437 Roo.data.Record.REJECT
23438 Roo.data.Record.COMMIT
23444 * Fires when the data cache has been cleared.
23445 * @param {Store} this
23449 * @event beforeload
23450 * Fires before a request is made for a new data object. If the beforeload handler returns false
23451 * the load action will be canceled.
23452 * @param {Store} this
23453 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23457 * @event beforeloadadd
23458 * Fires after a new set of Records has been loaded.
23459 * @param {Store} this
23460 * @param {Roo.data.Record[]} records The Records that were loaded
23461 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23463 beforeloadadd : true,
23466 * Fires after a new set of Records has been loaded, before they are added to the store.
23467 * @param {Store} this
23468 * @param {Roo.data.Record[]} records The Records that were loaded
23469 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23470 * @params {Object} return from reader
23474 * @event loadexception
23475 * Fires if an exception occurs in the Proxy during loading.
23476 * Called with the signature of the Proxy's "loadexception" event.
23477 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
23480 * @param {Object} return from JsonData.reader() - success, totalRecords, records
23481 * @param {Object} load options
23482 * @param {Object} jsonData from your request (normally this contains the Exception)
23484 loadexception : true
23488 this.proxy = Roo.factory(this.proxy, Roo.data);
23489 this.proxy.xmodule = this.xmodule || false;
23490 this.relayEvents(this.proxy, ["loadexception"]);
23492 this.sortToggle = {};
23493 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
23495 Roo.data.Store.superclass.constructor.call(this);
23497 if(this.inlineData){
23498 this.loadData(this.inlineData);
23499 delete this.inlineData;
23503 Roo.extend(Roo.data.Store, Roo.util.Observable, {
23505 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
23506 * without a remote query - used by combo/forms at present.
23510 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
23513 * @cfg {Array} data Inline data to be loaded when the store is initialized.
23516 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
23517 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
23520 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
23521 * on any HTTP request
23524 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
23527 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
23531 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
23532 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
23534 remoteSort : false,
23537 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
23538 * loaded or when a record is removed. (defaults to false).
23540 pruneModifiedRecords : false,
23543 lastOptions : null,
23546 * Add Records to the Store and fires the add event.
23547 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23549 add : function(records){
23550 records = [].concat(records);
23551 for(var i = 0, len = records.length; i < len; i++){
23552 records[i].join(this);
23554 var index = this.data.length;
23555 this.data.addAll(records);
23556 this.fireEvent("add", this, records, index);
23560 * Remove a Record from the Store and fires the remove event.
23561 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23563 remove : function(record){
23564 var index = this.data.indexOf(record);
23565 this.data.removeAt(index);
23567 if(this.pruneModifiedRecords){
23568 this.modified.remove(record);
23570 this.fireEvent("remove", this, record, index);
23574 * Remove all Records from the Store and fires the clear event.
23576 removeAll : function(){
23578 if(this.pruneModifiedRecords){
23579 this.modified = [];
23581 this.fireEvent("clear", this);
23585 * Inserts Records to the Store at the given index and fires the add event.
23586 * @param {Number} index The start index at which to insert the passed Records.
23587 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23589 insert : function(index, records){
23590 records = [].concat(records);
23591 for(var i = 0, len = records.length; i < len; i++){
23592 this.data.insert(index, records[i]);
23593 records[i].join(this);
23595 this.fireEvent("add", this, records, index);
23599 * Get the index within the cache of the passed Record.
23600 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23601 * @return {Number} The index of the passed Record. Returns -1 if not found.
23603 indexOf : function(record){
23604 return this.data.indexOf(record);
23608 * Get the index within the cache of the Record with the passed id.
23609 * @param {String} id The id of the Record to find.
23610 * @return {Number} The index of the Record. Returns -1 if not found.
23612 indexOfId : function(id){
23613 return this.data.indexOfKey(id);
23617 * Get the Record with the specified id.
23618 * @param {String} id The id of the Record to find.
23619 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23621 getById : function(id){
23622 return this.data.key(id);
23626 * Get the Record at the specified index.
23627 * @param {Number} index The index of the Record to find.
23628 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23630 getAt : function(index){
23631 return this.data.itemAt(index);
23635 * Returns a range of Records between specified indices.
23636 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23637 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23638 * @return {Roo.data.Record[]} An array of Records
23640 getRange : function(start, end){
23641 return this.data.getRange(start, end);
23645 storeOptions : function(o){
23646 o = Roo.apply({}, o);
23649 this.lastOptions = o;
23653 * Loads the Record cache from the configured Proxy using the configured Reader.
23655 * If using remote paging, then the first load call must specify the <em>start</em>
23656 * and <em>limit</em> properties in the options.params property to establish the initial
23657 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23659 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23660 * and this call will return before the new data has been loaded. Perform any post-processing
23661 * in a callback function, or in a "load" event handler.</strong>
23663 * @param {Object} options An object containing properties which control loading options:<ul>
23664 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23665 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23666 * passed the following arguments:<ul>
23667 * <li>r : Roo.data.Record[]</li>
23668 * <li>options: Options object from the load call</li>
23669 * <li>success: Boolean success indicator</li></ul></li>
23670 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23671 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23674 load : function(options){
23675 options = options || {};
23676 if(this.fireEvent("beforeload", this, options) !== false){
23677 this.storeOptions(options);
23678 var p = Roo.apply(options.params || {}, this.baseParams);
23679 // if meta was not loaded from remote source.. try requesting it.
23680 if (!this.reader.metaFromRemote) {
23681 p._requestMeta = 1;
23683 if(this.sortInfo && this.remoteSort){
23684 var pn = this.paramNames;
23685 p[pn["sort"]] = this.sortInfo.field;
23686 p[pn["dir"]] = this.sortInfo.direction;
23688 if (this.multiSort) {
23689 var pn = this.paramNames;
23690 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23693 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23698 * Reloads the Record cache from the configured Proxy using the configured Reader and
23699 * the options from the last load operation performed.
23700 * @param {Object} options (optional) An object containing properties which may override the options
23701 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23702 * the most recently used options are reused).
23704 reload : function(options){
23705 this.load(Roo.applyIf(options||{}, this.lastOptions));
23709 // Called as a callback by the Reader during a load operation.
23710 loadRecords : function(o, options, success){
23711 if(!o || success === false){
23712 if(success !== false){
23713 this.fireEvent("load", this, [], options, o);
23715 if(options.callback){
23716 options.callback.call(options.scope || this, [], options, false);
23720 // if data returned failure - throw an exception.
23721 if (o.success === false) {
23722 // show a message if no listener is registered.
23723 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23724 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23726 // loadmask wil be hooked into this..
23727 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23730 var r = o.records, t = o.totalRecords || r.length;
23732 this.fireEvent("beforeloadadd", this, r, options, o);
23734 if(!options || options.add !== true){
23735 if(this.pruneModifiedRecords){
23736 this.modified = [];
23738 for(var i = 0, len = r.length; i < len; i++){
23742 this.data = this.snapshot;
23743 delete this.snapshot;
23746 this.data.addAll(r);
23747 this.totalLength = t;
23749 this.fireEvent("datachanged", this);
23751 this.totalLength = Math.max(t, this.data.length+r.length);
23755 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23757 var e = new Roo.data.Record({});
23759 e.set(this.parent.displayField, this.parent.emptyTitle);
23760 e.set(this.parent.valueField, '');
23765 this.fireEvent("load", this, r, options, o);
23766 if(options.callback){
23767 options.callback.call(options.scope || this, r, options, true);
23773 * Loads data from a passed data block. A Reader which understands the format of the data
23774 * must have been configured in the constructor.
23775 * @param {Object} data The data block from which to read the Records. The format of the data expected
23776 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23777 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23779 loadData : function(o, append){
23780 var r = this.reader.readRecords(o);
23781 this.loadRecords(r, {add: append}, true);
23785 * using 'cn' the nested child reader read the child array into it's child stores.
23786 * @param {Object} rec The record with a 'children array
23788 loadDataFromChildren : function(rec)
23790 this.loadData(this.reader.toLoadData(rec));
23795 * Gets the number of cached records.
23797 * <em>If using paging, this may not be the total size of the dataset. If the data object
23798 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23799 * the data set size</em>
23801 getCount : function(){
23802 return this.data.length || 0;
23806 * Gets the total number of records in the dataset as returned by the server.
23808 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23809 * the dataset size</em>
23811 getTotalCount : function(){
23812 return this.totalLength || 0;
23816 * Returns the sort state of the Store as an object with two properties:
23818 field {String} The name of the field by which the Records are sorted
23819 direction {String} The sort order, "ASC" or "DESC"
23822 getSortState : function(){
23823 return this.sortInfo;
23827 applySort : function(){
23828 if(this.sortInfo && !this.remoteSort){
23829 var s = this.sortInfo, f = s.field;
23830 var st = this.fields.get(f).sortType;
23831 var fn = function(r1, r2){
23832 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23833 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23835 this.data.sort(s.direction, fn);
23836 if(this.snapshot && this.snapshot != this.data){
23837 this.snapshot.sort(s.direction, fn);
23843 * Sets the default sort column and order to be used by the next load operation.
23844 * @param {String} fieldName The name of the field to sort by.
23845 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23847 setDefaultSort : function(field, dir){
23848 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23852 * Sort the Records.
23853 * If remote sorting is used, the sort is performed on the server, and the cache is
23854 * reloaded. If local sorting is used, the cache is sorted internally.
23855 * @param {String} fieldName The name of the field to sort by.
23856 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23858 sort : function(fieldName, dir){
23859 var f = this.fields.get(fieldName);
23861 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23863 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23864 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23869 this.sortToggle[f.name] = dir;
23870 this.sortInfo = {field: f.name, direction: dir};
23871 if(!this.remoteSort){
23873 this.fireEvent("datachanged", this);
23875 this.load(this.lastOptions);
23880 * Calls the specified function for each of the Records in the cache.
23881 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23882 * Returning <em>false</em> aborts and exits the iteration.
23883 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23885 each : function(fn, scope){
23886 this.data.each(fn, scope);
23890 * Gets all records modified since the last commit. Modified records are persisted across load operations
23891 * (e.g., during paging).
23892 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23894 getModifiedRecords : function(){
23895 return this.modified;
23899 createFilterFn : function(property, value, anyMatch){
23900 if(!value.exec){ // not a regex
23901 value = String(value);
23902 if(value.length == 0){
23905 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23907 return function(r){
23908 return value.test(r.data[property]);
23913 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23914 * @param {String} property A field on your records
23915 * @param {Number} start The record index to start at (defaults to 0)
23916 * @param {Number} end The last record index to include (defaults to length - 1)
23917 * @return {Number} The sum
23919 sum : function(property, start, end){
23920 var rs = this.data.items, v = 0;
23921 start = start || 0;
23922 end = (end || end === 0) ? end : rs.length-1;
23924 for(var i = start; i <= end; i++){
23925 v += (rs[i].data[property] || 0);
23931 * Filter the records by a specified property.
23932 * @param {String} field A field on your records
23933 * @param {String/RegExp} value Either a string that the field
23934 * should start with or a RegExp to test against the field
23935 * @param {Boolean} anyMatch True to match any part not just the beginning
23937 filter : function(property, value, anyMatch){
23938 var fn = this.createFilterFn(property, value, anyMatch);
23939 return fn ? this.filterBy(fn) : this.clearFilter();
23943 * Filter by a function. The specified function will be called with each
23944 * record in this data source. If the function returns true the record is included,
23945 * otherwise it is filtered.
23946 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23947 * @param {Object} scope (optional) The scope of the function (defaults to this)
23949 filterBy : function(fn, scope){
23950 this.snapshot = this.snapshot || this.data;
23951 this.data = this.queryBy(fn, scope||this);
23952 this.fireEvent("datachanged", this);
23956 * Query the records by a specified property.
23957 * @param {String} field A field on your records
23958 * @param {String/RegExp} value Either a string that the field
23959 * should start with or a RegExp to test against the field
23960 * @param {Boolean} anyMatch True to match any part not just the beginning
23961 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23963 query : function(property, value, anyMatch){
23964 var fn = this.createFilterFn(property, value, anyMatch);
23965 return fn ? this.queryBy(fn) : this.data.clone();
23969 * Query by a function. The specified function will be called with each
23970 * record in this data source. If the function returns true the record is included
23972 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23973 * @param {Object} scope (optional) The scope of the function (defaults to this)
23974 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23976 queryBy : function(fn, scope){
23977 var data = this.snapshot || this.data;
23978 return data.filterBy(fn, scope||this);
23982 * Collects unique values for a particular dataIndex from this store.
23983 * @param {String} dataIndex The property to collect
23984 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23985 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23986 * @return {Array} An array of the unique values
23988 collect : function(dataIndex, allowNull, bypassFilter){
23989 var d = (bypassFilter === true && this.snapshot) ?
23990 this.snapshot.items : this.data.items;
23991 var v, sv, r = [], l = {};
23992 for(var i = 0, len = d.length; i < len; i++){
23993 v = d[i].data[dataIndex];
23995 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24004 * Revert to a view of the Record cache with no filtering applied.
24005 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24007 clearFilter : function(suppressEvent){
24008 if(this.snapshot && this.snapshot != this.data){
24009 this.data = this.snapshot;
24010 delete this.snapshot;
24011 if(suppressEvent !== true){
24012 this.fireEvent("datachanged", this);
24018 afterEdit : function(record){
24019 if(this.modified.indexOf(record) == -1){
24020 this.modified.push(record);
24022 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24026 afterReject : function(record){
24027 this.modified.remove(record);
24028 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24032 afterCommit : function(record){
24033 this.modified.remove(record);
24034 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24038 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24039 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24041 commitChanges : function(){
24042 var m = this.modified.slice(0);
24043 this.modified = [];
24044 for(var i = 0, len = m.length; i < len; i++){
24050 * Cancel outstanding changes on all changed records.
24052 rejectChanges : function(){
24053 var m = this.modified.slice(0);
24054 this.modified = [];
24055 for(var i = 0, len = m.length; i < len; i++){
24060 onMetaChange : function(meta, rtype, o){
24061 this.recordType = rtype;
24062 this.fields = rtype.prototype.fields;
24063 delete this.snapshot;
24064 this.sortInfo = meta.sortInfo || this.sortInfo;
24065 this.modified = [];
24066 this.fireEvent('metachange', this, this.reader.meta);
24069 moveIndex : function(data, type)
24071 var index = this.indexOf(data);
24073 var newIndex = index + type;
24077 this.insert(newIndex, data);
24082 * Ext JS Library 1.1.1
24083 * Copyright(c) 2006-2007, Ext JS, LLC.
24085 * Originally Released Under LGPL - original licence link has changed is not relivant.
24088 * <script type="text/javascript">
24092 * @class Roo.data.SimpleStore
24093 * @extends Roo.data.Store
24094 * Small helper class to make creating Stores from Array data easier.
24095 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24096 * @cfg {Array} fields An array of field definition objects, or field name strings.
24097 * @cfg {Object} an existing reader (eg. copied from another store)
24098 * @cfg {Array} data The multi-dimensional array of data
24100 * @param {Object} config
24102 Roo.data.SimpleStore = function(config)
24104 Roo.data.SimpleStore.superclass.constructor.call(this, {
24106 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24109 Roo.data.Record.create(config.fields)
24111 proxy : new Roo.data.MemoryProxy(config.data)
24115 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24117 * Ext JS Library 1.1.1
24118 * Copyright(c) 2006-2007, Ext JS, LLC.
24120 * Originally Released Under LGPL - original licence link has changed is not relivant.
24123 * <script type="text/javascript">
24128 * @extends Roo.data.Store
24129 * @class Roo.data.JsonStore
24130 * Small helper class to make creating Stores for JSON data easier. <br/>
24132 var store = new Roo.data.JsonStore({
24133 url: 'get-images.php',
24135 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24138 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24139 * JsonReader and HttpProxy (unless inline data is provided).</b>
24140 * @cfg {Array} fields An array of field definition objects, or field name strings.
24142 * @param {Object} config
24144 Roo.data.JsonStore = function(c){
24145 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24146 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24147 reader: new Roo.data.JsonReader(c, c.fields)
24150 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
24152 * Ext JS Library 1.1.1
24153 * Copyright(c) 2006-2007, Ext JS, LLC.
24155 * Originally Released Under LGPL - original licence link has changed is not relivant.
24158 * <script type="text/javascript">
24162 Roo.data.Field = function(config){
24163 if(typeof config == "string"){
24164 config = {name: config};
24166 Roo.apply(this, config);
24169 this.type = "auto";
24172 var st = Roo.data.SortTypes;
24173 // named sortTypes are supported, here we look them up
24174 if(typeof this.sortType == "string"){
24175 this.sortType = st[this.sortType];
24178 // set default sortType for strings and dates
24179 if(!this.sortType){
24182 this.sortType = st.asUCString;
24185 this.sortType = st.asDate;
24188 this.sortType = st.none;
24193 var stripRe = /[\$,%]/g;
24195 // prebuilt conversion function for this field, instead of
24196 // switching every time we're reading a value
24198 var cv, dateFormat = this.dateFormat;
24203 cv = function(v){ return v; };
24206 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24210 return v !== undefined && v !== null && v !== '' ?
24211 parseInt(String(v).replace(stripRe, ""), 10) : '';
24216 return v !== undefined && v !== null && v !== '' ?
24217 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24222 cv = function(v){ return v === true || v === "true" || v == 1; };
24229 if(v instanceof Date){
24233 if(dateFormat == "timestamp"){
24234 return new Date(v*1000);
24236 return Date.parseDate(v, dateFormat);
24238 var parsed = Date.parse(v);
24239 return parsed ? new Date(parsed) : null;
24248 Roo.data.Field.prototype = {
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">
24265 // Base class for reading structured data from a data source. This class is intended to be
24266 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24269 * @class Roo.data.DataReader
24270 * Base class for reading structured data from a data source. This class is intended to be
24271 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24274 Roo.data.DataReader = function(meta, recordType){
24278 this.recordType = recordType instanceof Array ?
24279 Roo.data.Record.create(recordType) : recordType;
24282 Roo.data.DataReader.prototype = {
24285 readerType : 'Data',
24287 * Create an empty record
24288 * @param {Object} data (optional) - overlay some values
24289 * @return {Roo.data.Record} record created.
24291 newRow : function(d) {
24293 this.recordType.prototype.fields.each(function(c) {
24295 case 'int' : da[c.name] = 0; break;
24296 case 'date' : da[c.name] = new Date(); break;
24297 case 'float' : da[c.name] = 0.0; break;
24298 case 'boolean' : da[c.name] = false; break;
24299 default : da[c.name] = ""; break;
24303 return new this.recordType(Roo.apply(da, d));
24309 * Ext JS Library 1.1.1
24310 * Copyright(c) 2006-2007, Ext JS, LLC.
24312 * Originally Released Under LGPL - original licence link has changed is not relivant.
24315 * <script type="text/javascript">
24319 * @class Roo.data.DataProxy
24320 * @extends Roo.data.Observable
24321 * This class is an abstract base class for implementations which provide retrieval of
24322 * unformatted data objects.<br>
24324 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24325 * (of the appropriate type which knows how to parse the data object) to provide a block of
24326 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24328 * Custom implementations must implement the load method as described in
24329 * {@link Roo.data.HttpProxy#load}.
24331 Roo.data.DataProxy = function(){
24334 * @event beforeload
24335 * Fires before a network request is made to retrieve a data object.
24336 * @param {Object} This DataProxy object.
24337 * @param {Object} params The params parameter to the load function.
24342 * Fires before the load method's callback is called.
24343 * @param {Object} This DataProxy object.
24344 * @param {Object} o The data object.
24345 * @param {Object} arg The callback argument object passed to the load function.
24349 * @event loadexception
24350 * Fires if an Exception occurs during data retrieval.
24351 * @param {Object} This DataProxy object.
24352 * @param {Object} o The data object.
24353 * @param {Object} arg The callback argument object passed to the load function.
24354 * @param {Object} e The Exception.
24356 loadexception : true
24358 Roo.data.DataProxy.superclass.constructor.call(this);
24361 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24364 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24368 * Ext JS Library 1.1.1
24369 * Copyright(c) 2006-2007, Ext JS, LLC.
24371 * Originally Released Under LGPL - original licence link has changed is not relivant.
24374 * <script type="text/javascript">
24377 * @class Roo.data.MemoryProxy
24378 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24379 * to the Reader when its load method is called.
24381 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24383 Roo.data.MemoryProxy = function(data){
24387 Roo.data.MemoryProxy.superclass.constructor.call(this);
24391 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24394 * Load data from the requested source (in this case an in-memory
24395 * data object passed to the constructor), read the data object into
24396 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24397 * process that block using the passed callback.
24398 * @param {Object} params This parameter is not used by the MemoryProxy class.
24399 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24400 * object into a block of Roo.data.Records.
24401 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24402 * The function must be passed <ul>
24403 * <li>The Record block object</li>
24404 * <li>The "arg" argument from the load function</li>
24405 * <li>A boolean success indicator</li>
24407 * @param {Object} scope The scope in which to call the callback
24408 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24410 load : function(params, reader, callback, scope, arg){
24411 params = params || {};
24414 result = reader.readRecords(params.data ? params.data :this.data);
24416 this.fireEvent("loadexception", this, arg, null, e);
24417 callback.call(scope, null, arg, false);
24420 callback.call(scope, result, arg, true);
24424 update : function(params, records){
24429 * Ext JS Library 1.1.1
24430 * Copyright(c) 2006-2007, Ext JS, LLC.
24432 * Originally Released Under LGPL - original licence link has changed is not relivant.
24435 * <script type="text/javascript">
24438 * @class Roo.data.HttpProxy
24439 * @extends Roo.data.DataProxy
24440 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24441 * configured to reference a certain URL.<br><br>
24443 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24444 * from which the running page was served.<br><br>
24446 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24448 * Be aware that to enable the browser to parse an XML document, the server must set
24449 * the Content-Type header in the HTTP response to "text/xml".
24451 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24452 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24453 * will be used to make the request.
24455 Roo.data.HttpProxy = function(conn){
24456 Roo.data.HttpProxy.superclass.constructor.call(this);
24457 // is conn a conn config or a real conn?
24459 this.useAjax = !conn || !conn.events;
24463 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24464 // thse are take from connection...
24467 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24470 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24471 * extra parameters to each request made by this object. (defaults to undefined)
24474 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24475 * to each request made by this object. (defaults to undefined)
24478 * @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)
24481 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24484 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24490 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24494 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24495 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24496 * a finer-grained basis than the DataProxy events.
24498 getConnection : function(){
24499 return this.useAjax ? Roo.Ajax : this.conn;
24503 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24504 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24505 * process that block using the passed callback.
24506 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24507 * for the request to the remote server.
24508 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24509 * object into a block of Roo.data.Records.
24510 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24511 * The function must be passed <ul>
24512 * <li>The Record block object</li>
24513 * <li>The "arg" argument from the load function</li>
24514 * <li>A boolean success indicator</li>
24516 * @param {Object} scope The scope in which to call the callback
24517 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24519 load : function(params, reader, callback, scope, arg){
24520 if(this.fireEvent("beforeload", this, params) !== false){
24522 params : params || {},
24524 callback : callback,
24529 callback : this.loadResponse,
24533 Roo.applyIf(o, this.conn);
24534 if(this.activeRequest){
24535 Roo.Ajax.abort(this.activeRequest);
24537 this.activeRequest = Roo.Ajax.request(o);
24539 this.conn.request(o);
24542 callback.call(scope||this, null, arg, false);
24547 loadResponse : function(o, success, response){
24548 delete this.activeRequest;
24550 this.fireEvent("loadexception", this, o, response);
24551 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24556 result = o.reader.read(response);
24558 this.fireEvent("loadexception", this, o, response, e);
24559 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24563 this.fireEvent("load", this, o, o.request.arg);
24564 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24568 update : function(dataSet){
24573 updateResponse : function(dataSet){
24578 * Ext JS Library 1.1.1
24579 * Copyright(c) 2006-2007, Ext JS, LLC.
24581 * Originally Released Under LGPL - original licence link has changed is not relivant.
24584 * <script type="text/javascript">
24588 * @class Roo.data.ScriptTagProxy
24589 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24590 * other than the originating domain of the running page.<br><br>
24592 * <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
24593 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24595 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24596 * source code that is used as the source inside a <script> tag.<br><br>
24598 * In order for the browser to process the returned data, the server must wrap the data object
24599 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24600 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24601 * depending on whether the callback name was passed:
24604 boolean scriptTag = false;
24605 String cb = request.getParameter("callback");
24608 response.setContentType("text/javascript");
24610 response.setContentType("application/x-json");
24612 Writer out = response.getWriter();
24614 out.write(cb + "(");
24616 out.print(dataBlock.toJsonString());
24623 * @param {Object} config A configuration object.
24625 Roo.data.ScriptTagProxy = function(config){
24626 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24627 Roo.apply(this, config);
24628 this.head = document.getElementsByTagName("head")[0];
24631 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24633 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24635 * @cfg {String} url The URL from which to request the data object.
24638 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24642 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24643 * the server the name of the callback function set up by the load call to process the returned data object.
24644 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24645 * javascript output which calls this named function passing the data object as its only parameter.
24647 callbackParam : "callback",
24649 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24650 * name to the request.
24655 * Load data from the configured URL, read the data object into
24656 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24657 * process that block using the passed callback.
24658 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24659 * for the request to the remote server.
24660 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24661 * object into a block of Roo.data.Records.
24662 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24663 * The function must be passed <ul>
24664 * <li>The Record block object</li>
24665 * <li>The "arg" argument from the load function</li>
24666 * <li>A boolean success indicator</li>
24668 * @param {Object} scope The scope in which to call the callback
24669 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24671 load : function(params, reader, callback, scope, arg){
24672 if(this.fireEvent("beforeload", this, params) !== false){
24674 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24676 var url = this.url;
24677 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24679 url += "&_dc=" + (new Date().getTime());
24681 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24684 cb : "stcCallback"+transId,
24685 scriptId : "stcScript"+transId,
24689 callback : callback,
24695 window[trans.cb] = function(o){
24696 conn.handleResponse(o, trans);
24699 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24701 if(this.autoAbort !== false){
24705 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24707 var script = document.createElement("script");
24708 script.setAttribute("src", url);
24709 script.setAttribute("type", "text/javascript");
24710 script.setAttribute("id", trans.scriptId);
24711 this.head.appendChild(script);
24713 this.trans = trans;
24715 callback.call(scope||this, null, arg, false);
24720 isLoading : function(){
24721 return this.trans ? true : false;
24725 * Abort the current server request.
24727 abort : function(){
24728 if(this.isLoading()){
24729 this.destroyTrans(this.trans);
24734 destroyTrans : function(trans, isLoaded){
24735 this.head.removeChild(document.getElementById(trans.scriptId));
24736 clearTimeout(trans.timeoutId);
24738 window[trans.cb] = undefined;
24740 delete window[trans.cb];
24743 // if hasn't been loaded, wait for load to remove it to prevent script error
24744 window[trans.cb] = function(){
24745 window[trans.cb] = undefined;
24747 delete window[trans.cb];
24754 handleResponse : function(o, trans){
24755 this.trans = false;
24756 this.destroyTrans(trans, true);
24759 result = trans.reader.readRecords(o);
24761 this.fireEvent("loadexception", this, o, trans.arg, e);
24762 trans.callback.call(trans.scope||window, null, trans.arg, false);
24765 this.fireEvent("load", this, o, trans.arg);
24766 trans.callback.call(trans.scope||window, result, trans.arg, true);
24770 handleFailure : function(trans){
24771 this.trans = false;
24772 this.destroyTrans(trans, false);
24773 this.fireEvent("loadexception", this, null, trans.arg);
24774 trans.callback.call(trans.scope||window, null, trans.arg, false);
24778 * Ext JS Library 1.1.1
24779 * Copyright(c) 2006-2007, Ext JS, LLC.
24781 * Originally Released Under LGPL - original licence link has changed is not relivant.
24784 * <script type="text/javascript">
24788 * @class Roo.data.JsonReader
24789 * @extends Roo.data.DataReader
24790 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24791 * based on mappings in a provided Roo.data.Record constructor.
24793 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24794 * in the reply previously.
24799 var RecordDef = Roo.data.Record.create([
24800 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24801 {name: 'occupation'} // This field will use "occupation" as the mapping.
24803 var myReader = new Roo.data.JsonReader({
24804 totalProperty: "results", // The property which contains the total dataset size (optional)
24805 root: "rows", // The property which contains an Array of row objects
24806 id: "id" // The property within each row object that provides an ID for the record (optional)
24810 * This would consume a JSON file like this:
24812 { 'results': 2, 'rows': [
24813 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24814 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24817 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24818 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24819 * paged from the remote server.
24820 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24821 * @cfg {String} root name of the property which contains the Array of row objects.
24822 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24823 * @cfg {Array} fields Array of field definition objects
24825 * Create a new JsonReader
24826 * @param {Object} meta Metadata configuration options
24827 * @param {Object} recordType Either an Array of field definition objects,
24828 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24830 Roo.data.JsonReader = function(meta, recordType){
24833 // set some defaults:
24834 Roo.applyIf(meta, {
24835 totalProperty: 'total',
24836 successProperty : 'success',
24841 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24843 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24845 readerType : 'Json',
24848 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24849 * Used by Store query builder to append _requestMeta to params.
24852 metaFromRemote : false,
24854 * This method is only used by a DataProxy which has retrieved data from a remote server.
24855 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24856 * @return {Object} data A data block which is used by an Roo.data.Store object as
24857 * a cache of Roo.data.Records.
24859 read : function(response){
24860 var json = response.responseText;
24862 var o = /* eval:var:o */ eval("("+json+")");
24864 throw {message: "JsonReader.read: Json object not found"};
24870 this.metaFromRemote = true;
24871 this.meta = o.metaData;
24872 this.recordType = Roo.data.Record.create(o.metaData.fields);
24873 this.onMetaChange(this.meta, this.recordType, o);
24875 return this.readRecords(o);
24878 // private function a store will implement
24879 onMetaChange : function(meta, recordType, o){
24886 simpleAccess: function(obj, subsc) {
24893 getJsonAccessor: function(){
24895 return function(expr) {
24897 return(re.test(expr))
24898 ? new Function("obj", "return obj." + expr)
24903 return Roo.emptyFn;
24908 * Create a data block containing Roo.data.Records from an XML document.
24909 * @param {Object} o An object which contains an Array of row objects in the property specified
24910 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24911 * which contains the total size of the dataset.
24912 * @return {Object} data A data block which is used by an Roo.data.Store object as
24913 * a cache of Roo.data.Records.
24915 readRecords : function(o){
24917 * After any data loads, the raw JSON data is available for further custom processing.
24921 var s = this.meta, Record = this.recordType,
24922 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24924 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24926 if(s.totalProperty) {
24927 this.getTotal = this.getJsonAccessor(s.totalProperty);
24929 if(s.successProperty) {
24930 this.getSuccess = this.getJsonAccessor(s.successProperty);
24932 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24934 var g = this.getJsonAccessor(s.id);
24935 this.getId = function(rec) {
24937 return (r === undefined || r === "") ? null : r;
24940 this.getId = function(){return null;};
24943 for(var jj = 0; jj < fl; jj++){
24945 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24946 this.ef[jj] = this.getJsonAccessor(map);
24950 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24951 if(s.totalProperty){
24952 var vt = parseInt(this.getTotal(o), 10);
24957 if(s.successProperty){
24958 var vs = this.getSuccess(o);
24959 if(vs === false || vs === 'false'){
24964 for(var i = 0; i < c; i++){
24967 var id = this.getId(n);
24968 for(var j = 0; j < fl; j++){
24970 var v = this.ef[j](n);
24972 Roo.log('missing convert for ' + f.name);
24976 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24978 var record = new Record(values, id);
24980 records[i] = record;
24986 totalRecords : totalRecords
24989 // used when loading children.. @see loadDataFromChildren
24990 toLoadData: function(rec)
24992 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
24993 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
24994 return { data : data, total : data.length };
24999 * Ext JS Library 1.1.1
25000 * Copyright(c) 2006-2007, Ext JS, LLC.
25002 * Originally Released Under LGPL - original licence link has changed is not relivant.
25005 * <script type="text/javascript">
25009 * @class Roo.data.XmlReader
25010 * @extends Roo.data.DataReader
25011 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25012 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25014 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25015 * header in the HTTP response must be set to "text/xml".</em>
25019 var RecordDef = Roo.data.Record.create([
25020 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25021 {name: 'occupation'} // This field will use "occupation" as the mapping.
25023 var myReader = new Roo.data.XmlReader({
25024 totalRecords: "results", // The element which contains the total dataset size (optional)
25025 record: "row", // The repeated element which contains row information
25026 id: "id" // The element within the row that provides an ID for the record (optional)
25030 * This would consume an XML file like this:
25034 <results>2</results>
25037 <name>Bill</name>
25038 <occupation>Gardener</occupation>
25042 <name>Ben</name>
25043 <occupation>Horticulturalist</occupation>
25047 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25048 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25049 * paged from the remote server.
25050 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25051 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25052 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25053 * a record identifier value.
25055 * Create a new XmlReader
25056 * @param {Object} meta Metadata configuration options
25057 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25058 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25059 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25061 Roo.data.XmlReader = function(meta, recordType){
25063 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25065 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25067 readerType : 'Xml',
25070 * This method is only used by a DataProxy which has retrieved data from a remote server.
25071 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25072 * to contain a method called 'responseXML' that returns an XML document object.
25073 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25074 * a cache of Roo.data.Records.
25076 read : function(response){
25077 var doc = response.responseXML;
25079 throw {message: "XmlReader.read: XML Document not available"};
25081 return this.readRecords(doc);
25085 * Create a data block containing Roo.data.Records from an XML document.
25086 * @param {Object} doc A parsed XML document.
25087 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25088 * a cache of Roo.data.Records.
25090 readRecords : function(doc){
25092 * After any data loads/reads, the raw XML Document is available for further custom processing.
25093 * @type XMLDocument
25095 this.xmlData = doc;
25096 var root = doc.documentElement || doc;
25097 var q = Roo.DomQuery;
25098 var recordType = this.recordType, fields = recordType.prototype.fields;
25099 var sid = this.meta.id;
25100 var totalRecords = 0, success = true;
25101 if(this.meta.totalRecords){
25102 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25105 if(this.meta.success){
25106 var sv = q.selectValue(this.meta.success, root, true);
25107 success = sv !== false && sv !== 'false';
25110 var ns = q.select(this.meta.record, root);
25111 for(var i = 0, len = ns.length; i < len; i++) {
25114 var id = sid ? q.selectValue(sid, n) : undefined;
25115 for(var j = 0, jlen = fields.length; j < jlen; j++){
25116 var f = fields.items[j];
25117 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25119 values[f.name] = v;
25121 var record = new recordType(values, id);
25123 records[records.length] = record;
25129 totalRecords : totalRecords || records.length
25134 * Ext JS Library 1.1.1
25135 * Copyright(c) 2006-2007, Ext JS, LLC.
25137 * Originally Released Under LGPL - original licence link has changed is not relivant.
25140 * <script type="text/javascript">
25144 * @class Roo.data.ArrayReader
25145 * @extends Roo.data.DataReader
25146 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25147 * Each element of that Array represents a row of data fields. The
25148 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25149 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25153 var RecordDef = Roo.data.Record.create([
25154 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25155 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25157 var myReader = new Roo.data.ArrayReader({
25158 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25162 * This would consume an Array like this:
25164 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25168 * Create a new JsonReader
25169 * @param {Object} meta Metadata configuration options.
25170 * @param {Object|Array} recordType Either an Array of field definition objects
25172 * @cfg {Array} fields Array of field definition objects
25173 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25174 * as specified to {@link Roo.data.Record#create},
25175 * or an {@link Roo.data.Record} object
25178 * created using {@link Roo.data.Record#create}.
25180 Roo.data.ArrayReader = function(meta, recordType)
25182 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25185 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25188 * Create a data block containing Roo.data.Records from an XML document.
25189 * @param {Object} o An Array of row objects which represents the dataset.
25190 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25191 * a cache of Roo.data.Records.
25193 readRecords : function(o)
25195 var sid = this.meta ? this.meta.id : null;
25196 var recordType = this.recordType, fields = recordType.prototype.fields;
25199 for(var i = 0; i < root.length; i++){
25202 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25203 for(var j = 0, jlen = fields.length; j < jlen; j++){
25204 var f = fields.items[j];
25205 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25206 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25208 values[f.name] = v;
25210 var record = new recordType(values, id);
25212 records[records.length] = record;
25216 totalRecords : records.length
25219 // used when loading children.. @see loadDataFromChildren
25220 toLoadData: function(rec)
25222 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25223 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25230 * Ext JS Library 1.1.1
25231 * Copyright(c) 2006-2007, Ext JS, LLC.
25233 * Originally Released Under LGPL - original licence link has changed is not relivant.
25236 * <script type="text/javascript">
25241 * @class Roo.data.Tree
25242 * @extends Roo.util.Observable
25243 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25244 * in the tree have most standard DOM functionality.
25246 * @param {Node} root (optional) The root node
25248 Roo.data.Tree = function(root){
25249 this.nodeHash = {};
25251 * The root node for this tree
25256 this.setRootNode(root);
25261 * Fires when a new child node is appended to a node in this tree.
25262 * @param {Tree} tree The owner tree
25263 * @param {Node} parent The parent node
25264 * @param {Node} node The newly appended node
25265 * @param {Number} index The index of the newly appended node
25270 * Fires when a child node is removed from a node in this tree.
25271 * @param {Tree} tree The owner tree
25272 * @param {Node} parent The parent node
25273 * @param {Node} node The child node removed
25278 * Fires when a node is moved to a new location in the tree
25279 * @param {Tree} tree The owner tree
25280 * @param {Node} node The node moved
25281 * @param {Node} oldParent The old parent of this node
25282 * @param {Node} newParent The new parent of this node
25283 * @param {Number} index The index it was moved to
25288 * Fires when a new child node is inserted in a node in this tree.
25289 * @param {Tree} tree The owner tree
25290 * @param {Node} parent The parent node
25291 * @param {Node} node The child node inserted
25292 * @param {Node} refNode The child node the node was inserted before
25296 * @event beforeappend
25297 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25298 * @param {Tree} tree The owner tree
25299 * @param {Node} parent The parent node
25300 * @param {Node} node The child node to be appended
25302 "beforeappend" : true,
25304 * @event beforeremove
25305 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25306 * @param {Tree} tree The owner tree
25307 * @param {Node} parent The parent node
25308 * @param {Node} node The child node to be removed
25310 "beforeremove" : true,
25312 * @event beforemove
25313 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25314 * @param {Tree} tree The owner tree
25315 * @param {Node} node The node being moved
25316 * @param {Node} oldParent The parent of the node
25317 * @param {Node} newParent The new parent the node is moving to
25318 * @param {Number} index The index it is being moved to
25320 "beforemove" : true,
25322 * @event beforeinsert
25323 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25324 * @param {Tree} tree The owner tree
25325 * @param {Node} parent The parent node
25326 * @param {Node} node The child node to be inserted
25327 * @param {Node} refNode The child node the node is being inserted before
25329 "beforeinsert" : true
25332 Roo.data.Tree.superclass.constructor.call(this);
25335 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25336 pathSeparator: "/",
25338 proxyNodeEvent : function(){
25339 return this.fireEvent.apply(this, arguments);
25343 * Returns the root node for this tree.
25346 getRootNode : function(){
25351 * Sets the root node for this tree.
25352 * @param {Node} node
25355 setRootNode : function(node){
25357 node.ownerTree = this;
25358 node.isRoot = true;
25359 this.registerNode(node);
25364 * Gets a node in this tree by its id.
25365 * @param {String} id
25368 getNodeById : function(id){
25369 return this.nodeHash[id];
25372 registerNode : function(node){
25373 this.nodeHash[node.id] = node;
25376 unregisterNode : function(node){
25377 delete this.nodeHash[node.id];
25380 toString : function(){
25381 return "[Tree"+(this.id?" "+this.id:"")+"]";
25386 * @class Roo.data.Node
25387 * @extends Roo.util.Observable
25388 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25389 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25391 * @param {Object} attributes The attributes/config for the node
25393 Roo.data.Node = function(attributes){
25395 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25398 this.attributes = attributes || {};
25399 this.leaf = this.attributes.leaf;
25401 * The node id. @type String
25403 this.id = this.attributes.id;
25405 this.id = Roo.id(null, "ynode-");
25406 this.attributes.id = this.id;
25411 * All child nodes of this node. @type Array
25413 this.childNodes = [];
25414 if(!this.childNodes.indexOf){ // indexOf is a must
25415 this.childNodes.indexOf = function(o){
25416 for(var i = 0, len = this.length; i < len; i++){
25425 * The parent node for this node. @type Node
25427 this.parentNode = null;
25429 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25431 this.firstChild = null;
25433 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25435 this.lastChild = null;
25437 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25439 this.previousSibling = null;
25441 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25443 this.nextSibling = null;
25448 * Fires when a new child node is appended
25449 * @param {Tree} tree The owner tree
25450 * @param {Node} this This node
25451 * @param {Node} node The newly appended node
25452 * @param {Number} index The index of the newly appended node
25457 * Fires when a child node is removed
25458 * @param {Tree} tree The owner tree
25459 * @param {Node} this This node
25460 * @param {Node} node The removed node
25465 * Fires when this node is moved to a new location in the tree
25466 * @param {Tree} tree The owner tree
25467 * @param {Node} this This node
25468 * @param {Node} oldParent The old parent of this node
25469 * @param {Node} newParent The new parent of this node
25470 * @param {Number} index The index it was moved to
25475 * Fires when a new child node is inserted.
25476 * @param {Tree} tree The owner tree
25477 * @param {Node} this This node
25478 * @param {Node} node The child node inserted
25479 * @param {Node} refNode The child node the node was inserted before
25483 * @event beforeappend
25484 * Fires before a new child is appended, return false to cancel the append.
25485 * @param {Tree} tree The owner tree
25486 * @param {Node} this This node
25487 * @param {Node} node The child node to be appended
25489 "beforeappend" : true,
25491 * @event beforeremove
25492 * Fires before a child is removed, return false to cancel the remove.
25493 * @param {Tree} tree The owner tree
25494 * @param {Node} this This node
25495 * @param {Node} node The child node to be removed
25497 "beforeremove" : true,
25499 * @event beforemove
25500 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25501 * @param {Tree} tree The owner tree
25502 * @param {Node} this This node
25503 * @param {Node} oldParent The parent of this node
25504 * @param {Node} newParent The new parent this node is moving to
25505 * @param {Number} index The index it is being moved to
25507 "beforemove" : true,
25509 * @event beforeinsert
25510 * Fires before a new child is inserted, return false to cancel the insert.
25511 * @param {Tree} tree The owner tree
25512 * @param {Node} this This node
25513 * @param {Node} node The child node to be inserted
25514 * @param {Node} refNode The child node the node is being inserted before
25516 "beforeinsert" : true
25518 this.listeners = this.attributes.listeners;
25519 Roo.data.Node.superclass.constructor.call(this);
25522 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25523 fireEvent : function(evtName){
25524 // first do standard event for this node
25525 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25528 // then bubble it up to the tree if the event wasn't cancelled
25529 var ot = this.getOwnerTree();
25531 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25539 * Returns true if this node is a leaf
25540 * @return {Boolean}
25542 isLeaf : function(){
25543 return this.leaf === true;
25547 setFirstChild : function(node){
25548 this.firstChild = node;
25552 setLastChild : function(node){
25553 this.lastChild = node;
25558 * Returns true if this node is the last child of its parent
25559 * @return {Boolean}
25561 isLast : function(){
25562 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25566 * Returns true if this node is the first child of its parent
25567 * @return {Boolean}
25569 isFirst : function(){
25570 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25573 hasChildNodes : function(){
25574 return !this.isLeaf() && this.childNodes.length > 0;
25578 * Insert node(s) as the last child node of this node.
25579 * @param {Node/Array} node The node or Array of nodes to append
25580 * @return {Node} The appended node if single append, or null if an array was passed
25582 appendChild : function(node){
25584 if(node instanceof Array){
25586 }else if(arguments.length > 1){
25590 // if passed an array or multiple args do them one by one
25592 for(var i = 0, len = multi.length; i < len; i++) {
25593 this.appendChild(multi[i]);
25596 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25599 var index = this.childNodes.length;
25600 var oldParent = node.parentNode;
25601 // it's a move, make sure we move it cleanly
25603 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25606 oldParent.removeChild(node);
25609 index = this.childNodes.length;
25611 this.setFirstChild(node);
25613 this.childNodes.push(node);
25614 node.parentNode = this;
25615 var ps = this.childNodes[index-1];
25617 node.previousSibling = ps;
25618 ps.nextSibling = node;
25620 node.previousSibling = null;
25622 node.nextSibling = null;
25623 this.setLastChild(node);
25624 node.setOwnerTree(this.getOwnerTree());
25625 this.fireEvent("append", this.ownerTree, this, node, index);
25626 if(this.ownerTree) {
25627 this.ownerTree.fireEvent("appendnode", this, node, index);
25630 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25637 * Removes a child node from this node.
25638 * @param {Node} node The node to remove
25639 * @return {Node} The removed node
25641 removeChild : function(node){
25642 var index = this.childNodes.indexOf(node);
25646 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25650 // remove it from childNodes collection
25651 this.childNodes.splice(index, 1);
25654 if(node.previousSibling){
25655 node.previousSibling.nextSibling = node.nextSibling;
25657 if(node.nextSibling){
25658 node.nextSibling.previousSibling = node.previousSibling;
25661 // update child refs
25662 if(this.firstChild == node){
25663 this.setFirstChild(node.nextSibling);
25665 if(this.lastChild == node){
25666 this.setLastChild(node.previousSibling);
25669 node.setOwnerTree(null);
25670 // clear any references from the node
25671 node.parentNode = null;
25672 node.previousSibling = null;
25673 node.nextSibling = null;
25674 this.fireEvent("remove", this.ownerTree, this, node);
25679 * Inserts the first node before the second node in this nodes childNodes collection.
25680 * @param {Node} node The node to insert
25681 * @param {Node} refNode The node to insert before (if null the node is appended)
25682 * @return {Node} The inserted node
25684 insertBefore : function(node, refNode){
25685 if(!refNode){ // like standard Dom, refNode can be null for append
25686 return this.appendChild(node);
25689 if(node == refNode){
25693 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25696 var index = this.childNodes.indexOf(refNode);
25697 var oldParent = node.parentNode;
25698 var refIndex = index;
25700 // when moving internally, indexes will change after remove
25701 if(oldParent == this && this.childNodes.indexOf(node) < index){
25705 // it's a move, make sure we move it cleanly
25707 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25710 oldParent.removeChild(node);
25713 this.setFirstChild(node);
25715 this.childNodes.splice(refIndex, 0, node);
25716 node.parentNode = this;
25717 var ps = this.childNodes[refIndex-1];
25719 node.previousSibling = ps;
25720 ps.nextSibling = node;
25722 node.previousSibling = null;
25724 node.nextSibling = refNode;
25725 refNode.previousSibling = node;
25726 node.setOwnerTree(this.getOwnerTree());
25727 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25729 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25735 * Returns the child node at the specified index.
25736 * @param {Number} index
25739 item : function(index){
25740 return this.childNodes[index];
25744 * Replaces one child node in this node with another.
25745 * @param {Node} newChild The replacement node
25746 * @param {Node} oldChild The node to replace
25747 * @return {Node} The replaced node
25749 replaceChild : function(newChild, oldChild){
25750 this.insertBefore(newChild, oldChild);
25751 this.removeChild(oldChild);
25756 * Returns the index of a child node
25757 * @param {Node} node
25758 * @return {Number} The index of the node or -1 if it was not found
25760 indexOf : function(child){
25761 return this.childNodes.indexOf(child);
25765 * Returns the tree this node is in.
25768 getOwnerTree : function(){
25769 // if it doesn't have one, look for one
25770 if(!this.ownerTree){
25774 this.ownerTree = p.ownerTree;
25780 return this.ownerTree;
25784 * Returns depth of this node (the root node has a depth of 0)
25787 getDepth : function(){
25790 while(p.parentNode){
25798 setOwnerTree : function(tree){
25799 // if it's move, we need to update everyone
25800 if(tree != this.ownerTree){
25801 if(this.ownerTree){
25802 this.ownerTree.unregisterNode(this);
25804 this.ownerTree = tree;
25805 var cs = this.childNodes;
25806 for(var i = 0, len = cs.length; i < len; i++) {
25807 cs[i].setOwnerTree(tree);
25810 tree.registerNode(this);
25816 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25817 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25818 * @return {String} The path
25820 getPath : function(attr){
25821 attr = attr || "id";
25822 var p = this.parentNode;
25823 var b = [this.attributes[attr]];
25825 b.unshift(p.attributes[attr]);
25828 var sep = this.getOwnerTree().pathSeparator;
25829 return sep + b.join(sep);
25833 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25834 * function call will be the scope provided or the current node. The arguments to the function
25835 * will be the args provided or the current node. If the function returns false at any point,
25836 * the bubble is stopped.
25837 * @param {Function} fn The function to call
25838 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25839 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25841 bubble : function(fn, scope, args){
25844 if(fn.call(scope || p, args || p) === false){
25852 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25853 * function call will be the scope provided or the current node. The arguments to the function
25854 * will be the args provided or the current node. If the function returns false at any point,
25855 * the cascade is stopped on that branch.
25856 * @param {Function} fn The function to call
25857 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25858 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25860 cascade : function(fn, scope, args){
25861 if(fn.call(scope || this, args || this) !== false){
25862 var cs = this.childNodes;
25863 for(var i = 0, len = cs.length; i < len; i++) {
25864 cs[i].cascade(fn, scope, args);
25870 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25871 * function call will be the scope provided or the current node. The arguments to the function
25872 * will be the args provided or the current node. If the function returns false at any point,
25873 * the iteration stops.
25874 * @param {Function} fn The function to call
25875 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25876 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25878 eachChild : function(fn, scope, args){
25879 var cs = this.childNodes;
25880 for(var i = 0, len = cs.length; i < len; i++) {
25881 if(fn.call(scope || this, args || cs[i]) === false){
25888 * Finds the first child that has the attribute with the specified value.
25889 * @param {String} attribute The attribute name
25890 * @param {Mixed} value The value to search for
25891 * @return {Node} The found child or null if none was found
25893 findChild : function(attribute, value){
25894 var cs = this.childNodes;
25895 for(var i = 0, len = cs.length; i < len; i++) {
25896 if(cs[i].attributes[attribute] == value){
25904 * Finds the first child by a custom function. The child matches if the function passed
25906 * @param {Function} fn
25907 * @param {Object} scope (optional)
25908 * @return {Node} The found child or null if none was found
25910 findChildBy : function(fn, scope){
25911 var cs = this.childNodes;
25912 for(var i = 0, len = cs.length; i < len; i++) {
25913 if(fn.call(scope||cs[i], cs[i]) === true){
25921 * Sorts this nodes children using the supplied sort function
25922 * @param {Function} fn
25923 * @param {Object} scope (optional)
25925 sort : function(fn, scope){
25926 var cs = this.childNodes;
25927 var len = cs.length;
25929 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25931 for(var i = 0; i < len; i++){
25933 n.previousSibling = cs[i-1];
25934 n.nextSibling = cs[i+1];
25936 this.setFirstChild(n);
25939 this.setLastChild(n);
25946 * Returns true if this node is an ancestor (at any point) of the passed node.
25947 * @param {Node} node
25948 * @return {Boolean}
25950 contains : function(node){
25951 return node.isAncestor(this);
25955 * Returns true if the passed node is an ancestor (at any point) of this node.
25956 * @param {Node} node
25957 * @return {Boolean}
25959 isAncestor : function(node){
25960 var p = this.parentNode;
25970 toString : function(){
25971 return "[Node"+(this.id?" "+this.id:"")+"]";
25975 * Ext JS Library 1.1.1
25976 * Copyright(c) 2006-2007, Ext JS, LLC.
25978 * Originally Released Under LGPL - original licence link has changed is not relivant.
25981 * <script type="text/javascript">
25986 * @class Roo.Shadow
25987 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25988 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25989 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25991 * Create a new Shadow
25992 * @param {Object} config The config object
25994 Roo.Shadow = function(config){
25995 Roo.apply(this, config);
25996 if(typeof this.mode != "string"){
25997 this.mode = this.defaultMode;
25999 var o = this.offset, a = {h: 0};
26000 var rad = Math.floor(this.offset/2);
26001 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26007 a.l -= this.offset + rad;
26008 a.t -= this.offset + rad;
26019 a.l -= (this.offset - rad);
26020 a.t -= this.offset + rad;
26022 a.w -= (this.offset - rad)*2;
26033 a.l -= (this.offset - rad);
26034 a.t -= (this.offset - rad);
26036 a.w -= (this.offset + rad + 1);
26037 a.h -= (this.offset + rad);
26046 Roo.Shadow.prototype = {
26048 * @cfg {String} mode
26049 * The shadow display mode. Supports the following options:<br />
26050 * sides: Shadow displays on both sides and bottom only<br />
26051 * frame: Shadow displays equally on all four sides<br />
26052 * drop: Traditional bottom-right drop shadow (default)
26055 * @cfg {String} offset
26056 * The number of pixels to offset the shadow from the element (defaults to 4)
26061 defaultMode: "drop",
26064 * Displays the shadow under the target element
26065 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26067 show : function(target){
26068 target = Roo.get(target);
26070 this.el = Roo.Shadow.Pool.pull();
26071 if(this.el.dom.nextSibling != target.dom){
26072 this.el.insertBefore(target);
26075 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26077 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26080 target.getLeft(true),
26081 target.getTop(true),
26085 this.el.dom.style.display = "block";
26089 * Returns true if the shadow is visible, else false
26091 isVisible : function(){
26092 return this.el ? true : false;
26096 * Direct alignment when values are already available. Show must be called at least once before
26097 * calling this method to ensure it is initialized.
26098 * @param {Number} left The target element left position
26099 * @param {Number} top The target element top position
26100 * @param {Number} width The target element width
26101 * @param {Number} height The target element height
26103 realign : function(l, t, w, h){
26107 var a = this.adjusts, d = this.el.dom, s = d.style;
26109 s.left = (l+a.l)+"px";
26110 s.top = (t+a.t)+"px";
26111 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26113 if(s.width != sws || s.height != shs){
26117 var cn = d.childNodes;
26118 var sww = Math.max(0, (sw-12))+"px";
26119 cn[0].childNodes[1].style.width = sww;
26120 cn[1].childNodes[1].style.width = sww;
26121 cn[2].childNodes[1].style.width = sww;
26122 cn[1].style.height = Math.max(0, (sh-12))+"px";
26128 * Hides this shadow
26132 this.el.dom.style.display = "none";
26133 Roo.Shadow.Pool.push(this.el);
26139 * Adjust the z-index of this shadow
26140 * @param {Number} zindex The new z-index
26142 setZIndex : function(z){
26145 this.el.setStyle("z-index", z);
26150 // Private utility class that manages the internal Shadow cache
26151 Roo.Shadow.Pool = function(){
26153 var markup = Roo.isIE ?
26154 '<div class="x-ie-shadow"></div>' :
26155 '<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>';
26158 var sh = p.shift();
26160 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26161 sh.autoBoxAdjust = false;
26166 push : function(sh){
26172 * Ext JS Library 1.1.1
26173 * Copyright(c) 2006-2007, Ext JS, LLC.
26175 * Originally Released Under LGPL - original licence link has changed is not relivant.
26178 * <script type="text/javascript">
26183 * @class Roo.SplitBar
26184 * @extends Roo.util.Observable
26185 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26189 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26190 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26191 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26192 split.minSize = 100;
26193 split.maxSize = 600;
26194 split.animate = true;
26195 split.on('moved', splitterMoved);
26198 * Create a new SplitBar
26199 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26200 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26201 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26202 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26203 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26204 position of the SplitBar).
26206 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26209 this.el = Roo.get(dragElement, true);
26210 this.el.dom.unselectable = "on";
26212 this.resizingEl = Roo.get(resizingElement, true);
26216 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26217 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26220 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26223 * The minimum size of the resizing element. (Defaults to 0)
26229 * The maximum size of the resizing element. (Defaults to 2000)
26232 this.maxSize = 2000;
26235 * Whether to animate the transition to the new size
26238 this.animate = false;
26241 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26244 this.useShim = false;
26249 if(!existingProxy){
26251 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26253 this.proxy = Roo.get(existingProxy).dom;
26256 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26259 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26262 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26265 this.dragSpecs = {};
26268 * @private The adapter to use to positon and resize elements
26270 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26271 this.adapter.init(this);
26273 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26275 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26276 this.el.addClass("x-splitbar-h");
26279 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26280 this.el.addClass("x-splitbar-v");
26286 * Fires when the splitter is moved (alias for {@link #event-moved})
26287 * @param {Roo.SplitBar} this
26288 * @param {Number} newSize the new width or height
26293 * Fires when the splitter is moved
26294 * @param {Roo.SplitBar} this
26295 * @param {Number} newSize the new width or height
26299 * @event beforeresize
26300 * Fires before the splitter is dragged
26301 * @param {Roo.SplitBar} this
26303 "beforeresize" : true,
26305 "beforeapply" : true
26308 Roo.util.Observable.call(this);
26311 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26312 onStartProxyDrag : function(x, y){
26313 this.fireEvent("beforeresize", this);
26315 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26317 o.enableDisplayMode("block");
26318 // all splitbars share the same overlay
26319 Roo.SplitBar.prototype.overlay = o;
26321 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26322 this.overlay.show();
26323 Roo.get(this.proxy).setDisplayed("block");
26324 var size = this.adapter.getElementSize(this);
26325 this.activeMinSize = this.getMinimumSize();;
26326 this.activeMaxSize = this.getMaximumSize();;
26327 var c1 = size - this.activeMinSize;
26328 var c2 = Math.max(this.activeMaxSize - size, 0);
26329 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26330 this.dd.resetConstraints();
26331 this.dd.setXConstraint(
26332 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26333 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26335 this.dd.setYConstraint(0, 0);
26337 this.dd.resetConstraints();
26338 this.dd.setXConstraint(0, 0);
26339 this.dd.setYConstraint(
26340 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26341 this.placement == Roo.SplitBar.TOP ? c2 : c1
26344 this.dragSpecs.startSize = size;
26345 this.dragSpecs.startPoint = [x, y];
26346 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26350 * @private Called after the drag operation by the DDProxy
26352 onEndProxyDrag : function(e){
26353 Roo.get(this.proxy).setDisplayed(false);
26354 var endPoint = Roo.lib.Event.getXY(e);
26356 this.overlay.hide();
26359 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26360 newSize = this.dragSpecs.startSize +
26361 (this.placement == Roo.SplitBar.LEFT ?
26362 endPoint[0] - this.dragSpecs.startPoint[0] :
26363 this.dragSpecs.startPoint[0] - endPoint[0]
26366 newSize = this.dragSpecs.startSize +
26367 (this.placement == Roo.SplitBar.TOP ?
26368 endPoint[1] - this.dragSpecs.startPoint[1] :
26369 this.dragSpecs.startPoint[1] - endPoint[1]
26372 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26373 if(newSize != this.dragSpecs.startSize){
26374 if(this.fireEvent('beforeapply', this, newSize) !== false){
26375 this.adapter.setElementSize(this, newSize);
26376 this.fireEvent("moved", this, newSize);
26377 this.fireEvent("resize", this, newSize);
26383 * Get the adapter this SplitBar uses
26384 * @return The adapter object
26386 getAdapter : function(){
26387 return this.adapter;
26391 * Set the adapter this SplitBar uses
26392 * @param {Object} adapter A SplitBar adapter object
26394 setAdapter : function(adapter){
26395 this.adapter = adapter;
26396 this.adapter.init(this);
26400 * Gets the minimum size for the resizing element
26401 * @return {Number} The minimum size
26403 getMinimumSize : function(){
26404 return this.minSize;
26408 * Sets the minimum size for the resizing element
26409 * @param {Number} minSize The minimum size
26411 setMinimumSize : function(minSize){
26412 this.minSize = minSize;
26416 * Gets the maximum size for the resizing element
26417 * @return {Number} The maximum size
26419 getMaximumSize : function(){
26420 return this.maxSize;
26424 * Sets the maximum size for the resizing element
26425 * @param {Number} maxSize The maximum size
26427 setMaximumSize : function(maxSize){
26428 this.maxSize = maxSize;
26432 * Sets the initialize size for the resizing element
26433 * @param {Number} size The initial size
26435 setCurrentSize : function(size){
26436 var oldAnimate = this.animate;
26437 this.animate = false;
26438 this.adapter.setElementSize(this, size);
26439 this.animate = oldAnimate;
26443 * Destroy this splitbar.
26444 * @param {Boolean} removeEl True to remove the element
26446 destroy : function(removeEl){
26448 this.shim.remove();
26451 this.proxy.parentNode.removeChild(this.proxy);
26459 * @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.
26461 Roo.SplitBar.createProxy = function(dir){
26462 var proxy = new Roo.Element(document.createElement("div"));
26463 proxy.unselectable();
26464 var cls = 'x-splitbar-proxy';
26465 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26466 document.body.appendChild(proxy.dom);
26471 * @class Roo.SplitBar.BasicLayoutAdapter
26472 * Default Adapter. It assumes the splitter and resizing element are not positioned
26473 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26475 Roo.SplitBar.BasicLayoutAdapter = function(){
26478 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26479 // do nothing for now
26480 init : function(s){
26484 * Called before drag operations to get the current size of the resizing element.
26485 * @param {Roo.SplitBar} s The SplitBar using this adapter
26487 getElementSize : function(s){
26488 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26489 return s.resizingEl.getWidth();
26491 return s.resizingEl.getHeight();
26496 * Called after drag operations to set the size of the resizing element.
26497 * @param {Roo.SplitBar} s The SplitBar using this adapter
26498 * @param {Number} newSize The new size to set
26499 * @param {Function} onComplete A function to be invoked when resizing is complete
26501 setElementSize : function(s, newSize, onComplete){
26502 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26504 s.resizingEl.setWidth(newSize);
26506 onComplete(s, newSize);
26509 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26514 s.resizingEl.setHeight(newSize);
26516 onComplete(s, newSize);
26519 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26526 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26527 * @extends Roo.SplitBar.BasicLayoutAdapter
26528 * Adapter that moves the splitter element to align with the resized sizing element.
26529 * Used with an absolute positioned SplitBar.
26530 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26531 * document.body, make sure you assign an id to the body element.
26533 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26534 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26535 this.container = Roo.get(container);
26538 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26539 init : function(s){
26540 this.basic.init(s);
26543 getElementSize : function(s){
26544 return this.basic.getElementSize(s);
26547 setElementSize : function(s, newSize, onComplete){
26548 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26551 moveSplitter : function(s){
26552 var yes = Roo.SplitBar;
26553 switch(s.placement){
26555 s.el.setX(s.resizingEl.getRight());
26558 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26561 s.el.setY(s.resizingEl.getBottom());
26564 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26571 * Orientation constant - Create a vertical SplitBar
26575 Roo.SplitBar.VERTICAL = 1;
26578 * Orientation constant - Create a horizontal SplitBar
26582 Roo.SplitBar.HORIZONTAL = 2;
26585 * Placement constant - The resizing element is to the left of the splitter element
26589 Roo.SplitBar.LEFT = 1;
26592 * Placement constant - The resizing element is to the right of the splitter element
26596 Roo.SplitBar.RIGHT = 2;
26599 * Placement constant - The resizing element is positioned above the splitter element
26603 Roo.SplitBar.TOP = 3;
26606 * Placement constant - The resizing element is positioned under splitter element
26610 Roo.SplitBar.BOTTOM = 4;
26613 * Ext JS Library 1.1.1
26614 * Copyright(c) 2006-2007, Ext JS, LLC.
26616 * Originally Released Under LGPL - original licence link has changed is not relivant.
26619 * <script type="text/javascript">
26624 * @extends Roo.util.Observable
26625 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26626 * This class also supports single and multi selection modes. <br>
26627 * Create a data model bound view:
26629 var store = new Roo.data.Store(...);
26631 var view = new Roo.View({
26633 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26635 singleSelect: true,
26636 selectedClass: "ydataview-selected",
26640 // listen for node click?
26641 view.on("click", function(vw, index, node, e){
26642 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26646 dataModel.load("foobar.xml");
26648 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26650 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26651 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26653 * Note: old style constructor is still suported (container, template, config)
26656 * Create a new View
26657 * @param {Object} config The config object
26660 Roo.View = function(config, depreciated_tpl, depreciated_config){
26662 this.parent = false;
26664 if (typeof(depreciated_tpl) == 'undefined') {
26665 // new way.. - universal constructor.
26666 Roo.apply(this, config);
26667 this.el = Roo.get(this.el);
26670 this.el = Roo.get(config);
26671 this.tpl = depreciated_tpl;
26672 Roo.apply(this, depreciated_config);
26674 this.wrapEl = this.el.wrap().wrap();
26675 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26678 if(typeof(this.tpl) == "string"){
26679 this.tpl = new Roo.Template(this.tpl);
26681 // support xtype ctors..
26682 this.tpl = new Roo.factory(this.tpl, Roo);
26686 this.tpl.compile();
26691 * @event beforeclick
26692 * Fires before a click is processed. Returns false to cancel the default action.
26693 * @param {Roo.View} this
26694 * @param {Number} index The index of the target node
26695 * @param {HTMLElement} node The target node
26696 * @param {Roo.EventObject} e The raw event object
26698 "beforeclick" : true,
26701 * Fires when a template node is clicked.
26702 * @param {Roo.View} this
26703 * @param {Number} index The index of the target node
26704 * @param {HTMLElement} node The target node
26705 * @param {Roo.EventObject} e The raw event object
26710 * Fires when a template node is double clicked.
26711 * @param {Roo.View} this
26712 * @param {Number} index The index of the target node
26713 * @param {HTMLElement} node The target node
26714 * @param {Roo.EventObject} e The raw event object
26718 * @event contextmenu
26719 * Fires when a template node is right clicked.
26720 * @param {Roo.View} this
26721 * @param {Number} index The index of the target node
26722 * @param {HTMLElement} node The target node
26723 * @param {Roo.EventObject} e The raw event object
26725 "contextmenu" : true,
26727 * @event selectionchange
26728 * Fires when the selected nodes change.
26729 * @param {Roo.View} this
26730 * @param {Array} selections Array of the selected nodes
26732 "selectionchange" : true,
26735 * @event beforeselect
26736 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26737 * @param {Roo.View} this
26738 * @param {HTMLElement} node The node to be selected
26739 * @param {Array} selections Array of currently selected nodes
26741 "beforeselect" : true,
26743 * @event preparedata
26744 * Fires on every row to render, to allow you to change the data.
26745 * @param {Roo.View} this
26746 * @param {Object} data to be rendered (change this)
26748 "preparedata" : true
26756 "click": this.onClick,
26757 "dblclick": this.onDblClick,
26758 "contextmenu": this.onContextMenu,
26762 this.selections = [];
26764 this.cmp = new Roo.CompositeElementLite([]);
26766 this.store = Roo.factory(this.store, Roo.data);
26767 this.setStore(this.store, true);
26770 if ( this.footer && this.footer.xtype) {
26772 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26774 this.footer.dataSource = this.store;
26775 this.footer.container = fctr;
26776 this.footer = Roo.factory(this.footer, Roo);
26777 fctr.insertFirst(this.el);
26779 // this is a bit insane - as the paging toolbar seems to detach the el..
26780 // dom.parentNode.parentNode.parentNode
26781 // they get detached?
26785 Roo.View.superclass.constructor.call(this);
26790 Roo.extend(Roo.View, Roo.util.Observable, {
26793 * @cfg {Roo.data.Store} store Data store to load data from.
26798 * @cfg {String|Roo.Element} el The container element.
26803 * @cfg {String|Roo.Template} tpl The template used by this View
26807 * @cfg {String} dataName the named area of the template to use as the data area
26808 * Works with domtemplates roo-name="name"
26812 * @cfg {String} selectedClass The css class to add to selected nodes
26814 selectedClass : "x-view-selected",
26816 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26821 * @cfg {String} text to display on mask (default Loading)
26825 * @cfg {Boolean} multiSelect Allow multiple selection
26827 multiSelect : false,
26829 * @cfg {Boolean} singleSelect Allow single selection
26831 singleSelect: false,
26834 * @cfg {Boolean} toggleSelect - selecting
26836 toggleSelect : false,
26839 * @cfg {Boolean} tickable - selecting
26844 * Returns the element this view is bound to.
26845 * @return {Roo.Element}
26847 getEl : function(){
26848 return this.wrapEl;
26854 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26856 refresh : function(){
26857 //Roo.log('refresh');
26860 // if we are using something like 'domtemplate', then
26861 // the what gets used is:
26862 // t.applySubtemplate(NAME, data, wrapping data..)
26863 // the outer template then get' applied with
26864 // the store 'extra data'
26865 // and the body get's added to the
26866 // roo-name="data" node?
26867 // <span class='roo-tpl-{name}'></span> ?????
26871 this.clearSelections();
26872 this.el.update("");
26874 var records = this.store.getRange();
26875 if(records.length < 1) {
26877 // is this valid?? = should it render a template??
26879 this.el.update(this.emptyText);
26883 if (this.dataName) {
26884 this.el.update(t.apply(this.store.meta)); //????
26885 el = this.el.child('.roo-tpl-' + this.dataName);
26888 for(var i = 0, len = records.length; i < len; i++){
26889 var data = this.prepareData(records[i].data, i, records[i]);
26890 this.fireEvent("preparedata", this, data, i, records[i]);
26892 var d = Roo.apply({}, data);
26895 Roo.apply(d, {'roo-id' : Roo.id()});
26899 Roo.each(this.parent.item, function(item){
26900 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26903 Roo.apply(d, {'roo-data-checked' : 'checked'});
26907 html[html.length] = Roo.util.Format.trim(
26909 t.applySubtemplate(this.dataName, d, this.store.meta) :
26916 el.update(html.join(""));
26917 this.nodes = el.dom.childNodes;
26918 this.updateIndexes(0);
26923 * Function to override to reformat the data that is sent to
26924 * the template for each node.
26925 * DEPRICATED - use the preparedata event handler.
26926 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26927 * a JSON object for an UpdateManager bound view).
26929 prepareData : function(data, index, record)
26931 this.fireEvent("preparedata", this, data, index, record);
26935 onUpdate : function(ds, record){
26936 // Roo.log('on update');
26937 this.clearSelections();
26938 var index = this.store.indexOf(record);
26939 var n = this.nodes[index];
26940 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26941 n.parentNode.removeChild(n);
26942 this.updateIndexes(index, index);
26948 onAdd : function(ds, records, index)
26950 //Roo.log(['on Add', ds, records, index] );
26951 this.clearSelections();
26952 if(this.nodes.length == 0){
26956 var n = this.nodes[index];
26957 for(var i = 0, len = records.length; i < len; i++){
26958 var d = this.prepareData(records[i].data, i, records[i]);
26960 this.tpl.insertBefore(n, d);
26963 this.tpl.append(this.el, d);
26966 this.updateIndexes(index);
26969 onRemove : function(ds, record, index){
26970 // Roo.log('onRemove');
26971 this.clearSelections();
26972 var el = this.dataName ?
26973 this.el.child('.roo-tpl-' + this.dataName) :
26976 el.dom.removeChild(this.nodes[index]);
26977 this.updateIndexes(index);
26981 * Refresh an individual node.
26982 * @param {Number} index
26984 refreshNode : function(index){
26985 this.onUpdate(this.store, this.store.getAt(index));
26988 updateIndexes : function(startIndex, endIndex){
26989 var ns = this.nodes;
26990 startIndex = startIndex || 0;
26991 endIndex = endIndex || ns.length - 1;
26992 for(var i = startIndex; i <= endIndex; i++){
26993 ns[i].nodeIndex = i;
26998 * Changes the data store this view uses and refresh the view.
26999 * @param {Store} store
27001 setStore : function(store, initial){
27002 if(!initial && this.store){
27003 this.store.un("datachanged", this.refresh);
27004 this.store.un("add", this.onAdd);
27005 this.store.un("remove", this.onRemove);
27006 this.store.un("update", this.onUpdate);
27007 this.store.un("clear", this.refresh);
27008 this.store.un("beforeload", this.onBeforeLoad);
27009 this.store.un("load", this.onLoad);
27010 this.store.un("loadexception", this.onLoad);
27014 store.on("datachanged", this.refresh, this);
27015 store.on("add", this.onAdd, this);
27016 store.on("remove", this.onRemove, this);
27017 store.on("update", this.onUpdate, this);
27018 store.on("clear", this.refresh, this);
27019 store.on("beforeload", this.onBeforeLoad, this);
27020 store.on("load", this.onLoad, this);
27021 store.on("loadexception", this.onLoad, this);
27029 * onbeforeLoad - masks the loading area.
27032 onBeforeLoad : function(store,opts)
27034 //Roo.log('onBeforeLoad');
27036 this.el.update("");
27038 this.el.mask(this.mask ? this.mask : "Loading" );
27040 onLoad : function ()
27047 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27048 * @param {HTMLElement} node
27049 * @return {HTMLElement} The template node
27051 findItemFromChild : function(node){
27052 var el = this.dataName ?
27053 this.el.child('.roo-tpl-' + this.dataName,true) :
27056 if(!node || node.parentNode == el){
27059 var p = node.parentNode;
27060 while(p && p != el){
27061 if(p.parentNode == el){
27070 onClick : function(e){
27071 var item = this.findItemFromChild(e.getTarget());
27073 var index = this.indexOf(item);
27074 if(this.onItemClick(item, index, e) !== false){
27075 this.fireEvent("click", this, index, item, e);
27078 this.clearSelections();
27083 onContextMenu : function(e){
27084 var item = this.findItemFromChild(e.getTarget());
27086 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27091 onDblClick : function(e){
27092 var item = this.findItemFromChild(e.getTarget());
27094 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27098 onItemClick : function(item, index, e)
27100 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27103 if (this.toggleSelect) {
27104 var m = this.isSelected(item) ? 'unselect' : 'select';
27107 _t[m](item, true, false);
27110 if(this.multiSelect || this.singleSelect){
27111 if(this.multiSelect && e.shiftKey && this.lastSelection){
27112 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27114 this.select(item, this.multiSelect && e.ctrlKey);
27115 this.lastSelection = item;
27118 if(!this.tickable){
27119 e.preventDefault();
27127 * Get the number of selected nodes.
27130 getSelectionCount : function(){
27131 return this.selections.length;
27135 * Get the currently selected nodes.
27136 * @return {Array} An array of HTMLElements
27138 getSelectedNodes : function(){
27139 return this.selections;
27143 * Get the indexes of the selected nodes.
27146 getSelectedIndexes : function(){
27147 var indexes = [], s = this.selections;
27148 for(var i = 0, len = s.length; i < len; i++){
27149 indexes.push(s[i].nodeIndex);
27155 * Clear all selections
27156 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27158 clearSelections : function(suppressEvent){
27159 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27160 this.cmp.elements = this.selections;
27161 this.cmp.removeClass(this.selectedClass);
27162 this.selections = [];
27163 if(!suppressEvent){
27164 this.fireEvent("selectionchange", this, this.selections);
27170 * Returns true if the passed node is selected
27171 * @param {HTMLElement/Number} node The node or node index
27172 * @return {Boolean}
27174 isSelected : function(node){
27175 var s = this.selections;
27179 node = this.getNode(node);
27180 return s.indexOf(node) !== -1;
27185 * @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
27186 * @param {Boolean} keepExisting (optional) true to keep existing selections
27187 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27189 select : function(nodeInfo, keepExisting, suppressEvent){
27190 if(nodeInfo instanceof Array){
27192 this.clearSelections(true);
27194 for(var i = 0, len = nodeInfo.length; i < len; i++){
27195 this.select(nodeInfo[i], true, true);
27199 var node = this.getNode(nodeInfo);
27200 if(!node || this.isSelected(node)){
27201 return; // already selected.
27204 this.clearSelections(true);
27207 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27208 Roo.fly(node).addClass(this.selectedClass);
27209 this.selections.push(node);
27210 if(!suppressEvent){
27211 this.fireEvent("selectionchange", this, this.selections);
27219 * @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
27220 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27221 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27223 unselect : function(nodeInfo, keepExisting, suppressEvent)
27225 if(nodeInfo instanceof Array){
27226 Roo.each(this.selections, function(s) {
27227 this.unselect(s, nodeInfo);
27231 var node = this.getNode(nodeInfo);
27232 if(!node || !this.isSelected(node)){
27233 //Roo.log("not selected");
27234 return; // not selected.
27238 Roo.each(this.selections, function(s) {
27240 Roo.fly(node).removeClass(this.selectedClass);
27247 this.selections= ns;
27248 this.fireEvent("selectionchange", this, this.selections);
27252 * Gets a template node.
27253 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27254 * @return {HTMLElement} The node or null if it wasn't found
27256 getNode : function(nodeInfo){
27257 if(typeof nodeInfo == "string"){
27258 return document.getElementById(nodeInfo);
27259 }else if(typeof nodeInfo == "number"){
27260 return this.nodes[nodeInfo];
27266 * Gets a range template nodes.
27267 * @param {Number} startIndex
27268 * @param {Number} endIndex
27269 * @return {Array} An array of nodes
27271 getNodes : function(start, end){
27272 var ns = this.nodes;
27273 start = start || 0;
27274 end = typeof end == "undefined" ? ns.length - 1 : end;
27277 for(var i = start; i <= end; i++){
27281 for(var i = start; i >= end; i--){
27289 * Finds the index of the passed node
27290 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27291 * @return {Number} The index of the node or -1
27293 indexOf : function(node){
27294 node = this.getNode(node);
27295 if(typeof node.nodeIndex == "number"){
27296 return node.nodeIndex;
27298 var ns = this.nodes;
27299 for(var i = 0, len = ns.length; i < len; i++){
27309 * Ext JS Library 1.1.1
27310 * Copyright(c) 2006-2007, Ext JS, LLC.
27312 * Originally Released Under LGPL - original licence link has changed is not relivant.
27315 * <script type="text/javascript">
27319 * @class Roo.JsonView
27320 * @extends Roo.View
27321 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27323 var view = new Roo.JsonView({
27324 container: "my-element",
27325 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27330 // listen for node click?
27331 view.on("click", function(vw, index, node, e){
27332 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27335 // direct load of JSON data
27336 view.load("foobar.php");
27338 // Example from my blog list
27339 var tpl = new Roo.Template(
27340 '<div class="entry">' +
27341 '<a class="entry-title" href="{link}">{title}</a>' +
27342 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27343 "</div><hr />"
27346 var moreView = new Roo.JsonView({
27347 container : "entry-list",
27351 moreView.on("beforerender", this.sortEntries, this);
27353 url: "/blog/get-posts.php",
27354 params: "allposts=true",
27355 text: "Loading Blog Entries..."
27359 * Note: old code is supported with arguments : (container, template, config)
27363 * Create a new JsonView
27365 * @param {Object} config The config object
27368 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27371 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27373 var um = this.el.getUpdateManager();
27374 um.setRenderer(this);
27375 um.on("update", this.onLoad, this);
27376 um.on("failure", this.onLoadException, this);
27379 * @event beforerender
27380 * Fires before rendering of the downloaded JSON data.
27381 * @param {Roo.JsonView} this
27382 * @param {Object} data The JSON data loaded
27386 * Fires when data is loaded.
27387 * @param {Roo.JsonView} this
27388 * @param {Object} data The JSON data loaded
27389 * @param {Object} response The raw Connect response object
27392 * @event loadexception
27393 * Fires when loading fails.
27394 * @param {Roo.JsonView} this
27395 * @param {Object} response The raw Connect response object
27398 'beforerender' : true,
27400 'loadexception' : true
27403 Roo.extend(Roo.JsonView, Roo.View, {
27405 * @type {String} The root property in the loaded JSON object that contains the data
27410 * Refreshes the view.
27412 refresh : function(){
27413 this.clearSelections();
27414 this.el.update("");
27416 var o = this.jsonData;
27417 if(o && o.length > 0){
27418 for(var i = 0, len = o.length; i < len; i++){
27419 var data = this.prepareData(o[i], i, o);
27420 html[html.length] = this.tpl.apply(data);
27423 html.push(this.emptyText);
27425 this.el.update(html.join(""));
27426 this.nodes = this.el.dom.childNodes;
27427 this.updateIndexes(0);
27431 * 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.
27432 * @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:
27435 url: "your-url.php",
27436 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27437 callback: yourFunction,
27438 scope: yourObject, //(optional scope)
27441 text: "Loading...",
27446 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27447 * 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.
27448 * @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}
27449 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27450 * @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.
27453 var um = this.el.getUpdateManager();
27454 um.update.apply(um, arguments);
27457 // note - render is a standard framework call...
27458 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27459 render : function(el, response){
27461 this.clearSelections();
27462 this.el.update("");
27465 if (response != '') {
27466 o = Roo.util.JSON.decode(response.responseText);
27469 o = o[this.jsonRoot];
27475 * The current JSON data or null
27478 this.beforeRender();
27483 * Get the number of records in the current JSON dataset
27486 getCount : function(){
27487 return this.jsonData ? this.jsonData.length : 0;
27491 * Returns the JSON object for the specified node(s)
27492 * @param {HTMLElement/Array} node The node or an array of nodes
27493 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27494 * you get the JSON object for the node
27496 getNodeData : function(node){
27497 if(node instanceof Array){
27499 for(var i = 0, len = node.length; i < len; i++){
27500 data.push(this.getNodeData(node[i]));
27504 return this.jsonData[this.indexOf(node)] || null;
27507 beforeRender : function(){
27508 this.snapshot = this.jsonData;
27510 this.sort.apply(this, this.sortInfo);
27512 this.fireEvent("beforerender", this, this.jsonData);
27515 onLoad : function(el, o){
27516 this.fireEvent("load", this, this.jsonData, o);
27519 onLoadException : function(el, o){
27520 this.fireEvent("loadexception", this, o);
27524 * Filter the data by a specific property.
27525 * @param {String} property A property on your JSON objects
27526 * @param {String/RegExp} value Either string that the property values
27527 * should start with, or a RegExp to test against the property
27529 filter : function(property, value){
27532 var ss = this.snapshot;
27533 if(typeof value == "string"){
27534 var vlen = value.length;
27536 this.clearFilter();
27539 value = value.toLowerCase();
27540 for(var i = 0, len = ss.length; i < len; i++){
27542 if(o[property].substr(0, vlen).toLowerCase() == value){
27546 } else if(value.exec){ // regex?
27547 for(var i = 0, len = ss.length; i < len; i++){
27549 if(value.test(o[property])){
27556 this.jsonData = data;
27562 * Filter by a function. The passed function will be called with each
27563 * object in the current dataset. If the function returns true the value is kept,
27564 * otherwise it is filtered.
27565 * @param {Function} fn
27566 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27568 filterBy : function(fn, scope){
27571 var ss = this.snapshot;
27572 for(var i = 0, len = ss.length; i < len; i++){
27574 if(fn.call(scope || this, o)){
27578 this.jsonData = data;
27584 * Clears the current filter.
27586 clearFilter : function(){
27587 if(this.snapshot && this.jsonData != this.snapshot){
27588 this.jsonData = this.snapshot;
27595 * Sorts the data for this view and refreshes it.
27596 * @param {String} property A property on your JSON objects to sort on
27597 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27598 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27600 sort : function(property, dir, sortType){
27601 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27604 var dsc = dir && dir.toLowerCase() == "desc";
27605 var f = function(o1, o2){
27606 var v1 = sortType ? sortType(o1[p]) : o1[p];
27607 var v2 = sortType ? sortType(o2[p]) : o2[p];
27610 return dsc ? +1 : -1;
27611 } else if(v1 > v2){
27612 return dsc ? -1 : +1;
27617 this.jsonData.sort(f);
27619 if(this.jsonData != this.snapshot){
27620 this.snapshot.sort(f);
27626 * Ext JS Library 1.1.1
27627 * Copyright(c) 2006-2007, Ext JS, LLC.
27629 * Originally Released Under LGPL - original licence link has changed is not relivant.
27632 * <script type="text/javascript">
27637 * @class Roo.ColorPalette
27638 * @extends Roo.Component
27639 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27640 * Here's an example of typical usage:
27642 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27643 cp.render('my-div');
27645 cp.on('select', function(palette, selColor){
27646 // do something with selColor
27650 * Create a new ColorPalette
27651 * @param {Object} config The config object
27653 Roo.ColorPalette = function(config){
27654 Roo.ColorPalette.superclass.constructor.call(this, config);
27658 * Fires when a color is selected
27659 * @param {ColorPalette} this
27660 * @param {String} color The 6-digit color hex code (without the # symbol)
27666 this.on("select", this.handler, this.scope, true);
27669 Roo.extend(Roo.ColorPalette, Roo.Component, {
27671 * @cfg {String} itemCls
27672 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27674 itemCls : "x-color-palette",
27676 * @cfg {String} value
27677 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27678 * the hex codes are case-sensitive.
27681 clickEvent:'click',
27683 ctype: "Roo.ColorPalette",
27686 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27688 allowReselect : false,
27691 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27692 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27693 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27694 * of colors with the width setting until the box is symmetrical.</p>
27695 * <p>You can override individual colors if needed:</p>
27697 var cp = new Roo.ColorPalette();
27698 cp.colors[0] = "FF0000"; // change the first box to red
27701 Or you can provide a custom array of your own for complete control:
27703 var cp = new Roo.ColorPalette();
27704 cp.colors = ["000000", "993300", "333300"];
27709 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27710 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27711 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27712 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27713 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27717 onRender : function(container, position){
27718 var t = new Roo.MasterTemplate(
27719 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27721 var c = this.colors;
27722 for(var i = 0, len = c.length; i < len; i++){
27725 var el = document.createElement("div");
27726 el.className = this.itemCls;
27728 container.dom.insertBefore(el, position);
27729 this.el = Roo.get(el);
27730 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27731 if(this.clickEvent != 'click'){
27732 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27737 afterRender : function(){
27738 Roo.ColorPalette.superclass.afterRender.call(this);
27740 var s = this.value;
27747 handleClick : function(e, t){
27748 e.preventDefault();
27749 if(!this.disabled){
27750 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27751 this.select(c.toUpperCase());
27756 * Selects the specified color in the palette (fires the select event)
27757 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27759 select : function(color){
27760 color = color.replace("#", "");
27761 if(color != this.value || this.allowReselect){
27764 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27766 el.child("a.color-"+color).addClass("x-color-palette-sel");
27767 this.value = color;
27768 this.fireEvent("select", this, color);
27773 * Ext JS Library 1.1.1
27774 * Copyright(c) 2006-2007, Ext JS, LLC.
27776 * Originally Released Under LGPL - original licence link has changed is not relivant.
27779 * <script type="text/javascript">
27783 * @class Roo.DatePicker
27784 * @extends Roo.Component
27785 * Simple date picker class.
27787 * Create a new DatePicker
27788 * @param {Object} config The config object
27790 Roo.DatePicker = function(config){
27791 Roo.DatePicker.superclass.constructor.call(this, config);
27793 this.value = config && config.value ?
27794 config.value.clearTime() : new Date().clearTime();
27799 * Fires when a date is selected
27800 * @param {DatePicker} this
27801 * @param {Date} date The selected date
27805 * @event monthchange
27806 * Fires when the displayed month changes
27807 * @param {DatePicker} this
27808 * @param {Date} date The selected month
27810 'monthchange': true
27814 this.on("select", this.handler, this.scope || this);
27816 // build the disabledDatesRE
27817 if(!this.disabledDatesRE && this.disabledDates){
27818 var dd = this.disabledDates;
27820 for(var i = 0; i < dd.length; i++){
27822 if(i != dd.length-1) {
27826 this.disabledDatesRE = new RegExp(re + ")");
27830 Roo.extend(Roo.DatePicker, Roo.Component, {
27832 * @cfg {String} todayText
27833 * The text to display on the button that selects the current date (defaults to "Today")
27835 todayText : "Today",
27837 * @cfg {String} okText
27838 * The text to display on the ok button
27840 okText : " OK ", //   to give the user extra clicking room
27842 * @cfg {String} cancelText
27843 * The text to display on the cancel button
27845 cancelText : "Cancel",
27847 * @cfg {String} todayTip
27848 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27850 todayTip : "{0} (Spacebar)",
27852 * @cfg {Date} minDate
27853 * Minimum allowable date (JavaScript date object, defaults to null)
27857 * @cfg {Date} maxDate
27858 * Maximum allowable date (JavaScript date object, defaults to null)
27862 * @cfg {String} minText
27863 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27865 minText : "This date is before the minimum date",
27867 * @cfg {String} maxText
27868 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27870 maxText : "This date is after the maximum date",
27872 * @cfg {String} format
27873 * The default date format string which can be overriden for localization support. The format must be
27874 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27878 * @cfg {Array} disabledDays
27879 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27881 disabledDays : null,
27883 * @cfg {String} disabledDaysText
27884 * The tooltip to display when the date falls on a disabled day (defaults to "")
27886 disabledDaysText : "",
27888 * @cfg {RegExp} disabledDatesRE
27889 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27891 disabledDatesRE : null,
27893 * @cfg {String} disabledDatesText
27894 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27896 disabledDatesText : "",
27898 * @cfg {Boolean} constrainToViewport
27899 * True to constrain the date picker to the viewport (defaults to true)
27901 constrainToViewport : true,
27903 * @cfg {Array} monthNames
27904 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27906 monthNames : Date.monthNames,
27908 * @cfg {Array} dayNames
27909 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27911 dayNames : Date.dayNames,
27913 * @cfg {String} nextText
27914 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27916 nextText: 'Next Month (Control+Right)',
27918 * @cfg {String} prevText
27919 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27921 prevText: 'Previous Month (Control+Left)',
27923 * @cfg {String} monthYearText
27924 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27926 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27928 * @cfg {Number} startDay
27929 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27933 * @cfg {Bool} showClear
27934 * Show a clear button (usefull for date form elements that can be blank.)
27940 * Sets the value of the date field
27941 * @param {Date} value The date to set
27943 setValue : function(value){
27944 var old = this.value;
27946 if (typeof(value) == 'string') {
27948 value = Date.parseDate(value, this.format);
27951 value = new Date();
27954 this.value = value.clearTime(true);
27956 this.update(this.value);
27961 * Gets the current selected value of the date field
27962 * @return {Date} The selected date
27964 getValue : function(){
27969 focus : function(){
27971 this.update(this.activeDate);
27976 onRender : function(container, position){
27979 '<table cellspacing="0">',
27980 '<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>',
27981 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27982 var dn = this.dayNames;
27983 for(var i = 0; i < 7; i++){
27984 var d = this.startDay+i;
27988 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27990 m[m.length] = "</tr></thead><tbody><tr>";
27991 for(var i = 0; i < 42; i++) {
27992 if(i % 7 == 0 && i != 0){
27993 m[m.length] = "</tr><tr>";
27995 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27997 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27998 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28000 var el = document.createElement("div");
28001 el.className = "x-date-picker";
28002 el.innerHTML = m.join("");
28004 container.dom.insertBefore(el, position);
28006 this.el = Roo.get(el);
28007 this.eventEl = Roo.get(el.firstChild);
28009 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28010 handler: this.showPrevMonth,
28012 preventDefault:true,
28016 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28017 handler: this.showNextMonth,
28019 preventDefault:true,
28023 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28025 this.monthPicker = this.el.down('div.x-date-mp');
28026 this.monthPicker.enableDisplayMode('block');
28028 var kn = new Roo.KeyNav(this.eventEl, {
28029 "left" : function(e){
28031 this.showPrevMonth() :
28032 this.update(this.activeDate.add("d", -1));
28035 "right" : function(e){
28037 this.showNextMonth() :
28038 this.update(this.activeDate.add("d", 1));
28041 "up" : function(e){
28043 this.showNextYear() :
28044 this.update(this.activeDate.add("d", -7));
28047 "down" : function(e){
28049 this.showPrevYear() :
28050 this.update(this.activeDate.add("d", 7));
28053 "pageUp" : function(e){
28054 this.showNextMonth();
28057 "pageDown" : function(e){
28058 this.showPrevMonth();
28061 "enter" : function(e){
28062 e.stopPropagation();
28069 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28071 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28073 this.el.unselectable();
28075 this.cells = this.el.select("table.x-date-inner tbody td");
28076 this.textNodes = this.el.query("table.x-date-inner tbody span");
28078 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28080 tooltip: this.monthYearText
28083 this.mbtn.on('click', this.showMonthPicker, this);
28084 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28087 var today = (new Date()).dateFormat(this.format);
28089 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28090 if (this.showClear) {
28091 baseTb.add( new Roo.Toolbar.Fill());
28094 text: String.format(this.todayText, today),
28095 tooltip: String.format(this.todayTip, today),
28096 handler: this.selectToday,
28100 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28103 if (this.showClear) {
28105 baseTb.add( new Roo.Toolbar.Fill());
28108 cls: 'x-btn-icon x-btn-clear',
28109 handler: function() {
28111 this.fireEvent("select", this, '');
28121 this.update(this.value);
28124 createMonthPicker : function(){
28125 if(!this.monthPicker.dom.firstChild){
28126 var buf = ['<table border="0" cellspacing="0">'];
28127 for(var i = 0; i < 6; i++){
28129 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28130 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28132 '<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>' :
28133 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28137 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28139 '</button><button type="button" class="x-date-mp-cancel">',
28141 '</button></td></tr>',
28144 this.monthPicker.update(buf.join(''));
28145 this.monthPicker.on('click', this.onMonthClick, this);
28146 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28148 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28149 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28151 this.mpMonths.each(function(m, a, i){
28154 m.dom.xmonth = 5 + Math.round(i * .5);
28156 m.dom.xmonth = Math.round((i-1) * .5);
28162 showMonthPicker : function(){
28163 this.createMonthPicker();
28164 var size = this.el.getSize();
28165 this.monthPicker.setSize(size);
28166 this.monthPicker.child('table').setSize(size);
28168 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28169 this.updateMPMonth(this.mpSelMonth);
28170 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28171 this.updateMPYear(this.mpSelYear);
28173 this.monthPicker.slideIn('t', {duration:.2});
28176 updateMPYear : function(y){
28178 var ys = this.mpYears.elements;
28179 for(var i = 1; i <= 10; i++){
28180 var td = ys[i-1], y2;
28182 y2 = y + Math.round(i * .5);
28183 td.firstChild.innerHTML = y2;
28186 y2 = y - (5-Math.round(i * .5));
28187 td.firstChild.innerHTML = y2;
28190 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28194 updateMPMonth : function(sm){
28195 this.mpMonths.each(function(m, a, i){
28196 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28200 selectMPMonth: function(m){
28204 onMonthClick : function(e, t){
28206 var el = new Roo.Element(t), pn;
28207 if(el.is('button.x-date-mp-cancel')){
28208 this.hideMonthPicker();
28210 else if(el.is('button.x-date-mp-ok')){
28211 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28212 this.hideMonthPicker();
28214 else if(pn = el.up('td.x-date-mp-month', 2)){
28215 this.mpMonths.removeClass('x-date-mp-sel');
28216 pn.addClass('x-date-mp-sel');
28217 this.mpSelMonth = pn.dom.xmonth;
28219 else if(pn = el.up('td.x-date-mp-year', 2)){
28220 this.mpYears.removeClass('x-date-mp-sel');
28221 pn.addClass('x-date-mp-sel');
28222 this.mpSelYear = pn.dom.xyear;
28224 else if(el.is('a.x-date-mp-prev')){
28225 this.updateMPYear(this.mpyear-10);
28227 else if(el.is('a.x-date-mp-next')){
28228 this.updateMPYear(this.mpyear+10);
28232 onMonthDblClick : function(e, t){
28234 var el = new Roo.Element(t), pn;
28235 if(pn = el.up('td.x-date-mp-month', 2)){
28236 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28237 this.hideMonthPicker();
28239 else if(pn = el.up('td.x-date-mp-year', 2)){
28240 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28241 this.hideMonthPicker();
28245 hideMonthPicker : function(disableAnim){
28246 if(this.monthPicker){
28247 if(disableAnim === true){
28248 this.monthPicker.hide();
28250 this.monthPicker.slideOut('t', {duration:.2});
28256 showPrevMonth : function(e){
28257 this.update(this.activeDate.add("mo", -1));
28261 showNextMonth : function(e){
28262 this.update(this.activeDate.add("mo", 1));
28266 showPrevYear : function(){
28267 this.update(this.activeDate.add("y", -1));
28271 showNextYear : function(){
28272 this.update(this.activeDate.add("y", 1));
28276 handleMouseWheel : function(e){
28277 var delta = e.getWheelDelta();
28279 this.showPrevMonth();
28281 } else if(delta < 0){
28282 this.showNextMonth();
28288 handleDateClick : function(e, t){
28290 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28291 this.setValue(new Date(t.dateValue));
28292 this.fireEvent("select", this, this.value);
28297 selectToday : function(){
28298 this.setValue(new Date().clearTime());
28299 this.fireEvent("select", this, this.value);
28303 update : function(date)
28305 var vd = this.activeDate;
28306 this.activeDate = date;
28308 var t = date.getTime();
28309 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28310 this.cells.removeClass("x-date-selected");
28311 this.cells.each(function(c){
28312 if(c.dom.firstChild.dateValue == t){
28313 c.addClass("x-date-selected");
28314 setTimeout(function(){
28315 try{c.dom.firstChild.focus();}catch(e){}
28324 var days = date.getDaysInMonth();
28325 var firstOfMonth = date.getFirstDateOfMonth();
28326 var startingPos = firstOfMonth.getDay()-this.startDay;
28328 if(startingPos <= this.startDay){
28332 var pm = date.add("mo", -1);
28333 var prevStart = pm.getDaysInMonth()-startingPos;
28335 var cells = this.cells.elements;
28336 var textEls = this.textNodes;
28337 days += startingPos;
28339 // convert everything to numbers so it's fast
28340 var day = 86400000;
28341 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28342 var today = new Date().clearTime().getTime();
28343 var sel = date.clearTime().getTime();
28344 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28345 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28346 var ddMatch = this.disabledDatesRE;
28347 var ddText = this.disabledDatesText;
28348 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28349 var ddaysText = this.disabledDaysText;
28350 var format = this.format;
28352 var setCellClass = function(cal, cell){
28354 var t = d.getTime();
28355 cell.firstChild.dateValue = t;
28357 cell.className += " x-date-today";
28358 cell.title = cal.todayText;
28361 cell.className += " x-date-selected";
28362 setTimeout(function(){
28363 try{cell.firstChild.focus();}catch(e){}
28368 cell.className = " x-date-disabled";
28369 cell.title = cal.minText;
28373 cell.className = " x-date-disabled";
28374 cell.title = cal.maxText;
28378 if(ddays.indexOf(d.getDay()) != -1){
28379 cell.title = ddaysText;
28380 cell.className = " x-date-disabled";
28383 if(ddMatch && format){
28384 var fvalue = d.dateFormat(format);
28385 if(ddMatch.test(fvalue)){
28386 cell.title = ddText.replace("%0", fvalue);
28387 cell.className = " x-date-disabled";
28393 for(; i < startingPos; i++) {
28394 textEls[i].innerHTML = (++prevStart);
28395 d.setDate(d.getDate()+1);
28396 cells[i].className = "x-date-prevday";
28397 setCellClass(this, cells[i]);
28399 for(; i < days; i++){
28400 intDay = i - startingPos + 1;
28401 textEls[i].innerHTML = (intDay);
28402 d.setDate(d.getDate()+1);
28403 cells[i].className = "x-date-active";
28404 setCellClass(this, cells[i]);
28407 for(; i < 42; i++) {
28408 textEls[i].innerHTML = (++extraDays);
28409 d.setDate(d.getDate()+1);
28410 cells[i].className = "x-date-nextday";
28411 setCellClass(this, cells[i]);
28414 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28415 this.fireEvent('monthchange', this, date);
28417 if(!this.internalRender){
28418 var main = this.el.dom.firstChild;
28419 var w = main.offsetWidth;
28420 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28421 Roo.fly(main).setWidth(w);
28422 this.internalRender = true;
28423 // opera does not respect the auto grow header center column
28424 // then, after it gets a width opera refuses to recalculate
28425 // without a second pass
28426 if(Roo.isOpera && !this.secondPass){
28427 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28428 this.secondPass = true;
28429 this.update.defer(10, this, [date]);
28437 * Ext JS Library 1.1.1
28438 * Copyright(c) 2006-2007, Ext JS, LLC.
28440 * Originally Released Under LGPL - original licence link has changed is not relivant.
28443 * <script type="text/javascript">
28446 * @class Roo.TabPanel
28447 * @extends Roo.util.Observable
28448 * A lightweight tab container.
28452 // basic tabs 1, built from existing content
28453 var tabs = new Roo.TabPanel("tabs1");
28454 tabs.addTab("script", "View Script");
28455 tabs.addTab("markup", "View Markup");
28456 tabs.activate("script");
28458 // more advanced tabs, built from javascript
28459 var jtabs = new Roo.TabPanel("jtabs");
28460 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28462 // set up the UpdateManager
28463 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28464 var updater = tab2.getUpdateManager();
28465 updater.setDefaultUrl("ajax1.htm");
28466 tab2.on('activate', updater.refresh, updater, true);
28468 // Use setUrl for Ajax loading
28469 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28470 tab3.setUrl("ajax2.htm", null, true);
28473 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28476 jtabs.activate("jtabs-1");
28479 * Create a new TabPanel.
28480 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28481 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28483 Roo.TabPanel = function(container, config){
28485 * The container element for this TabPanel.
28486 * @type Roo.Element
28488 this.el = Roo.get(container, true);
28490 if(typeof config == "boolean"){
28491 this.tabPosition = config ? "bottom" : "top";
28493 Roo.apply(this, config);
28496 if(this.tabPosition == "bottom"){
28497 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28498 this.el.addClass("x-tabs-bottom");
28500 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28501 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28502 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28504 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28506 if(this.tabPosition != "bottom"){
28507 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28508 * @type Roo.Element
28510 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28511 this.el.addClass("x-tabs-top");
28515 this.bodyEl.setStyle("position", "relative");
28517 this.active = null;
28518 this.activateDelegate = this.activate.createDelegate(this);
28523 * Fires when the active tab changes
28524 * @param {Roo.TabPanel} this
28525 * @param {Roo.TabPanelItem} activePanel The new active tab
28529 * @event beforetabchange
28530 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28531 * @param {Roo.TabPanel} this
28532 * @param {Object} e Set cancel to true on this object to cancel the tab change
28533 * @param {Roo.TabPanelItem} tab The tab being changed to
28535 "beforetabchange" : true
28538 Roo.EventManager.onWindowResize(this.onResize, this);
28539 this.cpad = this.el.getPadding("lr");
28540 this.hiddenCount = 0;
28543 // toolbar on the tabbar support...
28544 if (this.toolbar) {
28545 var tcfg = this.toolbar;
28546 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28547 this.toolbar = new Roo.Toolbar(tcfg);
28548 if (Roo.isSafari) {
28549 var tbl = tcfg.container.child('table', true);
28550 tbl.setAttribute('width', '100%');
28557 Roo.TabPanel.superclass.constructor.call(this);
28560 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28562 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28564 tabPosition : "top",
28566 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28568 currentTabWidth : 0,
28570 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28574 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28578 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28580 preferredTabWidth : 175,
28582 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28584 resizeTabs : false,
28586 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28588 monitorResize : true,
28590 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28595 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28596 * @param {String} id The id of the div to use <b>or create</b>
28597 * @param {String} text The text for the tab
28598 * @param {String} content (optional) Content to put in the TabPanelItem body
28599 * @param {Boolean} closable (optional) True to create a close icon on the tab
28600 * @return {Roo.TabPanelItem} The created TabPanelItem
28602 addTab : function(id, text, content, closable){
28603 var item = new Roo.TabPanelItem(this, id, text, closable);
28604 this.addTabItem(item);
28606 item.setContent(content);
28612 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28613 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28614 * @return {Roo.TabPanelItem}
28616 getTab : function(id){
28617 return this.items[id];
28621 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28622 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28624 hideTab : function(id){
28625 var t = this.items[id];
28628 this.hiddenCount++;
28629 this.autoSizeTabs();
28634 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28635 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28637 unhideTab : function(id){
28638 var t = this.items[id];
28640 t.setHidden(false);
28641 this.hiddenCount--;
28642 this.autoSizeTabs();
28647 * Adds an existing {@link Roo.TabPanelItem}.
28648 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28650 addTabItem : function(item){
28651 this.items[item.id] = item;
28652 this.items.push(item);
28653 if(this.resizeTabs){
28654 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28655 this.autoSizeTabs();
28662 * Removes a {@link Roo.TabPanelItem}.
28663 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28665 removeTab : function(id){
28666 var items = this.items;
28667 var tab = items[id];
28668 if(!tab) { return; }
28669 var index = items.indexOf(tab);
28670 if(this.active == tab && items.length > 1){
28671 var newTab = this.getNextAvailable(index);
28676 this.stripEl.dom.removeChild(tab.pnode.dom);
28677 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28678 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28680 items.splice(index, 1);
28681 delete this.items[tab.id];
28682 tab.fireEvent("close", tab);
28683 tab.purgeListeners();
28684 this.autoSizeTabs();
28687 getNextAvailable : function(start){
28688 var items = this.items;
28690 // look for a next tab that will slide over to
28691 // replace the one being removed
28692 while(index < items.length){
28693 var item = items[++index];
28694 if(item && !item.isHidden()){
28698 // if one isn't found select the previous tab (on the left)
28701 var item = items[--index];
28702 if(item && !item.isHidden()){
28710 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28711 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28713 disableTab : function(id){
28714 var tab = this.items[id];
28715 if(tab && this.active != tab){
28721 * Enables a {@link Roo.TabPanelItem} that is disabled.
28722 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28724 enableTab : function(id){
28725 var tab = this.items[id];
28730 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28731 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28732 * @return {Roo.TabPanelItem} The TabPanelItem.
28734 activate : function(id){
28735 var tab = this.items[id];
28739 if(tab == this.active || tab.disabled){
28743 this.fireEvent("beforetabchange", this, e, tab);
28744 if(e.cancel !== true && !tab.disabled){
28746 this.active.hide();
28748 this.active = this.items[id];
28749 this.active.show();
28750 this.fireEvent("tabchange", this, this.active);
28756 * Gets the active {@link Roo.TabPanelItem}.
28757 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28759 getActiveTab : function(){
28760 return this.active;
28764 * Updates the tab body element to fit the height of the container element
28765 * for overflow scrolling
28766 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28768 syncHeight : function(targetHeight){
28769 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28770 var bm = this.bodyEl.getMargins();
28771 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28772 this.bodyEl.setHeight(newHeight);
28776 onResize : function(){
28777 if(this.monitorResize){
28778 this.autoSizeTabs();
28783 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28785 beginUpdate : function(){
28786 this.updating = true;
28790 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28792 endUpdate : function(){
28793 this.updating = false;
28794 this.autoSizeTabs();
28798 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28800 autoSizeTabs : function(){
28801 var count = this.items.length;
28802 var vcount = count - this.hiddenCount;
28803 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28806 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28807 var availWidth = Math.floor(w / vcount);
28808 var b = this.stripBody;
28809 if(b.getWidth() > w){
28810 var tabs = this.items;
28811 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28812 if(availWidth < this.minTabWidth){
28813 /*if(!this.sleft){ // incomplete scrolling code
28814 this.createScrollButtons();
28817 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28820 if(this.currentTabWidth < this.preferredTabWidth){
28821 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28827 * Returns the number of tabs in this TabPanel.
28830 getCount : function(){
28831 return this.items.length;
28835 * Resizes all the tabs to the passed width
28836 * @param {Number} The new width
28838 setTabWidth : function(width){
28839 this.currentTabWidth = width;
28840 for(var i = 0, len = this.items.length; i < len; i++) {
28841 if(!this.items[i].isHidden()) {
28842 this.items[i].setWidth(width);
28848 * Destroys this TabPanel
28849 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28851 destroy : function(removeEl){
28852 Roo.EventManager.removeResizeListener(this.onResize, this);
28853 for(var i = 0, len = this.items.length; i < len; i++){
28854 this.items[i].purgeListeners();
28856 if(removeEl === true){
28857 this.el.update("");
28864 * @class Roo.TabPanelItem
28865 * @extends Roo.util.Observable
28866 * Represents an individual item (tab plus body) in a TabPanel.
28867 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28868 * @param {String} id The id of this TabPanelItem
28869 * @param {String} text The text for the tab of this TabPanelItem
28870 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28872 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28874 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28875 * @type Roo.TabPanel
28877 this.tabPanel = tabPanel;
28879 * The id for this TabPanelItem
28884 this.disabled = false;
28888 this.loaded = false;
28889 this.closable = closable;
28892 * The body element for this TabPanelItem.
28893 * @type Roo.Element
28895 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28896 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28897 this.bodyEl.setStyle("display", "block");
28898 this.bodyEl.setStyle("zoom", "1");
28901 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28903 this.el = Roo.get(els.el, true);
28904 this.inner = Roo.get(els.inner, true);
28905 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28906 this.pnode = Roo.get(els.el.parentNode, true);
28907 this.el.on("mousedown", this.onTabMouseDown, this);
28908 this.el.on("click", this.onTabClick, this);
28911 var c = Roo.get(els.close, true);
28912 c.dom.title = this.closeText;
28913 c.addClassOnOver("close-over");
28914 c.on("click", this.closeClick, this);
28920 * Fires when this tab becomes the active tab.
28921 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28922 * @param {Roo.TabPanelItem} this
28926 * @event beforeclose
28927 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28928 * @param {Roo.TabPanelItem} this
28929 * @param {Object} e Set cancel to true on this object to cancel the close.
28931 "beforeclose": true,
28934 * Fires when this tab is closed.
28935 * @param {Roo.TabPanelItem} this
28939 * @event deactivate
28940 * Fires when this tab is no longer the active tab.
28941 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28942 * @param {Roo.TabPanelItem} this
28944 "deactivate" : true
28946 this.hidden = false;
28948 Roo.TabPanelItem.superclass.constructor.call(this);
28951 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28952 purgeListeners : function(){
28953 Roo.util.Observable.prototype.purgeListeners.call(this);
28954 this.el.removeAllListeners();
28957 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28960 this.pnode.addClass("on");
28963 this.tabPanel.stripWrap.repaint();
28965 this.fireEvent("activate", this.tabPanel, this);
28969 * Returns true if this tab is the active tab.
28970 * @return {Boolean}
28972 isActive : function(){
28973 return this.tabPanel.getActiveTab() == this;
28977 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28980 this.pnode.removeClass("on");
28982 this.fireEvent("deactivate", this.tabPanel, this);
28985 hideAction : function(){
28986 this.bodyEl.hide();
28987 this.bodyEl.setStyle("position", "absolute");
28988 this.bodyEl.setLeft("-20000px");
28989 this.bodyEl.setTop("-20000px");
28992 showAction : function(){
28993 this.bodyEl.setStyle("position", "relative");
28994 this.bodyEl.setTop("");
28995 this.bodyEl.setLeft("");
28996 this.bodyEl.show();
29000 * Set the tooltip for the tab.
29001 * @param {String} tooltip The tab's tooltip
29003 setTooltip : function(text){
29004 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29005 this.textEl.dom.qtip = text;
29006 this.textEl.dom.removeAttribute('title');
29008 this.textEl.dom.title = text;
29012 onTabClick : function(e){
29013 e.preventDefault();
29014 this.tabPanel.activate(this.id);
29017 onTabMouseDown : function(e){
29018 e.preventDefault();
29019 this.tabPanel.activate(this.id);
29022 getWidth : function(){
29023 return this.inner.getWidth();
29026 setWidth : function(width){
29027 var iwidth = width - this.pnode.getPadding("lr");
29028 this.inner.setWidth(iwidth);
29029 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29030 this.pnode.setWidth(width);
29034 * Show or hide the tab
29035 * @param {Boolean} hidden True to hide or false to show.
29037 setHidden : function(hidden){
29038 this.hidden = hidden;
29039 this.pnode.setStyle("display", hidden ? "none" : "");
29043 * Returns true if this tab is "hidden"
29044 * @return {Boolean}
29046 isHidden : function(){
29047 return this.hidden;
29051 * Returns the text for this tab
29054 getText : function(){
29058 autoSize : function(){
29059 //this.el.beginMeasure();
29060 this.textEl.setWidth(1);
29062 * #2804 [new] Tabs in Roojs
29063 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29065 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29066 //this.el.endMeasure();
29070 * Sets the text for the tab (Note: this also sets the tooltip text)
29071 * @param {String} text The tab's text and tooltip
29073 setText : function(text){
29075 this.textEl.update(text);
29076 this.setTooltip(text);
29077 if(!this.tabPanel.resizeTabs){
29082 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29084 activate : function(){
29085 this.tabPanel.activate(this.id);
29089 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29091 disable : function(){
29092 if(this.tabPanel.active != this){
29093 this.disabled = true;
29094 this.pnode.addClass("disabled");
29099 * Enables this TabPanelItem if it was previously disabled.
29101 enable : function(){
29102 this.disabled = false;
29103 this.pnode.removeClass("disabled");
29107 * Sets the content for this TabPanelItem.
29108 * @param {String} content The content
29109 * @param {Boolean} loadScripts true to look for and load scripts
29111 setContent : function(content, loadScripts){
29112 this.bodyEl.update(content, loadScripts);
29116 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29117 * @return {Roo.UpdateManager} The UpdateManager
29119 getUpdateManager : function(){
29120 return this.bodyEl.getUpdateManager();
29124 * Set a URL to be used to load the content for this TabPanelItem.
29125 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29126 * @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)
29127 * @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)
29128 * @return {Roo.UpdateManager} The UpdateManager
29130 setUrl : function(url, params, loadOnce){
29131 if(this.refreshDelegate){
29132 this.un('activate', this.refreshDelegate);
29134 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29135 this.on("activate", this.refreshDelegate);
29136 return this.bodyEl.getUpdateManager();
29140 _handleRefresh : function(url, params, loadOnce){
29141 if(!loadOnce || !this.loaded){
29142 var updater = this.bodyEl.getUpdateManager();
29143 updater.update(url, params, this._setLoaded.createDelegate(this));
29148 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29149 * Will fail silently if the setUrl method has not been called.
29150 * This does not activate the panel, just updates its content.
29152 refresh : function(){
29153 if(this.refreshDelegate){
29154 this.loaded = false;
29155 this.refreshDelegate();
29160 _setLoaded : function(){
29161 this.loaded = true;
29165 closeClick : function(e){
29168 this.fireEvent("beforeclose", this, o);
29169 if(o.cancel !== true){
29170 this.tabPanel.removeTab(this.id);
29174 * The text displayed in the tooltip for the close icon.
29177 closeText : "Close this tab"
29181 Roo.TabPanel.prototype.createStrip = function(container){
29182 var strip = document.createElement("div");
29183 strip.className = "x-tabs-wrap";
29184 container.appendChild(strip);
29188 Roo.TabPanel.prototype.createStripList = function(strip){
29189 // div wrapper for retard IE
29190 // returns the "tr" element.
29191 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29192 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29193 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29194 return strip.firstChild.firstChild.firstChild.firstChild;
29197 Roo.TabPanel.prototype.createBody = function(container){
29198 var body = document.createElement("div");
29199 Roo.id(body, "tab-body");
29200 Roo.fly(body).addClass("x-tabs-body");
29201 container.appendChild(body);
29205 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29206 var body = Roo.getDom(id);
29208 body = document.createElement("div");
29211 Roo.fly(body).addClass("x-tabs-item-body");
29212 bodyEl.insertBefore(body, bodyEl.firstChild);
29216 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29217 var td = document.createElement("td");
29218 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29219 //stripEl.appendChild(td);
29221 td.className = "x-tabs-closable";
29222 if(!this.closeTpl){
29223 this.closeTpl = new Roo.Template(
29224 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29225 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29226 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29229 var el = this.closeTpl.overwrite(td, {"text": text});
29230 var close = el.getElementsByTagName("div")[0];
29231 var inner = el.getElementsByTagName("em")[0];
29232 return {"el": el, "close": close, "inner": inner};
29235 this.tabTpl = new Roo.Template(
29236 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29237 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29240 var el = this.tabTpl.overwrite(td, {"text": text});
29241 var inner = el.getElementsByTagName("em")[0];
29242 return {"el": el, "inner": inner};
29246 * Ext JS Library 1.1.1
29247 * Copyright(c) 2006-2007, Ext JS, LLC.
29249 * Originally Released Under LGPL - original licence link has changed is not relivant.
29252 * <script type="text/javascript">
29256 * @class Roo.Button
29257 * @extends Roo.util.Observable
29258 * Simple Button class
29259 * @cfg {String} text The button text
29260 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29261 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29262 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29263 * @cfg {Object} scope The scope of the handler
29264 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29265 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29266 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29267 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29268 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29269 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29270 applies if enableToggle = true)
29271 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29272 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29273 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29275 * Create a new button
29276 * @param {Object} config The config object
29278 Roo.Button = function(renderTo, config)
29282 renderTo = config.renderTo || false;
29285 Roo.apply(this, config);
29289 * Fires when this button is clicked
29290 * @param {Button} this
29291 * @param {EventObject} e The click event
29296 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29297 * @param {Button} this
29298 * @param {Boolean} pressed
29303 * Fires when the mouse hovers over the button
29304 * @param {Button} this
29305 * @param {Event} e The event object
29307 'mouseover' : true,
29310 * Fires when the mouse exits the button
29311 * @param {Button} this
29312 * @param {Event} e The event object
29317 * Fires when the button is rendered
29318 * @param {Button} this
29323 this.menu = Roo.menu.MenuMgr.get(this.menu);
29325 // register listeners first!! - so render can be captured..
29326 Roo.util.Observable.call(this);
29328 this.render(renderTo);
29334 Roo.extend(Roo.Button, Roo.util.Observable, {
29340 * Read-only. True if this button is hidden
29345 * Read-only. True if this button is disabled
29350 * Read-only. True if this button is pressed (only if enableToggle = true)
29356 * @cfg {Number} tabIndex
29357 * The DOM tabIndex for this button (defaults to undefined)
29359 tabIndex : undefined,
29362 * @cfg {Boolean} enableToggle
29363 * True to enable pressed/not pressed toggling (defaults to false)
29365 enableToggle: false,
29367 * @cfg {Mixed} menu
29368 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29372 * @cfg {String} menuAlign
29373 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29375 menuAlign : "tl-bl?",
29378 * @cfg {String} iconCls
29379 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29381 iconCls : undefined,
29383 * @cfg {String} type
29384 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29389 menuClassTarget: 'tr',
29392 * @cfg {String} clickEvent
29393 * The type of event to map to the button's event handler (defaults to 'click')
29395 clickEvent : 'click',
29398 * @cfg {Boolean} handleMouseEvents
29399 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29401 handleMouseEvents : true,
29404 * @cfg {String} tooltipType
29405 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29407 tooltipType : 'qtip',
29410 * @cfg {String} cls
29411 * A CSS class to apply to the button's main element.
29415 * @cfg {Roo.Template} template (Optional)
29416 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29417 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29418 * require code modifications if required elements (e.g. a button) aren't present.
29422 render : function(renderTo){
29424 if(this.hideParent){
29425 this.parentEl = Roo.get(renderTo);
29427 if(!this.dhconfig){
29428 if(!this.template){
29429 if(!Roo.Button.buttonTemplate){
29430 // hideous table template
29431 Roo.Button.buttonTemplate = new Roo.Template(
29432 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29433 '<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>',
29434 "</tr></tbody></table>");
29436 this.template = Roo.Button.buttonTemplate;
29438 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29439 var btnEl = btn.child("button:first");
29440 btnEl.on('focus', this.onFocus, this);
29441 btnEl.on('blur', this.onBlur, this);
29443 btn.addClass(this.cls);
29446 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29449 btnEl.addClass(this.iconCls);
29451 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29454 if(this.tabIndex !== undefined){
29455 btnEl.dom.tabIndex = this.tabIndex;
29458 if(typeof this.tooltip == 'object'){
29459 Roo.QuickTips.tips(Roo.apply({
29463 btnEl.dom[this.tooltipType] = this.tooltip;
29467 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29471 this.el.dom.id = this.el.id = this.id;
29474 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29475 this.menu.on("show", this.onMenuShow, this);
29476 this.menu.on("hide", this.onMenuHide, this);
29478 btn.addClass("x-btn");
29479 if(Roo.isIE && !Roo.isIE7){
29480 this.autoWidth.defer(1, this);
29484 if(this.handleMouseEvents){
29485 btn.on("mouseover", this.onMouseOver, this);
29486 btn.on("mouseout", this.onMouseOut, this);
29487 btn.on("mousedown", this.onMouseDown, this);
29489 btn.on(this.clickEvent, this.onClick, this);
29490 //btn.on("mouseup", this.onMouseUp, this);
29497 Roo.ButtonToggleMgr.register(this);
29499 this.el.addClass("x-btn-pressed");
29502 var repeater = new Roo.util.ClickRepeater(btn,
29503 typeof this.repeat == "object" ? this.repeat : {}
29505 repeater.on("click", this.onClick, this);
29508 this.fireEvent('render', this);
29512 * Returns the button's underlying element
29513 * @return {Roo.Element} The element
29515 getEl : function(){
29520 * Destroys this Button and removes any listeners.
29522 destroy : function(){
29523 Roo.ButtonToggleMgr.unregister(this);
29524 this.el.removeAllListeners();
29525 this.purgeListeners();
29530 autoWidth : function(){
29532 this.el.setWidth("auto");
29533 if(Roo.isIE7 && Roo.isStrict){
29534 var ib = this.el.child('button');
29535 if(ib && ib.getWidth() > 20){
29537 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29542 this.el.beginMeasure();
29544 if(this.el.getWidth() < this.minWidth){
29545 this.el.setWidth(this.minWidth);
29548 this.el.endMeasure();
29555 * Assigns this button's click handler
29556 * @param {Function} handler The function to call when the button is clicked
29557 * @param {Object} scope (optional) Scope for the function passed in
29559 setHandler : function(handler, scope){
29560 this.handler = handler;
29561 this.scope = scope;
29565 * Sets this button's text
29566 * @param {String} text The button text
29568 setText : function(text){
29571 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29577 * Gets the text for this button
29578 * @return {String} The button text
29580 getText : function(){
29588 this.hidden = false;
29590 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29598 this.hidden = true;
29600 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29605 * Convenience function for boolean show/hide
29606 * @param {Boolean} visible True to show, false to hide
29608 setVisible: function(visible){
29617 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29618 * @param {Boolean} state (optional) Force a particular state
29620 toggle : function(state){
29621 state = state === undefined ? !this.pressed : state;
29622 if(state != this.pressed){
29624 this.el.addClass("x-btn-pressed");
29625 this.pressed = true;
29626 this.fireEvent("toggle", this, true);
29628 this.el.removeClass("x-btn-pressed");
29629 this.pressed = false;
29630 this.fireEvent("toggle", this, false);
29632 if(this.toggleHandler){
29633 this.toggleHandler.call(this.scope || this, this, state);
29641 focus : function(){
29642 this.el.child('button:first').focus();
29646 * Disable this button
29648 disable : function(){
29650 this.el.addClass("x-btn-disabled");
29652 this.disabled = true;
29656 * Enable this button
29658 enable : function(){
29660 this.el.removeClass("x-btn-disabled");
29662 this.disabled = false;
29666 * Convenience function for boolean enable/disable
29667 * @param {Boolean} enabled True to enable, false to disable
29669 setDisabled : function(v){
29670 this[v !== true ? "enable" : "disable"]();
29674 onClick : function(e)
29677 e.preventDefault();
29682 if(!this.disabled){
29683 if(this.enableToggle){
29686 if(this.menu && !this.menu.isVisible()){
29687 this.menu.show(this.el, this.menuAlign);
29689 this.fireEvent("click", this, e);
29691 this.el.removeClass("x-btn-over");
29692 this.handler.call(this.scope || this, this, e);
29697 onMouseOver : function(e){
29698 if(!this.disabled){
29699 this.el.addClass("x-btn-over");
29700 this.fireEvent('mouseover', this, e);
29704 onMouseOut : function(e){
29705 if(!e.within(this.el, true)){
29706 this.el.removeClass("x-btn-over");
29707 this.fireEvent('mouseout', this, e);
29711 onFocus : function(e){
29712 if(!this.disabled){
29713 this.el.addClass("x-btn-focus");
29717 onBlur : function(e){
29718 this.el.removeClass("x-btn-focus");
29721 onMouseDown : function(e){
29722 if(!this.disabled && e.button == 0){
29723 this.el.addClass("x-btn-click");
29724 Roo.get(document).on('mouseup', this.onMouseUp, this);
29728 onMouseUp : function(e){
29730 this.el.removeClass("x-btn-click");
29731 Roo.get(document).un('mouseup', this.onMouseUp, this);
29735 onMenuShow : function(e){
29736 this.el.addClass("x-btn-menu-active");
29739 onMenuHide : function(e){
29740 this.el.removeClass("x-btn-menu-active");
29744 // Private utility class used by Button
29745 Roo.ButtonToggleMgr = function(){
29748 function toggleGroup(btn, state){
29750 var g = groups[btn.toggleGroup];
29751 for(var i = 0, l = g.length; i < l; i++){
29753 g[i].toggle(false);
29760 register : function(btn){
29761 if(!btn.toggleGroup){
29764 var g = groups[btn.toggleGroup];
29766 g = groups[btn.toggleGroup] = [];
29769 btn.on("toggle", toggleGroup);
29772 unregister : function(btn){
29773 if(!btn.toggleGroup){
29776 var g = groups[btn.toggleGroup];
29779 btn.un("toggle", toggleGroup);
29785 * Ext JS Library 1.1.1
29786 * Copyright(c) 2006-2007, Ext JS, LLC.
29788 * Originally Released Under LGPL - original licence link has changed is not relivant.
29791 * <script type="text/javascript">
29795 * @class Roo.SplitButton
29796 * @extends Roo.Button
29797 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29798 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29799 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29800 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29801 * @cfg {String} arrowTooltip The title attribute of the arrow
29803 * Create a new menu button
29804 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29805 * @param {Object} config The config object
29807 Roo.SplitButton = function(renderTo, config){
29808 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29810 * @event arrowclick
29811 * Fires when this button's arrow is clicked
29812 * @param {SplitButton} this
29813 * @param {EventObject} e The click event
29815 this.addEvents({"arrowclick":true});
29818 Roo.extend(Roo.SplitButton, Roo.Button, {
29819 render : function(renderTo){
29820 // this is one sweet looking template!
29821 var tpl = new Roo.Template(
29822 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29823 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29824 '<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>',
29825 "</tbody></table></td><td>",
29826 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29827 '<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>',
29828 "</tbody></table></td></tr></table>"
29830 var btn = tpl.append(renderTo, [this.text, this.type], true);
29831 var btnEl = btn.child("button");
29833 btn.addClass(this.cls);
29836 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29839 btnEl.addClass(this.iconCls);
29841 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29845 if(this.handleMouseEvents){
29846 btn.on("mouseover", this.onMouseOver, this);
29847 btn.on("mouseout", this.onMouseOut, this);
29848 btn.on("mousedown", this.onMouseDown, this);
29849 btn.on("mouseup", this.onMouseUp, this);
29851 btn.on(this.clickEvent, this.onClick, this);
29853 if(typeof this.tooltip == 'object'){
29854 Roo.QuickTips.tips(Roo.apply({
29858 btnEl.dom[this.tooltipType] = this.tooltip;
29861 if(this.arrowTooltip){
29862 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29871 this.el.addClass("x-btn-pressed");
29873 if(Roo.isIE && !Roo.isIE7){
29874 this.autoWidth.defer(1, this);
29879 this.menu.on("show", this.onMenuShow, this);
29880 this.menu.on("hide", this.onMenuHide, this);
29882 this.fireEvent('render', this);
29886 autoWidth : function(){
29888 var tbl = this.el.child("table:first");
29889 var tbl2 = this.el.child("table:last");
29890 this.el.setWidth("auto");
29891 tbl.setWidth("auto");
29892 if(Roo.isIE7 && Roo.isStrict){
29893 var ib = this.el.child('button:first');
29894 if(ib && ib.getWidth() > 20){
29896 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29901 this.el.beginMeasure();
29903 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29904 tbl.setWidth(this.minWidth-tbl2.getWidth());
29907 this.el.endMeasure();
29910 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29914 * Sets this button's click handler
29915 * @param {Function} handler The function to call when the button is clicked
29916 * @param {Object} scope (optional) Scope for the function passed above
29918 setHandler : function(handler, scope){
29919 this.handler = handler;
29920 this.scope = scope;
29924 * Sets this button's arrow click handler
29925 * @param {Function} handler The function to call when the arrow is clicked
29926 * @param {Object} scope (optional) Scope for the function passed above
29928 setArrowHandler : function(handler, scope){
29929 this.arrowHandler = handler;
29930 this.scope = scope;
29936 focus : function(){
29938 this.el.child("button:first").focus();
29943 onClick : function(e){
29944 e.preventDefault();
29945 if(!this.disabled){
29946 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29947 if(this.menu && !this.menu.isVisible()){
29948 this.menu.show(this.el, this.menuAlign);
29950 this.fireEvent("arrowclick", this, e);
29951 if(this.arrowHandler){
29952 this.arrowHandler.call(this.scope || this, this, e);
29955 this.fireEvent("click", this, e);
29957 this.handler.call(this.scope || this, this, e);
29963 onMouseDown : function(e){
29964 if(!this.disabled){
29965 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29969 onMouseUp : function(e){
29970 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29975 // backwards compat
29976 Roo.MenuButton = Roo.SplitButton;/*
29978 * Ext JS Library 1.1.1
29979 * Copyright(c) 2006-2007, Ext JS, LLC.
29981 * Originally Released Under LGPL - original licence link has changed is not relivant.
29984 * <script type="text/javascript">
29988 * @class Roo.Toolbar
29989 * Basic Toolbar class.
29991 * Creates a new Toolbar
29992 * @param {Object} container The config object
29994 Roo.Toolbar = function(container, buttons, config)
29996 /// old consturctor format still supported..
29997 if(container instanceof Array){ // omit the container for later rendering
29998 buttons = container;
30002 if (typeof(container) == 'object' && container.xtype) {
30003 config = container;
30004 container = config.container;
30005 buttons = config.buttons || []; // not really - use items!!
30008 if (config && config.items) {
30009 xitems = config.items;
30010 delete config.items;
30012 Roo.apply(this, config);
30013 this.buttons = buttons;
30016 this.render(container);
30018 this.xitems = xitems;
30019 Roo.each(xitems, function(b) {
30025 Roo.Toolbar.prototype = {
30027 * @cfg {Array} items
30028 * array of button configs or elements to add (will be converted to a MixedCollection)
30032 * @cfg {String/HTMLElement/Element} container
30033 * The id or element that will contain the toolbar
30036 render : function(ct){
30037 this.el = Roo.get(ct);
30039 this.el.addClass(this.cls);
30041 // using a table allows for vertical alignment
30042 // 100% width is needed by Safari...
30043 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30044 this.tr = this.el.child("tr", true);
30046 this.items = new Roo.util.MixedCollection(false, function(o){
30047 return o.id || ("item" + (++autoId));
30050 this.add.apply(this, this.buttons);
30051 delete this.buttons;
30056 * Adds element(s) to the toolbar -- this function takes a variable number of
30057 * arguments of mixed type and adds them to the toolbar.
30058 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30060 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30061 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30062 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30063 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30064 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30065 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30066 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30067 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30068 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30070 * @param {Mixed} arg2
30071 * @param {Mixed} etc.
30074 var a = arguments, l = a.length;
30075 for(var i = 0; i < l; i++){
30080 _add : function(el) {
30083 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30086 if (el.applyTo){ // some kind of form field
30087 return this.addField(el);
30089 if (el.render){ // some kind of Toolbar.Item
30090 return this.addItem(el);
30092 if (typeof el == "string"){ // string
30093 if(el == "separator" || el == "-"){
30094 return this.addSeparator();
30097 return this.addSpacer();
30100 return this.addFill();
30102 return this.addText(el);
30105 if(el.tagName){ // element
30106 return this.addElement(el);
30108 if(typeof el == "object"){ // must be button config?
30109 return this.addButton(el);
30111 // and now what?!?!
30117 * Add an Xtype element
30118 * @param {Object} xtype Xtype Object
30119 * @return {Object} created Object
30121 addxtype : function(e){
30122 return this.add(e);
30126 * Returns the Element for this toolbar.
30127 * @return {Roo.Element}
30129 getEl : function(){
30135 * @return {Roo.Toolbar.Item} The separator item
30137 addSeparator : function(){
30138 return this.addItem(new Roo.Toolbar.Separator());
30142 * Adds a spacer element
30143 * @return {Roo.Toolbar.Spacer} The spacer item
30145 addSpacer : function(){
30146 return this.addItem(new Roo.Toolbar.Spacer());
30150 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30151 * @return {Roo.Toolbar.Fill} The fill item
30153 addFill : function(){
30154 return this.addItem(new Roo.Toolbar.Fill());
30158 * Adds any standard HTML element to the toolbar
30159 * @param {String/HTMLElement/Element} el The element or id of the element to add
30160 * @return {Roo.Toolbar.Item} The element's item
30162 addElement : function(el){
30163 return this.addItem(new Roo.Toolbar.Item(el));
30166 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30167 * @type Roo.util.MixedCollection
30172 * Adds any Toolbar.Item or subclass
30173 * @param {Roo.Toolbar.Item} item
30174 * @return {Roo.Toolbar.Item} The item
30176 addItem : function(item){
30177 var td = this.nextBlock();
30179 this.items.add(item);
30184 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30185 * @param {Object/Array} config A button config or array of configs
30186 * @return {Roo.Toolbar.Button/Array}
30188 addButton : function(config){
30189 if(config instanceof Array){
30191 for(var i = 0, len = config.length; i < len; i++) {
30192 buttons.push(this.addButton(config[i]));
30197 if(!(config instanceof Roo.Toolbar.Button)){
30199 new Roo.Toolbar.SplitButton(config) :
30200 new Roo.Toolbar.Button(config);
30202 var td = this.nextBlock();
30209 * Adds text to the toolbar
30210 * @param {String} text The text to add
30211 * @return {Roo.Toolbar.Item} The element's item
30213 addText : function(text){
30214 return this.addItem(new Roo.Toolbar.TextItem(text));
30218 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30219 * @param {Number} index The index where the item is to be inserted
30220 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30221 * @return {Roo.Toolbar.Button/Item}
30223 insertButton : function(index, item){
30224 if(item instanceof Array){
30226 for(var i = 0, len = item.length; i < len; i++) {
30227 buttons.push(this.insertButton(index + i, item[i]));
30231 if (!(item instanceof Roo.Toolbar.Button)){
30232 item = new Roo.Toolbar.Button(item);
30234 var td = document.createElement("td");
30235 this.tr.insertBefore(td, this.tr.childNodes[index]);
30237 this.items.insert(index, item);
30242 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30243 * @param {Object} config
30244 * @return {Roo.Toolbar.Item} The element's item
30246 addDom : function(config, returnEl){
30247 var td = this.nextBlock();
30248 Roo.DomHelper.overwrite(td, config);
30249 var ti = new Roo.Toolbar.Item(td.firstChild);
30251 this.items.add(ti);
30256 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30257 * @type Roo.util.MixedCollection
30262 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30263 * Note: the field should not have been rendered yet. For a field that has already been
30264 * rendered, use {@link #addElement}.
30265 * @param {Roo.form.Field} field
30266 * @return {Roo.ToolbarItem}
30270 addField : function(field) {
30271 if (!this.fields) {
30273 this.fields = new Roo.util.MixedCollection(false, function(o){
30274 return o.id || ("item" + (++autoId));
30279 var td = this.nextBlock();
30281 var ti = new Roo.Toolbar.Item(td.firstChild);
30283 this.items.add(ti);
30284 this.fields.add(field);
30295 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30296 this.el.child('div').hide();
30304 this.el.child('div').show();
30308 nextBlock : function(){
30309 var td = document.createElement("td");
30310 this.tr.appendChild(td);
30315 destroy : function(){
30316 if(this.items){ // rendered?
30317 Roo.destroy.apply(Roo, this.items.items);
30319 if(this.fields){ // rendered?
30320 Roo.destroy.apply(Roo, this.fields.items);
30322 Roo.Element.uncache(this.el, this.tr);
30327 * @class Roo.Toolbar.Item
30328 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30330 * Creates a new Item
30331 * @param {HTMLElement} el
30333 Roo.Toolbar.Item = function(el){
30335 if (typeof (el.xtype) != 'undefined') {
30340 this.el = Roo.getDom(el);
30341 this.id = Roo.id(this.el);
30342 this.hidden = false;
30347 * Fires when the button is rendered
30348 * @param {Button} this
30352 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30354 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30355 //Roo.Toolbar.Item.prototype = {
30358 * Get this item's HTML Element
30359 * @return {HTMLElement}
30361 getEl : function(){
30366 render : function(td){
30369 td.appendChild(this.el);
30371 this.fireEvent('render', this);
30375 * Removes and destroys this item.
30377 destroy : function(){
30378 this.td.parentNode.removeChild(this.td);
30385 this.hidden = false;
30386 this.td.style.display = "";
30393 this.hidden = true;
30394 this.td.style.display = "none";
30398 * Convenience function for boolean show/hide.
30399 * @param {Boolean} visible true to show/false to hide
30401 setVisible: function(visible){
30410 * Try to focus this item.
30412 focus : function(){
30413 Roo.fly(this.el).focus();
30417 * Disables this item.
30419 disable : function(){
30420 Roo.fly(this.td).addClass("x-item-disabled");
30421 this.disabled = true;
30422 this.el.disabled = true;
30426 * Enables this item.
30428 enable : function(){
30429 Roo.fly(this.td).removeClass("x-item-disabled");
30430 this.disabled = false;
30431 this.el.disabled = false;
30437 * @class Roo.Toolbar.Separator
30438 * @extends Roo.Toolbar.Item
30439 * A simple toolbar separator class
30441 * Creates a new Separator
30443 Roo.Toolbar.Separator = function(cfg){
30445 var s = document.createElement("span");
30446 s.className = "ytb-sep";
30451 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30453 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30454 enable:Roo.emptyFn,
30455 disable:Roo.emptyFn,
30460 * @class Roo.Toolbar.Spacer
30461 * @extends Roo.Toolbar.Item
30462 * A simple element that adds extra horizontal space to a toolbar.
30464 * Creates a new Spacer
30466 Roo.Toolbar.Spacer = function(cfg){
30467 var s = document.createElement("div");
30468 s.className = "ytb-spacer";
30472 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30474 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30475 enable:Roo.emptyFn,
30476 disable:Roo.emptyFn,
30481 * @class Roo.Toolbar.Fill
30482 * @extends Roo.Toolbar.Spacer
30483 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30485 * Creates a new Spacer
30487 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30489 render : function(td){
30490 td.style.width = '100%';
30491 Roo.Toolbar.Fill.superclass.render.call(this, td);
30496 * @class Roo.Toolbar.TextItem
30497 * @extends Roo.Toolbar.Item
30498 * A simple class that renders text directly into a toolbar.
30500 * Creates a new TextItem
30501 * @cfg {string} text
30503 Roo.Toolbar.TextItem = function(cfg){
30504 var text = cfg || "";
30505 if (typeof(cfg) == 'object') {
30506 text = cfg.text || "";
30510 var s = document.createElement("span");
30511 s.className = "ytb-text";
30512 s.innerHTML = text;
30517 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30519 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30522 enable:Roo.emptyFn,
30523 disable:Roo.emptyFn,
30528 * @class Roo.Toolbar.Button
30529 * @extends Roo.Button
30530 * A button that renders into a toolbar.
30532 * Creates a new Button
30533 * @param {Object} config A standard {@link Roo.Button} config object
30535 Roo.Toolbar.Button = function(config){
30536 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30538 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30539 render : function(td){
30541 Roo.Toolbar.Button.superclass.render.call(this, td);
30545 * Removes and destroys this button
30547 destroy : function(){
30548 Roo.Toolbar.Button.superclass.destroy.call(this);
30549 this.td.parentNode.removeChild(this.td);
30553 * Shows this button
30556 this.hidden = false;
30557 this.td.style.display = "";
30561 * Hides this button
30564 this.hidden = true;
30565 this.td.style.display = "none";
30569 * Disables this item
30571 disable : function(){
30572 Roo.fly(this.td).addClass("x-item-disabled");
30573 this.disabled = true;
30577 * Enables this item
30579 enable : function(){
30580 Roo.fly(this.td).removeClass("x-item-disabled");
30581 this.disabled = false;
30584 // backwards compat
30585 Roo.ToolbarButton = Roo.Toolbar.Button;
30588 * @class Roo.Toolbar.SplitButton
30589 * @extends Roo.SplitButton
30590 * A menu button that renders into a toolbar.
30592 * Creates a new SplitButton
30593 * @param {Object} config A standard {@link Roo.SplitButton} config object
30595 Roo.Toolbar.SplitButton = function(config){
30596 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30598 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30599 render : function(td){
30601 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30605 * Removes and destroys this button
30607 destroy : function(){
30608 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30609 this.td.parentNode.removeChild(this.td);
30613 * Shows this button
30616 this.hidden = false;
30617 this.td.style.display = "";
30621 * Hides this button
30624 this.hidden = true;
30625 this.td.style.display = "none";
30629 // backwards compat
30630 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30632 * Ext JS Library 1.1.1
30633 * Copyright(c) 2006-2007, Ext JS, LLC.
30635 * Originally Released Under LGPL - original licence link has changed is not relivant.
30638 * <script type="text/javascript">
30642 * @class Roo.PagingToolbar
30643 * @extends Roo.Toolbar
30644 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30646 * Create a new PagingToolbar
30647 * @param {Object} config The config object
30649 Roo.PagingToolbar = function(el, ds, config)
30651 // old args format still supported... - xtype is prefered..
30652 if (typeof(el) == 'object' && el.xtype) {
30653 // created from xtype...
30655 ds = el.dataSource;
30656 el = config.container;
30659 if (config.items) {
30660 items = config.items;
30664 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30667 this.renderButtons(this.el);
30670 // supprot items array.
30672 Roo.each(items, function(e) {
30673 this.add(Roo.factory(e));
30678 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30680 * @cfg {Roo.data.Store} dataSource
30681 * The underlying data store providing the paged data
30684 * @cfg {String/HTMLElement/Element} container
30685 * container The id or element that will contain the toolbar
30688 * @cfg {Boolean} displayInfo
30689 * True to display the displayMsg (defaults to false)
30692 * @cfg {Number} pageSize
30693 * The number of records to display per page (defaults to 20)
30697 * @cfg {String} displayMsg
30698 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30700 displayMsg : 'Displaying {0} - {1} of {2}',
30702 * @cfg {String} emptyMsg
30703 * The message to display when no records are found (defaults to "No data to display")
30705 emptyMsg : 'No data to display',
30707 * Customizable piece of the default paging text (defaults to "Page")
30710 beforePageText : "Page",
30712 * Customizable piece of the default paging text (defaults to "of %0")
30715 afterPageText : "of {0}",
30717 * Customizable piece of the default paging text (defaults to "First Page")
30720 firstText : "First Page",
30722 * Customizable piece of the default paging text (defaults to "Previous Page")
30725 prevText : "Previous Page",
30727 * Customizable piece of the default paging text (defaults to "Next Page")
30730 nextText : "Next Page",
30732 * Customizable piece of the default paging text (defaults to "Last Page")
30735 lastText : "Last Page",
30737 * Customizable piece of the default paging text (defaults to "Refresh")
30740 refreshText : "Refresh",
30743 renderButtons : function(el){
30744 Roo.PagingToolbar.superclass.render.call(this, el);
30745 this.first = this.addButton({
30746 tooltip: this.firstText,
30747 cls: "x-btn-icon x-grid-page-first",
30749 handler: this.onClick.createDelegate(this, ["first"])
30751 this.prev = this.addButton({
30752 tooltip: this.prevText,
30753 cls: "x-btn-icon x-grid-page-prev",
30755 handler: this.onClick.createDelegate(this, ["prev"])
30757 //this.addSeparator();
30758 this.add(this.beforePageText);
30759 this.field = Roo.get(this.addDom({
30764 cls: "x-grid-page-number"
30766 this.field.on("keydown", this.onPagingKeydown, this);
30767 this.field.on("focus", function(){this.dom.select();});
30768 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30769 this.field.setHeight(18);
30770 //this.addSeparator();
30771 this.next = this.addButton({
30772 tooltip: this.nextText,
30773 cls: "x-btn-icon x-grid-page-next",
30775 handler: this.onClick.createDelegate(this, ["next"])
30777 this.last = this.addButton({
30778 tooltip: this.lastText,
30779 cls: "x-btn-icon x-grid-page-last",
30781 handler: this.onClick.createDelegate(this, ["last"])
30783 //this.addSeparator();
30784 this.loading = this.addButton({
30785 tooltip: this.refreshText,
30786 cls: "x-btn-icon x-grid-loading",
30787 handler: this.onClick.createDelegate(this, ["refresh"])
30790 if(this.displayInfo){
30791 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30796 updateInfo : function(){
30797 if(this.displayEl){
30798 var count = this.ds.getCount();
30799 var msg = count == 0 ?
30803 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30805 this.displayEl.update(msg);
30810 onLoad : function(ds, r, o){
30811 this.cursor = o.params ? o.params.start : 0;
30812 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30814 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30815 this.field.dom.value = ap;
30816 this.first.setDisabled(ap == 1);
30817 this.prev.setDisabled(ap == 1);
30818 this.next.setDisabled(ap == ps);
30819 this.last.setDisabled(ap == ps);
30820 this.loading.enable();
30825 getPageData : function(){
30826 var total = this.ds.getTotalCount();
30829 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30830 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30835 onLoadError : function(){
30836 this.loading.enable();
30840 onPagingKeydown : function(e){
30841 var k = e.getKey();
30842 var d = this.getPageData();
30844 var v = this.field.dom.value, pageNum;
30845 if(!v || isNaN(pageNum = parseInt(v, 10))){
30846 this.field.dom.value = d.activePage;
30849 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30850 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30853 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))
30855 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30856 this.field.dom.value = pageNum;
30857 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30860 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30862 var v = this.field.dom.value, pageNum;
30863 var increment = (e.shiftKey) ? 10 : 1;
30864 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30867 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30868 this.field.dom.value = d.activePage;
30871 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30873 this.field.dom.value = parseInt(v, 10) + increment;
30874 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30875 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30882 beforeLoad : function(){
30884 this.loading.disable();
30889 onClick : function(which){
30893 ds.load({params:{start: 0, limit: this.pageSize}});
30896 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30899 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30902 var total = ds.getTotalCount();
30903 var extra = total % this.pageSize;
30904 var lastStart = extra ? (total - extra) : total-this.pageSize;
30905 ds.load({params:{start: lastStart, limit: this.pageSize}});
30908 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30914 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30915 * @param {Roo.data.Store} store The data store to unbind
30917 unbind : function(ds){
30918 ds.un("beforeload", this.beforeLoad, this);
30919 ds.un("load", this.onLoad, this);
30920 ds.un("loadexception", this.onLoadError, this);
30921 ds.un("remove", this.updateInfo, this);
30922 ds.un("add", this.updateInfo, this);
30923 this.ds = undefined;
30927 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30928 * @param {Roo.data.Store} store The data store to bind
30930 bind : function(ds){
30931 ds.on("beforeload", this.beforeLoad, this);
30932 ds.on("load", this.onLoad, this);
30933 ds.on("loadexception", this.onLoadError, this);
30934 ds.on("remove", this.updateInfo, this);
30935 ds.on("add", this.updateInfo, this);
30940 * Ext JS Library 1.1.1
30941 * Copyright(c) 2006-2007, Ext JS, LLC.
30943 * Originally Released Under LGPL - original licence link has changed is not relivant.
30946 * <script type="text/javascript">
30950 * @class Roo.Resizable
30951 * @extends Roo.util.Observable
30952 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30953 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30954 * 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
30955 * the element will be wrapped for you automatically.</p>
30956 * <p>Here is the list of valid resize handles:</p>
30959 ------ -------------------
30968 'hd' horizontal drag
30971 * <p>Here's an example showing the creation of a typical Resizable:</p>
30973 var resizer = new Roo.Resizable("element-id", {
30981 resizer.on("resize", myHandler);
30983 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30984 * resizer.east.setDisplayed(false);</p>
30985 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30986 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30987 * resize operation's new size (defaults to [0, 0])
30988 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30989 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30990 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30991 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30992 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30993 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30994 * @cfg {Number} width The width of the element in pixels (defaults to null)
30995 * @cfg {Number} height The height of the element in pixels (defaults to null)
30996 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30997 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30998 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30999 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31000 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31001 * in favor of the handles config option (defaults to false)
31002 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31003 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31004 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31005 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31006 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31007 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31008 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31009 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31010 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31011 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31012 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31014 * Create a new resizable component
31015 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31016 * @param {Object} config configuration options
31018 Roo.Resizable = function(el, config)
31020 this.el = Roo.get(el);
31022 if(config && config.wrap){
31023 config.resizeChild = this.el;
31024 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31025 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31026 this.el.setStyle("overflow", "hidden");
31027 this.el.setPositioning(config.resizeChild.getPositioning());
31028 config.resizeChild.clearPositioning();
31029 if(!config.width || !config.height){
31030 var csize = config.resizeChild.getSize();
31031 this.el.setSize(csize.width, csize.height);
31033 if(config.pinned && !config.adjustments){
31034 config.adjustments = "auto";
31038 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31039 this.proxy.unselectable();
31040 this.proxy.enableDisplayMode('block');
31042 Roo.apply(this, config);
31045 this.disableTrackOver = true;
31046 this.el.addClass("x-resizable-pinned");
31048 // if the element isn't positioned, make it relative
31049 var position = this.el.getStyle("position");
31050 if(position != "absolute" && position != "fixed"){
31051 this.el.setStyle("position", "relative");
31053 if(!this.handles){ // no handles passed, must be legacy style
31054 this.handles = 's,e,se';
31055 if(this.multiDirectional){
31056 this.handles += ',n,w';
31059 if(this.handles == "all"){
31060 this.handles = "n s e w ne nw se sw";
31062 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31063 var ps = Roo.Resizable.positions;
31064 for(var i = 0, len = hs.length; i < len; i++){
31065 if(hs[i] && ps[hs[i]]){
31066 var pos = ps[hs[i]];
31067 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31071 this.corner = this.southeast;
31073 // updateBox = the box can move..
31074 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31075 this.updateBox = true;
31078 this.activeHandle = null;
31080 if(this.resizeChild){
31081 if(typeof this.resizeChild == "boolean"){
31082 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31084 this.resizeChild = Roo.get(this.resizeChild, true);
31088 if(this.adjustments == "auto"){
31089 var rc = this.resizeChild;
31090 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31091 if(rc && (hw || hn)){
31092 rc.position("relative");
31093 rc.setLeft(hw ? hw.el.getWidth() : 0);
31094 rc.setTop(hn ? hn.el.getHeight() : 0);
31096 this.adjustments = [
31097 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31098 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31102 if(this.draggable){
31103 this.dd = this.dynamic ?
31104 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31105 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31111 * @event beforeresize
31112 * Fired before resize is allowed. Set enabled to false to cancel resize.
31113 * @param {Roo.Resizable} this
31114 * @param {Roo.EventObject} e The mousedown event
31116 "beforeresize" : true,
31119 * Fired a resizing.
31120 * @param {Roo.Resizable} this
31121 * @param {Number} x The new x position
31122 * @param {Number} y The new y position
31123 * @param {Number} w The new w width
31124 * @param {Number} h The new h hight
31125 * @param {Roo.EventObject} e The mouseup event
31130 * Fired after a resize.
31131 * @param {Roo.Resizable} this
31132 * @param {Number} width The new width
31133 * @param {Number} height The new height
31134 * @param {Roo.EventObject} e The mouseup event
31139 if(this.width !== null && this.height !== null){
31140 this.resizeTo(this.width, this.height);
31142 this.updateChildSize();
31145 this.el.dom.style.zoom = 1;
31147 Roo.Resizable.superclass.constructor.call(this);
31150 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31151 resizeChild : false,
31152 adjustments : [0, 0],
31162 multiDirectional : false,
31163 disableTrackOver : false,
31164 easing : 'easeOutStrong',
31165 widthIncrement : 0,
31166 heightIncrement : 0,
31170 preserveRatio : false,
31171 transparent: false,
31177 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31179 constrainTo: undefined,
31181 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31183 resizeRegion: undefined,
31187 * Perform a manual resize
31188 * @param {Number} width
31189 * @param {Number} height
31191 resizeTo : function(width, height){
31192 this.el.setSize(width, height);
31193 this.updateChildSize();
31194 this.fireEvent("resize", this, width, height, null);
31198 startSizing : function(e, handle){
31199 this.fireEvent("beforeresize", this, e);
31200 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31203 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31204 this.overlay.unselectable();
31205 this.overlay.enableDisplayMode("block");
31206 this.overlay.on("mousemove", this.onMouseMove, this);
31207 this.overlay.on("mouseup", this.onMouseUp, this);
31209 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31211 this.resizing = true;
31212 this.startBox = this.el.getBox();
31213 this.startPoint = e.getXY();
31214 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31215 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31217 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31218 this.overlay.show();
31220 if(this.constrainTo) {
31221 var ct = Roo.get(this.constrainTo);
31222 this.resizeRegion = ct.getRegion().adjust(
31223 ct.getFrameWidth('t'),
31224 ct.getFrameWidth('l'),
31225 -ct.getFrameWidth('b'),
31226 -ct.getFrameWidth('r')
31230 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31232 this.proxy.setBox(this.startBox);
31234 this.proxy.setStyle('visibility', 'visible');
31240 onMouseDown : function(handle, e){
31243 this.activeHandle = handle;
31244 this.startSizing(e, handle);
31249 onMouseUp : function(e){
31250 var size = this.resizeElement();
31251 this.resizing = false;
31253 this.overlay.hide();
31255 this.fireEvent("resize", this, size.width, size.height, e);
31259 updateChildSize : function(){
31261 if(this.resizeChild){
31263 var child = this.resizeChild;
31264 var adj = this.adjustments;
31265 if(el.dom.offsetWidth){
31266 var b = el.getSize(true);
31267 child.setSize(b.width+adj[0], b.height+adj[1]);
31269 // Second call here for IE
31270 // The first call enables instant resizing and
31271 // the second call corrects scroll bars if they
31274 setTimeout(function(){
31275 if(el.dom.offsetWidth){
31276 var b = el.getSize(true);
31277 child.setSize(b.width+adj[0], b.height+adj[1]);
31285 snap : function(value, inc, min){
31286 if(!inc || !value) {
31289 var newValue = value;
31290 var m = value % inc;
31293 newValue = value + (inc-m);
31295 newValue = value - m;
31298 return Math.max(min, newValue);
31302 resizeElement : function(){
31303 var box = this.proxy.getBox();
31304 if(this.updateBox){
31305 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31307 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31309 this.updateChildSize();
31317 constrain : function(v, diff, m, mx){
31320 }else if(v - diff > mx){
31327 onMouseMove : function(e){
31330 try{// try catch so if something goes wrong the user doesn't get hung
31332 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31336 //var curXY = this.startPoint;
31337 var curSize = this.curSize || this.startBox;
31338 var x = this.startBox.x, y = this.startBox.y;
31339 var ox = x, oy = y;
31340 var w = curSize.width, h = curSize.height;
31341 var ow = w, oh = h;
31342 var mw = this.minWidth, mh = this.minHeight;
31343 var mxw = this.maxWidth, mxh = this.maxHeight;
31344 var wi = this.widthIncrement;
31345 var hi = this.heightIncrement;
31347 var eventXY = e.getXY();
31348 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31349 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31351 var pos = this.activeHandle.position;
31356 w = Math.min(Math.max(mw, w), mxw);
31361 h = Math.min(Math.max(mh, h), mxh);
31366 w = Math.min(Math.max(mw, w), mxw);
31367 h = Math.min(Math.max(mh, h), mxh);
31370 diffY = this.constrain(h, diffY, mh, mxh);
31377 var adiffX = Math.abs(diffX);
31378 var sub = (adiffX % wi); // how much
31379 if (sub > (wi/2)) { // far enough to snap
31380 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31382 // remove difference..
31383 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31387 x = Math.max(this.minX, x);
31390 diffX = this.constrain(w, diffX, mw, mxw);
31396 w = Math.min(Math.max(mw, w), mxw);
31397 diffY = this.constrain(h, diffY, mh, mxh);
31402 diffX = this.constrain(w, diffX, mw, mxw);
31403 diffY = this.constrain(h, diffY, mh, mxh);
31410 diffX = this.constrain(w, diffX, mw, mxw);
31412 h = Math.min(Math.max(mh, h), mxh);
31418 var sw = this.snap(w, wi, mw);
31419 var sh = this.snap(h, hi, mh);
31420 if(sw != w || sh != h){
31443 if(this.preserveRatio){
31448 h = Math.min(Math.max(mh, h), mxh);
31453 w = Math.min(Math.max(mw, w), mxw);
31458 w = Math.min(Math.max(mw, w), mxw);
31464 w = Math.min(Math.max(mw, w), mxw);
31470 h = Math.min(Math.max(mh, h), mxh);
31478 h = Math.min(Math.max(mh, h), mxh);
31488 h = Math.min(Math.max(mh, h), mxh);
31496 if (pos == 'hdrag') {
31499 this.proxy.setBounds(x, y, w, h);
31501 this.resizeElement();
31505 this.fireEvent("resizing", this, x, y, w, h, e);
31509 handleOver : function(){
31511 this.el.addClass("x-resizable-over");
31516 handleOut : function(){
31517 if(!this.resizing){
31518 this.el.removeClass("x-resizable-over");
31523 * Returns the element this component is bound to.
31524 * @return {Roo.Element}
31526 getEl : function(){
31531 * Returns the resizeChild element (or null).
31532 * @return {Roo.Element}
31534 getResizeChild : function(){
31535 return this.resizeChild;
31537 groupHandler : function()
31542 * Destroys this resizable. If the element was wrapped and
31543 * removeEl is not true then the element remains.
31544 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31546 destroy : function(removeEl){
31547 this.proxy.remove();
31549 this.overlay.removeAllListeners();
31550 this.overlay.remove();
31552 var ps = Roo.Resizable.positions;
31554 if(typeof ps[k] != "function" && this[ps[k]]){
31555 var h = this[ps[k]];
31556 h.el.removeAllListeners();
31561 this.el.update("");
31568 // hash to map config positions to true positions
31569 Roo.Resizable.positions = {
31570 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31575 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31577 // only initialize the template if resizable is used
31578 var tpl = Roo.DomHelper.createTemplate(
31579 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31582 Roo.Resizable.Handle.prototype.tpl = tpl;
31584 this.position = pos;
31586 // show north drag fro topdra
31587 var handlepos = pos == 'hdrag' ? 'north' : pos;
31589 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31590 if (pos == 'hdrag') {
31591 this.el.setStyle('cursor', 'pointer');
31593 this.el.unselectable();
31595 this.el.setOpacity(0);
31597 this.el.on("mousedown", this.onMouseDown, this);
31598 if(!disableTrackOver){
31599 this.el.on("mouseover", this.onMouseOver, this);
31600 this.el.on("mouseout", this.onMouseOut, this);
31605 Roo.Resizable.Handle.prototype = {
31606 afterResize : function(rz){
31611 onMouseDown : function(e){
31612 this.rz.onMouseDown(this, e);
31615 onMouseOver : function(e){
31616 this.rz.handleOver(this, e);
31619 onMouseOut : function(e){
31620 this.rz.handleOut(this, e);
31624 * Ext JS Library 1.1.1
31625 * Copyright(c) 2006-2007, Ext JS, LLC.
31627 * Originally Released Under LGPL - original licence link has changed is not relivant.
31630 * <script type="text/javascript">
31634 * @class Roo.Editor
31635 * @extends Roo.Component
31636 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31638 * Create a new Editor
31639 * @param {Roo.form.Field} field The Field object (or descendant)
31640 * @param {Object} config The config object
31642 Roo.Editor = function(field, config){
31643 Roo.Editor.superclass.constructor.call(this, config);
31644 this.field = field;
31647 * @event beforestartedit
31648 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31649 * false from the handler of this event.
31650 * @param {Editor} this
31651 * @param {Roo.Element} boundEl The underlying element bound to this editor
31652 * @param {Mixed} value The field value being set
31654 "beforestartedit" : true,
31657 * Fires when this editor is displayed
31658 * @param {Roo.Element} boundEl The underlying element bound to this editor
31659 * @param {Mixed} value The starting field value
31661 "startedit" : true,
31663 * @event beforecomplete
31664 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31665 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31666 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31667 * event will not fire since no edit actually occurred.
31668 * @param {Editor} this
31669 * @param {Mixed} value The current field value
31670 * @param {Mixed} startValue The original field value
31672 "beforecomplete" : true,
31675 * Fires after editing is complete and any changed value has been written to the underlying field.
31676 * @param {Editor} this
31677 * @param {Mixed} value The current field value
31678 * @param {Mixed} startValue The original field value
31682 * @event specialkey
31683 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31684 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31685 * @param {Roo.form.Field} this
31686 * @param {Roo.EventObject} e The event object
31688 "specialkey" : true
31692 Roo.extend(Roo.Editor, Roo.Component, {
31694 * @cfg {Boolean/String} autosize
31695 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31696 * or "height" to adopt the height only (defaults to false)
31699 * @cfg {Boolean} revertInvalid
31700 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31701 * validation fails (defaults to true)
31704 * @cfg {Boolean} ignoreNoChange
31705 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31706 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31707 * will never be ignored.
31710 * @cfg {Boolean} hideEl
31711 * False to keep the bound element visible while the editor is displayed (defaults to true)
31714 * @cfg {Mixed} value
31715 * The data value of the underlying field (defaults to "")
31719 * @cfg {String} alignment
31720 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31724 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31725 * for bottom-right shadow (defaults to "frame")
31729 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31733 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31735 completeOnEnter : false,
31737 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31739 cancelOnEsc : false,
31741 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31746 onRender : function(ct, position){
31747 this.el = new Roo.Layer({
31748 shadow: this.shadow,
31754 constrain: this.constrain
31756 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31757 if(this.field.msgTarget != 'title'){
31758 this.field.msgTarget = 'qtip';
31760 this.field.render(this.el);
31762 this.field.el.dom.setAttribute('autocomplete', 'off');
31764 this.field.on("specialkey", this.onSpecialKey, this);
31765 if(this.swallowKeys){
31766 this.field.el.swallowEvent(['keydown','keypress']);
31769 this.field.on("blur", this.onBlur, this);
31770 if(this.field.grow){
31771 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31775 onSpecialKey : function(field, e)
31777 //Roo.log('editor onSpecialKey');
31778 if(this.completeOnEnter && e.getKey() == e.ENTER){
31780 this.completeEdit();
31783 // do not fire special key otherwise it might hide close the editor...
31784 if(e.getKey() == e.ENTER){
31787 if(this.cancelOnEsc && e.getKey() == e.ESC){
31791 this.fireEvent('specialkey', field, e);
31796 * Starts the editing process and shows the editor.
31797 * @param {String/HTMLElement/Element} el The element to edit
31798 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31799 * to the innerHTML of el.
31801 startEdit : function(el, value){
31803 this.completeEdit();
31805 this.boundEl = Roo.get(el);
31806 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31807 if(!this.rendered){
31808 this.render(this.parentEl || document.body);
31810 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31813 this.startValue = v;
31814 this.field.setValue(v);
31816 var sz = this.boundEl.getSize();
31817 switch(this.autoSize){
31819 this.setSize(sz.width, "");
31822 this.setSize("", sz.height);
31825 this.setSize(sz.width, sz.height);
31828 this.el.alignTo(this.boundEl, this.alignment);
31829 this.editing = true;
31831 Roo.QuickTips.disable();
31837 * Sets the height and width of this editor.
31838 * @param {Number} width The new width
31839 * @param {Number} height The new height
31841 setSize : function(w, h){
31842 this.field.setSize(w, h);
31849 * Realigns the editor to the bound field based on the current alignment config value.
31851 realign : function(){
31852 this.el.alignTo(this.boundEl, this.alignment);
31856 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31857 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31859 completeEdit : function(remainVisible){
31863 var v = this.getValue();
31864 if(this.revertInvalid !== false && !this.field.isValid()){
31865 v = this.startValue;
31866 this.cancelEdit(true);
31868 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31869 this.editing = false;
31873 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31874 this.editing = false;
31875 if(this.updateEl && this.boundEl){
31876 this.boundEl.update(v);
31878 if(remainVisible !== true){
31881 this.fireEvent("complete", this, v, this.startValue);
31886 onShow : function(){
31888 if(this.hideEl !== false){
31889 this.boundEl.hide();
31892 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31893 this.fixIEFocus = true;
31894 this.deferredFocus.defer(50, this);
31896 this.field.focus();
31898 this.fireEvent("startedit", this.boundEl, this.startValue);
31901 deferredFocus : function(){
31903 this.field.focus();
31908 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31909 * reverted to the original starting value.
31910 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31911 * cancel (defaults to false)
31913 cancelEdit : function(remainVisible){
31915 this.setValue(this.startValue);
31916 if(remainVisible !== true){
31923 onBlur : function(){
31924 if(this.allowBlur !== true && this.editing){
31925 this.completeEdit();
31930 onHide : function(){
31932 this.completeEdit();
31936 if(this.field.collapse){
31937 this.field.collapse();
31940 if(this.hideEl !== false){
31941 this.boundEl.show();
31944 Roo.QuickTips.enable();
31949 * Sets the data value of the editor
31950 * @param {Mixed} value Any valid value supported by the underlying field
31952 setValue : function(v){
31953 this.field.setValue(v);
31957 * Gets the data value of the editor
31958 * @return {Mixed} The data value
31960 getValue : function(){
31961 return this.field.getValue();
31965 * Ext JS Library 1.1.1
31966 * Copyright(c) 2006-2007, Ext JS, LLC.
31968 * Originally Released Under LGPL - original licence link has changed is not relivant.
31971 * <script type="text/javascript">
31975 * @class Roo.BasicDialog
31976 * @extends Roo.util.Observable
31977 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31979 var dlg = new Roo.BasicDialog("my-dlg", {
31988 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31989 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31990 dlg.addButton('Cancel', dlg.hide, dlg);
31993 <b>A Dialog should always be a direct child of the body element.</b>
31994 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31995 * @cfg {String} title Default text to display in the title bar (defaults to null)
31996 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31997 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31998 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31999 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32000 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32001 * (defaults to null with no animation)
32002 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32003 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32004 * property for valid values (defaults to 'all')
32005 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32006 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32007 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32008 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32009 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32010 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32011 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32012 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32013 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32014 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32015 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32016 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32017 * draggable = true (defaults to false)
32018 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32019 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32020 * shadow (defaults to false)
32021 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32022 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32023 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32024 * @cfg {Array} buttons Array of buttons
32025 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32027 * Create a new BasicDialog.
32028 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32029 * @param {Object} config Configuration options
32031 Roo.BasicDialog = function(el, config){
32032 this.el = Roo.get(el);
32033 var dh = Roo.DomHelper;
32034 if(!this.el && config && config.autoCreate){
32035 if(typeof config.autoCreate == "object"){
32036 if(!config.autoCreate.id){
32037 config.autoCreate.id = el;
32039 this.el = dh.append(document.body,
32040 config.autoCreate, true);
32042 this.el = dh.append(document.body,
32043 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32047 el.setDisplayed(true);
32048 el.hide = this.hideAction;
32050 el.addClass("x-dlg");
32052 Roo.apply(this, config);
32054 this.proxy = el.createProxy("x-dlg-proxy");
32055 this.proxy.hide = this.hideAction;
32056 this.proxy.setOpacity(.5);
32060 el.setWidth(config.width);
32063 el.setHeight(config.height);
32065 this.size = el.getSize();
32066 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32067 this.xy = [config.x,config.y];
32069 this.xy = el.getCenterXY(true);
32071 /** The header element @type Roo.Element */
32072 this.header = el.child("> .x-dlg-hd");
32073 /** The body element @type Roo.Element */
32074 this.body = el.child("> .x-dlg-bd");
32075 /** The footer element @type Roo.Element */
32076 this.footer = el.child("> .x-dlg-ft");
32079 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32082 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32085 this.header.unselectable();
32087 this.header.update(this.title);
32089 // this element allows the dialog to be focused for keyboard event
32090 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32091 this.focusEl.swallowEvent("click", true);
32093 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32095 // wrap the body and footer for special rendering
32096 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32098 this.bwrap.dom.appendChild(this.footer.dom);
32101 this.bg = this.el.createChild({
32102 tag: "div", cls:"x-dlg-bg",
32103 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32105 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32108 if(this.autoScroll !== false && !this.autoTabs){
32109 this.body.setStyle("overflow", "auto");
32112 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32114 if(this.closable !== false){
32115 this.el.addClass("x-dlg-closable");
32116 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32117 this.close.on("click", this.closeClick, this);
32118 this.close.addClassOnOver("x-dlg-close-over");
32120 if(this.collapsible !== false){
32121 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32122 this.collapseBtn.on("click", this.collapseClick, this);
32123 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32124 this.header.on("dblclick", this.collapseClick, this);
32126 if(this.resizable !== false){
32127 this.el.addClass("x-dlg-resizable");
32128 this.resizer = new Roo.Resizable(el, {
32129 minWidth: this.minWidth || 80,
32130 minHeight:this.minHeight || 80,
32131 handles: this.resizeHandles || "all",
32134 this.resizer.on("beforeresize", this.beforeResize, this);
32135 this.resizer.on("resize", this.onResize, this);
32137 if(this.draggable !== false){
32138 el.addClass("x-dlg-draggable");
32139 if (!this.proxyDrag) {
32140 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32143 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32145 dd.setHandleElId(this.header.id);
32146 dd.endDrag = this.endMove.createDelegate(this);
32147 dd.startDrag = this.startMove.createDelegate(this);
32148 dd.onDrag = this.onDrag.createDelegate(this);
32153 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32154 this.mask.enableDisplayMode("block");
32156 this.el.addClass("x-dlg-modal");
32159 this.shadow = new Roo.Shadow({
32160 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32161 offset : this.shadowOffset
32164 this.shadowOffset = 0;
32166 if(Roo.useShims && this.shim !== false){
32167 this.shim = this.el.createShim();
32168 this.shim.hide = this.hideAction;
32176 if (this.buttons) {
32177 var bts= this.buttons;
32179 Roo.each(bts, function(b) {
32188 * Fires when a key is pressed
32189 * @param {Roo.BasicDialog} this
32190 * @param {Roo.EventObject} e
32195 * Fires when this dialog is moved by the user.
32196 * @param {Roo.BasicDialog} this
32197 * @param {Number} x The new page X
32198 * @param {Number} y The new page Y
32203 * Fires when this dialog is resized by the user.
32204 * @param {Roo.BasicDialog} this
32205 * @param {Number} width The new width
32206 * @param {Number} height The new height
32210 * @event beforehide
32211 * Fires before this dialog is hidden.
32212 * @param {Roo.BasicDialog} this
32214 "beforehide" : true,
32217 * Fires when this dialog is hidden.
32218 * @param {Roo.BasicDialog} this
32222 * @event beforeshow
32223 * Fires before this dialog is shown.
32224 * @param {Roo.BasicDialog} this
32226 "beforeshow" : true,
32229 * Fires when this dialog is shown.
32230 * @param {Roo.BasicDialog} this
32234 el.on("keydown", this.onKeyDown, this);
32235 el.on("mousedown", this.toFront, this);
32236 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32238 Roo.DialogManager.register(this);
32239 Roo.BasicDialog.superclass.constructor.call(this);
32242 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32243 shadowOffset: Roo.isIE ? 6 : 5,
32246 minButtonWidth: 75,
32247 defaultButton: null,
32248 buttonAlign: "right",
32253 * Sets the dialog title text
32254 * @param {String} text The title text to display
32255 * @return {Roo.BasicDialog} this
32257 setTitle : function(text){
32258 this.header.update(text);
32263 closeClick : function(){
32268 collapseClick : function(){
32269 this[this.collapsed ? "expand" : "collapse"]();
32273 * Collapses the dialog to its minimized state (only the title bar is visible).
32274 * Equivalent to the user clicking the collapse dialog button.
32276 collapse : function(){
32277 if(!this.collapsed){
32278 this.collapsed = true;
32279 this.el.addClass("x-dlg-collapsed");
32280 this.restoreHeight = this.el.getHeight();
32281 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32286 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32287 * clicking the expand dialog button.
32289 expand : function(){
32290 if(this.collapsed){
32291 this.collapsed = false;
32292 this.el.removeClass("x-dlg-collapsed");
32293 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32298 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32299 * @return {Roo.TabPanel} The tabs component
32301 initTabs : function(){
32302 var tabs = this.getTabs();
32303 while(tabs.getTab(0)){
32306 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32308 tabs.addTab(Roo.id(dom), dom.title);
32316 beforeResize : function(){
32317 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32321 onResize : function(){
32322 this.refreshSize();
32323 this.syncBodyHeight();
32324 this.adjustAssets();
32326 this.fireEvent("resize", this, this.size.width, this.size.height);
32330 onKeyDown : function(e){
32331 if(this.isVisible()){
32332 this.fireEvent("keydown", this, e);
32337 * Resizes the dialog.
32338 * @param {Number} width
32339 * @param {Number} height
32340 * @return {Roo.BasicDialog} this
32342 resizeTo : function(width, height){
32343 this.el.setSize(width, height);
32344 this.size = {width: width, height: height};
32345 this.syncBodyHeight();
32346 if(this.fixedcenter){
32349 if(this.isVisible()){
32350 this.constrainXY();
32351 this.adjustAssets();
32353 this.fireEvent("resize", this, width, height);
32359 * Resizes the dialog to fit the specified content size.
32360 * @param {Number} width
32361 * @param {Number} height
32362 * @return {Roo.BasicDialog} this
32364 setContentSize : function(w, h){
32365 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32366 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32367 //if(!this.el.isBorderBox()){
32368 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32369 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32372 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32373 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32375 this.resizeTo(w, h);
32380 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32381 * executed in response to a particular key being pressed while the dialog is active.
32382 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32383 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32384 * @param {Function} fn The function to call
32385 * @param {Object} scope (optional) The scope of the function
32386 * @return {Roo.BasicDialog} this
32388 addKeyListener : function(key, fn, scope){
32389 var keyCode, shift, ctrl, alt;
32390 if(typeof key == "object" && !(key instanceof Array)){
32391 keyCode = key["key"];
32392 shift = key["shift"];
32393 ctrl = key["ctrl"];
32398 var handler = function(dlg, e){
32399 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32400 var k = e.getKey();
32401 if(keyCode instanceof Array){
32402 for(var i = 0, len = keyCode.length; i < len; i++){
32403 if(keyCode[i] == k){
32404 fn.call(scope || window, dlg, k, e);
32410 fn.call(scope || window, dlg, k, e);
32415 this.on("keydown", handler);
32420 * Returns the TabPanel component (creates it if it doesn't exist).
32421 * Note: If you wish to simply check for the existence of tabs without creating them,
32422 * check for a null 'tabs' property.
32423 * @return {Roo.TabPanel} The tabs component
32425 getTabs : function(){
32427 this.el.addClass("x-dlg-auto-tabs");
32428 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32429 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32435 * Adds a button to the footer section of the dialog.
32436 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32437 * object or a valid Roo.DomHelper element config
32438 * @param {Function} handler The function called when the button is clicked
32439 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32440 * @return {Roo.Button} The new button
32442 addButton : function(config, handler, scope){
32443 var dh = Roo.DomHelper;
32445 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32447 if(!this.btnContainer){
32448 var tb = this.footer.createChild({
32450 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32451 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32453 this.btnContainer = tb.firstChild.firstChild.firstChild;
32458 minWidth: this.minButtonWidth,
32461 if(typeof config == "string"){
32462 bconfig.text = config;
32465 bconfig.dhconfig = config;
32467 Roo.apply(bconfig, config);
32471 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32472 bconfig.position = Math.max(0, bconfig.position);
32473 fc = this.btnContainer.childNodes[bconfig.position];
32476 var btn = new Roo.Button(
32478 this.btnContainer.insertBefore(document.createElement("td"),fc)
32479 : this.btnContainer.appendChild(document.createElement("td")),
32480 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32483 this.syncBodyHeight();
32486 * Array of all the buttons that have been added to this dialog via addButton
32491 this.buttons.push(btn);
32496 * Sets the default button to be focused when the dialog is displayed.
32497 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32498 * @return {Roo.BasicDialog} this
32500 setDefaultButton : function(btn){
32501 this.defaultButton = btn;
32506 getHeaderFooterHeight : function(safe){
32509 height += this.header.getHeight();
32512 var fm = this.footer.getMargins();
32513 height += (this.footer.getHeight()+fm.top+fm.bottom);
32515 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32516 height += this.centerBg.getPadding("tb");
32521 syncBodyHeight : function()
32523 var bd = this.body, // the text
32524 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32526 var height = this.size.height - this.getHeaderFooterHeight(false);
32527 bd.setHeight(height-bd.getMargins("tb"));
32528 var hh = this.header.getHeight();
32529 var h = this.size.height-hh;
32532 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32533 bw.setHeight(h-cb.getPadding("tb"));
32535 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32536 bd.setWidth(bw.getWidth(true));
32538 this.tabs.syncHeight();
32540 this.tabs.el.repaint();
32546 * Restores the previous state of the dialog if Roo.state is configured.
32547 * @return {Roo.BasicDialog} this
32549 restoreState : function(){
32550 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32551 if(box && box.width){
32552 this.xy = [box.x, box.y];
32553 this.resizeTo(box.width, box.height);
32559 beforeShow : function(){
32561 if(this.fixedcenter){
32562 this.xy = this.el.getCenterXY(true);
32565 Roo.get(document.body).addClass("x-body-masked");
32566 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32569 this.constrainXY();
32573 animShow : function(){
32574 var b = Roo.get(this.animateTarget).getBox();
32575 this.proxy.setSize(b.width, b.height);
32576 this.proxy.setLocation(b.x, b.y);
32578 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32579 true, .35, this.showEl.createDelegate(this));
32583 * Shows the dialog.
32584 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32585 * @return {Roo.BasicDialog} this
32587 show : function(animateTarget){
32588 if (this.fireEvent("beforeshow", this) === false){
32591 if(this.syncHeightBeforeShow){
32592 this.syncBodyHeight();
32593 }else if(this.firstShow){
32594 this.firstShow = false;
32595 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32597 this.animateTarget = animateTarget || this.animateTarget;
32598 if(!this.el.isVisible()){
32600 if(this.animateTarget && Roo.get(this.animateTarget)){
32610 showEl : function(){
32612 this.el.setXY(this.xy);
32614 this.adjustAssets(true);
32617 // IE peekaboo bug - fix found by Dave Fenwick
32621 this.fireEvent("show", this);
32625 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32626 * dialog itself will receive focus.
32628 focus : function(){
32629 if(this.defaultButton){
32630 this.defaultButton.focus();
32632 this.focusEl.focus();
32637 constrainXY : function(){
32638 if(this.constraintoviewport !== false){
32639 if(!this.viewSize){
32640 if(this.container){
32641 var s = this.container.getSize();
32642 this.viewSize = [s.width, s.height];
32644 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32647 var s = Roo.get(this.container||document).getScroll();
32649 var x = this.xy[0], y = this.xy[1];
32650 var w = this.size.width, h = this.size.height;
32651 var vw = this.viewSize[0], vh = this.viewSize[1];
32652 // only move it if it needs it
32654 // first validate right/bottom
32655 if(x + w > vw+s.left){
32659 if(y + h > vh+s.top){
32663 // then make sure top/left isn't negative
32675 if(this.isVisible()){
32676 this.el.setLocation(x, y);
32677 this.adjustAssets();
32684 onDrag : function(){
32685 if(!this.proxyDrag){
32686 this.xy = this.el.getXY();
32687 this.adjustAssets();
32692 adjustAssets : function(doShow){
32693 var x = this.xy[0], y = this.xy[1];
32694 var w = this.size.width, h = this.size.height;
32695 if(doShow === true){
32697 this.shadow.show(this.el);
32703 if(this.shadow && this.shadow.isVisible()){
32704 this.shadow.show(this.el);
32706 if(this.shim && this.shim.isVisible()){
32707 this.shim.setBounds(x, y, w, h);
32712 adjustViewport : function(w, h){
32714 w = Roo.lib.Dom.getViewWidth();
32715 h = Roo.lib.Dom.getViewHeight();
32718 this.viewSize = [w, h];
32719 if(this.modal && this.mask.isVisible()){
32720 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32721 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32723 if(this.isVisible()){
32724 this.constrainXY();
32729 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32730 * shadow, proxy, mask, etc.) Also removes all event listeners.
32731 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32733 destroy : function(removeEl){
32734 if(this.isVisible()){
32735 this.animateTarget = null;
32738 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32740 this.tabs.destroy(removeEl);
32753 for(var i = 0, len = this.buttons.length; i < len; i++){
32754 this.buttons[i].destroy();
32757 this.el.removeAllListeners();
32758 if(removeEl === true){
32759 this.el.update("");
32762 Roo.DialogManager.unregister(this);
32766 startMove : function(){
32767 if(this.proxyDrag){
32770 if(this.constraintoviewport !== false){
32771 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32776 endMove : function(){
32777 if(!this.proxyDrag){
32778 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32780 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32783 this.refreshSize();
32784 this.adjustAssets();
32786 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32790 * Brings this dialog to the front of any other visible dialogs
32791 * @return {Roo.BasicDialog} this
32793 toFront : function(){
32794 Roo.DialogManager.bringToFront(this);
32799 * Sends this dialog to the back (under) of any other visible dialogs
32800 * @return {Roo.BasicDialog} this
32802 toBack : function(){
32803 Roo.DialogManager.sendToBack(this);
32808 * Centers this dialog in the viewport
32809 * @return {Roo.BasicDialog} this
32811 center : function(){
32812 var xy = this.el.getCenterXY(true);
32813 this.moveTo(xy[0], xy[1]);
32818 * Moves the dialog's top-left corner to the specified point
32819 * @param {Number} x
32820 * @param {Number} y
32821 * @return {Roo.BasicDialog} this
32823 moveTo : function(x, y){
32825 if(this.isVisible()){
32826 this.el.setXY(this.xy);
32827 this.adjustAssets();
32833 * Aligns the dialog to the specified element
32834 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32835 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32836 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32837 * @return {Roo.BasicDialog} this
32839 alignTo : function(element, position, offsets){
32840 this.xy = this.el.getAlignToXY(element, position, offsets);
32841 if(this.isVisible()){
32842 this.el.setXY(this.xy);
32843 this.adjustAssets();
32849 * Anchors an element to another element and realigns it when the window is resized.
32850 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32851 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32852 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32853 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32854 * is a number, it is used as the buffer delay (defaults to 50ms).
32855 * @return {Roo.BasicDialog} this
32857 anchorTo : function(el, alignment, offsets, monitorScroll){
32858 var action = function(){
32859 this.alignTo(el, alignment, offsets);
32861 Roo.EventManager.onWindowResize(action, this);
32862 var tm = typeof monitorScroll;
32863 if(tm != 'undefined'){
32864 Roo.EventManager.on(window, 'scroll', action, this,
32865 {buffer: tm == 'number' ? monitorScroll : 50});
32872 * Returns true if the dialog is visible
32873 * @return {Boolean}
32875 isVisible : function(){
32876 return this.el.isVisible();
32880 animHide : function(callback){
32881 var b = Roo.get(this.animateTarget).getBox();
32883 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32885 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32886 this.hideEl.createDelegate(this, [callback]));
32890 * Hides the dialog.
32891 * @param {Function} callback (optional) Function to call when the dialog is hidden
32892 * @return {Roo.BasicDialog} this
32894 hide : function(callback){
32895 if (this.fireEvent("beforehide", this) === false){
32899 this.shadow.hide();
32904 // sometimes animateTarget seems to get set.. causing problems...
32905 // this just double checks..
32906 if(this.animateTarget && Roo.get(this.animateTarget)) {
32907 this.animHide(callback);
32910 this.hideEl(callback);
32916 hideEl : function(callback){
32920 Roo.get(document.body).removeClass("x-body-masked");
32922 this.fireEvent("hide", this);
32923 if(typeof callback == "function"){
32929 hideAction : function(){
32930 this.setLeft("-10000px");
32931 this.setTop("-10000px");
32932 this.setStyle("visibility", "hidden");
32936 refreshSize : function(){
32937 this.size = this.el.getSize();
32938 this.xy = this.el.getXY();
32939 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32943 // z-index is managed by the DialogManager and may be overwritten at any time
32944 setZIndex : function(index){
32946 this.mask.setStyle("z-index", index);
32949 this.shim.setStyle("z-index", ++index);
32952 this.shadow.setZIndex(++index);
32954 this.el.setStyle("z-index", ++index);
32956 this.proxy.setStyle("z-index", ++index);
32959 this.resizer.proxy.setStyle("z-index", ++index);
32962 this.lastZIndex = index;
32966 * Returns the element for this dialog
32967 * @return {Roo.Element} The underlying dialog Element
32969 getEl : function(){
32975 * @class Roo.DialogManager
32976 * Provides global access to BasicDialogs that have been created and
32977 * support for z-indexing (layering) multiple open dialogs.
32979 Roo.DialogManager = function(){
32981 var accessList = [];
32985 var sortDialogs = function(d1, d2){
32986 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32990 var orderDialogs = function(){
32991 accessList.sort(sortDialogs);
32992 var seed = Roo.DialogManager.zseed;
32993 for(var i = 0, len = accessList.length; i < len; i++){
32994 var dlg = accessList[i];
32996 dlg.setZIndex(seed + (i*10));
33003 * The starting z-index for BasicDialogs (defaults to 9000)
33004 * @type Number The z-index value
33009 register : function(dlg){
33010 list[dlg.id] = dlg;
33011 accessList.push(dlg);
33015 unregister : function(dlg){
33016 delete list[dlg.id];
33019 if(!accessList.indexOf){
33020 for( i = 0, len = accessList.length; i < len; i++){
33021 if(accessList[i] == dlg){
33022 accessList.splice(i, 1);
33027 i = accessList.indexOf(dlg);
33029 accessList.splice(i, 1);
33035 * Gets a registered dialog by id
33036 * @param {String/Object} id The id of the dialog or a dialog
33037 * @return {Roo.BasicDialog} this
33039 get : function(id){
33040 return typeof id == "object" ? id : list[id];
33044 * Brings the specified dialog to the front
33045 * @param {String/Object} dlg The id of the dialog or a dialog
33046 * @return {Roo.BasicDialog} this
33048 bringToFront : function(dlg){
33049 dlg = this.get(dlg);
33052 dlg._lastAccess = new Date().getTime();
33059 * Sends the specified dialog to the back
33060 * @param {String/Object} dlg The id of the dialog or a dialog
33061 * @return {Roo.BasicDialog} this
33063 sendToBack : function(dlg){
33064 dlg = this.get(dlg);
33065 dlg._lastAccess = -(new Date().getTime());
33071 * Hides all dialogs
33073 hideAll : function(){
33074 for(var id in list){
33075 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33084 * @class Roo.LayoutDialog
33085 * @extends Roo.BasicDialog
33086 * Dialog which provides adjustments for working with a layout in a Dialog.
33087 * Add your necessary layout config options to the dialog's config.<br>
33088 * Example usage (including a nested layout):
33091 dialog = new Roo.LayoutDialog("download-dlg", {
33100 // layout config merges with the dialog config
33102 tabPosition: "top",
33103 alwaysShowTabs: true
33106 dialog.addKeyListener(27, dialog.hide, dialog);
33107 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33108 dialog.addButton("Build It!", this.getDownload, this);
33110 // we can even add nested layouts
33111 var innerLayout = new Roo.BorderLayout("dl-inner", {
33121 innerLayout.beginUpdate();
33122 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33123 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33124 innerLayout.endUpdate(true);
33126 var layout = dialog.getLayout();
33127 layout.beginUpdate();
33128 layout.add("center", new Roo.ContentPanel("standard-panel",
33129 {title: "Download the Source", fitToFrame:true}));
33130 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33131 {title: "Build your own roo.js"}));
33132 layout.getRegion("center").showPanel(sp);
33133 layout.endUpdate();
33137 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33138 * @param {Object} config configuration options
33140 Roo.LayoutDialog = function(el, cfg){
33143 if (typeof(cfg) == 'undefined') {
33144 config = Roo.apply({}, el);
33145 // not sure why we use documentElement here.. - it should always be body.
33146 // IE7 borks horribly if we use documentElement.
33147 // webkit also does not like documentElement - it creates a body element...
33148 el = Roo.get( document.body || document.documentElement ).createChild();
33149 //config.autoCreate = true;
33153 config.autoTabs = false;
33154 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33155 this.body.setStyle({overflow:"hidden", position:"relative"});
33156 this.layout = new Roo.BorderLayout(this.body.dom, config);
33157 this.layout.monitorWindowResize = false;
33158 this.el.addClass("x-dlg-auto-layout");
33159 // fix case when center region overwrites center function
33160 this.center = Roo.BasicDialog.prototype.center;
33161 this.on("show", this.layout.layout, this.layout, true);
33162 if (config.items) {
33163 var xitems = config.items;
33164 delete config.items;
33165 Roo.each(xitems, this.addxtype, this);
33170 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33172 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33175 endUpdate : function(){
33176 this.layout.endUpdate();
33180 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33183 beginUpdate : function(){
33184 this.layout.beginUpdate();
33188 * Get the BorderLayout for this dialog
33189 * @return {Roo.BorderLayout}
33191 getLayout : function(){
33192 return this.layout;
33195 showEl : function(){
33196 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33198 this.layout.layout();
33203 // Use the syncHeightBeforeShow config option to control this automatically
33204 syncBodyHeight : function(){
33205 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33206 if(this.layout){this.layout.layout();}
33210 * Add an xtype element (actually adds to the layout.)
33211 * @return {Object} xdata xtype object data.
33214 addxtype : function(c) {
33215 return this.layout.addxtype(c);
33219 * Ext JS Library 1.1.1
33220 * Copyright(c) 2006-2007, Ext JS, LLC.
33222 * Originally Released Under LGPL - original licence link has changed is not relivant.
33225 * <script type="text/javascript">
33229 * @class Roo.MessageBox
33230 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33234 Roo.Msg.alert('Status', 'Changes saved successfully.');
33236 // Prompt for user data:
33237 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33239 // process text value...
33243 // Show a dialog using config options:
33245 title:'Save Changes?',
33246 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33247 buttons: Roo.Msg.YESNOCANCEL,
33254 Roo.MessageBox = function(){
33255 var dlg, opt, mask, waitTimer;
33256 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33257 var buttons, activeTextEl, bwidth;
33260 var handleButton = function(button){
33262 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33266 var handleHide = function(){
33267 if(opt && opt.cls){
33268 dlg.el.removeClass(opt.cls);
33271 Roo.TaskMgr.stop(waitTimer);
33277 var updateButtons = function(b){
33280 buttons["ok"].hide();
33281 buttons["cancel"].hide();
33282 buttons["yes"].hide();
33283 buttons["no"].hide();
33284 dlg.footer.dom.style.display = 'none';
33287 dlg.footer.dom.style.display = '';
33288 for(var k in buttons){
33289 if(typeof buttons[k] != "function"){
33292 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33293 width += buttons[k].el.getWidth()+15;
33303 var handleEsc = function(d, k, e){
33304 if(opt && opt.closable !== false){
33314 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33315 * @return {Roo.BasicDialog} The BasicDialog element
33317 getDialog : function(){
33319 dlg = new Roo.BasicDialog("x-msg-box", {
33324 constraintoviewport:false,
33326 collapsible : false,
33329 width:400, height:100,
33330 buttonAlign:"center",
33331 closeClick : function(){
33332 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33333 handleButton("no");
33335 handleButton("cancel");
33339 dlg.on("hide", handleHide);
33341 dlg.addKeyListener(27, handleEsc);
33343 var bt = this.buttonText;
33344 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33345 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33346 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33347 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33348 bodyEl = dlg.body.createChild({
33350 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>'
33352 msgEl = bodyEl.dom.firstChild;
33353 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33354 textboxEl.enableDisplayMode();
33355 textboxEl.addKeyListener([10,13], function(){
33356 if(dlg.isVisible() && opt && opt.buttons){
33357 if(opt.buttons.ok){
33358 handleButton("ok");
33359 }else if(opt.buttons.yes){
33360 handleButton("yes");
33364 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33365 textareaEl.enableDisplayMode();
33366 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33367 progressEl.enableDisplayMode();
33368 var pf = progressEl.dom.firstChild;
33370 pp = Roo.get(pf.firstChild);
33371 pp.setHeight(pf.offsetHeight);
33379 * Updates the message box body text
33380 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33381 * the XHTML-compliant non-breaking space character '&#160;')
33382 * @return {Roo.MessageBox} This message box
33384 updateText : function(text){
33385 if(!dlg.isVisible() && !opt.width){
33386 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33388 msgEl.innerHTML = text || ' ';
33390 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33391 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33393 Math.min(opt.width || cw , this.maxWidth),
33394 Math.max(opt.minWidth || this.minWidth, bwidth)
33397 activeTextEl.setWidth(w);
33399 if(dlg.isVisible()){
33400 dlg.fixedcenter = false;
33402 // to big, make it scroll. = But as usual stupid IE does not support
33405 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33406 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33407 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33409 bodyEl.dom.style.height = '';
33410 bodyEl.dom.style.overflowY = '';
33413 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33415 bodyEl.dom.style.overflowX = '';
33418 dlg.setContentSize(w, bodyEl.getHeight());
33419 if(dlg.isVisible()){
33420 dlg.fixedcenter = true;
33426 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33427 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33428 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33429 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33430 * @return {Roo.MessageBox} This message box
33432 updateProgress : function(value, text){
33434 this.updateText(text);
33436 if (pp) { // weird bug on my firefox - for some reason this is not defined
33437 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33443 * Returns true if the message box is currently displayed
33444 * @return {Boolean} True if the message box is visible, else false
33446 isVisible : function(){
33447 return dlg && dlg.isVisible();
33451 * Hides the message box if it is displayed
33454 if(this.isVisible()){
33460 * Displays a new message box, or reinitializes an existing message box, based on the config options
33461 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33462 * The following config object properties are supported:
33464 Property Type Description
33465 ---------- --------------- ------------------------------------------------------------------------------------
33466 animEl String/Element An id or Element from which the message box should animate as it opens and
33467 closes (defaults to undefined)
33468 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33469 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33470 closable Boolean False to hide the top-right close button (defaults to true). Note that
33471 progress and wait dialogs will ignore this property and always hide the
33472 close button as they can only be closed programmatically.
33473 cls String A custom CSS class to apply to the message box element
33474 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33475 displayed (defaults to 75)
33476 fn Function A callback function to execute after closing the dialog. The arguments to the
33477 function will be btn (the name of the button that was clicked, if applicable,
33478 e.g. "ok"), and text (the value of the active text field, if applicable).
33479 Progress and wait dialogs will ignore this option since they do not respond to
33480 user actions and can only be closed programmatically, so any required function
33481 should be called by the same code after it closes the dialog.
33482 icon String A CSS class that provides a background image to be used as an icon for
33483 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33484 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33485 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33486 modal Boolean False to allow user interaction with the page while the message box is
33487 displayed (defaults to true)
33488 msg String A string that will replace the existing message box body text (defaults
33489 to the XHTML-compliant non-breaking space character ' ')
33490 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33491 progress Boolean True to display a progress bar (defaults to false)
33492 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33493 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33494 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33495 title String The title text
33496 value String The string value to set into the active textbox element if displayed
33497 wait Boolean True to display a progress bar (defaults to false)
33498 width Number The width of the dialog in pixels
33505 msg: 'Please enter your address:',
33507 buttons: Roo.MessageBox.OKCANCEL,
33510 animEl: 'addAddressBtn'
33513 * @param {Object} config Configuration options
33514 * @return {Roo.MessageBox} This message box
33516 show : function(options)
33519 // this causes nightmares if you show one dialog after another
33520 // especially on callbacks..
33522 if(this.isVisible()){
33525 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33526 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33527 Roo.log("New Dialog Message:" + options.msg )
33528 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33529 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33532 var d = this.getDialog();
33534 d.setTitle(opt.title || " ");
33535 d.close.setDisplayed(opt.closable !== false);
33536 activeTextEl = textboxEl;
33537 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33542 textareaEl.setHeight(typeof opt.multiline == "number" ?
33543 opt.multiline : this.defaultTextHeight);
33544 activeTextEl = textareaEl;
33553 progressEl.setDisplayed(opt.progress === true);
33554 this.updateProgress(0);
33555 activeTextEl.dom.value = opt.value || "";
33557 dlg.setDefaultButton(activeTextEl);
33559 var bs = opt.buttons;
33562 db = buttons["ok"];
33563 }else if(bs && bs.yes){
33564 db = buttons["yes"];
33566 dlg.setDefaultButton(db);
33568 bwidth = updateButtons(opt.buttons);
33569 this.updateText(opt.msg);
33571 d.el.addClass(opt.cls);
33573 d.proxyDrag = opt.proxyDrag === true;
33574 d.modal = opt.modal !== false;
33575 d.mask = opt.modal !== false ? mask : false;
33576 if(!d.isVisible()){
33577 // force it to the end of the z-index stack so it gets a cursor in FF
33578 document.body.appendChild(dlg.el.dom);
33579 d.animateTarget = null;
33580 d.show(options.animEl);
33586 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33587 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33588 * and closing the message box when the process is complete.
33589 * @param {String} title The title bar text
33590 * @param {String} msg The message box body text
33591 * @return {Roo.MessageBox} This message box
33593 progress : function(title, msg){
33600 minWidth: this.minProgressWidth,
33607 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33608 * If a callback function is passed it will be called after the user clicks the button, and the
33609 * id of the button that was clicked will be passed as the only parameter to the callback
33610 * (could also be the top-right close button).
33611 * @param {String} title The title bar text
33612 * @param {String} msg The message box body text
33613 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33614 * @param {Object} scope (optional) The scope of the callback function
33615 * @return {Roo.MessageBox} This message box
33617 alert : function(title, msg, fn, scope){
33630 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33631 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33632 * You are responsible for closing the message box when the process is complete.
33633 * @param {String} msg The message box body text
33634 * @param {String} title (optional) The title bar text
33635 * @return {Roo.MessageBox} This message box
33637 wait : function(msg, title){
33648 waitTimer = Roo.TaskMgr.start({
33650 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33658 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33659 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33660 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33661 * @param {String} title The title bar text
33662 * @param {String} msg The message box body text
33663 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33664 * @param {Object} scope (optional) The scope of the callback function
33665 * @return {Roo.MessageBox} This message box
33667 confirm : function(title, msg, fn, scope){
33671 buttons: this.YESNO,
33680 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33681 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33682 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33683 * (could also be the top-right close button) and the text that was entered will be passed as the two
33684 * parameters to the callback.
33685 * @param {String} title The title bar text
33686 * @param {String} msg The message box body text
33687 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33688 * @param {Object} scope (optional) The scope of the callback function
33689 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33690 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33691 * @return {Roo.MessageBox} This message box
33693 prompt : function(title, msg, fn, scope, multiline){
33697 buttons: this.OKCANCEL,
33702 multiline: multiline,
33709 * Button config that displays a single OK button
33714 * Button config that displays Yes and No buttons
33717 YESNO : {yes:true, no:true},
33719 * Button config that displays OK and Cancel buttons
33722 OKCANCEL : {ok:true, cancel:true},
33724 * Button config that displays Yes, No and Cancel buttons
33727 YESNOCANCEL : {yes:true, no:true, cancel:true},
33730 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33733 defaultTextHeight : 75,
33735 * The maximum width in pixels of the message box (defaults to 600)
33740 * The minimum width in pixels of the message box (defaults to 100)
33745 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33746 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33749 minProgressWidth : 250,
33751 * An object containing the default button text strings that can be overriden for localized language support.
33752 * Supported properties are: ok, cancel, yes and no.
33753 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33766 * Shorthand for {@link Roo.MessageBox}
33768 Roo.Msg = Roo.MessageBox;/*
33770 * Ext JS Library 1.1.1
33771 * Copyright(c) 2006-2007, Ext JS, LLC.
33773 * Originally Released Under LGPL - original licence link has changed is not relivant.
33776 * <script type="text/javascript">
33779 * @class Roo.QuickTips
33780 * Provides attractive and customizable tooltips for any element.
33783 Roo.QuickTips = function(){
33784 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33785 var ce, bd, xy, dd;
33786 var visible = false, disabled = true, inited = false;
33787 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33789 var onOver = function(e){
33793 var t = e.getTarget();
33794 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33797 if(ce && t == ce.el){
33798 clearTimeout(hideProc);
33801 if(t && tagEls[t.id]){
33802 tagEls[t.id].el = t;
33803 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33806 var ttp, et = Roo.fly(t);
33807 var ns = cfg.namespace;
33808 if(tm.interceptTitles && t.title){
33811 t.removeAttribute("title");
33812 e.preventDefault();
33814 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33817 showProc = show.defer(tm.showDelay, tm, [{
33819 text: ttp.replace(/\\n/g,'<br/>'),
33820 width: et.getAttributeNS(ns, cfg.width),
33821 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33822 title: et.getAttributeNS(ns, cfg.title),
33823 cls: et.getAttributeNS(ns, cfg.cls)
33828 var onOut = function(e){
33829 clearTimeout(showProc);
33830 var t = e.getTarget();
33831 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33832 hideProc = setTimeout(hide, tm.hideDelay);
33836 var onMove = function(e){
33842 if(tm.trackMouse && ce){
33847 var onDown = function(e){
33848 clearTimeout(showProc);
33849 clearTimeout(hideProc);
33851 if(tm.hideOnClick){
33854 tm.enable.defer(100, tm);
33859 var getPad = function(){
33860 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33863 var show = function(o){
33867 clearTimeout(dismissProc);
33869 if(removeCls){ // in case manually hidden
33870 el.removeClass(removeCls);
33874 el.addClass(ce.cls);
33875 removeCls = ce.cls;
33878 tipTitle.update(ce.title);
33881 tipTitle.update('');
33884 el.dom.style.width = tm.maxWidth+'px';
33885 //tipBody.dom.style.width = '';
33886 tipBodyText.update(o.text);
33887 var p = getPad(), w = ce.width;
33889 var td = tipBodyText.dom;
33890 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33891 if(aw > tm.maxWidth){
33893 }else if(aw < tm.minWidth){
33899 //tipBody.setWidth(w);
33900 el.setWidth(parseInt(w, 10) + p);
33901 if(ce.autoHide === false){
33902 close.setDisplayed(true);
33907 close.setDisplayed(false);
33913 el.avoidY = xy[1]-18;
33918 el.setStyle("visibility", "visible");
33919 el.fadeIn({callback: afterShow});
33925 var afterShow = function(){
33929 if(tm.autoDismiss && ce.autoHide !== false){
33930 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33935 var hide = function(noanim){
33936 clearTimeout(dismissProc);
33937 clearTimeout(hideProc);
33939 if(el.isVisible()){
33941 if(noanim !== true && tm.animate){
33942 el.fadeOut({callback: afterHide});
33949 var afterHide = function(){
33952 el.removeClass(removeCls);
33959 * @cfg {Number} minWidth
33960 * The minimum width of the quick tip (defaults to 40)
33964 * @cfg {Number} maxWidth
33965 * The maximum width of the quick tip (defaults to 300)
33969 * @cfg {Boolean} interceptTitles
33970 * True to automatically use the element's DOM title value if available (defaults to false)
33972 interceptTitles : false,
33974 * @cfg {Boolean} trackMouse
33975 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33977 trackMouse : false,
33979 * @cfg {Boolean} hideOnClick
33980 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33982 hideOnClick : true,
33984 * @cfg {Number} showDelay
33985 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33989 * @cfg {Number} hideDelay
33990 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33994 * @cfg {Boolean} autoHide
33995 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33996 * Used in conjunction with hideDelay.
34001 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34002 * (defaults to true). Used in conjunction with autoDismissDelay.
34004 autoDismiss : true,
34007 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34009 autoDismissDelay : 5000,
34011 * @cfg {Boolean} animate
34012 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34017 * @cfg {String} title
34018 * Title text to display (defaults to ''). This can be any valid HTML markup.
34022 * @cfg {String} text
34023 * Body text to display (defaults to ''). This can be any valid HTML markup.
34027 * @cfg {String} cls
34028 * A CSS class to apply to the base quick tip element (defaults to '').
34032 * @cfg {Number} width
34033 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34034 * minWidth or maxWidth.
34039 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34040 * or display QuickTips in a page.
34043 tm = Roo.QuickTips;
34044 cfg = tm.tagConfig;
34046 if(!Roo.isReady){ // allow calling of init() before onReady
34047 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34050 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34051 el.fxDefaults = {stopFx: true};
34052 // maximum custom styling
34053 //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>');
34054 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>');
34055 tipTitle = el.child('h3');
34056 tipTitle.enableDisplayMode("block");
34057 tipBody = el.child('div.x-tip-bd');
34058 tipBodyText = el.child('div.x-tip-bd-inner');
34059 //bdLeft = el.child('div.x-tip-bd-left');
34060 //bdRight = el.child('div.x-tip-bd-right');
34061 close = el.child('div.x-tip-close');
34062 close.enableDisplayMode("block");
34063 close.on("click", hide);
34064 var d = Roo.get(document);
34065 d.on("mousedown", onDown);
34066 d.on("mouseover", onOver);
34067 d.on("mouseout", onOut);
34068 d.on("mousemove", onMove);
34069 esc = d.addKeyListener(27, hide);
34072 dd = el.initDD("default", null, {
34073 onDrag : function(){
34077 dd.setHandleElId(tipTitle.id);
34086 * Configures a new quick tip instance and assigns it to a target element. The following config options
34089 Property Type Description
34090 ---------- --------------------- ------------------------------------------------------------------------
34091 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34093 * @param {Object} config The config object
34095 register : function(config){
34096 var cs = config instanceof Array ? config : arguments;
34097 for(var i = 0, len = cs.length; i < len; i++) {
34099 var target = c.target;
34101 if(target instanceof Array){
34102 for(var j = 0, jlen = target.length; j < jlen; j++){
34103 tagEls[target[j]] = c;
34106 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34113 * Removes this quick tip from its element and destroys it.
34114 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34116 unregister : function(el){
34117 delete tagEls[Roo.id(el)];
34121 * Enable this quick tip.
34123 enable : function(){
34124 if(inited && disabled){
34126 if(locks.length < 1){
34133 * Disable this quick tip.
34135 disable : function(){
34137 clearTimeout(showProc);
34138 clearTimeout(hideProc);
34139 clearTimeout(dismissProc);
34147 * Returns true if the quick tip is enabled, else false.
34149 isEnabled : function(){
34155 namespace : "roo", // was ext?? this may break..
34156 alt_namespace : "ext",
34157 attribute : "qtip",
34167 // backwards compat
34168 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34170 * Ext JS Library 1.1.1
34171 * Copyright(c) 2006-2007, Ext JS, LLC.
34173 * Originally Released Under LGPL - original licence link has changed is not relivant.
34176 * <script type="text/javascript">
34181 * @class Roo.tree.TreePanel
34182 * @extends Roo.data.Tree
34184 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34185 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34186 * @cfg {Boolean} enableDD true to enable drag and drop
34187 * @cfg {Boolean} enableDrag true to enable just drag
34188 * @cfg {Boolean} enableDrop true to enable just drop
34189 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34190 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34191 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34192 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34193 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34194 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34195 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34196 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34197 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34198 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34199 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34200 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34201 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34202 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34203 * @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>
34204 * @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>
34207 * @param {String/HTMLElement/Element} el The container element
34208 * @param {Object} config
34210 Roo.tree.TreePanel = function(el, config){
34212 var loader = false;
34214 root = config.root;
34215 delete config.root;
34217 if (config.loader) {
34218 loader = config.loader;
34219 delete config.loader;
34222 Roo.apply(this, config);
34223 Roo.tree.TreePanel.superclass.constructor.call(this);
34224 this.el = Roo.get(el);
34225 this.el.addClass('x-tree');
34226 //console.log(root);
34228 this.setRootNode( Roo.factory(root, Roo.tree));
34231 this.loader = Roo.factory(loader, Roo.tree);
34234 * Read-only. The id of the container element becomes this TreePanel's id.
34236 this.id = this.el.id;
34239 * @event beforeload
34240 * Fires before a node is loaded, return false to cancel
34241 * @param {Node} node The node being loaded
34243 "beforeload" : true,
34246 * Fires when a node is loaded
34247 * @param {Node} node The node that was loaded
34251 * @event textchange
34252 * Fires when the text for a node is changed
34253 * @param {Node} node The node
34254 * @param {String} text The new text
34255 * @param {String} oldText The old text
34257 "textchange" : true,
34259 * @event beforeexpand
34260 * Fires before a node is expanded, return false to cancel.
34261 * @param {Node} node The node
34262 * @param {Boolean} deep
34263 * @param {Boolean} anim
34265 "beforeexpand" : true,
34267 * @event beforecollapse
34268 * Fires before a node is collapsed, return false to cancel.
34269 * @param {Node} node The node
34270 * @param {Boolean} deep
34271 * @param {Boolean} anim
34273 "beforecollapse" : true,
34276 * Fires when a node is expanded
34277 * @param {Node} node The node
34281 * @event disabledchange
34282 * Fires when the disabled status of a node changes
34283 * @param {Node} node The node
34284 * @param {Boolean} disabled
34286 "disabledchange" : true,
34289 * Fires when a node is collapsed
34290 * @param {Node} node The node
34294 * @event beforeclick
34295 * Fires before click processing on a node. Return false to cancel the default action.
34296 * @param {Node} node The node
34297 * @param {Roo.EventObject} e The event object
34299 "beforeclick":true,
34301 * @event checkchange
34302 * Fires when a node with a checkbox's checked property changes
34303 * @param {Node} this This node
34304 * @param {Boolean} checked
34306 "checkchange":true,
34309 * Fires when a node is clicked
34310 * @param {Node} node The node
34311 * @param {Roo.EventObject} e The event object
34316 * Fires when a node is double clicked
34317 * @param {Node} node The node
34318 * @param {Roo.EventObject} e The event object
34322 * @event contextmenu
34323 * Fires when a node is right clicked
34324 * @param {Node} node The node
34325 * @param {Roo.EventObject} e The event object
34327 "contextmenu":true,
34329 * @event beforechildrenrendered
34330 * Fires right before the child nodes for a node are rendered
34331 * @param {Node} node The node
34333 "beforechildrenrendered":true,
34336 * Fires when a node starts being dragged
34337 * @param {Roo.tree.TreePanel} this
34338 * @param {Roo.tree.TreeNode} node
34339 * @param {event} e The raw browser event
34341 "startdrag" : true,
34344 * Fires when a drag operation is complete
34345 * @param {Roo.tree.TreePanel} this
34346 * @param {Roo.tree.TreeNode} node
34347 * @param {event} e The raw browser event
34352 * Fires when a dragged node is dropped on a valid DD target
34353 * @param {Roo.tree.TreePanel} this
34354 * @param {Roo.tree.TreeNode} node
34355 * @param {DD} dd The dd it was dropped on
34356 * @param {event} e The raw browser event
34360 * @event beforenodedrop
34361 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34362 * passed to handlers has the following properties:<br />
34363 * <ul style="padding:5px;padding-left:16px;">
34364 * <li>tree - The TreePanel</li>
34365 * <li>target - The node being targeted for the drop</li>
34366 * <li>data - The drag data from the drag source</li>
34367 * <li>point - The point of the drop - append, above or below</li>
34368 * <li>source - The drag source</li>
34369 * <li>rawEvent - Raw mouse event</li>
34370 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34371 * to be inserted by setting them on this object.</li>
34372 * <li>cancel - Set this to true to cancel the drop.</li>
34374 * @param {Object} dropEvent
34376 "beforenodedrop" : true,
34379 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34380 * passed to handlers has the following properties:<br />
34381 * <ul style="padding:5px;padding-left:16px;">
34382 * <li>tree - The TreePanel</li>
34383 * <li>target - The node being targeted for the drop</li>
34384 * <li>data - The drag data from the drag source</li>
34385 * <li>point - The point of the drop - append, above or below</li>
34386 * <li>source - The drag source</li>
34387 * <li>rawEvent - Raw mouse event</li>
34388 * <li>dropNode - Dropped node(s).</li>
34390 * @param {Object} dropEvent
34394 * @event nodedragover
34395 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34396 * passed to handlers has the following properties:<br />
34397 * <ul style="padding:5px;padding-left:16px;">
34398 * <li>tree - The TreePanel</li>
34399 * <li>target - The node being targeted for the drop</li>
34400 * <li>data - The drag data from the drag source</li>
34401 * <li>point - The point of the drop - append, above or below</li>
34402 * <li>source - The drag source</li>
34403 * <li>rawEvent - Raw mouse event</li>
34404 * <li>dropNode - Drop node(s) provided by the source.</li>
34405 * <li>cancel - Set this to true to signal drop not allowed.</li>
34407 * @param {Object} dragOverEvent
34409 "nodedragover" : true,
34411 * @event appendnode
34412 * Fires when append node to the tree
34413 * @param {Roo.tree.TreePanel} this
34414 * @param {Roo.tree.TreeNode} node
34415 * @param {Number} index The index of the newly appended node
34417 "appendnode" : true
34420 if(this.singleExpand){
34421 this.on("beforeexpand", this.restrictExpand, this);
34424 this.editor.tree = this;
34425 this.editor = Roo.factory(this.editor, Roo.tree);
34428 if (this.selModel) {
34429 this.selModel = Roo.factory(this.selModel, Roo.tree);
34433 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34434 rootVisible : true,
34435 animate: Roo.enableFx,
34438 hlDrop : Roo.enableFx,
34442 rendererTip: false,
34444 restrictExpand : function(node){
34445 var p = node.parentNode;
34447 if(p.expandedChild && p.expandedChild.parentNode == p){
34448 p.expandedChild.collapse();
34450 p.expandedChild = node;
34454 // private override
34455 setRootNode : function(node){
34456 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34457 if(!this.rootVisible){
34458 node.ui = new Roo.tree.RootTreeNodeUI(node);
34464 * Returns the container element for this TreePanel
34466 getEl : function(){
34471 * Returns the default TreeLoader for this TreePanel
34473 getLoader : function(){
34474 return this.loader;
34480 expandAll : function(){
34481 this.root.expand(true);
34485 * Collapse all nodes
34487 collapseAll : function(){
34488 this.root.collapse(true);
34492 * Returns the selection model used by this TreePanel
34494 getSelectionModel : function(){
34495 if(!this.selModel){
34496 this.selModel = new Roo.tree.DefaultSelectionModel();
34498 return this.selModel;
34502 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34503 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34504 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34507 getChecked : function(a, startNode){
34508 startNode = startNode || this.root;
34510 var f = function(){
34511 if(this.attributes.checked){
34512 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34515 startNode.cascade(f);
34520 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34521 * @param {String} path
34522 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34523 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34524 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34526 expandPath : function(path, attr, callback){
34527 attr = attr || "id";
34528 var keys = path.split(this.pathSeparator);
34529 var curNode = this.root;
34530 if(curNode.attributes[attr] != keys[1]){ // invalid root
34532 callback(false, null);
34537 var f = function(){
34538 if(++index == keys.length){
34540 callback(true, curNode);
34544 var c = curNode.findChild(attr, keys[index]);
34547 callback(false, curNode);
34552 c.expand(false, false, f);
34554 curNode.expand(false, false, f);
34558 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34559 * @param {String} path
34560 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34561 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34562 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34564 selectPath : function(path, attr, callback){
34565 attr = attr || "id";
34566 var keys = path.split(this.pathSeparator);
34567 var v = keys.pop();
34568 if(keys.length > 0){
34569 var f = function(success, node){
34570 if(success && node){
34571 var n = node.findChild(attr, v);
34577 }else if(callback){
34578 callback(false, n);
34582 callback(false, n);
34586 this.expandPath(keys.join(this.pathSeparator), attr, f);
34588 this.root.select();
34590 callback(true, this.root);
34595 getTreeEl : function(){
34600 * Trigger rendering of this TreePanel
34602 render : function(){
34603 if (this.innerCt) {
34604 return this; // stop it rendering more than once!!
34607 this.innerCt = this.el.createChild({tag:"ul",
34608 cls:"x-tree-root-ct " +
34609 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34611 if(this.containerScroll){
34612 Roo.dd.ScrollManager.register(this.el);
34614 if((this.enableDD || this.enableDrop) && !this.dropZone){
34616 * The dropZone used by this tree if drop is enabled
34617 * @type Roo.tree.TreeDropZone
34619 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34620 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34623 if((this.enableDD || this.enableDrag) && !this.dragZone){
34625 * The dragZone used by this tree if drag is enabled
34626 * @type Roo.tree.TreeDragZone
34628 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34629 ddGroup: this.ddGroup || "TreeDD",
34630 scroll: this.ddScroll
34633 this.getSelectionModel().init(this);
34635 Roo.log("ROOT not set in tree");
34638 this.root.render();
34639 if(!this.rootVisible){
34640 this.root.renderChildren();
34646 * Ext JS Library 1.1.1
34647 * Copyright(c) 2006-2007, Ext JS, LLC.
34649 * Originally Released Under LGPL - original licence link has changed is not relivant.
34652 * <script type="text/javascript">
34657 * @class Roo.tree.DefaultSelectionModel
34658 * @extends Roo.util.Observable
34659 * The default single selection for a TreePanel.
34660 * @param {Object} cfg Configuration
34662 Roo.tree.DefaultSelectionModel = function(cfg){
34663 this.selNode = null;
34669 * @event selectionchange
34670 * Fires when the selected node changes
34671 * @param {DefaultSelectionModel} this
34672 * @param {TreeNode} node the new selection
34674 "selectionchange" : true,
34677 * @event beforeselect
34678 * Fires before the selected node changes, return false to cancel the change
34679 * @param {DefaultSelectionModel} this
34680 * @param {TreeNode} node the new selection
34681 * @param {TreeNode} node the old selection
34683 "beforeselect" : true
34686 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34689 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34690 init : function(tree){
34692 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34693 tree.on("click", this.onNodeClick, this);
34696 onNodeClick : function(node, e){
34697 if (e.ctrlKey && this.selNode == node) {
34698 this.unselect(node);
34706 * @param {TreeNode} node The node to select
34707 * @return {TreeNode} The selected node
34709 select : function(node){
34710 var last = this.selNode;
34711 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34713 last.ui.onSelectedChange(false);
34715 this.selNode = node;
34716 node.ui.onSelectedChange(true);
34717 this.fireEvent("selectionchange", this, node, last);
34724 * @param {TreeNode} node The node to unselect
34726 unselect : function(node){
34727 if(this.selNode == node){
34728 this.clearSelections();
34733 * Clear all selections
34735 clearSelections : function(){
34736 var n = this.selNode;
34738 n.ui.onSelectedChange(false);
34739 this.selNode = null;
34740 this.fireEvent("selectionchange", this, null);
34746 * Get the selected node
34747 * @return {TreeNode} The selected node
34749 getSelectedNode : function(){
34750 return this.selNode;
34754 * Returns true if the node is selected
34755 * @param {TreeNode} node The node to check
34756 * @return {Boolean}
34758 isSelected : function(node){
34759 return this.selNode == node;
34763 * Selects the node above the selected node in the tree, intelligently walking the nodes
34764 * @return TreeNode The new selection
34766 selectPrevious : function(){
34767 var s = this.selNode || this.lastSelNode;
34771 var ps = s.previousSibling;
34773 if(!ps.isExpanded() || ps.childNodes.length < 1){
34774 return this.select(ps);
34776 var lc = ps.lastChild;
34777 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34780 return this.select(lc);
34782 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34783 return this.select(s.parentNode);
34789 * Selects the node above the selected node in the tree, intelligently walking the nodes
34790 * @return TreeNode The new selection
34792 selectNext : function(){
34793 var s = this.selNode || this.lastSelNode;
34797 if(s.firstChild && s.isExpanded()){
34798 return this.select(s.firstChild);
34799 }else if(s.nextSibling){
34800 return this.select(s.nextSibling);
34801 }else if(s.parentNode){
34803 s.parentNode.bubble(function(){
34804 if(this.nextSibling){
34805 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34814 onKeyDown : function(e){
34815 var s = this.selNode || this.lastSelNode;
34816 // undesirable, but required
34821 var k = e.getKey();
34829 this.selectPrevious();
34832 e.preventDefault();
34833 if(s.hasChildNodes()){
34834 if(!s.isExpanded()){
34836 }else if(s.firstChild){
34837 this.select(s.firstChild, e);
34842 e.preventDefault();
34843 if(s.hasChildNodes() && s.isExpanded()){
34845 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34846 this.select(s.parentNode, e);
34854 * @class Roo.tree.MultiSelectionModel
34855 * @extends Roo.util.Observable
34856 * Multi selection for a TreePanel.
34857 * @param {Object} cfg Configuration
34859 Roo.tree.MultiSelectionModel = function(){
34860 this.selNodes = [];
34864 * @event selectionchange
34865 * Fires when the selected nodes change
34866 * @param {MultiSelectionModel} this
34867 * @param {Array} nodes Array of the selected nodes
34869 "selectionchange" : true
34871 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34875 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34876 init : function(tree){
34878 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34879 tree.on("click", this.onNodeClick, this);
34882 onNodeClick : function(node, e){
34883 this.select(node, e, e.ctrlKey);
34888 * @param {TreeNode} node The node to select
34889 * @param {EventObject} e (optional) An event associated with the selection
34890 * @param {Boolean} keepExisting True to retain existing selections
34891 * @return {TreeNode} The selected node
34893 select : function(node, e, keepExisting){
34894 if(keepExisting !== true){
34895 this.clearSelections(true);
34897 if(this.isSelected(node)){
34898 this.lastSelNode = node;
34901 this.selNodes.push(node);
34902 this.selMap[node.id] = node;
34903 this.lastSelNode = node;
34904 node.ui.onSelectedChange(true);
34905 this.fireEvent("selectionchange", this, this.selNodes);
34911 * @param {TreeNode} node The node to unselect
34913 unselect : function(node){
34914 if(this.selMap[node.id]){
34915 node.ui.onSelectedChange(false);
34916 var sn = this.selNodes;
34919 index = sn.indexOf(node);
34921 for(var i = 0, len = sn.length; i < len; i++){
34929 this.selNodes.splice(index, 1);
34931 delete this.selMap[node.id];
34932 this.fireEvent("selectionchange", this, this.selNodes);
34937 * Clear all selections
34939 clearSelections : function(suppressEvent){
34940 var sn = this.selNodes;
34942 for(var i = 0, len = sn.length; i < len; i++){
34943 sn[i].ui.onSelectedChange(false);
34945 this.selNodes = [];
34947 if(suppressEvent !== true){
34948 this.fireEvent("selectionchange", this, this.selNodes);
34954 * Returns true if the node is selected
34955 * @param {TreeNode} node The node to check
34956 * @return {Boolean}
34958 isSelected : function(node){
34959 return this.selMap[node.id] ? true : false;
34963 * Returns an array of the selected nodes
34966 getSelectedNodes : function(){
34967 return this.selNodes;
34970 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34972 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34974 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34977 * Ext JS Library 1.1.1
34978 * Copyright(c) 2006-2007, Ext JS, LLC.
34980 * Originally Released Under LGPL - original licence link has changed is not relivant.
34983 * <script type="text/javascript">
34987 * @class Roo.tree.TreeNode
34988 * @extends Roo.data.Node
34989 * @cfg {String} text The text for this node
34990 * @cfg {Boolean} expanded true to start the node expanded
34991 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34992 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34993 * @cfg {Boolean} disabled true to start the node disabled
34994 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34995 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34996 * @cfg {String} cls A css class to be added to the node
34997 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34998 * @cfg {String} href URL of the link used for the node (defaults to #)
34999 * @cfg {String} hrefTarget target frame for the link
35000 * @cfg {String} qtip An Ext QuickTip for the node
35001 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35002 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35003 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35004 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35005 * (defaults to undefined with no checkbox rendered)
35007 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35009 Roo.tree.TreeNode = function(attributes){
35010 attributes = attributes || {};
35011 if(typeof attributes == "string"){
35012 attributes = {text: attributes};
35014 this.childrenRendered = false;
35015 this.rendered = false;
35016 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35017 this.expanded = attributes.expanded === true;
35018 this.isTarget = attributes.isTarget !== false;
35019 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35020 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35023 * Read-only. The text for this node. To change it use setText().
35026 this.text = attributes.text;
35028 * True if this node is disabled.
35031 this.disabled = attributes.disabled === true;
35035 * @event textchange
35036 * Fires when the text for this node is changed
35037 * @param {Node} this This node
35038 * @param {String} text The new text
35039 * @param {String} oldText The old text
35041 "textchange" : true,
35043 * @event beforeexpand
35044 * Fires before this node is expanded, return false to cancel.
35045 * @param {Node} this This node
35046 * @param {Boolean} deep
35047 * @param {Boolean} anim
35049 "beforeexpand" : true,
35051 * @event beforecollapse
35052 * Fires before this node is collapsed, return false to cancel.
35053 * @param {Node} this This node
35054 * @param {Boolean} deep
35055 * @param {Boolean} anim
35057 "beforecollapse" : true,
35060 * Fires when this node is expanded
35061 * @param {Node} this This node
35065 * @event disabledchange
35066 * Fires when the disabled status of this node changes
35067 * @param {Node} this This node
35068 * @param {Boolean} disabled
35070 "disabledchange" : true,
35073 * Fires when this node is collapsed
35074 * @param {Node} this This node
35078 * @event beforeclick
35079 * Fires before click processing. Return false to cancel the default action.
35080 * @param {Node} this This node
35081 * @param {Roo.EventObject} e The event object
35083 "beforeclick":true,
35085 * @event checkchange
35086 * Fires when a node with a checkbox's checked property changes
35087 * @param {Node} this This node
35088 * @param {Boolean} checked
35090 "checkchange":true,
35093 * Fires when this node is clicked
35094 * @param {Node} this This node
35095 * @param {Roo.EventObject} e The event object
35100 * Fires when this node is double clicked
35101 * @param {Node} this This node
35102 * @param {Roo.EventObject} e The event object
35106 * @event contextmenu
35107 * Fires when this node is right clicked
35108 * @param {Node} this This node
35109 * @param {Roo.EventObject} e The event object
35111 "contextmenu":true,
35113 * @event beforechildrenrendered
35114 * Fires right before the child nodes for this node are rendered
35115 * @param {Node} this This node
35117 "beforechildrenrendered":true
35120 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35123 * Read-only. The UI for this node
35126 this.ui = new uiClass(this);
35128 // finally support items[]
35129 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35134 Roo.each(this.attributes.items, function(c) {
35135 this.appendChild(Roo.factory(c,Roo.Tree));
35137 delete this.attributes.items;
35142 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35143 preventHScroll: true,
35145 * Returns true if this node is expanded
35146 * @return {Boolean}
35148 isExpanded : function(){
35149 return this.expanded;
35153 * Returns the UI object for this node
35154 * @return {TreeNodeUI}
35156 getUI : function(){
35160 // private override
35161 setFirstChild : function(node){
35162 var of = this.firstChild;
35163 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35164 if(this.childrenRendered && of && node != of){
35165 of.renderIndent(true, true);
35168 this.renderIndent(true, true);
35172 // private override
35173 setLastChild : function(node){
35174 var ol = this.lastChild;
35175 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35176 if(this.childrenRendered && ol && node != ol){
35177 ol.renderIndent(true, true);
35180 this.renderIndent(true, true);
35184 // these methods are overridden to provide lazy rendering support
35185 // private override
35186 appendChild : function()
35188 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35189 if(node && this.childrenRendered){
35192 this.ui.updateExpandIcon();
35196 // private override
35197 removeChild : function(node){
35198 this.ownerTree.getSelectionModel().unselect(node);
35199 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35200 // if it's been rendered remove dom node
35201 if(this.childrenRendered){
35204 if(this.childNodes.length < 1){
35205 this.collapse(false, false);
35207 this.ui.updateExpandIcon();
35209 if(!this.firstChild) {
35210 this.childrenRendered = false;
35215 // private override
35216 insertBefore : function(node, refNode){
35217 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35218 if(newNode && refNode && this.childrenRendered){
35221 this.ui.updateExpandIcon();
35226 * Sets the text for this node
35227 * @param {String} text
35229 setText : function(text){
35230 var oldText = this.text;
35232 this.attributes.text = text;
35233 if(this.rendered){ // event without subscribing
35234 this.ui.onTextChange(this, text, oldText);
35236 this.fireEvent("textchange", this, text, oldText);
35240 * Triggers selection of this node
35242 select : function(){
35243 this.getOwnerTree().getSelectionModel().select(this);
35247 * Triggers deselection of this node
35249 unselect : function(){
35250 this.getOwnerTree().getSelectionModel().unselect(this);
35254 * Returns true if this node is selected
35255 * @return {Boolean}
35257 isSelected : function(){
35258 return this.getOwnerTree().getSelectionModel().isSelected(this);
35262 * Expand this node.
35263 * @param {Boolean} deep (optional) True to expand all children as well
35264 * @param {Boolean} anim (optional) false to cancel the default animation
35265 * @param {Function} callback (optional) A callback to be called when
35266 * expanding this node completes (does not wait for deep expand to complete).
35267 * Called with 1 parameter, this node.
35269 expand : function(deep, anim, callback){
35270 if(!this.expanded){
35271 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35274 if(!this.childrenRendered){
35275 this.renderChildren();
35277 this.expanded = true;
35279 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35280 this.ui.animExpand(function(){
35281 this.fireEvent("expand", this);
35282 if(typeof callback == "function"){
35286 this.expandChildNodes(true);
35288 }.createDelegate(this));
35292 this.fireEvent("expand", this);
35293 if(typeof callback == "function"){
35298 if(typeof callback == "function"){
35303 this.expandChildNodes(true);
35307 isHiddenRoot : function(){
35308 return this.isRoot && !this.getOwnerTree().rootVisible;
35312 * Collapse this node.
35313 * @param {Boolean} deep (optional) True to collapse all children as well
35314 * @param {Boolean} anim (optional) false to cancel the default animation
35316 collapse : function(deep, anim){
35317 if(this.expanded && !this.isHiddenRoot()){
35318 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35321 this.expanded = false;
35322 if((this.getOwnerTree().animate && anim !== false) || anim){
35323 this.ui.animCollapse(function(){
35324 this.fireEvent("collapse", this);
35326 this.collapseChildNodes(true);
35328 }.createDelegate(this));
35331 this.ui.collapse();
35332 this.fireEvent("collapse", this);
35336 var cs = this.childNodes;
35337 for(var i = 0, len = cs.length; i < len; i++) {
35338 cs[i].collapse(true, false);
35344 delayedExpand : function(delay){
35345 if(!this.expandProcId){
35346 this.expandProcId = this.expand.defer(delay, this);
35351 cancelExpand : function(){
35352 if(this.expandProcId){
35353 clearTimeout(this.expandProcId);
35355 this.expandProcId = false;
35359 * Toggles expanded/collapsed state of the node
35361 toggle : function(){
35370 * Ensures all parent nodes are expanded
35372 ensureVisible : function(callback){
35373 var tree = this.getOwnerTree();
35374 tree.expandPath(this.parentNode.getPath(), false, function(){
35375 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35376 Roo.callback(callback);
35377 }.createDelegate(this));
35381 * Expand all child nodes
35382 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35384 expandChildNodes : function(deep){
35385 var cs = this.childNodes;
35386 for(var i = 0, len = cs.length; i < len; i++) {
35387 cs[i].expand(deep);
35392 * Collapse all child nodes
35393 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35395 collapseChildNodes : function(deep){
35396 var cs = this.childNodes;
35397 for(var i = 0, len = cs.length; i < len; i++) {
35398 cs[i].collapse(deep);
35403 * Disables this node
35405 disable : function(){
35406 this.disabled = true;
35408 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35409 this.ui.onDisableChange(this, true);
35411 this.fireEvent("disabledchange", this, true);
35415 * Enables this node
35417 enable : function(){
35418 this.disabled = false;
35419 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35420 this.ui.onDisableChange(this, false);
35422 this.fireEvent("disabledchange", this, false);
35426 renderChildren : function(suppressEvent){
35427 if(suppressEvent !== false){
35428 this.fireEvent("beforechildrenrendered", this);
35430 var cs = this.childNodes;
35431 for(var i = 0, len = cs.length; i < len; i++){
35432 cs[i].render(true);
35434 this.childrenRendered = true;
35438 sort : function(fn, scope){
35439 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35440 if(this.childrenRendered){
35441 var cs = this.childNodes;
35442 for(var i = 0, len = cs.length; i < len; i++){
35443 cs[i].render(true);
35449 render : function(bulkRender){
35450 this.ui.render(bulkRender);
35451 if(!this.rendered){
35452 this.rendered = true;
35454 this.expanded = false;
35455 this.expand(false, false);
35461 renderIndent : function(deep, refresh){
35463 this.ui.childIndent = null;
35465 this.ui.renderIndent();
35466 if(deep === true && this.childrenRendered){
35467 var cs = this.childNodes;
35468 for(var i = 0, len = cs.length; i < len; i++){
35469 cs[i].renderIndent(true, refresh);
35475 * Ext JS Library 1.1.1
35476 * Copyright(c) 2006-2007, Ext JS, LLC.
35478 * Originally Released Under LGPL - original licence link has changed is not relivant.
35481 * <script type="text/javascript">
35485 * @class Roo.tree.AsyncTreeNode
35486 * @extends Roo.tree.TreeNode
35487 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35489 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35491 Roo.tree.AsyncTreeNode = function(config){
35492 this.loaded = false;
35493 this.loading = false;
35494 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35496 * @event beforeload
35497 * Fires before this node is loaded, return false to cancel
35498 * @param {Node} this This node
35500 this.addEvents({'beforeload':true, 'load': true});
35503 * Fires when this node is loaded
35504 * @param {Node} this This node
35507 * The loader used by this node (defaults to using the tree's defined loader)
35512 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35513 expand : function(deep, anim, callback){
35514 if(this.loading){ // if an async load is already running, waiting til it's done
35516 var f = function(){
35517 if(!this.loading){ // done loading
35518 clearInterval(timer);
35519 this.expand(deep, anim, callback);
35521 }.createDelegate(this);
35522 timer = setInterval(f, 200);
35526 if(this.fireEvent("beforeload", this) === false){
35529 this.loading = true;
35530 this.ui.beforeLoad(this);
35531 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35533 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35537 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35541 * Returns true if this node is currently loading
35542 * @return {Boolean}
35544 isLoading : function(){
35545 return this.loading;
35548 loadComplete : function(deep, anim, callback){
35549 this.loading = false;
35550 this.loaded = true;
35551 this.ui.afterLoad(this);
35552 this.fireEvent("load", this);
35553 this.expand(deep, anim, callback);
35557 * Returns true if this node has been loaded
35558 * @return {Boolean}
35560 isLoaded : function(){
35561 return this.loaded;
35564 hasChildNodes : function(){
35565 if(!this.isLeaf() && !this.loaded){
35568 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35573 * Trigger a reload for this node
35574 * @param {Function} callback
35576 reload : function(callback){
35577 this.collapse(false, false);
35578 while(this.firstChild){
35579 this.removeChild(this.firstChild);
35581 this.childrenRendered = false;
35582 this.loaded = false;
35583 if(this.isHiddenRoot()){
35584 this.expanded = false;
35586 this.expand(false, false, callback);
35590 * Ext JS Library 1.1.1
35591 * Copyright(c) 2006-2007, Ext JS, LLC.
35593 * Originally Released Under LGPL - original licence link has changed is not relivant.
35596 * <script type="text/javascript">
35600 * @class Roo.tree.TreeNodeUI
35602 * @param {Object} node The node to render
35603 * The TreeNode UI implementation is separate from the
35604 * tree implementation. Unless you are customizing the tree UI,
35605 * you should never have to use this directly.
35607 Roo.tree.TreeNodeUI = function(node){
35609 this.rendered = false;
35610 this.animating = false;
35611 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35614 Roo.tree.TreeNodeUI.prototype = {
35615 removeChild : function(node){
35617 this.ctNode.removeChild(node.ui.getEl());
35621 beforeLoad : function(){
35622 this.addClass("x-tree-node-loading");
35625 afterLoad : function(){
35626 this.removeClass("x-tree-node-loading");
35629 onTextChange : function(node, text, oldText){
35631 this.textNode.innerHTML = text;
35635 onDisableChange : function(node, state){
35636 this.disabled = state;
35638 this.addClass("x-tree-node-disabled");
35640 this.removeClass("x-tree-node-disabled");
35644 onSelectedChange : function(state){
35647 this.addClass("x-tree-selected");
35650 this.removeClass("x-tree-selected");
35654 onMove : function(tree, node, oldParent, newParent, index, refNode){
35655 this.childIndent = null;
35657 var targetNode = newParent.ui.getContainer();
35658 if(!targetNode){//target not rendered
35659 this.holder = document.createElement("div");
35660 this.holder.appendChild(this.wrap);
35663 var insertBefore = refNode ? refNode.ui.getEl() : null;
35665 targetNode.insertBefore(this.wrap, insertBefore);
35667 targetNode.appendChild(this.wrap);
35669 this.node.renderIndent(true);
35673 addClass : function(cls){
35675 Roo.fly(this.elNode).addClass(cls);
35679 removeClass : function(cls){
35681 Roo.fly(this.elNode).removeClass(cls);
35685 remove : function(){
35687 this.holder = document.createElement("div");
35688 this.holder.appendChild(this.wrap);
35692 fireEvent : function(){
35693 return this.node.fireEvent.apply(this.node, arguments);
35696 initEvents : function(){
35697 this.node.on("move", this.onMove, this);
35698 var E = Roo.EventManager;
35699 var a = this.anchor;
35701 var el = Roo.fly(a, '_treeui');
35703 if(Roo.isOpera){ // opera render bug ignores the CSS
35704 el.setStyle("text-decoration", "none");
35707 el.on("click", this.onClick, this);
35708 el.on("dblclick", this.onDblClick, this);
35711 Roo.EventManager.on(this.checkbox,
35712 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35715 el.on("contextmenu", this.onContextMenu, this);
35717 var icon = Roo.fly(this.iconNode);
35718 icon.on("click", this.onClick, this);
35719 icon.on("dblclick", this.onDblClick, this);
35720 icon.on("contextmenu", this.onContextMenu, this);
35721 E.on(this.ecNode, "click", this.ecClick, this, true);
35723 if(this.node.disabled){
35724 this.addClass("x-tree-node-disabled");
35726 if(this.node.hidden){
35727 this.addClass("x-tree-node-disabled");
35729 var ot = this.node.getOwnerTree();
35730 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35731 if(dd && (!this.node.isRoot || ot.rootVisible)){
35732 Roo.dd.Registry.register(this.elNode, {
35734 handles: this.getDDHandles(),
35740 getDDHandles : function(){
35741 return [this.iconNode, this.textNode];
35746 this.wrap.style.display = "none";
35752 this.wrap.style.display = "";
35756 onContextMenu : function(e){
35757 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35758 e.preventDefault();
35760 this.fireEvent("contextmenu", this.node, e);
35764 onClick : function(e){
35769 if(this.fireEvent("beforeclick", this.node, e) !== false){
35770 if(!this.disabled && this.node.attributes.href){
35771 this.fireEvent("click", this.node, e);
35774 e.preventDefault();
35779 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35780 this.node.toggle();
35783 this.fireEvent("click", this.node, e);
35789 onDblClick : function(e){
35790 e.preventDefault();
35795 this.toggleCheck();
35797 if(!this.animating && this.node.hasChildNodes()){
35798 this.node.toggle();
35800 this.fireEvent("dblclick", this.node, e);
35803 onCheckChange : function(){
35804 var checked = this.checkbox.checked;
35805 this.node.attributes.checked = checked;
35806 this.fireEvent('checkchange', this.node, checked);
35809 ecClick : function(e){
35810 if(!this.animating && this.node.hasChildNodes()){
35811 this.node.toggle();
35815 startDrop : function(){
35816 this.dropping = true;
35819 // delayed drop so the click event doesn't get fired on a drop
35820 endDrop : function(){
35821 setTimeout(function(){
35822 this.dropping = false;
35823 }.createDelegate(this), 50);
35826 expand : function(){
35827 this.updateExpandIcon();
35828 this.ctNode.style.display = "";
35831 focus : function(){
35832 if(!this.node.preventHScroll){
35833 try{this.anchor.focus();
35835 }else if(!Roo.isIE){
35837 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35838 var l = noscroll.scrollLeft;
35839 this.anchor.focus();
35840 noscroll.scrollLeft = l;
35845 toggleCheck : function(value){
35846 var cb = this.checkbox;
35848 cb.checked = (value === undefined ? !cb.checked : value);
35854 this.anchor.blur();
35858 animExpand : function(callback){
35859 var ct = Roo.get(this.ctNode);
35861 if(!this.node.hasChildNodes()){
35862 this.updateExpandIcon();
35863 this.ctNode.style.display = "";
35864 Roo.callback(callback);
35867 this.animating = true;
35868 this.updateExpandIcon();
35871 callback : function(){
35872 this.animating = false;
35873 Roo.callback(callback);
35876 duration: this.node.ownerTree.duration || .25
35880 highlight : function(){
35881 var tree = this.node.getOwnerTree();
35882 Roo.fly(this.wrap).highlight(
35883 tree.hlColor || "C3DAF9",
35884 {endColor: tree.hlBaseColor}
35888 collapse : function(){
35889 this.updateExpandIcon();
35890 this.ctNode.style.display = "none";
35893 animCollapse : function(callback){
35894 var ct = Roo.get(this.ctNode);
35895 ct.enableDisplayMode('block');
35898 this.animating = true;
35899 this.updateExpandIcon();
35902 callback : function(){
35903 this.animating = false;
35904 Roo.callback(callback);
35907 duration: this.node.ownerTree.duration || .25
35911 getContainer : function(){
35912 return this.ctNode;
35915 getEl : function(){
35919 appendDDGhost : function(ghostNode){
35920 ghostNode.appendChild(this.elNode.cloneNode(true));
35923 getDDRepairXY : function(){
35924 return Roo.lib.Dom.getXY(this.iconNode);
35927 onRender : function(){
35931 render : function(bulkRender){
35932 var n = this.node, a = n.attributes;
35933 var targetNode = n.parentNode ?
35934 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35936 if(!this.rendered){
35937 this.rendered = true;
35939 this.renderElements(n, a, targetNode, bulkRender);
35942 if(this.textNode.setAttributeNS){
35943 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35945 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35948 this.textNode.setAttribute("ext:qtip", a.qtip);
35950 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35953 }else if(a.qtipCfg){
35954 a.qtipCfg.target = Roo.id(this.textNode);
35955 Roo.QuickTips.register(a.qtipCfg);
35958 if(!this.node.expanded){
35959 this.updateExpandIcon();
35962 if(bulkRender === true) {
35963 targetNode.appendChild(this.wrap);
35968 renderElements : function(n, a, targetNode, bulkRender)
35970 // add some indent caching, this helps performance when rendering a large tree
35971 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35972 var t = n.getOwnerTree();
35973 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35974 if (typeof(n.attributes.html) != 'undefined') {
35975 txt = n.attributes.html;
35977 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
35978 var cb = typeof a.checked == 'boolean';
35979 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35980 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35981 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35982 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35983 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35984 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35985 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35986 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35987 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35988 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35991 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35992 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35993 n.nextSibling.ui.getEl(), buf.join(""));
35995 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35998 this.elNode = this.wrap.childNodes[0];
35999 this.ctNode = this.wrap.childNodes[1];
36000 var cs = this.elNode.childNodes;
36001 this.indentNode = cs[0];
36002 this.ecNode = cs[1];
36003 this.iconNode = cs[2];
36006 this.checkbox = cs[3];
36009 this.anchor = cs[index];
36010 this.textNode = cs[index].firstChild;
36013 getAnchor : function(){
36014 return this.anchor;
36017 getTextEl : function(){
36018 return this.textNode;
36021 getIconEl : function(){
36022 return this.iconNode;
36025 isChecked : function(){
36026 return this.checkbox ? this.checkbox.checked : false;
36029 updateExpandIcon : function(){
36031 var n = this.node, c1, c2;
36032 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36033 var hasChild = n.hasChildNodes();
36037 c1 = "x-tree-node-collapsed";
36038 c2 = "x-tree-node-expanded";
36041 c1 = "x-tree-node-expanded";
36042 c2 = "x-tree-node-collapsed";
36045 this.removeClass("x-tree-node-leaf");
36046 this.wasLeaf = false;
36048 if(this.c1 != c1 || this.c2 != c2){
36049 Roo.fly(this.elNode).replaceClass(c1, c2);
36050 this.c1 = c1; this.c2 = c2;
36053 // this changes non-leafs into leafs if they have no children.
36054 // it's not very rational behaviour..
36056 if(!this.wasLeaf && this.node.leaf){
36057 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36060 this.wasLeaf = true;
36063 var ecc = "x-tree-ec-icon "+cls;
36064 if(this.ecc != ecc){
36065 this.ecNode.className = ecc;
36071 getChildIndent : function(){
36072 if(!this.childIndent){
36076 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36078 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36080 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36085 this.childIndent = buf.join("");
36087 return this.childIndent;
36090 renderIndent : function(){
36093 var p = this.node.parentNode;
36095 indent = p.ui.getChildIndent();
36097 if(this.indentMarkup != indent){ // don't rerender if not required
36098 this.indentNode.innerHTML = indent;
36099 this.indentMarkup = indent;
36101 this.updateExpandIcon();
36106 Roo.tree.RootTreeNodeUI = function(){
36107 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36109 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36110 render : function(){
36111 if(!this.rendered){
36112 var targetNode = this.node.ownerTree.innerCt.dom;
36113 this.node.expanded = true;
36114 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36115 this.wrap = this.ctNode = targetNode.firstChild;
36118 collapse : function(){
36120 expand : function(){
36124 * Ext JS Library 1.1.1
36125 * Copyright(c) 2006-2007, Ext JS, LLC.
36127 * Originally Released Under LGPL - original licence link has changed is not relivant.
36130 * <script type="text/javascript">
36133 * @class Roo.tree.TreeLoader
36134 * @extends Roo.util.Observable
36135 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36136 * nodes from a specified URL. The response must be a javascript Array definition
36137 * who's elements are node definition objects. eg:
36142 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36143 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36150 * The old style respose with just an array is still supported, but not recommended.
36153 * A server request is sent, and child nodes are loaded only when a node is expanded.
36154 * The loading node's id is passed to the server under the parameter name "node" to
36155 * enable the server to produce the correct child nodes.
36157 * To pass extra parameters, an event handler may be attached to the "beforeload"
36158 * event, and the parameters specified in the TreeLoader's baseParams property:
36160 myTreeLoader.on("beforeload", function(treeLoader, node) {
36161 this.baseParams.category = node.attributes.category;
36166 * This would pass an HTTP parameter called "category" to the server containing
36167 * the value of the Node's "category" attribute.
36169 * Creates a new Treeloader.
36170 * @param {Object} config A config object containing config properties.
36172 Roo.tree.TreeLoader = function(config){
36173 this.baseParams = {};
36174 this.requestMethod = "POST";
36175 Roo.apply(this, config);
36180 * @event beforeload
36181 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36182 * @param {Object} This TreeLoader object.
36183 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36184 * @param {Object} callback The callback function specified in the {@link #load} call.
36189 * Fires when the node has been successfuly loaded.
36190 * @param {Object} This TreeLoader object.
36191 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36192 * @param {Object} response The response object containing the data from the server.
36196 * @event loadexception
36197 * Fires if the network request failed.
36198 * @param {Object} This TreeLoader object.
36199 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36200 * @param {Object} response The response object containing the data from the server.
36202 loadexception : true,
36205 * Fires before a node is created, enabling you to return custom Node types
36206 * @param {Object} This TreeLoader object.
36207 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36212 Roo.tree.TreeLoader.superclass.constructor.call(this);
36215 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36217 * @cfg {String} dataUrl The URL from which to request a Json string which
36218 * specifies an array of node definition object representing the child nodes
36222 * @cfg {String} requestMethod either GET or POST
36223 * defaults to POST (due to BC)
36227 * @cfg {Object} baseParams (optional) An object containing properties which
36228 * specify HTTP parameters to be passed to each request for child nodes.
36231 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36232 * created by this loader. If the attributes sent by the server have an attribute in this object,
36233 * they take priority.
36236 * @cfg {Object} uiProviders (optional) An object containing properties which
36238 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36239 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36240 * <i>uiProvider</i> attribute of a returned child node is a string rather
36241 * than a reference to a TreeNodeUI implementation, this that string value
36242 * is used as a property name in the uiProviders object. You can define the provider named
36243 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36248 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36249 * child nodes before loading.
36251 clearOnLoad : true,
36254 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36255 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36256 * Grid query { data : [ .....] }
36261 * @cfg {String} queryParam (optional)
36262 * Name of the query as it will be passed on the querystring (defaults to 'node')
36263 * eg. the request will be ?node=[id]
36270 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36271 * This is called automatically when a node is expanded, but may be used to reload
36272 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36273 * @param {Roo.tree.TreeNode} node
36274 * @param {Function} callback
36276 load : function(node, callback){
36277 if(this.clearOnLoad){
36278 while(node.firstChild){
36279 node.removeChild(node.firstChild);
36282 if(node.attributes.children){ // preloaded json children
36283 var cs = node.attributes.children;
36284 for(var i = 0, len = cs.length; i < len; i++){
36285 node.appendChild(this.createNode(cs[i]));
36287 if(typeof callback == "function"){
36290 }else if(this.dataUrl){
36291 this.requestData(node, callback);
36295 getParams: function(node){
36296 var buf = [], bp = this.baseParams;
36297 for(var key in bp){
36298 if(typeof bp[key] != "function"){
36299 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36302 var n = this.queryParam === false ? 'node' : this.queryParam;
36303 buf.push(n + "=", encodeURIComponent(node.id));
36304 return buf.join("");
36307 requestData : function(node, callback){
36308 if(this.fireEvent("beforeload", this, node, callback) !== false){
36309 this.transId = Roo.Ajax.request({
36310 method:this.requestMethod,
36311 url: this.dataUrl||this.url,
36312 success: this.handleResponse,
36313 failure: this.handleFailure,
36315 argument: {callback: callback, node: node},
36316 params: this.getParams(node)
36319 // if the load is cancelled, make sure we notify
36320 // the node that we are done
36321 if(typeof callback == "function"){
36327 isLoading : function(){
36328 return this.transId ? true : false;
36331 abort : function(){
36332 if(this.isLoading()){
36333 Roo.Ajax.abort(this.transId);
36338 createNode : function(attr)
36340 // apply baseAttrs, nice idea Corey!
36341 if(this.baseAttrs){
36342 Roo.applyIf(attr, this.baseAttrs);
36344 if(this.applyLoader !== false){
36345 attr.loader = this;
36347 // uiProvider = depreciated..
36349 if(typeof(attr.uiProvider) == 'string'){
36350 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36351 /** eval:var:attr */ eval(attr.uiProvider);
36353 if(typeof(this.uiProviders['default']) != 'undefined') {
36354 attr.uiProvider = this.uiProviders['default'];
36357 this.fireEvent('create', this, attr);
36359 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36361 new Roo.tree.TreeNode(attr) :
36362 new Roo.tree.AsyncTreeNode(attr));
36365 processResponse : function(response, node, callback)
36367 var json = response.responseText;
36370 var o = Roo.decode(json);
36372 if (this.root === false && typeof(o.success) != undefined) {
36373 this.root = 'data'; // the default behaviour for list like data..
36376 if (this.root !== false && !o.success) {
36377 // it's a failure condition.
36378 var a = response.argument;
36379 this.fireEvent("loadexception", this, a.node, response);
36380 Roo.log("Load failed - should have a handler really");
36386 if (this.root !== false) {
36390 for(var i = 0, len = o.length; i < len; i++){
36391 var n = this.createNode(o[i]);
36393 node.appendChild(n);
36396 if(typeof callback == "function"){
36397 callback(this, node);
36400 this.handleFailure(response);
36404 handleResponse : function(response){
36405 this.transId = false;
36406 var a = response.argument;
36407 this.processResponse(response, a.node, a.callback);
36408 this.fireEvent("load", this, a.node, response);
36411 handleFailure : function(response)
36413 // should handle failure better..
36414 this.transId = false;
36415 var a = response.argument;
36416 this.fireEvent("loadexception", this, a.node, response);
36417 if(typeof a.callback == "function"){
36418 a.callback(this, a.node);
36423 * Ext JS Library 1.1.1
36424 * Copyright(c) 2006-2007, Ext JS, LLC.
36426 * Originally Released Under LGPL - original licence link has changed is not relivant.
36429 * <script type="text/javascript">
36433 * @class Roo.tree.TreeFilter
36434 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36435 * @param {TreePanel} tree
36436 * @param {Object} config (optional)
36438 Roo.tree.TreeFilter = function(tree, config){
36440 this.filtered = {};
36441 Roo.apply(this, config);
36444 Roo.tree.TreeFilter.prototype = {
36451 * Filter the data by a specific attribute.
36452 * @param {String/RegExp} value Either string that the attribute value
36453 * should start with or a RegExp to test against the attribute
36454 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36455 * @param {TreeNode} startNode (optional) The node to start the filter at.
36457 filter : function(value, attr, startNode){
36458 attr = attr || "text";
36460 if(typeof value == "string"){
36461 var vlen = value.length;
36462 // auto clear empty filter
36463 if(vlen == 0 && this.clearBlank){
36467 value = value.toLowerCase();
36469 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36471 }else if(value.exec){ // regex?
36473 return value.test(n.attributes[attr]);
36476 throw 'Illegal filter type, must be string or regex';
36478 this.filterBy(f, null, startNode);
36482 * Filter by a function. The passed function will be called with each
36483 * node in the tree (or from the startNode). If the function returns true, the node is kept
36484 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36485 * @param {Function} fn The filter function
36486 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36488 filterBy : function(fn, scope, startNode){
36489 startNode = startNode || this.tree.root;
36490 if(this.autoClear){
36493 var af = this.filtered, rv = this.reverse;
36494 var f = function(n){
36495 if(n == startNode){
36501 var m = fn.call(scope || n, n);
36509 startNode.cascade(f);
36512 if(typeof id != "function"){
36514 if(n && n.parentNode){
36515 n.parentNode.removeChild(n);
36523 * Clears the current filter. Note: with the "remove" option
36524 * set a filter cannot be cleared.
36526 clear : function(){
36528 var af = this.filtered;
36530 if(typeof id != "function"){
36537 this.filtered = {};
36542 * Ext JS Library 1.1.1
36543 * Copyright(c) 2006-2007, Ext JS, LLC.
36545 * Originally Released Under LGPL - original licence link has changed is not relivant.
36548 * <script type="text/javascript">
36553 * @class Roo.tree.TreeSorter
36554 * Provides sorting of nodes in a TreePanel
36556 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36557 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36558 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36559 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36560 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36561 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36563 * @param {TreePanel} tree
36564 * @param {Object} config
36566 Roo.tree.TreeSorter = function(tree, config){
36567 Roo.apply(this, config);
36568 tree.on("beforechildrenrendered", this.doSort, this);
36569 tree.on("append", this.updateSort, this);
36570 tree.on("insert", this.updateSort, this);
36572 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36573 var p = this.property || "text";
36574 var sortType = this.sortType;
36575 var fs = this.folderSort;
36576 var cs = this.caseSensitive === true;
36577 var leafAttr = this.leafAttr || 'leaf';
36579 this.sortFn = function(n1, n2){
36581 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36584 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36588 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36589 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36591 return dsc ? +1 : -1;
36593 return dsc ? -1 : +1;
36600 Roo.tree.TreeSorter.prototype = {
36601 doSort : function(node){
36602 node.sort(this.sortFn);
36605 compareNodes : function(n1, n2){
36606 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36609 updateSort : function(tree, node){
36610 if(node.childrenRendered){
36611 this.doSort.defer(1, this, [node]);
36616 * Ext JS Library 1.1.1
36617 * Copyright(c) 2006-2007, Ext JS, LLC.
36619 * Originally Released Under LGPL - original licence link has changed is not relivant.
36622 * <script type="text/javascript">
36625 if(Roo.dd.DropZone){
36627 Roo.tree.TreeDropZone = function(tree, config){
36628 this.allowParentInsert = false;
36629 this.allowContainerDrop = false;
36630 this.appendOnly = false;
36631 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36633 this.lastInsertClass = "x-tree-no-status";
36634 this.dragOverData = {};
36637 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36638 ddGroup : "TreeDD",
36641 expandDelay : 1000,
36643 expandNode : function(node){
36644 if(node.hasChildNodes() && !node.isExpanded()){
36645 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36649 queueExpand : function(node){
36650 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36653 cancelExpand : function(){
36654 if(this.expandProcId){
36655 clearTimeout(this.expandProcId);
36656 this.expandProcId = false;
36660 isValidDropPoint : function(n, pt, dd, e, data){
36661 if(!n || !data){ return false; }
36662 var targetNode = n.node;
36663 var dropNode = data.node;
36664 // default drop rules
36665 if(!(targetNode && targetNode.isTarget && pt)){
36668 if(pt == "append" && targetNode.allowChildren === false){
36671 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36674 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36677 // reuse the object
36678 var overEvent = this.dragOverData;
36679 overEvent.tree = this.tree;
36680 overEvent.target = targetNode;
36681 overEvent.data = data;
36682 overEvent.point = pt;
36683 overEvent.source = dd;
36684 overEvent.rawEvent = e;
36685 overEvent.dropNode = dropNode;
36686 overEvent.cancel = false;
36687 var result = this.tree.fireEvent("nodedragover", overEvent);
36688 return overEvent.cancel === false && result !== false;
36691 getDropPoint : function(e, n, dd)
36695 return tn.allowChildren !== false ? "append" : false; // always append for root
36697 var dragEl = n.ddel;
36698 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36699 var y = Roo.lib.Event.getPageY(e);
36700 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36702 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36703 var noAppend = tn.allowChildren === false;
36704 if(this.appendOnly || tn.parentNode.allowChildren === false){
36705 return noAppend ? false : "append";
36707 var noBelow = false;
36708 if(!this.allowParentInsert){
36709 noBelow = tn.hasChildNodes() && tn.isExpanded();
36711 var q = (b - t) / (noAppend ? 2 : 3);
36712 if(y >= t && y < (t + q)){
36714 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36721 onNodeEnter : function(n, dd, e, data)
36723 this.cancelExpand();
36726 onNodeOver : function(n, dd, e, data)
36729 var pt = this.getDropPoint(e, n, dd);
36732 // auto node expand check
36733 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36734 this.queueExpand(node);
36735 }else if(pt != "append"){
36736 this.cancelExpand();
36739 // set the insert point style on the target node
36740 var returnCls = this.dropNotAllowed;
36741 if(this.isValidDropPoint(n, pt, dd, e, data)){
36746 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36747 cls = "x-tree-drag-insert-above";
36748 }else if(pt == "below"){
36749 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36750 cls = "x-tree-drag-insert-below";
36752 returnCls = "x-tree-drop-ok-append";
36753 cls = "x-tree-drag-append";
36755 if(this.lastInsertClass != cls){
36756 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36757 this.lastInsertClass = cls;
36764 onNodeOut : function(n, dd, e, data){
36766 this.cancelExpand();
36767 this.removeDropIndicators(n);
36770 onNodeDrop : function(n, dd, e, data){
36771 var point = this.getDropPoint(e, n, dd);
36772 var targetNode = n.node;
36773 targetNode.ui.startDrop();
36774 if(!this.isValidDropPoint(n, point, dd, e, data)){
36775 targetNode.ui.endDrop();
36778 // first try to find the drop node
36779 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36782 target: targetNode,
36787 dropNode: dropNode,
36790 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36791 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36792 targetNode.ui.endDrop();
36795 // allow target changing
36796 targetNode = dropEvent.target;
36797 if(point == "append" && !targetNode.isExpanded()){
36798 targetNode.expand(false, null, function(){
36799 this.completeDrop(dropEvent);
36800 }.createDelegate(this));
36802 this.completeDrop(dropEvent);
36807 completeDrop : function(de){
36808 var ns = de.dropNode, p = de.point, t = de.target;
36809 if(!(ns instanceof Array)){
36813 for(var i = 0, len = ns.length; i < len; i++){
36816 t.parentNode.insertBefore(n, t);
36817 }else if(p == "below"){
36818 t.parentNode.insertBefore(n, t.nextSibling);
36824 if(this.tree.hlDrop){
36828 this.tree.fireEvent("nodedrop", de);
36831 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36832 if(this.tree.hlDrop){
36833 dropNode.ui.focus();
36834 dropNode.ui.highlight();
36836 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36839 getTree : function(){
36843 removeDropIndicators : function(n){
36846 Roo.fly(el).removeClass([
36847 "x-tree-drag-insert-above",
36848 "x-tree-drag-insert-below",
36849 "x-tree-drag-append"]);
36850 this.lastInsertClass = "_noclass";
36854 beforeDragDrop : function(target, e, id){
36855 this.cancelExpand();
36859 afterRepair : function(data){
36860 if(data && Roo.enableFx){
36861 data.node.ui.highlight();
36871 * Ext JS Library 1.1.1
36872 * Copyright(c) 2006-2007, Ext JS, LLC.
36874 * Originally Released Under LGPL - original licence link has changed is not relivant.
36877 * <script type="text/javascript">
36881 if(Roo.dd.DragZone){
36882 Roo.tree.TreeDragZone = function(tree, config){
36883 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36887 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36888 ddGroup : "TreeDD",
36890 onBeforeDrag : function(data, e){
36892 return n && n.draggable && !n.disabled;
36896 onInitDrag : function(e){
36897 var data = this.dragData;
36898 this.tree.getSelectionModel().select(data.node);
36899 this.proxy.update("");
36900 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36901 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36904 getRepairXY : function(e, data){
36905 return data.node.ui.getDDRepairXY();
36908 onEndDrag : function(data, e){
36909 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36914 onValidDrop : function(dd, e, id){
36915 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36919 beforeInvalidDrop : function(e, id){
36920 // this scrolls the original position back into view
36921 var sm = this.tree.getSelectionModel();
36922 sm.clearSelections();
36923 sm.select(this.dragData.node);
36928 * Ext JS Library 1.1.1
36929 * Copyright(c) 2006-2007, Ext JS, LLC.
36931 * Originally Released Under LGPL - original licence link has changed is not relivant.
36934 * <script type="text/javascript">
36937 * @class Roo.tree.TreeEditor
36938 * @extends Roo.Editor
36939 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36940 * as the editor field.
36942 * @param {Object} config (used to be the tree panel.)
36943 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36945 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36946 * @cfg {Roo.form.TextField|Object} field The field configuration
36950 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36953 if (oldconfig) { // old style..
36954 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36957 tree = config.tree;
36958 config.field = config.field || {};
36959 config.field.xtype = 'TextField';
36960 field = Roo.factory(config.field, Roo.form);
36962 config = config || {};
36967 * @event beforenodeedit
36968 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36969 * false from the handler of this event.
36970 * @param {Editor} this
36971 * @param {Roo.tree.Node} node
36973 "beforenodeedit" : true
36977 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36981 tree.on('beforeclick', this.beforeNodeClick, this);
36982 tree.getTreeEl().on('mousedown', this.hide, this);
36983 this.on('complete', this.updateNode, this);
36984 this.on('beforestartedit', this.fitToTree, this);
36985 this.on('startedit', this.bindScroll, this, {delay:10});
36986 this.on('specialkey', this.onSpecialKey, this);
36989 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36991 * @cfg {String} alignment
36992 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36998 * @cfg {Boolean} hideEl
36999 * True to hide the bound element while the editor is displayed (defaults to false)
37003 * @cfg {String} cls
37004 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37006 cls: "x-small-editor x-tree-editor",
37008 * @cfg {Boolean} shim
37009 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37015 * @cfg {Number} maxWidth
37016 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37017 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37018 * scroll and client offsets into account prior to each edit.
37025 fitToTree : function(ed, el){
37026 var td = this.tree.getTreeEl().dom, nd = el.dom;
37027 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37028 td.scrollLeft = nd.offsetLeft;
37032 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37033 this.setSize(w, '');
37035 return this.fireEvent('beforenodeedit', this, this.editNode);
37040 triggerEdit : function(node){
37041 this.completeEdit();
37042 this.editNode = node;
37043 this.startEdit(node.ui.textNode, node.text);
37047 bindScroll : function(){
37048 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37052 beforeNodeClick : function(node, e){
37053 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37054 this.lastClick = new Date();
37055 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37057 this.triggerEdit(node);
37064 updateNode : function(ed, value){
37065 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37066 this.editNode.setText(value);
37070 onHide : function(){
37071 Roo.tree.TreeEditor.superclass.onHide.call(this);
37073 this.editNode.ui.focus();
37078 onSpecialKey : function(field, e){
37079 var k = e.getKey();
37083 }else if(k == e.ENTER && !e.hasModifier()){
37085 this.completeEdit();
37088 });//<Script type="text/javascript">
37091 * Ext JS Library 1.1.1
37092 * Copyright(c) 2006-2007, Ext JS, LLC.
37094 * Originally Released Under LGPL - original licence link has changed is not relivant.
37097 * <script type="text/javascript">
37101 * Not documented??? - probably should be...
37104 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37105 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37107 renderElements : function(n, a, targetNode, bulkRender){
37108 //consel.log("renderElements?");
37109 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37111 var t = n.getOwnerTree();
37112 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37114 var cols = t.columns;
37115 var bw = t.borderWidth;
37117 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37118 var cb = typeof a.checked == "boolean";
37119 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37120 var colcls = 'x-t-' + tid + '-c0';
37122 '<li class="x-tree-node">',
37125 '<div class="x-tree-node-el ', a.cls,'">',
37127 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37130 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37131 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37132 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37133 (a.icon ? ' x-tree-node-inline-icon' : ''),
37134 (a.iconCls ? ' '+a.iconCls : ''),
37135 '" unselectable="on" />',
37136 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37137 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37139 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37140 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37141 '<span unselectable="on" qtip="' + tx + '">',
37145 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37146 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37148 for(var i = 1, len = cols.length; i < len; i++){
37150 colcls = 'x-t-' + tid + '-c' +i;
37151 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37152 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37153 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37159 '<div class="x-clear"></div></div>',
37160 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37163 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37164 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37165 n.nextSibling.ui.getEl(), buf.join(""));
37167 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37169 var el = this.wrap.firstChild;
37171 this.elNode = el.firstChild;
37172 this.ranchor = el.childNodes[1];
37173 this.ctNode = this.wrap.childNodes[1];
37174 var cs = el.firstChild.childNodes;
37175 this.indentNode = cs[0];
37176 this.ecNode = cs[1];
37177 this.iconNode = cs[2];
37180 this.checkbox = cs[3];
37183 this.anchor = cs[index];
37185 this.textNode = cs[index].firstChild;
37187 //el.on("click", this.onClick, this);
37188 //el.on("dblclick", this.onDblClick, this);
37191 // console.log(this);
37193 initEvents : function(){
37194 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37197 var a = this.ranchor;
37199 var el = Roo.get(a);
37201 if(Roo.isOpera){ // opera render bug ignores the CSS
37202 el.setStyle("text-decoration", "none");
37205 el.on("click", this.onClick, this);
37206 el.on("dblclick", this.onDblClick, this);
37207 el.on("contextmenu", this.onContextMenu, this);
37211 /*onSelectedChange : function(state){
37214 this.addClass("x-tree-selected");
37217 this.removeClass("x-tree-selected");
37220 addClass : function(cls){
37222 Roo.fly(this.elRow).addClass(cls);
37228 removeClass : function(cls){
37230 Roo.fly(this.elRow).removeClass(cls);
37236 });//<Script type="text/javascript">
37240 * Ext JS Library 1.1.1
37241 * Copyright(c) 2006-2007, Ext JS, LLC.
37243 * Originally Released Under LGPL - original licence link has changed is not relivant.
37246 * <script type="text/javascript">
37251 * @class Roo.tree.ColumnTree
37252 * @extends Roo.data.TreePanel
37253 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37254 * @cfg {int} borderWidth compined right/left border allowance
37256 * @param {String/HTMLElement/Element} el The container element
37257 * @param {Object} config
37259 Roo.tree.ColumnTree = function(el, config)
37261 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37265 * Fire this event on a container when it resizes
37266 * @param {int} w Width
37267 * @param {int} h Height
37271 this.on('resize', this.onResize, this);
37274 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37278 borderWidth: Roo.isBorderBox ? 0 : 2,
37281 render : function(){
37282 // add the header.....
37284 Roo.tree.ColumnTree.superclass.render.apply(this);
37286 this.el.addClass('x-column-tree');
37288 this.headers = this.el.createChild(
37289 {cls:'x-tree-headers'},this.innerCt.dom);
37291 var cols = this.columns, c;
37292 var totalWidth = 0;
37294 var len = cols.length;
37295 for(var i = 0; i < len; i++){
37297 totalWidth += c.width;
37298 this.headEls.push(this.headers.createChild({
37299 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37301 cls:'x-tree-hd-text',
37304 style:'width:'+(c.width-this.borderWidth)+'px;'
37307 this.headers.createChild({cls:'x-clear'});
37308 // prevent floats from wrapping when clipped
37309 this.headers.setWidth(totalWidth);
37310 //this.innerCt.setWidth(totalWidth);
37311 this.innerCt.setStyle({ overflow: 'auto' });
37312 this.onResize(this.width, this.height);
37316 onResize : function(w,h)
37321 this.innerCt.setWidth(this.width);
37322 this.innerCt.setHeight(this.height-20);
37325 var cols = this.columns, c;
37326 var totalWidth = 0;
37328 var len = cols.length;
37329 for(var i = 0; i < len; i++){
37331 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37332 // it's the expander..
37333 expEl = this.headEls[i];
37336 totalWidth += c.width;
37340 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37342 this.headers.setWidth(w-20);
37351 * Ext JS Library 1.1.1
37352 * Copyright(c) 2006-2007, Ext JS, LLC.
37354 * Originally Released Under LGPL - original licence link has changed is not relivant.
37357 * <script type="text/javascript">
37361 * @class Roo.menu.Menu
37362 * @extends Roo.util.Observable
37363 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37364 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37366 * Creates a new Menu
37367 * @param {Object} config Configuration options
37369 Roo.menu.Menu = function(config){
37371 Roo.menu.Menu.superclass.constructor.call(this, config);
37373 this.id = this.id || Roo.id();
37376 * @event beforeshow
37377 * Fires before this menu is displayed
37378 * @param {Roo.menu.Menu} this
37382 * @event beforehide
37383 * Fires before this menu is hidden
37384 * @param {Roo.menu.Menu} this
37389 * Fires after this menu is displayed
37390 * @param {Roo.menu.Menu} this
37395 * Fires after this menu is hidden
37396 * @param {Roo.menu.Menu} this
37401 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37402 * @param {Roo.menu.Menu} this
37403 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37404 * @param {Roo.EventObject} e
37409 * Fires when the mouse is hovering over this menu
37410 * @param {Roo.menu.Menu} this
37411 * @param {Roo.EventObject} e
37412 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37417 * Fires when the mouse exits this menu
37418 * @param {Roo.menu.Menu} this
37419 * @param {Roo.EventObject} e
37420 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37425 * Fires when a menu item contained in this menu is clicked
37426 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37427 * @param {Roo.EventObject} e
37431 if (this.registerMenu) {
37432 Roo.menu.MenuMgr.register(this);
37435 var mis = this.items;
37436 this.items = new Roo.util.MixedCollection();
37438 this.add.apply(this, mis);
37442 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37444 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37448 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37449 * for bottom-right shadow (defaults to "sides")
37453 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37454 * this menu (defaults to "tl-tr?")
37456 subMenuAlign : "tl-tr?",
37458 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37459 * relative to its element of origin (defaults to "tl-bl?")
37461 defaultAlign : "tl-bl?",
37463 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37465 allowOtherMenus : false,
37467 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37469 registerMenu : true,
37474 render : function(){
37478 var el = this.el = new Roo.Layer({
37480 shadow:this.shadow,
37482 parentEl: this.parentEl || document.body,
37486 this.keyNav = new Roo.menu.MenuNav(this);
37489 el.addClass("x-menu-plain");
37492 el.addClass(this.cls);
37494 // generic focus element
37495 this.focusEl = el.createChild({
37496 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37498 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37499 //disabling touch- as it's causing issues ..
37500 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37501 ul.on('click' , this.onClick, this);
37504 ul.on("mouseover", this.onMouseOver, this);
37505 ul.on("mouseout", this.onMouseOut, this);
37506 this.items.each(function(item){
37511 var li = document.createElement("li");
37512 li.className = "x-menu-list-item";
37513 ul.dom.appendChild(li);
37514 item.render(li, this);
37521 autoWidth : function(){
37522 var el = this.el, ul = this.ul;
37526 var w = this.width;
37529 }else if(Roo.isIE){
37530 el.setWidth(this.minWidth);
37531 var t = el.dom.offsetWidth; // force recalc
37532 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37537 delayAutoWidth : function(){
37540 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37542 this.awTask.delay(20);
37547 findTargetItem : function(e){
37548 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37549 if(t && t.menuItemId){
37550 return this.items.get(t.menuItemId);
37555 onClick : function(e){
37556 Roo.log("menu.onClick");
37557 var t = this.findTargetItem(e);
37562 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37563 if(t == this.activeItem && t.shouldDeactivate(e)){
37564 this.activeItem.deactivate();
37565 delete this.activeItem;
37569 this.setActiveItem(t, true);
37577 this.fireEvent("click", this, t, e);
37581 setActiveItem : function(item, autoExpand){
37582 if(item != this.activeItem){
37583 if(this.activeItem){
37584 this.activeItem.deactivate();
37586 this.activeItem = item;
37587 item.activate(autoExpand);
37588 }else if(autoExpand){
37594 tryActivate : function(start, step){
37595 var items = this.items;
37596 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37597 var item = items.get(i);
37598 if(!item.disabled && item.canActivate){
37599 this.setActiveItem(item, false);
37607 onMouseOver : function(e){
37609 if(t = this.findTargetItem(e)){
37610 if(t.canActivate && !t.disabled){
37611 this.setActiveItem(t, true);
37614 this.fireEvent("mouseover", this, e, t);
37618 onMouseOut : function(e){
37620 if(t = this.findTargetItem(e)){
37621 if(t == this.activeItem && t.shouldDeactivate(e)){
37622 this.activeItem.deactivate();
37623 delete this.activeItem;
37626 this.fireEvent("mouseout", this, e, t);
37630 * Read-only. Returns true if the menu is currently displayed, else false.
37633 isVisible : function(){
37634 return this.el && !this.hidden;
37638 * Displays this menu relative to another element
37639 * @param {String/HTMLElement/Roo.Element} element The element to align to
37640 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37641 * the element (defaults to this.defaultAlign)
37642 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37644 show : function(el, pos, parentMenu){
37645 this.parentMenu = parentMenu;
37649 this.fireEvent("beforeshow", this);
37650 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37654 * Displays this menu at a specific xy position
37655 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37656 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37658 showAt : function(xy, parentMenu, /* private: */_e){
37659 this.parentMenu = parentMenu;
37664 this.fireEvent("beforeshow", this);
37665 xy = this.el.adjustForConstraints(xy);
37669 this.hidden = false;
37671 this.fireEvent("show", this);
37674 focus : function(){
37676 this.doFocus.defer(50, this);
37680 doFocus : function(){
37682 this.focusEl.focus();
37687 * Hides this menu and optionally all parent menus
37688 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37690 hide : function(deep){
37691 if(this.el && this.isVisible()){
37692 this.fireEvent("beforehide", this);
37693 if(this.activeItem){
37694 this.activeItem.deactivate();
37695 this.activeItem = null;
37698 this.hidden = true;
37699 this.fireEvent("hide", this);
37701 if(deep === true && this.parentMenu){
37702 this.parentMenu.hide(true);
37707 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37708 * Any of the following are valid:
37710 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37711 * <li>An HTMLElement object which will be converted to a menu item</li>
37712 * <li>A menu item config object that will be created as a new menu item</li>
37713 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37714 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37719 var menu = new Roo.menu.Menu();
37721 // Create a menu item to add by reference
37722 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37724 // Add a bunch of items at once using different methods.
37725 // Only the last item added will be returned.
37726 var item = menu.add(
37727 menuItem, // add existing item by ref
37728 'Dynamic Item', // new TextItem
37729 '-', // new separator
37730 { text: 'Config Item' } // new item by config
37733 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37734 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37737 var a = arguments, l = a.length, item;
37738 for(var i = 0; i < l; i++){
37740 if ((typeof(el) == "object") && el.xtype && el.xns) {
37741 el = Roo.factory(el, Roo.menu);
37744 if(el.render){ // some kind of Item
37745 item = this.addItem(el);
37746 }else if(typeof el == "string"){ // string
37747 if(el == "separator" || el == "-"){
37748 item = this.addSeparator();
37750 item = this.addText(el);
37752 }else if(el.tagName || el.el){ // element
37753 item = this.addElement(el);
37754 }else if(typeof el == "object"){ // must be menu item config?
37755 item = this.addMenuItem(el);
37762 * Returns this menu's underlying {@link Roo.Element} object
37763 * @return {Roo.Element} The element
37765 getEl : function(){
37773 * Adds a separator bar to the menu
37774 * @return {Roo.menu.Item} The menu item that was added
37776 addSeparator : function(){
37777 return this.addItem(new Roo.menu.Separator());
37781 * Adds an {@link Roo.Element} object to the menu
37782 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37783 * @return {Roo.menu.Item} The menu item that was added
37785 addElement : function(el){
37786 return this.addItem(new Roo.menu.BaseItem(el));
37790 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37791 * @param {Roo.menu.Item} item The menu item to add
37792 * @return {Roo.menu.Item} The menu item that was added
37794 addItem : function(item){
37795 this.items.add(item);
37797 var li = document.createElement("li");
37798 li.className = "x-menu-list-item";
37799 this.ul.dom.appendChild(li);
37800 item.render(li, this);
37801 this.delayAutoWidth();
37807 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37808 * @param {Object} config A MenuItem config object
37809 * @return {Roo.menu.Item} The menu item that was added
37811 addMenuItem : function(config){
37812 if(!(config instanceof Roo.menu.Item)){
37813 if(typeof config.checked == "boolean"){ // must be check menu item config?
37814 config = new Roo.menu.CheckItem(config);
37816 config = new Roo.menu.Item(config);
37819 return this.addItem(config);
37823 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37824 * @param {String} text The text to display in the menu item
37825 * @return {Roo.menu.Item} The menu item that was added
37827 addText : function(text){
37828 return this.addItem(new Roo.menu.TextItem({ text : text }));
37832 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37833 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37834 * @param {Roo.menu.Item} item The menu item to add
37835 * @return {Roo.menu.Item} The menu item that was added
37837 insert : function(index, item){
37838 this.items.insert(index, item);
37840 var li = document.createElement("li");
37841 li.className = "x-menu-list-item";
37842 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37843 item.render(li, this);
37844 this.delayAutoWidth();
37850 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37851 * @param {Roo.menu.Item} item The menu item to remove
37853 remove : function(item){
37854 this.items.removeKey(item.id);
37859 * Removes and destroys all items in the menu
37861 removeAll : function(){
37863 while(f = this.items.first()){
37869 // MenuNav is a private utility class used internally by the Menu
37870 Roo.menu.MenuNav = function(menu){
37871 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37872 this.scope = this.menu = menu;
37875 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37876 doRelay : function(e, h){
37877 var k = e.getKey();
37878 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37879 this.menu.tryActivate(0, 1);
37882 return h.call(this.scope || this, e, this.menu);
37885 up : function(e, m){
37886 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37887 m.tryActivate(m.items.length-1, -1);
37891 down : function(e, m){
37892 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37893 m.tryActivate(0, 1);
37897 right : function(e, m){
37899 m.activeItem.expandMenu(true);
37903 left : function(e, m){
37905 if(m.parentMenu && m.parentMenu.activeItem){
37906 m.parentMenu.activeItem.activate();
37910 enter : function(e, m){
37912 e.stopPropagation();
37913 m.activeItem.onClick(e);
37914 m.fireEvent("click", this, m.activeItem);
37920 * Ext JS Library 1.1.1
37921 * Copyright(c) 2006-2007, Ext JS, LLC.
37923 * Originally Released Under LGPL - original licence link has changed is not relivant.
37926 * <script type="text/javascript">
37930 * @class Roo.menu.MenuMgr
37931 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37934 Roo.menu.MenuMgr = function(){
37935 var menus, active, groups = {}, attached = false, lastShow = new Date();
37937 // private - called when first menu is created
37940 active = new Roo.util.MixedCollection();
37941 Roo.get(document).addKeyListener(27, function(){
37942 if(active.length > 0){
37949 function hideAll(){
37950 if(active && active.length > 0){
37951 var c = active.clone();
37952 c.each(function(m){
37959 function onHide(m){
37961 if(active.length < 1){
37962 Roo.get(document).un("mousedown", onMouseDown);
37968 function onShow(m){
37969 var last = active.last();
37970 lastShow = new Date();
37973 Roo.get(document).on("mousedown", onMouseDown);
37977 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37978 m.parentMenu.activeChild = m;
37979 }else if(last && last.isVisible()){
37980 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37985 function onBeforeHide(m){
37987 m.activeChild.hide();
37989 if(m.autoHideTimer){
37990 clearTimeout(m.autoHideTimer);
37991 delete m.autoHideTimer;
37996 function onBeforeShow(m){
37997 var pm = m.parentMenu;
37998 if(!pm && !m.allowOtherMenus){
38000 }else if(pm && pm.activeChild && active != m){
38001 pm.activeChild.hide();
38006 function onMouseDown(e){
38007 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38013 function onBeforeCheck(mi, state){
38015 var g = groups[mi.group];
38016 for(var i = 0, l = g.length; i < l; i++){
38018 g[i].setChecked(false);
38027 * Hides all menus that are currently visible
38029 hideAll : function(){
38034 register : function(menu){
38038 menus[menu.id] = menu;
38039 menu.on("beforehide", onBeforeHide);
38040 menu.on("hide", onHide);
38041 menu.on("beforeshow", onBeforeShow);
38042 menu.on("show", onShow);
38043 var g = menu.group;
38044 if(g && menu.events["checkchange"]){
38048 groups[g].push(menu);
38049 menu.on("checkchange", onCheck);
38054 * Returns a {@link Roo.menu.Menu} object
38055 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38056 * be used to generate and return a new Menu instance.
38058 get : function(menu){
38059 if(typeof menu == "string"){ // menu id
38060 return menus[menu];
38061 }else if(menu.events){ // menu instance
38063 }else if(typeof menu.length == 'number'){ // array of menu items?
38064 return new Roo.menu.Menu({items:menu});
38065 }else{ // otherwise, must be a config
38066 return new Roo.menu.Menu(menu);
38071 unregister : function(menu){
38072 delete menus[menu.id];
38073 menu.un("beforehide", onBeforeHide);
38074 menu.un("hide", onHide);
38075 menu.un("beforeshow", onBeforeShow);
38076 menu.un("show", onShow);
38077 var g = menu.group;
38078 if(g && menu.events["checkchange"]){
38079 groups[g].remove(menu);
38080 menu.un("checkchange", onCheck);
38085 registerCheckable : function(menuItem){
38086 var g = menuItem.group;
38091 groups[g].push(menuItem);
38092 menuItem.on("beforecheckchange", onBeforeCheck);
38097 unregisterCheckable : function(menuItem){
38098 var g = menuItem.group;
38100 groups[g].remove(menuItem);
38101 menuItem.un("beforecheckchange", onBeforeCheck);
38107 * Ext JS Library 1.1.1
38108 * Copyright(c) 2006-2007, Ext JS, LLC.
38110 * Originally Released Under LGPL - original licence link has changed is not relivant.
38113 * <script type="text/javascript">
38118 * @class Roo.menu.BaseItem
38119 * @extends Roo.Component
38120 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38121 * management and base configuration options shared by all menu components.
38123 * Creates a new BaseItem
38124 * @param {Object} config Configuration options
38126 Roo.menu.BaseItem = function(config){
38127 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38132 * Fires when this item is clicked
38133 * @param {Roo.menu.BaseItem} this
38134 * @param {Roo.EventObject} e
38139 * Fires when this item is activated
38140 * @param {Roo.menu.BaseItem} this
38144 * @event deactivate
38145 * Fires when this item is deactivated
38146 * @param {Roo.menu.BaseItem} this
38152 this.on("click", this.handler, this.scope, true);
38156 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38158 * @cfg {Function} handler
38159 * A function that will handle the click event of this menu item (defaults to undefined)
38162 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38164 canActivate : false,
38167 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38172 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38174 activeClass : "x-menu-item-active",
38176 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38178 hideOnClick : true,
38180 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38185 ctype: "Roo.menu.BaseItem",
38188 actionMode : "container",
38191 render : function(container, parentMenu){
38192 this.parentMenu = parentMenu;
38193 Roo.menu.BaseItem.superclass.render.call(this, container);
38194 this.container.menuItemId = this.id;
38198 onRender : function(container, position){
38199 this.el = Roo.get(this.el);
38200 container.dom.appendChild(this.el.dom);
38204 onClick : function(e){
38205 if(!this.disabled && this.fireEvent("click", this, e) !== false
38206 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38207 this.handleClick(e);
38214 activate : function(){
38218 var li = this.container;
38219 li.addClass(this.activeClass);
38220 this.region = li.getRegion().adjust(2, 2, -2, -2);
38221 this.fireEvent("activate", this);
38226 deactivate : function(){
38227 this.container.removeClass(this.activeClass);
38228 this.fireEvent("deactivate", this);
38232 shouldDeactivate : function(e){
38233 return !this.region || !this.region.contains(e.getPoint());
38237 handleClick : function(e){
38238 if(this.hideOnClick){
38239 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38244 expandMenu : function(autoActivate){
38249 hideMenu : function(){
38254 * Ext JS Library 1.1.1
38255 * Copyright(c) 2006-2007, Ext JS, LLC.
38257 * Originally Released Under LGPL - original licence link has changed is not relivant.
38260 * <script type="text/javascript">
38264 * @class Roo.menu.Adapter
38265 * @extends Roo.menu.BaseItem
38266 * 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.
38267 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38269 * Creates a new Adapter
38270 * @param {Object} config Configuration options
38272 Roo.menu.Adapter = function(component, config){
38273 Roo.menu.Adapter.superclass.constructor.call(this, config);
38274 this.component = component;
38276 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38278 canActivate : true,
38281 onRender : function(container, position){
38282 this.component.render(container);
38283 this.el = this.component.getEl();
38287 activate : function(){
38291 this.component.focus();
38292 this.fireEvent("activate", this);
38297 deactivate : function(){
38298 this.fireEvent("deactivate", this);
38302 disable : function(){
38303 this.component.disable();
38304 Roo.menu.Adapter.superclass.disable.call(this);
38308 enable : function(){
38309 this.component.enable();
38310 Roo.menu.Adapter.superclass.enable.call(this);
38314 * Ext JS Library 1.1.1
38315 * Copyright(c) 2006-2007, Ext JS, LLC.
38317 * Originally Released Under LGPL - original licence link has changed is not relivant.
38320 * <script type="text/javascript">
38324 * @class Roo.menu.TextItem
38325 * @extends Roo.menu.BaseItem
38326 * Adds a static text string to a menu, usually used as either a heading or group separator.
38327 * Note: old style constructor with text is still supported.
38330 * Creates a new TextItem
38331 * @param {Object} cfg Configuration
38333 Roo.menu.TextItem = function(cfg){
38334 if (typeof(cfg) == 'string') {
38337 Roo.apply(this,cfg);
38340 Roo.menu.TextItem.superclass.constructor.call(this);
38343 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38345 * @cfg {Boolean} text Text to show on item.
38350 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38352 hideOnClick : false,
38354 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38356 itemCls : "x-menu-text",
38359 onRender : function(){
38360 var s = document.createElement("span");
38361 s.className = this.itemCls;
38362 s.innerHTML = this.text;
38364 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38368 * Ext JS Library 1.1.1
38369 * Copyright(c) 2006-2007, Ext JS, LLC.
38371 * Originally Released Under LGPL - original licence link has changed is not relivant.
38374 * <script type="text/javascript">
38378 * @class Roo.menu.Separator
38379 * @extends Roo.menu.BaseItem
38380 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38381 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38383 * @param {Object} config Configuration options
38385 Roo.menu.Separator = function(config){
38386 Roo.menu.Separator.superclass.constructor.call(this, config);
38389 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38391 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38393 itemCls : "x-menu-sep",
38395 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38397 hideOnClick : false,
38400 onRender : function(li){
38401 var s = document.createElement("span");
38402 s.className = this.itemCls;
38403 s.innerHTML = " ";
38405 li.addClass("x-menu-sep-li");
38406 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38410 * Ext JS Library 1.1.1
38411 * Copyright(c) 2006-2007, Ext JS, LLC.
38413 * Originally Released Under LGPL - original licence link has changed is not relivant.
38416 * <script type="text/javascript">
38419 * @class Roo.menu.Item
38420 * @extends Roo.menu.BaseItem
38421 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38422 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38423 * activation and click handling.
38425 * Creates a new Item
38426 * @param {Object} config Configuration options
38428 Roo.menu.Item = function(config){
38429 Roo.menu.Item.superclass.constructor.call(this, config);
38431 this.menu = Roo.menu.MenuMgr.get(this.menu);
38434 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38437 * @cfg {String} text
38438 * The text to show on the menu item.
38442 * @cfg {String} HTML to render in menu
38443 * The text to show on the menu item (HTML version).
38447 * @cfg {String} icon
38448 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38452 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38454 itemCls : "x-menu-item",
38456 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38458 canActivate : true,
38460 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38463 // doc'd in BaseItem
38467 ctype: "Roo.menu.Item",
38470 onRender : function(container, position){
38471 var el = document.createElement("a");
38472 el.hideFocus = true;
38473 el.unselectable = "on";
38474 el.href = this.href || "#";
38475 if(this.hrefTarget){
38476 el.target = this.hrefTarget;
38478 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38480 var html = this.html.length ? this.html : String.format('{0}',this.text);
38482 el.innerHTML = String.format(
38483 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38484 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38486 Roo.menu.Item.superclass.onRender.call(this, container, position);
38490 * Sets the text to display in this menu item
38491 * @param {String} text The text to display
38492 * @param {Boolean} isHTML true to indicate text is pure html.
38494 setText : function(text, isHTML){
38502 var html = this.html.length ? this.html : String.format('{0}',this.text);
38504 this.el.update(String.format(
38505 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38506 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38507 this.parentMenu.autoWidth();
38512 handleClick : function(e){
38513 if(!this.href){ // if no link defined, stop the event automatically
38516 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38520 activate : function(autoExpand){
38521 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38531 shouldDeactivate : function(e){
38532 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38533 if(this.menu && this.menu.isVisible()){
38534 return !this.menu.getEl().getRegion().contains(e.getPoint());
38542 deactivate : function(){
38543 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38548 expandMenu : function(autoActivate){
38549 if(!this.disabled && this.menu){
38550 clearTimeout(this.hideTimer);
38551 delete this.hideTimer;
38552 if(!this.menu.isVisible() && !this.showTimer){
38553 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38554 }else if (this.menu.isVisible() && autoActivate){
38555 this.menu.tryActivate(0, 1);
38561 deferExpand : function(autoActivate){
38562 delete this.showTimer;
38563 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38565 this.menu.tryActivate(0, 1);
38570 hideMenu : function(){
38571 clearTimeout(this.showTimer);
38572 delete this.showTimer;
38573 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38574 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38579 deferHide : function(){
38580 delete this.hideTimer;
38585 * Ext JS Library 1.1.1
38586 * Copyright(c) 2006-2007, Ext JS, LLC.
38588 * Originally Released Under LGPL - original licence link has changed is not relivant.
38591 * <script type="text/javascript">
38595 * @class Roo.menu.CheckItem
38596 * @extends Roo.menu.Item
38597 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38599 * Creates a new CheckItem
38600 * @param {Object} config Configuration options
38602 Roo.menu.CheckItem = function(config){
38603 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38606 * @event beforecheckchange
38607 * Fires before the checked value is set, providing an opportunity to cancel if needed
38608 * @param {Roo.menu.CheckItem} this
38609 * @param {Boolean} checked The new checked value that will be set
38611 "beforecheckchange" : true,
38613 * @event checkchange
38614 * Fires after the checked value has been set
38615 * @param {Roo.menu.CheckItem} this
38616 * @param {Boolean} checked The checked value that was set
38618 "checkchange" : true
38620 if(this.checkHandler){
38621 this.on('checkchange', this.checkHandler, this.scope);
38624 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38626 * @cfg {String} group
38627 * All check items with the same group name will automatically be grouped into a single-select
38628 * radio button group (defaults to '')
38631 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38633 itemCls : "x-menu-item x-menu-check-item",
38635 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38637 groupClass : "x-menu-group-item",
38640 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38641 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38642 * initialized with checked = true will be rendered as checked.
38647 ctype: "Roo.menu.CheckItem",
38650 onRender : function(c){
38651 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38653 this.el.addClass(this.groupClass);
38655 Roo.menu.MenuMgr.registerCheckable(this);
38657 this.checked = false;
38658 this.setChecked(true, true);
38663 destroy : function(){
38665 Roo.menu.MenuMgr.unregisterCheckable(this);
38667 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38671 * Set the checked state of this item
38672 * @param {Boolean} checked The new checked value
38673 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38675 setChecked : function(state, suppressEvent){
38676 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38677 if(this.container){
38678 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38680 this.checked = state;
38681 if(suppressEvent !== true){
38682 this.fireEvent("checkchange", this, state);
38688 handleClick : function(e){
38689 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38690 this.setChecked(!this.checked);
38692 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38696 * Ext JS Library 1.1.1
38697 * Copyright(c) 2006-2007, Ext JS, LLC.
38699 * Originally Released Under LGPL - original licence link has changed is not relivant.
38702 * <script type="text/javascript">
38706 * @class Roo.menu.DateItem
38707 * @extends Roo.menu.Adapter
38708 * A menu item that wraps the {@link Roo.DatPicker} component.
38710 * Creates a new DateItem
38711 * @param {Object} config Configuration options
38713 Roo.menu.DateItem = function(config){
38714 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38715 /** The Roo.DatePicker object @type Roo.DatePicker */
38716 this.picker = this.component;
38717 this.addEvents({select: true});
38719 this.picker.on("render", function(picker){
38720 picker.getEl().swallowEvent("click");
38721 picker.container.addClass("x-menu-date-item");
38724 this.picker.on("select", this.onSelect, this);
38727 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38729 onSelect : function(picker, date){
38730 this.fireEvent("select", this, date, picker);
38731 Roo.menu.DateItem.superclass.handleClick.call(this);
38735 * Ext JS Library 1.1.1
38736 * Copyright(c) 2006-2007, Ext JS, LLC.
38738 * Originally Released Under LGPL - original licence link has changed is not relivant.
38741 * <script type="text/javascript">
38745 * @class Roo.menu.ColorItem
38746 * @extends Roo.menu.Adapter
38747 * A menu item that wraps the {@link Roo.ColorPalette} component.
38749 * Creates a new ColorItem
38750 * @param {Object} config Configuration options
38752 Roo.menu.ColorItem = function(config){
38753 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38754 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38755 this.palette = this.component;
38756 this.relayEvents(this.palette, ["select"]);
38757 if(this.selectHandler){
38758 this.on('select', this.selectHandler, this.scope);
38761 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38763 * Ext JS Library 1.1.1
38764 * Copyright(c) 2006-2007, Ext JS, LLC.
38766 * Originally Released Under LGPL - original licence link has changed is not relivant.
38769 * <script type="text/javascript">
38774 * @class Roo.menu.DateMenu
38775 * @extends Roo.menu.Menu
38776 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38778 * Creates a new DateMenu
38779 * @param {Object} config Configuration options
38781 Roo.menu.DateMenu = function(config){
38782 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38784 var di = new Roo.menu.DateItem(config);
38787 * The {@link Roo.DatePicker} instance for this DateMenu
38790 this.picker = di.picker;
38793 * @param {DatePicker} picker
38794 * @param {Date} date
38796 this.relayEvents(di, ["select"]);
38797 this.on('beforeshow', function(){
38799 this.picker.hideMonthPicker(false);
38803 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38807 * Ext JS Library 1.1.1
38808 * Copyright(c) 2006-2007, Ext JS, LLC.
38810 * Originally Released Under LGPL - original licence link has changed is not relivant.
38813 * <script type="text/javascript">
38818 * @class Roo.menu.ColorMenu
38819 * @extends Roo.menu.Menu
38820 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38822 * Creates a new ColorMenu
38823 * @param {Object} config Configuration options
38825 Roo.menu.ColorMenu = function(config){
38826 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38828 var ci = new Roo.menu.ColorItem(config);
38831 * The {@link Roo.ColorPalette} instance for this ColorMenu
38832 * @type ColorPalette
38834 this.palette = ci.palette;
38837 * @param {ColorPalette} palette
38838 * @param {String} color
38840 this.relayEvents(ci, ["select"]);
38842 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38844 * Ext JS Library 1.1.1
38845 * Copyright(c) 2006-2007, Ext JS, LLC.
38847 * Originally Released Under LGPL - original licence link has changed is not relivant.
38850 * <script type="text/javascript">
38854 * @class Roo.form.TextItem
38855 * @extends Roo.BoxComponent
38856 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38858 * Creates a new TextItem
38859 * @param {Object} config Configuration options
38861 Roo.form.TextItem = function(config){
38862 Roo.form.TextItem.superclass.constructor.call(this, config);
38865 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
38868 * @cfg {String} tag the tag for this item (default div)
38872 * @cfg {String} html the content for this item
38876 getAutoCreate : function()
38889 onRender : function(ct, position)
38891 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
38894 var cfg = this.getAutoCreate();
38896 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38898 if (!cfg.name.length) {
38901 this.el = ct.createChild(cfg, position);
38906 * @param {String} html update the Contents of the element.
38908 setHTML : function(html)
38910 this.fieldEl.dom.innerHTML = html;
38915 * Ext JS Library 1.1.1
38916 * Copyright(c) 2006-2007, Ext JS, LLC.
38918 * Originally Released Under LGPL - original licence link has changed is not relivant.
38921 * <script type="text/javascript">
38925 * @class Roo.form.Field
38926 * @extends Roo.BoxComponent
38927 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38929 * Creates a new Field
38930 * @param {Object} config Configuration options
38932 Roo.form.Field = function(config){
38933 Roo.form.Field.superclass.constructor.call(this, config);
38936 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38938 * @cfg {String} fieldLabel Label to use when rendering a form.
38941 * @cfg {String} qtip Mouse over tip
38945 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38947 invalidClass : "x-form-invalid",
38949 * @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")
38951 invalidText : "The value in this field is invalid",
38953 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38955 focusClass : "x-form-focus",
38957 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38958 automatic validation (defaults to "keyup").
38960 validationEvent : "keyup",
38962 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38964 validateOnBlur : true,
38966 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38968 validationDelay : 250,
38970 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38971 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38973 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38975 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38977 fieldClass : "x-form-field",
38979 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38982 ----------- ----------------------------------------------------------------------
38983 qtip Display a quick tip when the user hovers over the field
38984 title Display a default browser title attribute popup
38985 under Add a block div beneath the field containing the error text
38986 side Add an error icon to the right of the field with a popup on hover
38987 [element id] Add the error text directly to the innerHTML of the specified element
38990 msgTarget : 'qtip',
38992 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38997 * @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.
39002 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39007 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39009 inputType : undefined,
39012 * @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).
39014 tabIndex : undefined,
39017 isFormField : true,
39022 * @property {Roo.Element} fieldEl
39023 * Element Containing the rendered Field (with label etc.)
39026 * @cfg {Mixed} value A value to initialize this field with.
39031 * @cfg {String} name The field's HTML name attribute.
39034 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39037 loadedValue : false,
39041 initComponent : function(){
39042 Roo.form.Field.superclass.initComponent.call(this);
39046 * Fires when this field receives input focus.
39047 * @param {Roo.form.Field} this
39052 * Fires when this field loses input focus.
39053 * @param {Roo.form.Field} this
39057 * @event specialkey
39058 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39059 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39060 * @param {Roo.form.Field} this
39061 * @param {Roo.EventObject} e The event object
39066 * Fires just before the field blurs if the field value has changed.
39067 * @param {Roo.form.Field} this
39068 * @param {Mixed} newValue The new value
39069 * @param {Mixed} oldValue The original value
39074 * Fires after the field has been marked as invalid.
39075 * @param {Roo.form.Field} this
39076 * @param {String} msg The validation message
39081 * Fires after the field has been validated with no errors.
39082 * @param {Roo.form.Field} this
39087 * Fires after the key up
39088 * @param {Roo.form.Field} this
39089 * @param {Roo.EventObject} e The event Object
39096 * Returns the name attribute of the field if available
39097 * @return {String} name The field name
39099 getName: function(){
39100 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39104 onRender : function(ct, position){
39105 Roo.form.Field.superclass.onRender.call(this, ct, position);
39107 var cfg = this.getAutoCreate();
39109 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39111 if (!cfg.name.length) {
39114 if(this.inputType){
39115 cfg.type = this.inputType;
39117 this.el = ct.createChild(cfg, position);
39119 var type = this.el.dom.type;
39121 if(type == 'password'){
39124 this.el.addClass('x-form-'+type);
39127 this.el.dom.readOnly = true;
39129 if(this.tabIndex !== undefined){
39130 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39133 this.el.addClass([this.fieldClass, this.cls]);
39138 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39139 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39140 * @return {Roo.form.Field} this
39142 applyTo : function(target){
39143 this.allowDomMove = false;
39144 this.el = Roo.get(target);
39145 this.render(this.el.dom.parentNode);
39150 initValue : function(){
39151 if(this.value !== undefined){
39152 this.setValue(this.value);
39153 }else if(this.el.dom.value.length > 0){
39154 this.setValue(this.el.dom.value);
39159 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39160 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39162 isDirty : function() {
39163 if(this.disabled) {
39166 return String(this.getValue()) !== String(this.originalValue);
39170 * stores the current value in loadedValue
39172 resetHasChanged : function()
39174 this.loadedValue = String(this.getValue());
39177 * checks the current value against the 'loaded' value.
39178 * Note - will return false if 'resetHasChanged' has not been called first.
39180 hasChanged : function()
39182 if(this.disabled || this.readOnly) {
39185 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39191 afterRender : function(){
39192 Roo.form.Field.superclass.afterRender.call(this);
39197 fireKey : function(e){
39198 //Roo.log('field ' + e.getKey());
39199 if(e.isNavKeyPress()){
39200 this.fireEvent("specialkey", this, e);
39205 * Resets the current field value to the originally loaded value and clears any validation messages
39207 reset : function(){
39208 this.setValue(this.resetValue);
39209 this.originalValue = this.getValue();
39210 this.clearInvalid();
39214 initEvents : function(){
39215 // safari killled keypress - so keydown is now used..
39216 this.el.on("keydown" , this.fireKey, this);
39217 this.el.on("focus", this.onFocus, this);
39218 this.el.on("blur", this.onBlur, this);
39219 this.el.relayEvent('keyup', this);
39221 // reference to original value for reset
39222 this.originalValue = this.getValue();
39223 this.resetValue = this.getValue();
39227 onFocus : function(){
39228 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39229 this.el.addClass(this.focusClass);
39231 if(!this.hasFocus){
39232 this.hasFocus = true;
39233 this.startValue = this.getValue();
39234 this.fireEvent("focus", this);
39238 beforeBlur : Roo.emptyFn,
39241 onBlur : function(){
39243 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39244 this.el.removeClass(this.focusClass);
39246 this.hasFocus = false;
39247 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39250 var v = this.getValue();
39251 if(String(v) !== String(this.startValue)){
39252 this.fireEvent('change', this, v, this.startValue);
39254 this.fireEvent("blur", this);
39258 * Returns whether or not the field value is currently valid
39259 * @param {Boolean} preventMark True to disable marking the field invalid
39260 * @return {Boolean} True if the value is valid, else false
39262 isValid : function(preventMark){
39266 var restore = this.preventMark;
39267 this.preventMark = preventMark === true;
39268 var v = this.validateValue(this.processValue(this.getRawValue()));
39269 this.preventMark = restore;
39274 * Validates the field value
39275 * @return {Boolean} True if the value is valid, else false
39277 validate : function(){
39278 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39279 this.clearInvalid();
39285 processValue : function(value){
39290 // Subclasses should provide the validation implementation by overriding this
39291 validateValue : function(value){
39296 * Mark this field as invalid
39297 * @param {String} msg The validation message
39299 markInvalid : function(msg){
39300 if(!this.rendered || this.preventMark){ // not rendered
39304 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39306 obj.el.addClass(this.invalidClass);
39307 msg = msg || this.invalidText;
39308 switch(this.msgTarget){
39310 obj.el.dom.qtip = msg;
39311 obj.el.dom.qclass = 'x-form-invalid-tip';
39312 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39313 Roo.QuickTips.enable();
39317 this.el.dom.title = msg;
39321 var elp = this.el.findParent('.x-form-element', 5, true);
39322 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39323 this.errorEl.setWidth(elp.getWidth(true)-20);
39325 this.errorEl.update(msg);
39326 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39329 if(!this.errorIcon){
39330 var elp = this.el.findParent('.x-form-element', 5, true);
39331 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39333 this.alignErrorIcon();
39334 this.errorIcon.dom.qtip = msg;
39335 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39336 this.errorIcon.show();
39337 this.on('resize', this.alignErrorIcon, this);
39340 var t = Roo.getDom(this.msgTarget);
39342 t.style.display = this.msgDisplay;
39345 this.fireEvent('invalid', this, msg);
39349 alignErrorIcon : function(){
39350 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39354 * Clear any invalid styles/messages for this field
39356 clearInvalid : function(){
39357 if(!this.rendered || this.preventMark){ // not rendered
39360 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39362 obj.el.removeClass(this.invalidClass);
39363 switch(this.msgTarget){
39365 obj.el.dom.qtip = '';
39368 this.el.dom.title = '';
39372 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39376 if(this.errorIcon){
39377 this.errorIcon.dom.qtip = '';
39378 this.errorIcon.hide();
39379 this.un('resize', this.alignErrorIcon, this);
39383 var t = Roo.getDom(this.msgTarget);
39385 t.style.display = 'none';
39388 this.fireEvent('valid', this);
39392 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39393 * @return {Mixed} value The field value
39395 getRawValue : function(){
39396 var v = this.el.getValue();
39402 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39403 * @return {Mixed} value The field value
39405 getValue : function(){
39406 var v = this.el.getValue();
39412 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39413 * @param {Mixed} value The value to set
39415 setRawValue : function(v){
39416 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39420 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39421 * @param {Mixed} value The value to set
39423 setValue : function(v){
39426 this.el.dom.value = (v === null || v === undefined ? '' : v);
39431 adjustSize : function(w, h){
39432 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39433 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39437 adjustWidth : function(tag, w){
39438 tag = tag.toLowerCase();
39439 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39440 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39441 if(tag == 'input'){
39444 if(tag == 'textarea'){
39447 }else if(Roo.isOpera){
39448 if(tag == 'input'){
39451 if(tag == 'textarea'){
39461 // anything other than normal should be considered experimental
39462 Roo.form.Field.msgFx = {
39464 show: function(msgEl, f){
39465 msgEl.setDisplayed('block');
39468 hide : function(msgEl, f){
39469 msgEl.setDisplayed(false).update('');
39474 show: function(msgEl, f){
39475 msgEl.slideIn('t', {stopFx:true});
39478 hide : function(msgEl, f){
39479 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39484 show: function(msgEl, f){
39485 msgEl.fixDisplay();
39486 msgEl.alignTo(f.el, 'tl-tr');
39487 msgEl.slideIn('l', {stopFx:true});
39490 hide : function(msgEl, f){
39491 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39496 * Ext JS Library 1.1.1
39497 * Copyright(c) 2006-2007, Ext JS, LLC.
39499 * Originally Released Under LGPL - original licence link has changed is not relivant.
39502 * <script type="text/javascript">
39507 * @class Roo.form.TextField
39508 * @extends Roo.form.Field
39509 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39510 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39512 * Creates a new TextField
39513 * @param {Object} config Configuration options
39515 Roo.form.TextField = function(config){
39516 Roo.form.TextField.superclass.constructor.call(this, config);
39520 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39521 * according to the default logic, but this event provides a hook for the developer to apply additional
39522 * logic at runtime to resize the field if needed.
39523 * @param {Roo.form.Field} this This text field
39524 * @param {Number} width The new field width
39530 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39532 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39536 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39540 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39544 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39548 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39552 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39554 disableKeyFilter : false,
39556 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39560 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39564 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39566 maxLength : Number.MAX_VALUE,
39568 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39570 minLengthText : "The minimum length for this field is {0}",
39572 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39574 maxLengthText : "The maximum length for this field is {0}",
39576 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39578 selectOnFocus : false,
39580 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39582 allowLeadingSpace : false,
39584 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39586 blankText : "This field is required",
39588 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39589 * If available, this function will be called only after the basic validators all return true, and will be passed the
39590 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39594 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39595 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39596 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39600 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39604 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39610 initEvents : function()
39612 if (this.emptyText) {
39613 this.el.attr('placeholder', this.emptyText);
39616 Roo.form.TextField.superclass.initEvents.call(this);
39617 if(this.validationEvent == 'keyup'){
39618 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39619 this.el.on('keyup', this.filterValidation, this);
39621 else if(this.validationEvent !== false){
39622 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39625 if(this.selectOnFocus){
39626 this.on("focus", this.preFocus, this);
39628 if (!this.allowLeadingSpace) {
39629 this.on('blur', this.cleanLeadingSpace, this);
39632 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39633 this.el.on("keypress", this.filterKeys, this);
39636 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39637 this.el.on("click", this.autoSize, this);
39639 if(this.el.is('input[type=password]') && Roo.isSafari){
39640 this.el.on('keydown', this.SafariOnKeyDown, this);
39644 processValue : function(value){
39645 if(this.stripCharsRe){
39646 var newValue = value.replace(this.stripCharsRe, '');
39647 if(newValue !== value){
39648 this.setRawValue(newValue);
39655 filterValidation : function(e){
39656 if(!e.isNavKeyPress()){
39657 this.validationTask.delay(this.validationDelay);
39662 onKeyUp : function(e){
39663 if(!e.isNavKeyPress()){
39667 // private - clean the leading white space
39668 cleanLeadingSpace : function(e)
39670 if ( this.inputType == 'file') {
39674 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39677 * Resets the current field value to the originally-loaded value and clears any validation messages.
39680 reset : function(){
39681 Roo.form.TextField.superclass.reset.call(this);
39685 preFocus : function(){
39687 if(this.selectOnFocus){
39688 this.el.dom.select();
39694 filterKeys : function(e){
39695 var k = e.getKey();
39696 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39699 var c = e.getCharCode(), cc = String.fromCharCode(c);
39700 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39703 if(!this.maskRe.test(cc)){
39708 setValue : function(v){
39710 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39716 * Validates a value according to the field's validation rules and marks the field as invalid
39717 * if the validation fails
39718 * @param {Mixed} value The value to validate
39719 * @return {Boolean} True if the value is valid, else false
39721 validateValue : function(value){
39722 if(value.length < 1) { // if it's blank
39723 if(this.allowBlank){
39724 this.clearInvalid();
39727 this.markInvalid(this.blankText);
39731 if(value.length < this.minLength){
39732 this.markInvalid(String.format(this.minLengthText, this.minLength));
39735 if(value.length > this.maxLength){
39736 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39740 var vt = Roo.form.VTypes;
39741 if(!vt[this.vtype](value, this)){
39742 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39746 if(typeof this.validator == "function"){
39747 var msg = this.validator(value);
39749 this.markInvalid(msg);
39753 if(this.regex && !this.regex.test(value)){
39754 this.markInvalid(this.regexText);
39761 * Selects text in this field
39762 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39763 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39765 selectText : function(start, end){
39766 var v = this.getRawValue();
39768 start = start === undefined ? 0 : start;
39769 end = end === undefined ? v.length : end;
39770 var d = this.el.dom;
39771 if(d.setSelectionRange){
39772 d.setSelectionRange(start, end);
39773 }else if(d.createTextRange){
39774 var range = d.createTextRange();
39775 range.moveStart("character", start);
39776 range.moveEnd("character", v.length-end);
39783 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39784 * This only takes effect if grow = true, and fires the autosize event.
39786 autoSize : function(){
39787 if(!this.grow || !this.rendered){
39791 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39794 var v = el.dom.value;
39795 var d = document.createElement('div');
39796 d.appendChild(document.createTextNode(v));
39800 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39801 this.el.setWidth(w);
39802 this.fireEvent("autosize", this, w);
39806 SafariOnKeyDown : function(event)
39808 // this is a workaround for a password hang bug on chrome/ webkit.
39810 var isSelectAll = false;
39812 if(this.el.dom.selectionEnd > 0){
39813 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39815 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39816 event.preventDefault();
39821 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39823 event.preventDefault();
39824 // this is very hacky as keydown always get's upper case.
39826 var cc = String.fromCharCode(event.getCharCode());
39829 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39837 * Ext JS Library 1.1.1
39838 * Copyright(c) 2006-2007, Ext JS, LLC.
39840 * Originally Released Under LGPL - original licence link has changed is not relivant.
39843 * <script type="text/javascript">
39847 * @class Roo.form.Hidden
39848 * @extends Roo.form.TextField
39849 * Simple Hidden element used on forms
39851 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39854 * Creates a new Hidden form element.
39855 * @param {Object} config Configuration options
39860 // easy hidden field...
39861 Roo.form.Hidden = function(config){
39862 Roo.form.Hidden.superclass.constructor.call(this, config);
39865 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39867 inputType: 'hidden',
39870 labelSeparator: '',
39872 itemCls : 'x-form-item-display-none'
39880 * Ext JS Library 1.1.1
39881 * Copyright(c) 2006-2007, Ext JS, LLC.
39883 * Originally Released Under LGPL - original licence link has changed is not relivant.
39886 * <script type="text/javascript">
39890 * @class Roo.form.TriggerField
39891 * @extends Roo.form.TextField
39892 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39893 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39894 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39895 * for which you can provide a custom implementation. For example:
39897 var trigger = new Roo.form.TriggerField();
39898 trigger.onTriggerClick = myTriggerFn;
39899 trigger.applyTo('my-field');
39902 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39903 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39904 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39905 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39907 * Create a new TriggerField.
39908 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39909 * to the base TextField)
39911 Roo.form.TriggerField = function(config){
39912 this.mimicing = false;
39913 Roo.form.TriggerField.superclass.constructor.call(this, config);
39916 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39918 * @cfg {String} triggerClass A CSS class to apply to the trigger
39921 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39922 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39924 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39926 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39930 /** @cfg {Boolean} grow @hide */
39931 /** @cfg {Number} growMin @hide */
39932 /** @cfg {Number} growMax @hide */
39938 autoSize: Roo.emptyFn,
39942 deferHeight : true,
39945 actionMode : 'wrap',
39947 onResize : function(w, h){
39948 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39949 if(typeof w == 'number'){
39950 var x = w - this.trigger.getWidth();
39951 this.el.setWidth(this.adjustWidth('input', x));
39952 this.trigger.setStyle('left', x+'px');
39957 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39960 getResizeEl : function(){
39965 getPositionEl : function(){
39970 alignErrorIcon : function(){
39971 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39975 onRender : function(ct, position){
39976 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39977 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39978 this.trigger = this.wrap.createChild(this.triggerConfig ||
39979 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39980 if(this.hideTrigger){
39981 this.trigger.setDisplayed(false);
39983 this.initTrigger();
39985 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39990 initTrigger : function(){
39991 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39992 this.trigger.addClassOnOver('x-form-trigger-over');
39993 this.trigger.addClassOnClick('x-form-trigger-click');
39997 onDestroy : function(){
39999 this.trigger.removeAllListeners();
40000 this.trigger.remove();
40003 this.wrap.remove();
40005 Roo.form.TriggerField.superclass.onDestroy.call(this);
40009 onFocus : function(){
40010 Roo.form.TriggerField.superclass.onFocus.call(this);
40011 if(!this.mimicing){
40012 this.wrap.addClass('x-trigger-wrap-focus');
40013 this.mimicing = true;
40014 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40015 if(this.monitorTab){
40016 this.el.on("keydown", this.checkTab, this);
40022 checkTab : function(e){
40023 if(e.getKey() == e.TAB){
40024 this.triggerBlur();
40029 onBlur : function(){
40034 mimicBlur : function(e, t){
40035 if(!this.wrap.contains(t) && this.validateBlur()){
40036 this.triggerBlur();
40041 triggerBlur : function(){
40042 this.mimicing = false;
40043 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40044 if(this.monitorTab){
40045 this.el.un("keydown", this.checkTab, this);
40047 this.wrap.removeClass('x-trigger-wrap-focus');
40048 Roo.form.TriggerField.superclass.onBlur.call(this);
40052 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40053 validateBlur : function(e, t){
40058 onDisable : function(){
40059 Roo.form.TriggerField.superclass.onDisable.call(this);
40061 this.wrap.addClass('x-item-disabled');
40066 onEnable : function(){
40067 Roo.form.TriggerField.superclass.onEnable.call(this);
40069 this.wrap.removeClass('x-item-disabled');
40074 onShow : function(){
40075 var ae = this.getActionEl();
40078 ae.dom.style.display = '';
40079 ae.dom.style.visibility = 'visible';
40085 onHide : function(){
40086 var ae = this.getActionEl();
40087 ae.dom.style.display = 'none';
40091 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40092 * by an implementing function.
40094 * @param {EventObject} e
40096 onTriggerClick : Roo.emptyFn
40099 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40100 // to be extended by an implementing class. For an example of implementing this class, see the custom
40101 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40102 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40103 initComponent : function(){
40104 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40106 this.triggerConfig = {
40107 tag:'span', cls:'x-form-twin-triggers', cn:[
40108 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40109 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40113 getTrigger : function(index){
40114 return this.triggers[index];
40117 initTrigger : function(){
40118 var ts = this.trigger.select('.x-form-trigger', true);
40119 this.wrap.setStyle('overflow', 'hidden');
40120 var triggerField = this;
40121 ts.each(function(t, all, index){
40122 t.hide = function(){
40123 var w = triggerField.wrap.getWidth();
40124 this.dom.style.display = 'none';
40125 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40127 t.show = function(){
40128 var w = triggerField.wrap.getWidth();
40129 this.dom.style.display = '';
40130 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40132 var triggerIndex = 'Trigger'+(index+1);
40134 if(this['hide'+triggerIndex]){
40135 t.dom.style.display = 'none';
40137 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40138 t.addClassOnOver('x-form-trigger-over');
40139 t.addClassOnClick('x-form-trigger-click');
40141 this.triggers = ts.elements;
40144 onTrigger1Click : Roo.emptyFn,
40145 onTrigger2Click : Roo.emptyFn
40148 * Ext JS Library 1.1.1
40149 * Copyright(c) 2006-2007, Ext JS, LLC.
40151 * Originally Released Under LGPL - original licence link has changed is not relivant.
40154 * <script type="text/javascript">
40158 * @class Roo.form.TextArea
40159 * @extends Roo.form.TextField
40160 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40161 * support for auto-sizing.
40163 * Creates a new TextArea
40164 * @param {Object} config Configuration options
40166 Roo.form.TextArea = function(config){
40167 Roo.form.TextArea.superclass.constructor.call(this, config);
40168 // these are provided exchanges for backwards compat
40169 // minHeight/maxHeight were replaced by growMin/growMax to be
40170 // compatible with TextField growing config values
40171 if(this.minHeight !== undefined){
40172 this.growMin = this.minHeight;
40174 if(this.maxHeight !== undefined){
40175 this.growMax = this.maxHeight;
40179 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40181 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40185 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40189 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40190 * in the field (equivalent to setting overflow: hidden, defaults to false)
40192 preventScrollbars: false,
40194 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40195 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40199 onRender : function(ct, position){
40201 this.defaultAutoCreate = {
40203 style:"width:300px;height:60px;",
40204 autocomplete: "new-password"
40207 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40209 this.textSizeEl = Roo.DomHelper.append(document.body, {
40210 tag: "pre", cls: "x-form-grow-sizer"
40212 if(this.preventScrollbars){
40213 this.el.setStyle("overflow", "hidden");
40215 this.el.setHeight(this.growMin);
40219 onDestroy : function(){
40220 if(this.textSizeEl){
40221 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40223 Roo.form.TextArea.superclass.onDestroy.call(this);
40227 onKeyUp : function(e){
40228 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40234 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40235 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40237 autoSize : function(){
40238 if(!this.grow || !this.textSizeEl){
40242 var v = el.dom.value;
40243 var ts = this.textSizeEl;
40246 ts.appendChild(document.createTextNode(v));
40249 Roo.fly(ts).setWidth(this.el.getWidth());
40251 v = "  ";
40254 v = v.replace(/\n/g, '<p> </p>');
40256 v += " \n ";
40259 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40260 if(h != this.lastHeight){
40261 this.lastHeight = h;
40262 this.el.setHeight(h);
40263 this.fireEvent("autosize", this, h);
40268 * Ext JS Library 1.1.1
40269 * Copyright(c) 2006-2007, Ext JS, LLC.
40271 * Originally Released Under LGPL - original licence link has changed is not relivant.
40274 * <script type="text/javascript">
40279 * @class Roo.form.NumberField
40280 * @extends Roo.form.TextField
40281 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40283 * Creates a new NumberField
40284 * @param {Object} config Configuration options
40286 Roo.form.NumberField = function(config){
40287 Roo.form.NumberField.superclass.constructor.call(this, config);
40290 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40292 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40294 fieldClass: "x-form-field x-form-num-field",
40296 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40298 allowDecimals : true,
40300 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40302 decimalSeparator : ".",
40304 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40306 decimalPrecision : 2,
40308 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40310 allowNegative : true,
40312 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40314 minValue : Number.NEGATIVE_INFINITY,
40316 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40318 maxValue : Number.MAX_VALUE,
40320 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40322 minText : "The minimum value for this field is {0}",
40324 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40326 maxText : "The maximum value for this field is {0}",
40328 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40329 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40331 nanText : "{0} is not a valid number",
40334 initEvents : function(){
40335 Roo.form.NumberField.superclass.initEvents.call(this);
40336 var allowed = "0123456789";
40337 if(this.allowDecimals){
40338 allowed += this.decimalSeparator;
40340 if(this.allowNegative){
40343 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40344 var keyPress = function(e){
40345 var k = e.getKey();
40346 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40349 var c = e.getCharCode();
40350 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40354 this.el.on("keypress", keyPress, this);
40358 validateValue : function(value){
40359 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40362 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40365 var num = this.parseValue(value);
40367 this.markInvalid(String.format(this.nanText, value));
40370 if(num < this.minValue){
40371 this.markInvalid(String.format(this.minText, this.minValue));
40374 if(num > this.maxValue){
40375 this.markInvalid(String.format(this.maxText, this.maxValue));
40381 getValue : function(){
40382 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40386 parseValue : function(value){
40387 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40388 return isNaN(value) ? '' : value;
40392 fixPrecision : function(value){
40393 var nan = isNaN(value);
40394 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40395 return nan ? '' : value;
40397 return parseFloat(value).toFixed(this.decimalPrecision);
40400 setValue : function(v){
40401 v = this.fixPrecision(v);
40402 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40406 decimalPrecisionFcn : function(v){
40407 return Math.floor(v);
40410 beforeBlur : function(){
40411 var v = this.parseValue(this.getRawValue());
40418 * Ext JS Library 1.1.1
40419 * Copyright(c) 2006-2007, Ext JS, LLC.
40421 * Originally Released Under LGPL - original licence link has changed is not relivant.
40424 * <script type="text/javascript">
40428 * @class Roo.form.DateField
40429 * @extends Roo.form.TriggerField
40430 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40432 * Create a new DateField
40433 * @param {Object} config
40435 Roo.form.DateField = function(config)
40437 Roo.form.DateField.superclass.constructor.call(this, config);
40443 * Fires when a date is selected
40444 * @param {Roo.form.DateField} combo This combo box
40445 * @param {Date} date The date selected
40452 if(typeof this.minValue == "string") {
40453 this.minValue = this.parseDate(this.minValue);
40455 if(typeof this.maxValue == "string") {
40456 this.maxValue = this.parseDate(this.maxValue);
40458 this.ddMatch = null;
40459 if(this.disabledDates){
40460 var dd = this.disabledDates;
40462 for(var i = 0; i < dd.length; i++){
40464 if(i != dd.length-1) {
40468 this.ddMatch = new RegExp(re + ")");
40472 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40474 * @cfg {String} format
40475 * The default date format string which can be overriden for localization support. The format must be
40476 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40480 * @cfg {String} altFormats
40481 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40482 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40484 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40486 * @cfg {Array} disabledDays
40487 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40489 disabledDays : null,
40491 * @cfg {String} disabledDaysText
40492 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40494 disabledDaysText : "Disabled",
40496 * @cfg {Array} disabledDates
40497 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40498 * expression so they are very powerful. Some examples:
40500 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40501 * <li>["03/08", "09/16"] would disable those days for every year</li>
40502 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40503 * <li>["03/../2006"] would disable every day in March 2006</li>
40504 * <li>["^03"] would disable every day in every March</li>
40506 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40507 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40509 disabledDates : null,
40511 * @cfg {String} disabledDatesText
40512 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40514 disabledDatesText : "Disabled",
40516 * @cfg {Date/String} minValue
40517 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40518 * valid format (defaults to null).
40522 * @cfg {Date/String} maxValue
40523 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40524 * valid format (defaults to null).
40528 * @cfg {String} minText
40529 * The error text to display when the date in the cell is before minValue (defaults to
40530 * 'The date in this field must be after {minValue}').
40532 minText : "The date in this field must be equal to or after {0}",
40534 * @cfg {String} maxText
40535 * The error text to display when the date in the cell is after maxValue (defaults to
40536 * 'The date in this field must be before {maxValue}').
40538 maxText : "The date in this field must be equal to or before {0}",
40540 * @cfg {String} invalidText
40541 * The error text to display when the date in the field is invalid (defaults to
40542 * '{value} is not a valid date - it must be in the format {format}').
40544 invalidText : "{0} is not a valid date - it must be in the format {1}",
40546 * @cfg {String} triggerClass
40547 * An additional CSS class used to style the trigger button. The trigger will always get the
40548 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40549 * which displays a calendar icon).
40551 triggerClass : 'x-form-date-trigger',
40555 * @cfg {Boolean} useIso
40556 * if enabled, then the date field will use a hidden field to store the
40557 * real value as iso formated date. default (false)
40561 * @cfg {String/Object} autoCreate
40562 * A DomHelper element spec, or true for a default element spec (defaults to
40563 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40566 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40569 hiddenField: false,
40571 onRender : function(ct, position)
40573 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40575 //this.el.dom.removeAttribute('name');
40576 Roo.log("Changing name?");
40577 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40578 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40580 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40581 // prevent input submission
40582 this.hiddenName = this.name;
40589 validateValue : function(value)
40591 value = this.formatDate(value);
40592 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40593 Roo.log('super failed');
40596 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40599 var svalue = value;
40600 value = this.parseDate(value);
40602 Roo.log('parse date failed' + svalue);
40603 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40606 var time = value.getTime();
40607 if(this.minValue && time < this.minValue.getTime()){
40608 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40611 if(this.maxValue && time > this.maxValue.getTime()){
40612 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40615 if(this.disabledDays){
40616 var day = value.getDay();
40617 for(var i = 0; i < this.disabledDays.length; i++) {
40618 if(day === this.disabledDays[i]){
40619 this.markInvalid(this.disabledDaysText);
40624 var fvalue = this.formatDate(value);
40625 if(this.ddMatch && this.ddMatch.test(fvalue)){
40626 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40633 // Provides logic to override the default TriggerField.validateBlur which just returns true
40634 validateBlur : function(){
40635 return !this.menu || !this.menu.isVisible();
40638 getName: function()
40640 // returns hidden if it's set..
40641 if (!this.rendered) {return ''};
40642 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40647 * Returns the current date value of the date field.
40648 * @return {Date} The date value
40650 getValue : function(){
40652 return this.hiddenField ?
40653 this.hiddenField.value :
40654 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40658 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40659 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40660 * (the default format used is "m/d/y").
40663 //All of these calls set the same date value (May 4, 2006)
40665 //Pass a date object:
40666 var dt = new Date('5/4/06');
40667 dateField.setValue(dt);
40669 //Pass a date string (default format):
40670 dateField.setValue('5/4/06');
40672 //Pass a date string (custom format):
40673 dateField.format = 'Y-m-d';
40674 dateField.setValue('2006-5-4');
40676 * @param {String/Date} date The date or valid date string
40678 setValue : function(date){
40679 if (this.hiddenField) {
40680 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40682 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40683 // make sure the value field is always stored as a date..
40684 this.value = this.parseDate(date);
40690 parseDate : function(value){
40691 if(!value || value instanceof Date){
40694 var v = Date.parseDate(value, this.format);
40695 if (!v && this.useIso) {
40696 v = Date.parseDate(value, 'Y-m-d');
40698 if(!v && this.altFormats){
40699 if(!this.altFormatsArray){
40700 this.altFormatsArray = this.altFormats.split("|");
40702 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40703 v = Date.parseDate(value, this.altFormatsArray[i]);
40710 formatDate : function(date, fmt){
40711 return (!date || !(date instanceof Date)) ?
40712 date : date.dateFormat(fmt || this.format);
40717 select: function(m, d){
40720 this.fireEvent('select', this, d);
40722 show : function(){ // retain focus styling
40726 this.focus.defer(10, this);
40727 var ml = this.menuListeners;
40728 this.menu.un("select", ml.select, this);
40729 this.menu.un("show", ml.show, this);
40730 this.menu.un("hide", ml.hide, this);
40735 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40736 onTriggerClick : function(){
40740 if(this.menu == null){
40741 this.menu = new Roo.menu.DateMenu();
40743 Roo.apply(this.menu.picker, {
40744 showClear: this.allowBlank,
40745 minDate : this.minValue,
40746 maxDate : this.maxValue,
40747 disabledDatesRE : this.ddMatch,
40748 disabledDatesText : this.disabledDatesText,
40749 disabledDays : this.disabledDays,
40750 disabledDaysText : this.disabledDaysText,
40751 format : this.useIso ? 'Y-m-d' : this.format,
40752 minText : String.format(this.minText, this.formatDate(this.minValue)),
40753 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40755 this.menu.on(Roo.apply({}, this.menuListeners, {
40758 this.menu.picker.setValue(this.getValue() || new Date());
40759 this.menu.show(this.el, "tl-bl?");
40762 beforeBlur : function(){
40763 var v = this.parseDate(this.getRawValue());
40773 isDirty : function() {
40774 if(this.disabled) {
40778 if(typeof(this.startValue) === 'undefined'){
40782 return String(this.getValue()) !== String(this.startValue);
40786 cleanLeadingSpace : function(e)
40793 * Ext JS Library 1.1.1
40794 * Copyright(c) 2006-2007, Ext JS, LLC.
40796 * Originally Released Under LGPL - original licence link has changed is not relivant.
40799 * <script type="text/javascript">
40803 * @class Roo.form.MonthField
40804 * @extends Roo.form.TriggerField
40805 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40807 * Create a new MonthField
40808 * @param {Object} config
40810 Roo.form.MonthField = function(config){
40812 Roo.form.MonthField.superclass.constructor.call(this, config);
40818 * Fires when a date is selected
40819 * @param {Roo.form.MonthFieeld} combo This combo box
40820 * @param {Date} date The date selected
40827 if(typeof this.minValue == "string") {
40828 this.minValue = this.parseDate(this.minValue);
40830 if(typeof this.maxValue == "string") {
40831 this.maxValue = this.parseDate(this.maxValue);
40833 this.ddMatch = null;
40834 if(this.disabledDates){
40835 var dd = this.disabledDates;
40837 for(var i = 0; i < dd.length; i++){
40839 if(i != dd.length-1) {
40843 this.ddMatch = new RegExp(re + ")");
40847 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40849 * @cfg {String} format
40850 * The default date format string which can be overriden for localization support. The format must be
40851 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40855 * @cfg {String} altFormats
40856 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40857 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40859 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40861 * @cfg {Array} disabledDays
40862 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40864 disabledDays : [0,1,2,3,4,5,6],
40866 * @cfg {String} disabledDaysText
40867 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40869 disabledDaysText : "Disabled",
40871 * @cfg {Array} disabledDates
40872 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40873 * expression so they are very powerful. Some examples:
40875 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40876 * <li>["03/08", "09/16"] would disable those days for every year</li>
40877 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40878 * <li>["03/../2006"] would disable every day in March 2006</li>
40879 * <li>["^03"] would disable every day in every March</li>
40881 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40882 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40884 disabledDates : null,
40886 * @cfg {String} disabledDatesText
40887 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40889 disabledDatesText : "Disabled",
40891 * @cfg {Date/String} minValue
40892 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40893 * valid format (defaults to null).
40897 * @cfg {Date/String} maxValue
40898 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40899 * valid format (defaults to null).
40903 * @cfg {String} minText
40904 * The error text to display when the date in the cell is before minValue (defaults to
40905 * 'The date in this field must be after {minValue}').
40907 minText : "The date in this field must be equal to or after {0}",
40909 * @cfg {String} maxTextf
40910 * The error text to display when the date in the cell is after maxValue (defaults to
40911 * 'The date in this field must be before {maxValue}').
40913 maxText : "The date in this field must be equal to or before {0}",
40915 * @cfg {String} invalidText
40916 * The error text to display when the date in the field is invalid (defaults to
40917 * '{value} is not a valid date - it must be in the format {format}').
40919 invalidText : "{0} is not a valid date - it must be in the format {1}",
40921 * @cfg {String} triggerClass
40922 * An additional CSS class used to style the trigger button. The trigger will always get the
40923 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40924 * which displays a calendar icon).
40926 triggerClass : 'x-form-date-trigger',
40930 * @cfg {Boolean} useIso
40931 * if enabled, then the date field will use a hidden field to store the
40932 * real value as iso formated date. default (true)
40936 * @cfg {String/Object} autoCreate
40937 * A DomHelper element spec, or true for a default element spec (defaults to
40938 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40941 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40944 hiddenField: false,
40946 hideMonthPicker : false,
40948 onRender : function(ct, position)
40950 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40952 this.el.dom.removeAttribute('name');
40953 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40955 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40956 // prevent input submission
40957 this.hiddenName = this.name;
40964 validateValue : function(value)
40966 value = this.formatDate(value);
40967 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40970 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40973 var svalue = value;
40974 value = this.parseDate(value);
40976 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40979 var time = value.getTime();
40980 if(this.minValue && time < this.minValue.getTime()){
40981 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40984 if(this.maxValue && time > this.maxValue.getTime()){
40985 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40988 /*if(this.disabledDays){
40989 var day = value.getDay();
40990 for(var i = 0; i < this.disabledDays.length; i++) {
40991 if(day === this.disabledDays[i]){
40992 this.markInvalid(this.disabledDaysText);
40998 var fvalue = this.formatDate(value);
40999 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41000 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41008 // Provides logic to override the default TriggerField.validateBlur which just returns true
41009 validateBlur : function(){
41010 return !this.menu || !this.menu.isVisible();
41014 * Returns the current date value of the date field.
41015 * @return {Date} The date value
41017 getValue : function(){
41021 return this.hiddenField ?
41022 this.hiddenField.value :
41023 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41027 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41028 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41029 * (the default format used is "m/d/y").
41032 //All of these calls set the same date value (May 4, 2006)
41034 //Pass a date object:
41035 var dt = new Date('5/4/06');
41036 monthField.setValue(dt);
41038 //Pass a date string (default format):
41039 monthField.setValue('5/4/06');
41041 //Pass a date string (custom format):
41042 monthField.format = 'Y-m-d';
41043 monthField.setValue('2006-5-4');
41045 * @param {String/Date} date The date or valid date string
41047 setValue : function(date){
41048 Roo.log('month setValue' + date);
41049 // can only be first of month..
41051 var val = this.parseDate(date);
41053 if (this.hiddenField) {
41054 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41056 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41057 this.value = this.parseDate(date);
41061 parseDate : function(value){
41062 if(!value || value instanceof Date){
41063 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41066 var v = Date.parseDate(value, this.format);
41067 if (!v && this.useIso) {
41068 v = Date.parseDate(value, 'Y-m-d');
41072 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41076 if(!v && this.altFormats){
41077 if(!this.altFormatsArray){
41078 this.altFormatsArray = this.altFormats.split("|");
41080 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41081 v = Date.parseDate(value, this.altFormatsArray[i]);
41088 formatDate : function(date, fmt){
41089 return (!date || !(date instanceof Date)) ?
41090 date : date.dateFormat(fmt || this.format);
41095 select: function(m, d){
41097 this.fireEvent('select', this, d);
41099 show : function(){ // retain focus styling
41103 this.focus.defer(10, this);
41104 var ml = this.menuListeners;
41105 this.menu.un("select", ml.select, this);
41106 this.menu.un("show", ml.show, this);
41107 this.menu.un("hide", ml.hide, this);
41111 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41112 onTriggerClick : function(){
41116 if(this.menu == null){
41117 this.menu = new Roo.menu.DateMenu();
41121 Roo.apply(this.menu.picker, {
41123 showClear: this.allowBlank,
41124 minDate : this.minValue,
41125 maxDate : this.maxValue,
41126 disabledDatesRE : this.ddMatch,
41127 disabledDatesText : this.disabledDatesText,
41129 format : this.useIso ? 'Y-m-d' : this.format,
41130 minText : String.format(this.minText, this.formatDate(this.minValue)),
41131 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41134 this.menu.on(Roo.apply({}, this.menuListeners, {
41142 // hide month picker get's called when we called by 'before hide';
41144 var ignorehide = true;
41145 p.hideMonthPicker = function(disableAnim){
41149 if(this.monthPicker){
41150 Roo.log("hideMonthPicker called");
41151 if(disableAnim === true){
41152 this.monthPicker.hide();
41154 this.monthPicker.slideOut('t', {duration:.2});
41155 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41156 p.fireEvent("select", this, this.value);
41162 Roo.log('picker set value');
41163 Roo.log(this.getValue());
41164 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41165 m.show(this.el, 'tl-bl?');
41166 ignorehide = false;
41167 // this will trigger hideMonthPicker..
41170 // hidden the day picker
41171 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41177 p.showMonthPicker.defer(100, p);
41183 beforeBlur : function(){
41184 var v = this.parseDate(this.getRawValue());
41190 /** @cfg {Boolean} grow @hide */
41191 /** @cfg {Number} growMin @hide */
41192 /** @cfg {Number} growMax @hide */
41199 * Ext JS Library 1.1.1
41200 * Copyright(c) 2006-2007, Ext JS, LLC.
41202 * Originally Released Under LGPL - original licence link has changed is not relivant.
41205 * <script type="text/javascript">
41210 * @class Roo.form.ComboBox
41211 * @extends Roo.form.TriggerField
41212 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41214 * Create a new ComboBox.
41215 * @param {Object} config Configuration options
41217 Roo.form.ComboBox = function(config){
41218 Roo.form.ComboBox.superclass.constructor.call(this, config);
41222 * Fires when the dropdown list is expanded
41223 * @param {Roo.form.ComboBox} combo This combo box
41228 * Fires when the dropdown list is collapsed
41229 * @param {Roo.form.ComboBox} combo This combo box
41233 * @event beforeselect
41234 * Fires before a list item is selected. Return false to cancel the selection.
41235 * @param {Roo.form.ComboBox} combo This combo box
41236 * @param {Roo.data.Record} record The data record returned from the underlying store
41237 * @param {Number} index The index of the selected item in the dropdown list
41239 'beforeselect' : true,
41242 * Fires when a list item is selected
41243 * @param {Roo.form.ComboBox} combo This combo box
41244 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41245 * @param {Number} index The index of the selected item in the dropdown list
41249 * @event beforequery
41250 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41251 * The event object passed has these properties:
41252 * @param {Roo.form.ComboBox} combo This combo box
41253 * @param {String} query The query
41254 * @param {Boolean} forceAll true to force "all" query
41255 * @param {Boolean} cancel true to cancel the query
41256 * @param {Object} e The query event object
41258 'beforequery': true,
41261 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41262 * @param {Roo.form.ComboBox} combo This combo box
41267 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41268 * @param {Roo.form.ComboBox} combo This combo box
41269 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41275 if(this.transform){
41276 this.allowDomMove = false;
41277 var s = Roo.getDom(this.transform);
41278 if(!this.hiddenName){
41279 this.hiddenName = s.name;
41282 this.mode = 'local';
41283 var d = [], opts = s.options;
41284 for(var i = 0, len = opts.length;i < len; i++){
41286 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41288 this.value = value;
41290 d.push([value, o.text]);
41292 this.store = new Roo.data.SimpleStore({
41294 fields: ['value', 'text'],
41297 this.valueField = 'value';
41298 this.displayField = 'text';
41300 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41301 if(!this.lazyRender){
41302 this.target = true;
41303 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41304 s.parentNode.removeChild(s); // remove it
41305 this.render(this.el.parentNode);
41307 s.parentNode.removeChild(s); // remove it
41312 this.store = Roo.factory(this.store, Roo.data);
41315 this.selectedIndex = -1;
41316 if(this.mode == 'local'){
41317 if(config.queryDelay === undefined){
41318 this.queryDelay = 10;
41320 if(config.minChars === undefined){
41326 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41328 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41331 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41332 * rendering into an Roo.Editor, defaults to false)
41335 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41336 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41339 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41342 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41343 * the dropdown list (defaults to undefined, with no header element)
41347 * @cfg {String/Roo.Template} tpl The template to use to render the output
41351 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41353 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41355 listWidth: undefined,
41357 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41358 * mode = 'remote' or 'text' if mode = 'local')
41360 displayField: undefined,
41362 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41363 * mode = 'remote' or 'value' if mode = 'local').
41364 * Note: use of a valueField requires the user make a selection
41365 * in order for a value to be mapped.
41367 valueField: undefined,
41371 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41372 * field's data value (defaults to the underlying DOM element's name)
41374 hiddenName: undefined,
41376 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41380 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41382 selectedClass: 'x-combo-selected',
41384 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41385 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41386 * which displays a downward arrow icon).
41388 triggerClass : 'x-form-arrow-trigger',
41390 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41394 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41395 * anchor positions (defaults to 'tl-bl')
41397 listAlign: 'tl-bl?',
41399 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41403 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41404 * query specified by the allQuery config option (defaults to 'query')
41406 triggerAction: 'query',
41408 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41409 * (defaults to 4, does not apply if editable = false)
41413 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41414 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41418 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41419 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41423 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41424 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41428 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41429 * when editable = true (defaults to false)
41431 selectOnFocus:false,
41433 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41435 queryParam: 'query',
41437 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41438 * when mode = 'remote' (defaults to 'Loading...')
41440 loadingText: 'Loading...',
41442 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41446 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41450 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41451 * traditional select (defaults to true)
41455 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41459 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41463 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41464 * listWidth has a higher value)
41468 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41469 * allow the user to set arbitrary text into the field (defaults to false)
41471 forceSelection:false,
41473 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41474 * if typeAhead = true (defaults to 250)
41476 typeAheadDelay : 250,
41478 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41479 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41481 valueNotFoundText : undefined,
41483 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41485 blockFocus : false,
41488 * @cfg {Boolean} disableClear Disable showing of clear button.
41490 disableClear : false,
41492 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41494 alwaysQuery : false,
41500 // element that contains real text value.. (when hidden is used..)
41503 onRender : function(ct, position)
41505 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41507 if(this.hiddenName){
41508 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41510 this.hiddenField.value =
41511 this.hiddenValue !== undefined ? this.hiddenValue :
41512 this.value !== undefined ? this.value : '';
41514 // prevent input submission
41515 this.el.dom.removeAttribute('name');
41521 this.el.dom.setAttribute('autocomplete', 'off');
41524 var cls = 'x-combo-list';
41526 this.list = new Roo.Layer({
41527 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41530 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41531 this.list.setWidth(lw);
41532 this.list.swallowEvent('mousewheel');
41533 this.assetHeight = 0;
41536 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41537 this.assetHeight += this.header.getHeight();
41540 this.innerList = this.list.createChild({cls:cls+'-inner'});
41541 this.innerList.on('mouseover', this.onViewOver, this);
41542 this.innerList.on('mousemove', this.onViewMove, this);
41543 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41545 if(this.allowBlank && !this.pageSize && !this.disableClear){
41546 this.footer = this.list.createChild({cls:cls+'-ft'});
41547 this.pageTb = new Roo.Toolbar(this.footer);
41551 this.footer = this.list.createChild({cls:cls+'-ft'});
41552 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41553 {pageSize: this.pageSize});
41557 if (this.pageTb && this.allowBlank && !this.disableClear) {
41559 this.pageTb.add(new Roo.Toolbar.Fill(), {
41560 cls: 'x-btn-icon x-btn-clear',
41562 handler: function()
41565 _this.clearValue();
41566 _this.onSelect(false, -1);
41571 this.assetHeight += this.footer.getHeight();
41576 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41579 this.view = new Roo.View(this.innerList, this.tpl, {
41582 selectedClass: this.selectedClass
41585 this.view.on('click', this.onViewClick, this);
41587 this.store.on('beforeload', this.onBeforeLoad, this);
41588 this.store.on('load', this.onLoad, this);
41589 this.store.on('loadexception', this.onLoadException, this);
41591 if(this.resizable){
41592 this.resizer = new Roo.Resizable(this.list, {
41593 pinned:true, handles:'se'
41595 this.resizer.on('resize', function(r, w, h){
41596 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41597 this.listWidth = w;
41598 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41599 this.restrictHeight();
41601 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41603 if(!this.editable){
41604 this.editable = true;
41605 this.setEditable(false);
41609 if (typeof(this.events.add.listeners) != 'undefined') {
41611 this.addicon = this.wrap.createChild(
41612 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41614 this.addicon.on('click', function(e) {
41615 this.fireEvent('add', this);
41618 if (typeof(this.events.edit.listeners) != 'undefined') {
41620 this.editicon = this.wrap.createChild(
41621 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41622 if (this.addicon) {
41623 this.editicon.setStyle('margin-left', '40px');
41625 this.editicon.on('click', function(e) {
41627 // we fire even if inothing is selected..
41628 this.fireEvent('edit', this, this.lastData );
41638 initEvents : function(){
41639 Roo.form.ComboBox.superclass.initEvents.call(this);
41641 this.keyNav = new Roo.KeyNav(this.el, {
41642 "up" : function(e){
41643 this.inKeyMode = true;
41647 "down" : function(e){
41648 if(!this.isExpanded()){
41649 this.onTriggerClick();
41651 this.inKeyMode = true;
41656 "enter" : function(e){
41657 this.onViewClick();
41661 "esc" : function(e){
41665 "tab" : function(e){
41666 this.onViewClick(false);
41667 this.fireEvent("specialkey", this, e);
41673 doRelay : function(foo, bar, hname){
41674 if(hname == 'down' || this.scope.isExpanded()){
41675 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41682 this.queryDelay = Math.max(this.queryDelay || 10,
41683 this.mode == 'local' ? 10 : 250);
41684 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41685 if(this.typeAhead){
41686 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41688 if(this.editable !== false){
41689 this.el.on("keyup", this.onKeyUp, this);
41691 if(this.forceSelection){
41692 this.on('blur', this.doForce, this);
41696 onDestroy : function(){
41698 this.view.setStore(null);
41699 this.view.el.removeAllListeners();
41700 this.view.el.remove();
41701 this.view.purgeListeners();
41704 this.list.destroy();
41707 this.store.un('beforeload', this.onBeforeLoad, this);
41708 this.store.un('load', this.onLoad, this);
41709 this.store.un('loadexception', this.onLoadException, this);
41711 Roo.form.ComboBox.superclass.onDestroy.call(this);
41715 fireKey : function(e){
41716 if(e.isNavKeyPress() && !this.list.isVisible()){
41717 this.fireEvent("specialkey", this, e);
41722 onResize: function(w, h){
41723 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41725 if(typeof w != 'number'){
41726 // we do not handle it!?!?
41729 var tw = this.trigger.getWidth();
41730 tw += this.addicon ? this.addicon.getWidth() : 0;
41731 tw += this.editicon ? this.editicon.getWidth() : 0;
41733 this.el.setWidth( this.adjustWidth('input', x));
41735 this.trigger.setStyle('left', x+'px');
41737 if(this.list && this.listWidth === undefined){
41738 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41739 this.list.setWidth(lw);
41740 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41748 * Allow or prevent the user from directly editing the field text. If false is passed,
41749 * the user will only be able to select from the items defined in the dropdown list. This method
41750 * is the runtime equivalent of setting the 'editable' config option at config time.
41751 * @param {Boolean} value True to allow the user to directly edit the field text
41753 setEditable : function(value){
41754 if(value == this.editable){
41757 this.editable = value;
41759 this.el.dom.setAttribute('readOnly', true);
41760 this.el.on('mousedown', this.onTriggerClick, this);
41761 this.el.addClass('x-combo-noedit');
41763 this.el.dom.setAttribute('readOnly', false);
41764 this.el.un('mousedown', this.onTriggerClick, this);
41765 this.el.removeClass('x-combo-noedit');
41770 onBeforeLoad : function(){
41771 if(!this.hasFocus){
41774 this.innerList.update(this.loadingText ?
41775 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41776 this.restrictHeight();
41777 this.selectedIndex = -1;
41781 onLoad : function(){
41782 if(!this.hasFocus){
41785 if(this.store.getCount() > 0){
41787 this.restrictHeight();
41788 if(this.lastQuery == this.allQuery){
41790 this.el.dom.select();
41792 if(!this.selectByValue(this.value, true)){
41793 this.select(0, true);
41797 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41798 this.taTask.delay(this.typeAheadDelay);
41802 this.onEmptyResults();
41807 onLoadException : function()
41810 Roo.log(this.store.reader.jsonData);
41811 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41812 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41818 onTypeAhead : function(){
41819 if(this.store.getCount() > 0){
41820 var r = this.store.getAt(0);
41821 var newValue = r.data[this.displayField];
41822 var len = newValue.length;
41823 var selStart = this.getRawValue().length;
41824 if(selStart != len){
41825 this.setRawValue(newValue);
41826 this.selectText(selStart, newValue.length);
41832 onSelect : function(record, index){
41833 if(this.fireEvent('beforeselect', this, record, index) !== false){
41834 this.setFromData(index > -1 ? record.data : false);
41836 this.fireEvent('select', this, record, index);
41841 * Returns the currently selected field value or empty string if no value is set.
41842 * @return {String} value The selected value
41844 getValue : function(){
41845 if(this.valueField){
41846 return typeof this.value != 'undefined' ? this.value : '';
41848 return Roo.form.ComboBox.superclass.getValue.call(this);
41852 * Clears any text/value currently set in the field
41854 clearValue : function(){
41855 if(this.hiddenField){
41856 this.hiddenField.value = '';
41859 this.setRawValue('');
41860 this.lastSelectionText = '';
41865 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41866 * will be displayed in the field. If the value does not match the data value of an existing item,
41867 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41868 * Otherwise the field will be blank (although the value will still be set).
41869 * @param {String} value The value to match
41871 setValue : function(v){
41873 if(this.valueField){
41874 var r = this.findRecord(this.valueField, v);
41876 text = r.data[this.displayField];
41877 }else if(this.valueNotFoundText !== undefined){
41878 text = this.valueNotFoundText;
41881 this.lastSelectionText = text;
41882 if(this.hiddenField){
41883 this.hiddenField.value = v;
41885 Roo.form.ComboBox.superclass.setValue.call(this, text);
41889 * @property {Object} the last set data for the element
41894 * Sets the value of the field based on a object which is related to the record format for the store.
41895 * @param {Object} value the value to set as. or false on reset?
41897 setFromData : function(o){
41898 var dv = ''; // display value
41899 var vv = ''; // value value..
41901 if (this.displayField) {
41902 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41904 // this is an error condition!!!
41905 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41908 if(this.valueField){
41909 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41911 if(this.hiddenField){
41912 this.hiddenField.value = vv;
41914 this.lastSelectionText = dv;
41915 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41919 // no hidden field.. - we store the value in 'value', but still display
41920 // display field!!!!
41921 this.lastSelectionText = dv;
41922 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41928 reset : function(){
41929 // overridden so that last data is reset..
41930 this.setValue(this.resetValue);
41931 this.originalValue = this.getValue();
41932 this.clearInvalid();
41933 this.lastData = false;
41935 this.view.clearSelections();
41939 findRecord : function(prop, value){
41941 if(this.store.getCount() > 0){
41942 this.store.each(function(r){
41943 if(r.data[prop] == value){
41953 getName: function()
41955 // returns hidden if it's set..
41956 if (!this.rendered) {return ''};
41957 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41961 onViewMove : function(e, t){
41962 this.inKeyMode = false;
41966 onViewOver : function(e, t){
41967 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41970 var item = this.view.findItemFromChild(t);
41972 var index = this.view.indexOf(item);
41973 this.select(index, false);
41978 onViewClick : function(doFocus)
41980 var index = this.view.getSelectedIndexes()[0];
41981 var r = this.store.getAt(index);
41983 this.onSelect(r, index);
41985 if(doFocus !== false && !this.blockFocus){
41991 restrictHeight : function(){
41992 this.innerList.dom.style.height = '';
41993 var inner = this.innerList.dom;
41994 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41995 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41996 this.list.beginUpdate();
41997 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41998 this.list.alignTo(this.el, this.listAlign);
41999 this.list.endUpdate();
42003 onEmptyResults : function(){
42008 * Returns true if the dropdown list is expanded, else false.
42010 isExpanded : function(){
42011 return this.list.isVisible();
42015 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42016 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42017 * @param {String} value The data value of the item to select
42018 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42019 * selected item if it is not currently in view (defaults to true)
42020 * @return {Boolean} True if the value matched an item in the list, else false
42022 selectByValue : function(v, scrollIntoView){
42023 if(v !== undefined && v !== null){
42024 var r = this.findRecord(this.valueField || this.displayField, v);
42026 this.select(this.store.indexOf(r), scrollIntoView);
42034 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42035 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42036 * @param {Number} index The zero-based index of the list item to select
42037 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42038 * selected item if it is not currently in view (defaults to true)
42040 select : function(index, scrollIntoView){
42041 this.selectedIndex = index;
42042 this.view.select(index);
42043 if(scrollIntoView !== false){
42044 var el = this.view.getNode(index);
42046 this.innerList.scrollChildIntoView(el, false);
42052 selectNext : function(){
42053 var ct = this.store.getCount();
42055 if(this.selectedIndex == -1){
42057 }else if(this.selectedIndex < ct-1){
42058 this.select(this.selectedIndex+1);
42064 selectPrev : function(){
42065 var ct = this.store.getCount();
42067 if(this.selectedIndex == -1){
42069 }else if(this.selectedIndex != 0){
42070 this.select(this.selectedIndex-1);
42076 onKeyUp : function(e){
42077 if(this.editable !== false && !e.isSpecialKey()){
42078 this.lastKey = e.getKey();
42079 this.dqTask.delay(this.queryDelay);
42084 validateBlur : function(){
42085 return !this.list || !this.list.isVisible();
42089 initQuery : function(){
42090 this.doQuery(this.getRawValue());
42094 doForce : function(){
42095 if(this.el.dom.value.length > 0){
42096 this.el.dom.value =
42097 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42103 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42104 * query allowing the query action to be canceled if needed.
42105 * @param {String} query The SQL query to execute
42106 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42107 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42108 * saved in the current store (defaults to false)
42110 doQuery : function(q, forceAll){
42111 if(q === undefined || q === null){
42116 forceAll: forceAll,
42120 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42124 forceAll = qe.forceAll;
42125 if(forceAll === true || (q.length >= this.minChars)){
42126 if(this.lastQuery != q || this.alwaysQuery){
42127 this.lastQuery = q;
42128 if(this.mode == 'local'){
42129 this.selectedIndex = -1;
42131 this.store.clearFilter();
42133 this.store.filter(this.displayField, q);
42137 this.store.baseParams[this.queryParam] = q;
42139 params: this.getParams(q)
42144 this.selectedIndex = -1;
42151 getParams : function(q){
42153 //p[this.queryParam] = q;
42156 p.limit = this.pageSize;
42162 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42164 collapse : function(){
42165 if(!this.isExpanded()){
42169 Roo.get(document).un('mousedown', this.collapseIf, this);
42170 Roo.get(document).un('mousewheel', this.collapseIf, this);
42171 if (!this.editable) {
42172 Roo.get(document).un('keydown', this.listKeyPress, this);
42174 this.fireEvent('collapse', this);
42178 collapseIf : function(e){
42179 if(!e.within(this.wrap) && !e.within(this.list)){
42185 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42187 expand : function(){
42188 if(this.isExpanded() || !this.hasFocus){
42191 this.list.alignTo(this.el, this.listAlign);
42193 Roo.get(document).on('mousedown', this.collapseIf, this);
42194 Roo.get(document).on('mousewheel', this.collapseIf, this);
42195 if (!this.editable) {
42196 Roo.get(document).on('keydown', this.listKeyPress, this);
42199 this.fireEvent('expand', this);
42203 // Implements the default empty TriggerField.onTriggerClick function
42204 onTriggerClick : function(){
42208 if(this.isExpanded()){
42210 if (!this.blockFocus) {
42215 this.hasFocus = true;
42216 if(this.triggerAction == 'all') {
42217 this.doQuery(this.allQuery, true);
42219 this.doQuery(this.getRawValue());
42221 if (!this.blockFocus) {
42226 listKeyPress : function(e)
42228 //Roo.log('listkeypress');
42229 // scroll to first matching element based on key pres..
42230 if (e.isSpecialKey()) {
42233 var k = String.fromCharCode(e.getKey()).toUpperCase();
42236 var csel = this.view.getSelectedNodes();
42237 var cselitem = false;
42239 var ix = this.view.indexOf(csel[0]);
42240 cselitem = this.store.getAt(ix);
42241 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42247 this.store.each(function(v) {
42249 // start at existing selection.
42250 if (cselitem.id == v.id) {
42256 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42257 match = this.store.indexOf(v);
42262 if (match === false) {
42263 return true; // no more action?
42266 this.view.select(match);
42267 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42268 sn.scrollIntoView(sn.dom.parentNode, false);
42272 * @cfg {Boolean} grow
42276 * @cfg {Number} growMin
42280 * @cfg {Number} growMax
42288 * Copyright(c) 2010-2012, Roo J Solutions Limited
42295 * @class Roo.form.ComboBoxArray
42296 * @extends Roo.form.TextField
42297 * A facebook style adder... for lists of email / people / countries etc...
42298 * pick multiple items from a combo box, and shows each one.
42300 * Fred [x] Brian [x] [Pick another |v]
42303 * For this to work: it needs various extra information
42304 * - normal combo problay has
42306 * + displayField, valueField
42308 * For our purpose...
42311 * If we change from 'extends' to wrapping...
42318 * Create a new ComboBoxArray.
42319 * @param {Object} config Configuration options
42323 Roo.form.ComboBoxArray = function(config)
42327 * @event beforeremove
42328 * Fires before remove the value from the list
42329 * @param {Roo.form.ComboBoxArray} _self This combo box array
42330 * @param {Roo.form.ComboBoxArray.Item} item removed item
42332 'beforeremove' : true,
42335 * Fires when remove the value from the list
42336 * @param {Roo.form.ComboBoxArray} _self This combo box array
42337 * @param {Roo.form.ComboBoxArray.Item} item removed item
42344 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42346 this.items = new Roo.util.MixedCollection(false);
42348 // construct the child combo...
42358 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42361 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42366 // behavies liek a hiddne field
42367 inputType: 'hidden',
42369 * @cfg {Number} width The width of the box that displays the selected element
42376 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42380 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42382 hiddenName : false,
42384 * @cfg {String} seperator The value seperator normally ','
42388 // private the array of items that are displayed..
42390 // private - the hidden field el.
42392 // private - the filed el..
42395 //validateValue : function() { return true; }, // all values are ok!
42396 //onAddClick: function() { },
42398 onRender : function(ct, position)
42401 // create the standard hidden element
42402 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42405 // give fake names to child combo;
42406 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42407 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42409 this.combo = Roo.factory(this.combo, Roo.form);
42410 this.combo.onRender(ct, position);
42411 if (typeof(this.combo.width) != 'undefined') {
42412 this.combo.onResize(this.combo.width,0);
42415 this.combo.initEvents();
42417 // assigned so form know we need to do this..
42418 this.store = this.combo.store;
42419 this.valueField = this.combo.valueField;
42420 this.displayField = this.combo.displayField ;
42423 this.combo.wrap.addClass('x-cbarray-grp');
42425 var cbwrap = this.combo.wrap.createChild(
42426 {tag: 'div', cls: 'x-cbarray-cb'},
42431 this.hiddenEl = this.combo.wrap.createChild({
42432 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42434 this.el = this.combo.wrap.createChild({
42435 tag: 'input', type:'hidden' , name: this.name, value : ''
42437 // this.el.dom.removeAttribute("name");
42440 this.outerWrap = this.combo.wrap;
42441 this.wrap = cbwrap;
42443 this.outerWrap.setWidth(this.width);
42444 this.outerWrap.dom.removeChild(this.el.dom);
42446 this.wrap.dom.appendChild(this.el.dom);
42447 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42448 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42450 this.combo.trigger.setStyle('position','relative');
42451 this.combo.trigger.setStyle('left', '0px');
42452 this.combo.trigger.setStyle('top', '2px');
42454 this.combo.el.setStyle('vertical-align', 'text-bottom');
42456 //this.trigger.setStyle('vertical-align', 'top');
42458 // this should use the code from combo really... on('add' ....)
42462 this.adder = this.outerWrap.createChild(
42463 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42465 this.adder.on('click', function(e) {
42466 _t.fireEvent('adderclick', this, e);
42470 //this.adder.on('click', this.onAddClick, _t);
42473 this.combo.on('select', function(cb, rec, ix) {
42474 this.addItem(rec.data);
42477 cb.el.dom.value = '';
42478 //cb.lastData = rec.data;
42487 getName: function()
42489 // returns hidden if it's set..
42490 if (!this.rendered) {return ''};
42491 return this.hiddenName ? this.hiddenName : this.name;
42496 onResize: function(w, h){
42499 // not sure if this is needed..
42500 //this.combo.onResize(w,h);
42502 if(typeof w != 'number'){
42503 // we do not handle it!?!?
42506 var tw = this.combo.trigger.getWidth();
42507 tw += this.addicon ? this.addicon.getWidth() : 0;
42508 tw += this.editicon ? this.editicon.getWidth() : 0;
42510 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42512 this.combo.trigger.setStyle('left', '0px');
42514 if(this.list && this.listWidth === undefined){
42515 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42516 this.list.setWidth(lw);
42517 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42524 addItem: function(rec)
42526 var valueField = this.combo.valueField;
42527 var displayField = this.combo.displayField;
42529 if (this.items.indexOfKey(rec[valueField]) > -1) {
42530 //console.log("GOT " + rec.data.id);
42534 var x = new Roo.form.ComboBoxArray.Item({
42535 //id : rec[this.idField],
42537 displayField : displayField ,
42538 tipField : displayField ,
42542 this.items.add(rec[valueField],x);
42543 // add it before the element..
42544 this.updateHiddenEl();
42545 x.render(this.outerWrap, this.wrap.dom);
42546 // add the image handler..
42549 updateHiddenEl : function()
42552 if (!this.hiddenEl) {
42556 var idField = this.combo.valueField;
42558 this.items.each(function(f) {
42559 ar.push(f.data[idField]);
42561 this.hiddenEl.dom.value = ar.join(this.seperator);
42567 this.items.clear();
42569 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42573 this.el.dom.value = '';
42574 if (this.hiddenEl) {
42575 this.hiddenEl.dom.value = '';
42579 getValue: function()
42581 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42583 setValue: function(v) // not a valid action - must use addItems..
42588 if (this.store.isLocal && (typeof(v) == 'string')) {
42589 // then we can use the store to find the values..
42590 // comma seperated at present.. this needs to allow JSON based encoding..
42591 this.hiddenEl.value = v;
42593 Roo.each(v.split(this.seperator), function(k) {
42594 Roo.log("CHECK " + this.valueField + ',' + k);
42595 var li = this.store.query(this.valueField, k);
42600 add[this.valueField] = k;
42601 add[this.displayField] = li.item(0).data[this.displayField];
42607 if (typeof(v) == 'object' ) {
42608 // then let's assume it's an array of objects..
42609 Roo.each(v, function(l) {
42611 if (typeof(l) == 'string') {
42613 add[this.valueField] = l;
42614 add[this.displayField] = l
42623 setFromData: function(v)
42625 // this recieves an object, if setValues is called.
42627 this.el.dom.value = v[this.displayField];
42628 this.hiddenEl.dom.value = v[this.valueField];
42629 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42632 var kv = v[this.valueField];
42633 var dv = v[this.displayField];
42634 kv = typeof(kv) != 'string' ? '' : kv;
42635 dv = typeof(dv) != 'string' ? '' : dv;
42638 var keys = kv.split(this.seperator);
42639 var display = dv.split(this.seperator);
42640 for (var i = 0 ; i < keys.length; i++) {
42642 add[this.valueField] = keys[i];
42643 add[this.displayField] = display[i];
42651 * Validates the combox array value
42652 * @return {Boolean} True if the value is valid, else false
42654 validate : function(){
42655 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42656 this.clearInvalid();
42662 validateValue : function(value){
42663 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42671 isDirty : function() {
42672 if(this.disabled) {
42677 var d = Roo.decode(String(this.originalValue));
42679 return String(this.getValue()) !== String(this.originalValue);
42682 var originalValue = [];
42684 for (var i = 0; i < d.length; i++){
42685 originalValue.push(d[i][this.valueField]);
42688 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42697 * @class Roo.form.ComboBoxArray.Item
42698 * @extends Roo.BoxComponent
42699 * A selected item in the list
42700 * Fred [x] Brian [x] [Pick another |v]
42703 * Create a new item.
42704 * @param {Object} config Configuration options
42707 Roo.form.ComboBoxArray.Item = function(config) {
42708 config.id = Roo.id();
42709 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42712 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42715 displayField : false,
42719 defaultAutoCreate : {
42721 cls: 'x-cbarray-item',
42728 src : Roo.BLANK_IMAGE_URL ,
42736 onRender : function(ct, position)
42738 Roo.form.Field.superclass.onRender.call(this, ct, position);
42741 var cfg = this.getAutoCreate();
42742 this.el = ct.createChild(cfg, position);
42745 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42747 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42748 this.cb.renderer(this.data) :
42749 String.format('{0}',this.data[this.displayField]);
42752 this.el.child('div').dom.setAttribute('qtip',
42753 String.format('{0}',this.data[this.tipField])
42756 this.el.child('img').on('click', this.remove, this);
42760 remove : function()
42762 if(this.cb.disabled){
42766 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42767 this.cb.items.remove(this);
42768 this.el.child('img').un('click', this.remove, this);
42770 this.cb.updateHiddenEl();
42772 this.cb.fireEvent('remove', this.cb, this);
42777 * RooJS Library 1.1.1
42778 * Copyright(c) 2008-2011 Alan Knowles
42785 * @class Roo.form.ComboNested
42786 * @extends Roo.form.ComboBox
42787 * A combobox for that allows selection of nested items in a list,
42802 * Create a new ComboNested
42803 * @param {Object} config Configuration options
42805 Roo.form.ComboNested = function(config){
42806 Roo.form.ComboCheck.superclass.constructor.call(this, config);
42807 // should verify some data...
42809 // hiddenName = required..
42810 // displayField = required
42811 // valudField == required
42812 var req= [ 'hiddenName', 'displayField', 'valueField' ];
42814 Roo.each(req, function(e) {
42815 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
42816 throw "Roo.form.ComboNested : missing value for: " + e;
42823 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
42826 * @config {Number} max Number of columns to show
42831 list : null, // the outermost div..
42832 innerLists : null, // the
42836 loadingChildren : false,
42838 onRender : function(ct, position)
42840 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
42842 if(this.hiddenName){
42843 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42845 this.hiddenField.value =
42846 this.hiddenValue !== undefined ? this.hiddenValue :
42847 this.value !== undefined ? this.value : '';
42849 // prevent input submission
42850 this.el.dom.removeAttribute('name');
42856 this.el.dom.setAttribute('autocomplete', 'off');
42859 var cls = 'x-combo-list';
42861 this.list = new Roo.Layer({
42862 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
42865 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
42866 this.list.setWidth(lw);
42867 this.list.swallowEvent('mousewheel');
42868 this.assetHeight = 0;
42871 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
42872 this.assetHeight += this.header.getHeight();
42874 this.innerLists = [];
42877 for (var i =0 ; i < this.maxColumns; i++) {
42878 this.onRenderList( cls, i);
42881 // always needs footer, as we are going to have an 'OK' button.
42882 this.footer = this.list.createChild({cls:cls+'-ft'});
42883 this.pageTb = new Roo.Toolbar(this.footer);
42888 handler: function()
42894 if ( this.allowBlank && !this.disableClear) {
42896 this.pageTb.add(new Roo.Toolbar.Fill(), {
42897 cls: 'x-btn-icon x-btn-clear',
42899 handler: function()
42902 _this.clearValue();
42903 _this.onSelect(false, -1);
42908 this.assetHeight += this.footer.getHeight();
42912 onRenderList : function ( cls, i)
42915 var lw = Math.floor(
42916 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
42919 this.list.setWidth(lw); // default to '1'
42921 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
42922 //il.on('mouseover', this.onViewOver, this, { list: i });
42923 //il.on('mousemove', this.onViewMove, this, { list: i });
42925 il.setStyle({ 'overflow-x' : 'hidden'});
42928 this.tpl = new Roo.Template({
42929 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
42930 isEmpty: function (value, allValues) {
42932 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
42933 return dl ? 'has-children' : 'no-children'
42938 var store = this.store;
42940 store = new Roo.data.SimpleStore({
42941 //fields : this.store.reader.meta.fields,
42942 reader : this.store.reader,
42946 this.stores[i] = store;
42948 var view = this.views[i] = new Roo.View(
42954 selectedClass: this.selectedClass
42957 view.getEl().setWidth(lw);
42958 view.getEl().setStyle({
42959 position: i < 1 ? 'relative' : 'absolute',
42961 left: (i * lw ) + 'px',
42962 display : i > 0 ? 'none' : 'block'
42964 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
42965 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
42966 //view.on('click', this.onViewClick, this, { list : i });
42968 store.on('beforeload', this.onBeforeLoad, this);
42969 store.on('load', this.onLoad, this, { list : i});
42970 store.on('loadexception', this.onLoadException, this);
42972 // hide the other vies..
42978 restrictHeight : function()
42981 Roo.each(this.innerLists, function(il,i) {
42982 var el = this.views[i].getEl();
42983 el.dom.style.height = '';
42984 var inner = el.dom;
42985 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
42986 // only adjust heights on other ones..
42987 mh = Math.max(h, mh);
42990 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42991 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42998 this.list.beginUpdate();
42999 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43000 this.list.alignTo(this.el, this.listAlign);
43001 this.list.endUpdate();
43006 // -- store handlers..
43008 onBeforeLoad : function()
43010 if(!this.hasFocus){
43013 this.innerLists[0].update(this.loadingText ?
43014 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43015 this.restrictHeight();
43016 this.selectedIndex = -1;
43019 onLoad : function(a,b,c,d)
43021 if (!this.loadingChildren) {
43022 // then we are loading the top level. - hide the children
43023 for (var i = 1;i < this.views.length; i++) {
43024 this.views[i].getEl().setStyle({ display : 'none' });
43026 var lw = Math.floor(
43027 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43030 this.list.setWidth(lw); // default to '1'
43034 if(!this.hasFocus){
43038 if(this.store.getCount() > 0) {
43040 this.restrictHeight();
43042 this.onEmptyResults();
43045 if (!this.loadingChildren) {
43046 this.selectActive();
43049 this.stores[1].loadData([]);
43050 this.stores[2].loadData([]);
43059 onLoadException : function()
43062 Roo.log(this.store.reader.jsonData);
43063 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43064 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43069 // no cleaning of leading spaces on blur here.
43070 cleanLeadingSpace : function(e) { },
43073 onSelectChange : function (view, sels, opts )
43075 var ix = view.getSelectedIndexes();
43077 if (opts.list > this.maxColumns - 2) {
43078 if (view.store.getCount()< 1) {
43079 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43083 // used to clear ?? but if we are loading unselected
43084 this.setFromData(view.store.getAt(ix[0]).data);
43093 // this get's fired when trigger opens..
43094 // this.setFromData({});
43095 var str = this.stores[opts.list+1];
43096 str.data.clear(); // removeall wihtout the fire events..
43100 var rec = view.store.getAt(ix[0]);
43102 this.setFromData(rec.data);
43103 this.fireEvent('select', this, rec, ix[0]);
43105 var lw = Math.floor(
43107 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43108 ) / this.maxColumns
43110 this.loadingChildren = true;
43111 this.stores[opts.list+1].loadDataFromChildren( rec );
43112 this.loadingChildren = false;
43113 var dl = this.stores[opts.list+1]. getTotalCount();
43115 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43117 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43118 for (var i = opts.list+2; i < this.views.length;i++) {
43119 this.views[i].getEl().setStyle({ display : 'none' });
43122 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43123 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43125 if (this.isLoading) {
43126 // this.selectActive(opts.list);
43134 onDoubleClick : function()
43136 this.collapse(); //??
43144 recordToStack : function(store, prop, value, stack)
43146 var cstore = new Roo.data.SimpleStore({
43147 //fields : this.store.reader.meta.fields, // we need array reader.. for
43148 reader : this.store.reader,
43152 var record = false;
43154 if(store.getCount() < 1){
43157 store.each(function(r){
43158 if(r.data[prop] == value){
43163 if (r.data.cn && r.data.cn.length) {
43164 cstore.loadDataFromChildren( r);
43165 var cret = _this.recordToStack(cstore, prop, value, stack);
43166 if (cret !== false) {
43175 if (record == false) {
43178 stack.unshift(srec);
43183 * find the stack of stores that match our value.
43188 selectActive : function ()
43190 // if store is not loaded, then we will need to wait for that to happen first.
43192 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43193 for (var i = 0; i < stack.length; i++ ) {
43194 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43206 * Ext JS Library 1.1.1
43207 * Copyright(c) 2006-2007, Ext JS, LLC.
43209 * Originally Released Under LGPL - original licence link has changed is not relivant.
43212 * <script type="text/javascript">
43215 * @class Roo.form.Checkbox
43216 * @extends Roo.form.Field
43217 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43219 * Creates a new Checkbox
43220 * @param {Object} config Configuration options
43222 Roo.form.Checkbox = function(config){
43223 Roo.form.Checkbox.superclass.constructor.call(this, config);
43227 * Fires when the checkbox is checked or unchecked.
43228 * @param {Roo.form.Checkbox} this This checkbox
43229 * @param {Boolean} checked The new checked value
43235 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43237 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43239 focusClass : undefined,
43241 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43243 fieldClass: "x-form-field",
43245 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43249 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43250 * {tag: "input", type: "checkbox", autocomplete: "off"})
43252 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43254 * @cfg {String} boxLabel The text that appears beside the checkbox
43258 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43262 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43264 valueOff: '0', // value when not checked..
43266 actionMode : 'viewEl',
43269 itemCls : 'x-menu-check-item x-form-item',
43270 groupClass : 'x-menu-group-item',
43271 inputType : 'hidden',
43274 inSetChecked: false, // check that we are not calling self...
43276 inputElement: false, // real input element?
43277 basedOn: false, // ????
43279 isFormField: true, // not sure where this is needed!!!!
43281 onResize : function(){
43282 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43283 if(!this.boxLabel){
43284 this.el.alignTo(this.wrap, 'c-c');
43288 initEvents : function(){
43289 Roo.form.Checkbox.superclass.initEvents.call(this);
43290 this.el.on("click", this.onClick, this);
43291 this.el.on("change", this.onClick, this);
43295 getResizeEl : function(){
43299 getPositionEl : function(){
43304 onRender : function(ct, position){
43305 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43307 if(this.inputValue !== undefined){
43308 this.el.dom.value = this.inputValue;
43311 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43312 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43313 var viewEl = this.wrap.createChild({
43314 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43315 this.viewEl = viewEl;
43316 this.wrap.on('click', this.onClick, this);
43318 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43319 this.el.on('propertychange', this.setFromHidden, this); //ie
43324 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43325 // viewEl.on('click', this.onClick, this);
43327 //if(this.checked){
43328 this.setChecked(this.checked);
43330 //this.checked = this.el.dom;
43336 initValue : Roo.emptyFn,
43339 * Returns the checked state of the checkbox.
43340 * @return {Boolean} True if checked, else false
43342 getValue : function(){
43344 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43346 return this.valueOff;
43351 onClick : function(){
43352 if (this.disabled) {
43355 this.setChecked(!this.checked);
43357 //if(this.el.dom.checked != this.checked){
43358 // this.setValue(this.el.dom.checked);
43363 * Sets the checked state of the checkbox.
43364 * On is always based on a string comparison between inputValue and the param.
43365 * @param {Boolean/String} value - the value to set
43366 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43368 setValue : function(v,suppressEvent){
43371 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43372 //if(this.el && this.el.dom){
43373 // this.el.dom.checked = this.checked;
43374 // this.el.dom.defaultChecked = this.checked;
43376 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43377 //this.fireEvent("check", this, this.checked);
43380 setChecked : function(state,suppressEvent)
43382 if (this.inSetChecked) {
43383 this.checked = state;
43389 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43391 this.checked = state;
43392 if(suppressEvent !== true){
43393 this.fireEvent('check', this, state);
43395 this.inSetChecked = true;
43396 this.el.dom.value = state ? this.inputValue : this.valueOff;
43397 this.inSetChecked = false;
43400 // handle setting of hidden value by some other method!!?!?
43401 setFromHidden: function()
43406 //console.log("SET FROM HIDDEN");
43407 //alert('setFrom hidden');
43408 this.setValue(this.el.dom.value);
43411 onDestroy : function()
43414 Roo.get(this.viewEl).remove();
43417 Roo.form.Checkbox.superclass.onDestroy.call(this);
43420 setBoxLabel : function(str)
43422 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43427 * Ext JS Library 1.1.1
43428 * Copyright(c) 2006-2007, Ext JS, LLC.
43430 * Originally Released Under LGPL - original licence link has changed is not relivant.
43433 * <script type="text/javascript">
43437 * @class Roo.form.Radio
43438 * @extends Roo.form.Checkbox
43439 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43440 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43442 * Creates a new Radio
43443 * @param {Object} config Configuration options
43445 Roo.form.Radio = function(){
43446 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43448 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43449 inputType: 'radio',
43452 * If this radio is part of a group, it will return the selected value
43455 getGroupValue : function(){
43456 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43460 onRender : function(ct, position){
43461 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43463 if(this.inputValue !== undefined){
43464 this.el.dom.value = this.inputValue;
43467 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43468 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43469 //var viewEl = this.wrap.createChild({
43470 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43471 //this.viewEl = viewEl;
43472 //this.wrap.on('click', this.onClick, this);
43474 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43475 //this.el.on('propertychange', this.setFromHidden, this); //ie
43480 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43481 // viewEl.on('click', this.onClick, this);
43484 this.el.dom.checked = 'checked' ;
43490 });//<script type="text/javascript">
43493 * Based Ext JS Library 1.1.1
43494 * Copyright(c) 2006-2007, Ext JS, LLC.
43500 * @class Roo.HtmlEditorCore
43501 * @extends Roo.Component
43502 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43504 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43507 Roo.HtmlEditorCore = function(config){
43510 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43515 * @event initialize
43516 * Fires when the editor is fully initialized (including the iframe)
43517 * @param {Roo.HtmlEditorCore} this
43522 * Fires when the editor is first receives the focus. Any insertion must wait
43523 * until after this event.
43524 * @param {Roo.HtmlEditorCore} this
43528 * @event beforesync
43529 * Fires before the textarea is updated with content from the editor iframe. Return false
43530 * to cancel the sync.
43531 * @param {Roo.HtmlEditorCore} this
43532 * @param {String} html
43536 * @event beforepush
43537 * Fires before the iframe editor is updated with content from the textarea. Return false
43538 * to cancel the push.
43539 * @param {Roo.HtmlEditorCore} this
43540 * @param {String} html
43545 * Fires when the textarea is updated with content from the editor iframe.
43546 * @param {Roo.HtmlEditorCore} this
43547 * @param {String} html
43552 * Fires when the iframe editor is updated with content from the textarea.
43553 * @param {Roo.HtmlEditorCore} this
43554 * @param {String} html
43559 * @event editorevent
43560 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43561 * @param {Roo.HtmlEditorCore} this
43567 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43569 // defaults : white / black...
43570 this.applyBlacklists();
43577 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43581 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43587 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43592 * @cfg {Number} height (in pixels)
43596 * @cfg {Number} width (in pixels)
43601 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43604 stylesheets: false,
43609 // private properties
43610 validationEvent : false,
43612 initialized : false,
43614 sourceEditMode : false,
43615 onFocus : Roo.emptyFn,
43617 hideMode:'offsets',
43621 // blacklist + whitelisted elements..
43628 * Protected method that will not generally be called directly. It
43629 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43630 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43632 getDocMarkup : function(){
43636 // inherit styels from page...??
43637 if (this.stylesheets === false) {
43639 Roo.get(document.head).select('style').each(function(node) {
43640 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43643 Roo.get(document.head).select('link').each(function(node) {
43644 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43647 } else if (!this.stylesheets.length) {
43649 st = '<style type="text/css">' +
43650 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43653 for (var i in this.stylesheets) {
43654 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43659 st += '<style type="text/css">' +
43660 'IMG { cursor: pointer } ' +
43663 var cls = 'roo-htmleditor-body';
43665 if(this.bodyCls.length){
43666 cls += ' ' + this.bodyCls;
43669 return '<html><head>' + st +
43670 //<style type="text/css">' +
43671 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43673 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43677 onRender : function(ct, position)
43680 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43681 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43684 this.el.dom.style.border = '0 none';
43685 this.el.dom.setAttribute('tabIndex', -1);
43686 this.el.addClass('x-hidden hide');
43690 if(Roo.isIE){ // fix IE 1px bogus margin
43691 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43695 this.frameId = Roo.id();
43699 var iframe = this.owner.wrap.createChild({
43701 cls: 'form-control', // bootstrap..
43703 name: this.frameId,
43704 frameBorder : 'no',
43705 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43710 this.iframe = iframe.dom;
43712 this.assignDocWin();
43714 this.doc.designMode = 'on';
43717 this.doc.write(this.getDocMarkup());
43721 var task = { // must defer to wait for browser to be ready
43723 //console.log("run task?" + this.doc.readyState);
43724 this.assignDocWin();
43725 if(this.doc.body || this.doc.readyState == 'complete'){
43727 this.doc.designMode="on";
43731 Roo.TaskMgr.stop(task);
43732 this.initEditor.defer(10, this);
43739 Roo.TaskMgr.start(task);
43744 onResize : function(w, h)
43746 Roo.log('resize: ' +w + ',' + h );
43747 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43751 if(typeof w == 'number'){
43753 this.iframe.style.width = w + 'px';
43755 if(typeof h == 'number'){
43757 this.iframe.style.height = h + 'px';
43759 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43766 * Toggles the editor between standard and source edit mode.
43767 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43769 toggleSourceEdit : function(sourceEditMode){
43771 this.sourceEditMode = sourceEditMode === true;
43773 if(this.sourceEditMode){
43775 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43778 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43779 //this.iframe.className = '';
43782 //this.setSize(this.owner.wrap.getSize());
43783 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43790 * Protected method that will not generally be called directly. If you need/want
43791 * custom HTML cleanup, this is the method you should override.
43792 * @param {String} html The HTML to be cleaned
43793 * return {String} The cleaned HTML
43795 cleanHtml : function(html){
43796 html = String(html);
43797 if(html.length > 5){
43798 if(Roo.isSafari){ // strip safari nonsense
43799 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43802 if(html == ' '){
43809 * HTML Editor -> Textarea
43810 * Protected method that will not generally be called directly. Syncs the contents
43811 * of the editor iframe with the textarea.
43813 syncValue : function(){
43814 if(this.initialized){
43815 var bd = (this.doc.body || this.doc.documentElement);
43816 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43817 var html = bd.innerHTML;
43819 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43820 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43822 html = '<div style="'+m[0]+'">' + html + '</div>';
43825 html = this.cleanHtml(html);
43826 // fix up the special chars.. normaly like back quotes in word...
43827 // however we do not want to do this with chinese..
43828 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
43830 var cc = match.charCodeAt();
43832 // Get the character value, handling surrogate pairs
43833 if (match.length == 2) {
43834 // It's a surrogate pair, calculate the Unicode code point
43835 var high = match.charCodeAt(0) - 0xD800;
43836 var low = match.charCodeAt(1) - 0xDC00;
43837 cc = (high * 0x400) + low + 0x10000;
43839 (cc >= 0x4E00 && cc < 0xA000 ) ||
43840 (cc >= 0x3400 && cc < 0x4E00 ) ||
43841 (cc >= 0xf900 && cc < 0xfb00 )
43846 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
43847 return "&#" + cc + ";";
43854 if(this.owner.fireEvent('beforesync', this, html) !== false){
43855 this.el.dom.value = html;
43856 this.owner.fireEvent('sync', this, html);
43862 * Protected method that will not generally be called directly. Pushes the value of the textarea
43863 * into the iframe editor.
43865 pushValue : function(){
43866 if(this.initialized){
43867 var v = this.el.dom.value.trim();
43869 // if(v.length < 1){
43873 if(this.owner.fireEvent('beforepush', this, v) !== false){
43874 var d = (this.doc.body || this.doc.documentElement);
43876 this.cleanUpPaste();
43877 this.el.dom.value = d.innerHTML;
43878 this.owner.fireEvent('push', this, v);
43884 deferFocus : function(){
43885 this.focus.defer(10, this);
43889 focus : function(){
43890 if(this.win && !this.sourceEditMode){
43897 assignDocWin: function()
43899 var iframe = this.iframe;
43902 this.doc = iframe.contentWindow.document;
43903 this.win = iframe.contentWindow;
43905 // if (!Roo.get(this.frameId)) {
43908 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43909 // this.win = Roo.get(this.frameId).dom.contentWindow;
43911 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43915 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43916 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43921 initEditor : function(){
43922 //console.log("INIT EDITOR");
43923 this.assignDocWin();
43927 this.doc.designMode="on";
43929 this.doc.write(this.getDocMarkup());
43932 var dbody = (this.doc.body || this.doc.documentElement);
43933 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43934 // this copies styles from the containing element into thsi one..
43935 // not sure why we need all of this..
43936 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43938 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43939 //ss['background-attachment'] = 'fixed'; // w3c
43940 dbody.bgProperties = 'fixed'; // ie
43941 //Roo.DomHelper.applyStyles(dbody, ss);
43942 Roo.EventManager.on(this.doc, {
43943 //'mousedown': this.onEditorEvent,
43944 'mouseup': this.onEditorEvent,
43945 'dblclick': this.onEditorEvent,
43946 'click': this.onEditorEvent,
43947 'keyup': this.onEditorEvent,
43952 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43954 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43955 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43957 this.initialized = true;
43959 this.owner.fireEvent('initialize', this);
43964 onDestroy : function(){
43970 //for (var i =0; i < this.toolbars.length;i++) {
43971 // // fixme - ask toolbars for heights?
43972 // this.toolbars[i].onDestroy();
43975 //this.wrap.dom.innerHTML = '';
43976 //this.wrap.remove();
43981 onFirstFocus : function(){
43983 this.assignDocWin();
43986 this.activated = true;
43989 if(Roo.isGecko){ // prevent silly gecko errors
43991 var s = this.win.getSelection();
43992 if(!s.focusNode || s.focusNode.nodeType != 3){
43993 var r = s.getRangeAt(0);
43994 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43999 this.execCmd('useCSS', true);
44000 this.execCmd('styleWithCSS', false);
44003 this.owner.fireEvent('activate', this);
44007 adjustFont: function(btn){
44008 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44009 //if(Roo.isSafari){ // safari
44012 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44013 if(Roo.isSafari){ // safari
44014 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44015 v = (v < 10) ? 10 : v;
44016 v = (v > 48) ? 48 : v;
44017 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44022 v = Math.max(1, v+adjust);
44024 this.execCmd('FontSize', v );
44027 onEditorEvent : function(e)
44029 this.owner.fireEvent('editorevent', this, e);
44030 // this.updateToolbar();
44031 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44034 insertTag : function(tg)
44036 // could be a bit smarter... -> wrap the current selected tRoo..
44037 if (tg.toLowerCase() == 'span' ||
44038 tg.toLowerCase() == 'code' ||
44039 tg.toLowerCase() == 'sup' ||
44040 tg.toLowerCase() == 'sub'
44043 range = this.createRange(this.getSelection());
44044 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44045 wrappingNode.appendChild(range.extractContents());
44046 range.insertNode(wrappingNode);
44053 this.execCmd("formatblock", tg);
44057 insertText : function(txt)
44061 var range = this.createRange();
44062 range.deleteContents();
44063 //alert(Sender.getAttribute('label'));
44065 range.insertNode(this.doc.createTextNode(txt));
44071 * Executes a Midas editor command on the editor document and performs necessary focus and
44072 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44073 * @param {String} cmd The Midas command
44074 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44076 relayCmd : function(cmd, value){
44078 this.execCmd(cmd, value);
44079 this.owner.fireEvent('editorevent', this);
44080 //this.updateToolbar();
44081 this.owner.deferFocus();
44085 * Executes a Midas editor command directly on the editor document.
44086 * For visual commands, you should use {@link #relayCmd} instead.
44087 * <b>This should only be called after the editor is initialized.</b>
44088 * @param {String} cmd The Midas command
44089 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44091 execCmd : function(cmd, value){
44092 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44099 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44101 * @param {String} text | dom node..
44103 insertAtCursor : function(text)
44106 if(!this.activated){
44112 var r = this.doc.selection.createRange();
44123 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44127 // from jquery ui (MIT licenced)
44129 var win = this.win;
44131 if (win.getSelection && win.getSelection().getRangeAt) {
44132 range = win.getSelection().getRangeAt(0);
44133 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44134 range.insertNode(node);
44135 } else if (win.document.selection && win.document.selection.createRange) {
44136 // no firefox support
44137 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44138 win.document.selection.createRange().pasteHTML(txt);
44140 // no firefox support
44141 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44142 this.execCmd('InsertHTML', txt);
44151 mozKeyPress : function(e){
44153 var c = e.getCharCode(), cmd;
44156 c = String.fromCharCode(c).toLowerCase();
44170 this.cleanUpPaste.defer(100, this);
44178 e.preventDefault();
44186 fixKeys : function(){ // load time branching for fastest keydown performance
44188 return function(e){
44189 var k = e.getKey(), r;
44192 r = this.doc.selection.createRange();
44195 r.pasteHTML('    ');
44202 r = this.doc.selection.createRange();
44204 var target = r.parentElement();
44205 if(!target || target.tagName.toLowerCase() != 'li'){
44207 r.pasteHTML('<br />');
44213 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44214 this.cleanUpPaste.defer(100, this);
44220 }else if(Roo.isOpera){
44221 return function(e){
44222 var k = e.getKey();
44226 this.execCmd('InsertHTML','    ');
44229 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44230 this.cleanUpPaste.defer(100, this);
44235 }else if(Roo.isSafari){
44236 return function(e){
44237 var k = e.getKey();
44241 this.execCmd('InsertText','\t');
44245 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44246 this.cleanUpPaste.defer(100, this);
44254 getAllAncestors: function()
44256 var p = this.getSelectedNode();
44259 a.push(p); // push blank onto stack..
44260 p = this.getParentElement();
44264 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44268 a.push(this.doc.body);
44272 lastSelNode : false,
44275 getSelection : function()
44277 this.assignDocWin();
44278 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44281 getSelectedNode: function()
44283 // this may only work on Gecko!!!
44285 // should we cache this!!!!
44290 var range = this.createRange(this.getSelection()).cloneRange();
44293 var parent = range.parentElement();
44295 var testRange = range.duplicate();
44296 testRange.moveToElementText(parent);
44297 if (testRange.inRange(range)) {
44300 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44303 parent = parent.parentElement;
44308 // is ancestor a text element.
44309 var ac = range.commonAncestorContainer;
44310 if (ac.nodeType == 3) {
44311 ac = ac.parentNode;
44314 var ar = ac.childNodes;
44317 var other_nodes = [];
44318 var has_other_nodes = false;
44319 for (var i=0;i<ar.length;i++) {
44320 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44323 // fullly contained node.
44325 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44330 // probably selected..
44331 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44332 other_nodes.push(ar[i]);
44336 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44341 has_other_nodes = true;
44343 if (!nodes.length && other_nodes.length) {
44344 nodes= other_nodes;
44346 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44352 createRange: function(sel)
44354 // this has strange effects when using with
44355 // top toolbar - not sure if it's a great idea.
44356 //this.editor.contentWindow.focus();
44357 if (typeof sel != "undefined") {
44359 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44361 return this.doc.createRange();
44364 return this.doc.createRange();
44367 getParentElement: function()
44370 this.assignDocWin();
44371 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44373 var range = this.createRange(sel);
44376 var p = range.commonAncestorContainer;
44377 while (p.nodeType == 3) { // text node
44388 * Range intersection.. the hard stuff...
44392 * [ -- selected range --- ]
44396 * if end is before start or hits it. fail.
44397 * if start is after end or hits it fail.
44399 * if either hits (but other is outside. - then it's not
44405 // @see http://www.thismuchiknow.co.uk/?p=64.
44406 rangeIntersectsNode : function(range, node)
44408 var nodeRange = node.ownerDocument.createRange();
44410 nodeRange.selectNode(node);
44412 nodeRange.selectNodeContents(node);
44415 var rangeStartRange = range.cloneRange();
44416 rangeStartRange.collapse(true);
44418 var rangeEndRange = range.cloneRange();
44419 rangeEndRange.collapse(false);
44421 var nodeStartRange = nodeRange.cloneRange();
44422 nodeStartRange.collapse(true);
44424 var nodeEndRange = nodeRange.cloneRange();
44425 nodeEndRange.collapse(false);
44427 return rangeStartRange.compareBoundaryPoints(
44428 Range.START_TO_START, nodeEndRange) == -1 &&
44429 rangeEndRange.compareBoundaryPoints(
44430 Range.START_TO_START, nodeStartRange) == 1;
44434 rangeCompareNode : function(range, node)
44436 var nodeRange = node.ownerDocument.createRange();
44438 nodeRange.selectNode(node);
44440 nodeRange.selectNodeContents(node);
44444 range.collapse(true);
44446 nodeRange.collapse(true);
44448 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44449 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44451 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44453 var nodeIsBefore = ss == 1;
44454 var nodeIsAfter = ee == -1;
44456 if (nodeIsBefore && nodeIsAfter) {
44459 if (!nodeIsBefore && nodeIsAfter) {
44460 return 1; //right trailed.
44463 if (nodeIsBefore && !nodeIsAfter) {
44464 return 2; // left trailed.
44470 // private? - in a new class?
44471 cleanUpPaste : function()
44473 // cleans up the whole document..
44474 Roo.log('cleanuppaste');
44476 this.cleanUpChildren(this.doc.body);
44477 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44478 if (clean != this.doc.body.innerHTML) {
44479 this.doc.body.innerHTML = clean;
44484 cleanWordChars : function(input) {// change the chars to hex code
44485 var he = Roo.HtmlEditorCore;
44487 var output = input;
44488 Roo.each(he.swapCodes, function(sw) {
44489 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44491 output = output.replace(swapper, sw[1]);
44498 cleanUpChildren : function (n)
44500 if (!n.childNodes.length) {
44503 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44504 this.cleanUpChild(n.childNodes[i]);
44511 cleanUpChild : function (node)
44514 //console.log(node);
44515 if (node.nodeName == "#text") {
44516 // clean up silly Windows -- stuff?
44519 if (node.nodeName == "#comment") {
44520 node.parentNode.removeChild(node);
44521 // clean up silly Windows -- stuff?
44524 var lcname = node.tagName.toLowerCase();
44525 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44526 // whitelist of tags..
44528 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44530 node.parentNode.removeChild(node);
44535 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44537 // spans with no attributes - just remove them..
44538 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44539 remove_keep_children = true;
44542 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44543 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44545 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44546 // remove_keep_children = true;
44549 if (remove_keep_children) {
44550 this.cleanUpChildren(node);
44551 // inserts everything just before this node...
44552 while (node.childNodes.length) {
44553 var cn = node.childNodes[0];
44554 node.removeChild(cn);
44555 node.parentNode.insertBefore(cn, node);
44557 node.parentNode.removeChild(node);
44561 if (!node.attributes || !node.attributes.length) {
44566 this.cleanUpChildren(node);
44570 function cleanAttr(n,v)
44573 if (v.match(/^\./) || v.match(/^\//)) {
44576 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44579 if (v.match(/^#/)) {
44582 if (v.match(/^\{/)) { // allow template editing.
44585 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44586 node.removeAttribute(n);
44590 var cwhite = this.cwhite;
44591 var cblack = this.cblack;
44593 function cleanStyle(n,v)
44595 if (v.match(/expression/)) { //XSS?? should we even bother..
44596 node.removeAttribute(n);
44600 var parts = v.split(/;/);
44603 Roo.each(parts, function(p) {
44604 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44608 var l = p.split(':').shift().replace(/\s+/g,'');
44609 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44611 if ( cwhite.length && cblack.indexOf(l) > -1) {
44612 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44613 //node.removeAttribute(n);
44617 // only allow 'c whitelisted system attributes'
44618 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44619 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44620 //node.removeAttribute(n);
44630 if (clean.length) {
44631 node.setAttribute(n, clean.join(';'));
44633 node.removeAttribute(n);
44639 for (var i = node.attributes.length-1; i > -1 ; i--) {
44640 var a = node.attributes[i];
44643 if (a.name.toLowerCase().substr(0,2)=='on') {
44644 node.removeAttribute(a.name);
44647 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44648 node.removeAttribute(a.name);
44651 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44652 cleanAttr(a.name,a.value); // fixme..
44655 if (a.name == 'style') {
44656 cleanStyle(a.name,a.value);
44659 /// clean up MS crap..
44660 // tecnically this should be a list of valid class'es..
44663 if (a.name == 'class') {
44664 if (a.value.match(/^Mso/)) {
44665 node.removeAttribute('class');
44668 if (a.value.match(/^body$/)) {
44669 node.removeAttribute('class');
44680 this.cleanUpChildren(node);
44686 * Clean up MS wordisms...
44688 cleanWord : function(node)
44691 this.cleanWord(this.doc.body);
44696 node.nodeName == 'SPAN' &&
44697 !node.hasAttributes() &&
44698 node.childNodes.length == 1 &&
44699 node.firstChild.nodeName == "#text"
44701 var textNode = node.firstChild;
44702 node.removeChild(textNode);
44703 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44704 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44706 node.parentNode.insertBefore(textNode, node);
44707 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44708 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44710 node.parentNode.removeChild(node);
44713 if (node.nodeName == "#text") {
44714 // clean up silly Windows -- stuff?
44717 if (node.nodeName == "#comment") {
44718 node.parentNode.removeChild(node);
44719 // clean up silly Windows -- stuff?
44723 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44724 node.parentNode.removeChild(node);
44727 //Roo.log(node.tagName);
44728 // remove - but keep children..
44729 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44730 //Roo.log('-- removed');
44731 while (node.childNodes.length) {
44732 var cn = node.childNodes[0];
44733 node.removeChild(cn);
44734 node.parentNode.insertBefore(cn, node);
44735 // move node to parent - and clean it..
44736 this.cleanWord(cn);
44738 node.parentNode.removeChild(node);
44739 /// no need to iterate chidlren = it's got none..
44740 //this.iterateChildren(node, this.cleanWord);
44744 if (node.className.length) {
44746 var cn = node.className.split(/\W+/);
44748 Roo.each(cn, function(cls) {
44749 if (cls.match(/Mso[a-zA-Z]+/)) {
44754 node.className = cna.length ? cna.join(' ') : '';
44756 node.removeAttribute("class");
44760 if (node.hasAttribute("lang")) {
44761 node.removeAttribute("lang");
44764 if (node.hasAttribute("style")) {
44766 var styles = node.getAttribute("style").split(";");
44768 Roo.each(styles, function(s) {
44769 if (!s.match(/:/)) {
44772 var kv = s.split(":");
44773 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44776 // what ever is left... we allow.
44779 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44780 if (!nstyle.length) {
44781 node.removeAttribute('style');
44784 this.iterateChildren(node, this.cleanWord);
44790 * iterateChildren of a Node, calling fn each time, using this as the scole..
44791 * @param {DomNode} node node to iterate children of.
44792 * @param {Function} fn method of this class to call on each item.
44794 iterateChildren : function(node, fn)
44796 if (!node.childNodes.length) {
44799 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44800 fn.call(this, node.childNodes[i])
44806 * cleanTableWidths.
44808 * Quite often pasting from word etc.. results in tables with column and widths.
44809 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44812 cleanTableWidths : function(node)
44817 this.cleanTableWidths(this.doc.body);
44822 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44825 Roo.log(node.tagName);
44826 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44827 this.iterateChildren(node, this.cleanTableWidths);
44830 if (node.hasAttribute('width')) {
44831 node.removeAttribute('width');
44835 if (node.hasAttribute("style")) {
44838 var styles = node.getAttribute("style").split(";");
44840 Roo.each(styles, function(s) {
44841 if (!s.match(/:/)) {
44844 var kv = s.split(":");
44845 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44848 // what ever is left... we allow.
44851 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44852 if (!nstyle.length) {
44853 node.removeAttribute('style');
44857 this.iterateChildren(node, this.cleanTableWidths);
44865 domToHTML : function(currentElement, depth, nopadtext) {
44867 depth = depth || 0;
44868 nopadtext = nopadtext || false;
44870 if (!currentElement) {
44871 return this.domToHTML(this.doc.body);
44874 //Roo.log(currentElement);
44876 var allText = false;
44877 var nodeName = currentElement.nodeName;
44878 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44880 if (nodeName == '#text') {
44882 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44887 if (nodeName != 'BODY') {
44890 // Prints the node tagName, such as <A>, <IMG>, etc
44893 for(i = 0; i < currentElement.attributes.length;i++) {
44895 var aname = currentElement.attributes.item(i).name;
44896 if (!currentElement.attributes.item(i).value.length) {
44899 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44902 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44911 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44914 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44919 // Traverse the tree
44921 var currentElementChild = currentElement.childNodes.item(i);
44922 var allText = true;
44923 var innerHTML = '';
44925 while (currentElementChild) {
44926 // Formatting code (indent the tree so it looks nice on the screen)
44927 var nopad = nopadtext;
44928 if (lastnode == 'SPAN') {
44932 if (currentElementChild.nodeName == '#text') {
44933 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44934 toadd = nopadtext ? toadd : toadd.trim();
44935 if (!nopad && toadd.length > 80) {
44936 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44938 innerHTML += toadd;
44941 currentElementChild = currentElement.childNodes.item(i);
44947 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44949 // Recursively traverse the tree structure of the child node
44950 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44951 lastnode = currentElementChild.nodeName;
44953 currentElementChild=currentElement.childNodes.item(i);
44959 // The remaining code is mostly for formatting the tree
44960 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44965 ret+= "</"+tagName+">";
44971 applyBlacklists : function()
44973 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44974 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44978 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44979 if (b.indexOf(tag) > -1) {
44982 this.white.push(tag);
44986 Roo.each(w, function(tag) {
44987 if (b.indexOf(tag) > -1) {
44990 if (this.white.indexOf(tag) > -1) {
44993 this.white.push(tag);
44998 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44999 if (w.indexOf(tag) > -1) {
45002 this.black.push(tag);
45006 Roo.each(b, function(tag) {
45007 if (w.indexOf(tag) > -1) {
45010 if (this.black.indexOf(tag) > -1) {
45013 this.black.push(tag);
45018 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45019 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45023 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45024 if (b.indexOf(tag) > -1) {
45027 this.cwhite.push(tag);
45031 Roo.each(w, function(tag) {
45032 if (b.indexOf(tag) > -1) {
45035 if (this.cwhite.indexOf(tag) > -1) {
45038 this.cwhite.push(tag);
45043 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45044 if (w.indexOf(tag) > -1) {
45047 this.cblack.push(tag);
45051 Roo.each(b, function(tag) {
45052 if (w.indexOf(tag) > -1) {
45055 if (this.cblack.indexOf(tag) > -1) {
45058 this.cblack.push(tag);
45063 setStylesheets : function(stylesheets)
45065 if(typeof(stylesheets) == 'string'){
45066 Roo.get(this.iframe.contentDocument.head).createChild({
45068 rel : 'stylesheet',
45077 Roo.each(stylesheets, function(s) {
45082 Roo.get(_this.iframe.contentDocument.head).createChild({
45084 rel : 'stylesheet',
45093 removeStylesheets : function()
45097 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45102 setStyle : function(style)
45104 Roo.get(this.iframe.contentDocument.head).createChild({
45113 // hide stuff that is not compatible
45127 * @event specialkey
45131 * @cfg {String} fieldClass @hide
45134 * @cfg {String} focusClass @hide
45137 * @cfg {String} autoCreate @hide
45140 * @cfg {String} inputType @hide
45143 * @cfg {String} invalidClass @hide
45146 * @cfg {String} invalidText @hide
45149 * @cfg {String} msgFx @hide
45152 * @cfg {String} validateOnBlur @hide
45156 Roo.HtmlEditorCore.white = [
45157 'area', 'br', 'img', 'input', 'hr', 'wbr',
45159 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45160 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45161 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45162 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45163 'table', 'ul', 'xmp',
45165 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45168 'dir', 'menu', 'ol', 'ul', 'dl',
45174 Roo.HtmlEditorCore.black = [
45175 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45177 'base', 'basefont', 'bgsound', 'blink', 'body',
45178 'frame', 'frameset', 'head', 'html', 'ilayer',
45179 'iframe', 'layer', 'link', 'meta', 'object',
45180 'script', 'style' ,'title', 'xml' // clean later..
45182 Roo.HtmlEditorCore.clean = [
45183 'script', 'style', 'title', 'xml'
45185 Roo.HtmlEditorCore.remove = [
45190 Roo.HtmlEditorCore.ablack = [
45194 Roo.HtmlEditorCore.aclean = [
45195 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45199 Roo.HtmlEditorCore.pwhite= [
45200 'http', 'https', 'mailto'
45203 // white listed style attributes.
45204 Roo.HtmlEditorCore.cwhite= [
45205 // 'text-align', /// default is to allow most things..
45211 // black listed style attributes.
45212 Roo.HtmlEditorCore.cblack= [
45213 // 'font-size' -- this can be set by the project
45217 Roo.HtmlEditorCore.swapCodes =[
45228 //<script type="text/javascript">
45231 * Ext JS Library 1.1.1
45232 * Copyright(c) 2006-2007, Ext JS, LLC.
45238 Roo.form.HtmlEditor = function(config){
45242 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45244 if (!this.toolbars) {
45245 this.toolbars = [];
45247 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45253 * @class Roo.form.HtmlEditor
45254 * @extends Roo.form.Field
45255 * Provides a lightweight HTML Editor component.
45257 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45259 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45260 * supported by this editor.</b><br/><br/>
45261 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45262 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45264 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45266 * @cfg {Boolean} clearUp
45270 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45275 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45280 * @cfg {Number} height (in pixels)
45284 * @cfg {Number} width (in pixels)
45289 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45292 stylesheets: false,
45296 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45301 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45307 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45312 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45320 // private properties
45321 validationEvent : false,
45323 initialized : false,
45326 onFocus : Roo.emptyFn,
45328 hideMode:'offsets',
45330 actionMode : 'container', // defaults to hiding it...
45332 defaultAutoCreate : { // modified by initCompnoent..
45334 style:"width:500px;height:300px;",
45335 autocomplete: "new-password"
45339 initComponent : function(){
45342 * @event initialize
45343 * Fires when the editor is fully initialized (including the iframe)
45344 * @param {HtmlEditor} this
45349 * Fires when the editor is first receives the focus. Any insertion must wait
45350 * until after this event.
45351 * @param {HtmlEditor} this
45355 * @event beforesync
45356 * Fires before the textarea is updated with content from the editor iframe. Return false
45357 * to cancel the sync.
45358 * @param {HtmlEditor} this
45359 * @param {String} html
45363 * @event beforepush
45364 * Fires before the iframe editor is updated with content from the textarea. Return false
45365 * to cancel the push.
45366 * @param {HtmlEditor} this
45367 * @param {String} html
45372 * Fires when the textarea is updated with content from the editor iframe.
45373 * @param {HtmlEditor} this
45374 * @param {String} html
45379 * Fires when the iframe editor is updated with content from the textarea.
45380 * @param {HtmlEditor} this
45381 * @param {String} html
45385 * @event editmodechange
45386 * Fires when the editor switches edit modes
45387 * @param {HtmlEditor} this
45388 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45390 editmodechange: true,
45392 * @event editorevent
45393 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45394 * @param {HtmlEditor} this
45398 * @event firstfocus
45399 * Fires when on first focus - needed by toolbars..
45400 * @param {HtmlEditor} this
45405 * Auto save the htmlEditor value as a file into Events
45406 * @param {HtmlEditor} this
45410 * @event savedpreview
45411 * preview the saved version of htmlEditor
45412 * @param {HtmlEditor} this
45414 savedpreview: true,
45417 * @event stylesheetsclick
45418 * Fires when press the Sytlesheets button
45419 * @param {Roo.HtmlEditorCore} this
45421 stylesheetsclick: true
45423 this.defaultAutoCreate = {
45425 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45426 autocomplete: "new-password"
45431 * Protected method that will not generally be called directly. It
45432 * is called when the editor creates its toolbar. Override this method if you need to
45433 * add custom toolbar buttons.
45434 * @param {HtmlEditor} editor
45436 createToolbar : function(editor){
45437 Roo.log("create toolbars");
45438 if (!editor.toolbars || !editor.toolbars.length) {
45439 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45442 for (var i =0 ; i < editor.toolbars.length;i++) {
45443 editor.toolbars[i] = Roo.factory(
45444 typeof(editor.toolbars[i]) == 'string' ?
45445 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45446 Roo.form.HtmlEditor);
45447 editor.toolbars[i].init(editor);
45455 onRender : function(ct, position)
45458 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45460 this.wrap = this.el.wrap({
45461 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45464 this.editorcore.onRender(ct, position);
45466 if (this.resizable) {
45467 this.resizeEl = new Roo.Resizable(this.wrap, {
45471 minHeight : this.height,
45472 height: this.height,
45473 handles : this.resizable,
45476 resize : function(r, w, h) {
45477 _t.onResize(w,h); // -something
45483 this.createToolbar(this);
45487 this.setSize(this.wrap.getSize());
45489 if (this.resizeEl) {
45490 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45491 // should trigger onReize..
45494 this.keyNav = new Roo.KeyNav(this.el, {
45496 "tab" : function(e){
45497 e.preventDefault();
45499 var value = this.getValue();
45501 var start = this.el.dom.selectionStart;
45502 var end = this.el.dom.selectionEnd;
45506 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45507 this.el.dom.setSelectionRange(end + 1, end + 1);
45511 var f = value.substring(0, start).split("\t");
45513 if(f.pop().length != 0){
45517 this.setValue(f.join("\t") + value.substring(end));
45518 this.el.dom.setSelectionRange(start - 1, start - 1);
45522 "home" : function(e){
45523 e.preventDefault();
45525 var curr = this.el.dom.selectionStart;
45526 var lines = this.getValue().split("\n");
45533 this.el.dom.setSelectionRange(0, 0);
45539 for (var i = 0; i < lines.length;i++) {
45540 pos += lines[i].length;
45550 pos -= lines[i].length;
45556 this.el.dom.setSelectionRange(pos, pos);
45560 this.el.dom.selectionStart = pos;
45561 this.el.dom.selectionEnd = curr;
45564 "end" : function(e){
45565 e.preventDefault();
45567 var curr = this.el.dom.selectionStart;
45568 var lines = this.getValue().split("\n");
45575 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45581 for (var i = 0; i < lines.length;i++) {
45583 pos += lines[i].length;
45597 this.el.dom.setSelectionRange(pos, pos);
45601 this.el.dom.selectionStart = curr;
45602 this.el.dom.selectionEnd = pos;
45607 doRelay : function(foo, bar, hname){
45608 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45614 // if(this.autosave && this.w){
45615 // this.autoSaveFn = setInterval(this.autosave, 1000);
45620 onResize : function(w, h)
45622 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45627 if(typeof w == 'number'){
45628 var aw = w - this.wrap.getFrameWidth('lr');
45629 this.el.setWidth(this.adjustWidth('textarea', aw));
45632 if(typeof h == 'number'){
45634 for (var i =0; i < this.toolbars.length;i++) {
45635 // fixme - ask toolbars for heights?
45636 tbh += this.toolbars[i].tb.el.getHeight();
45637 if (this.toolbars[i].footer) {
45638 tbh += this.toolbars[i].footer.el.getHeight();
45645 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45646 ah -= 5; // knock a few pixes off for look..
45648 this.el.setHeight(this.adjustWidth('textarea', ah));
45652 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45653 this.editorcore.onResize(ew,eh);
45658 * Toggles the editor between standard and source edit mode.
45659 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45661 toggleSourceEdit : function(sourceEditMode)
45663 this.editorcore.toggleSourceEdit(sourceEditMode);
45665 if(this.editorcore.sourceEditMode){
45666 Roo.log('editor - showing textarea');
45669 // Roo.log(this.syncValue());
45670 this.editorcore.syncValue();
45671 this.el.removeClass('x-hidden');
45672 this.el.dom.removeAttribute('tabIndex');
45675 for (var i = 0; i < this.toolbars.length; i++) {
45676 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45677 this.toolbars[i].tb.hide();
45678 this.toolbars[i].footer.hide();
45683 Roo.log('editor - hiding textarea');
45685 // Roo.log(this.pushValue());
45686 this.editorcore.pushValue();
45688 this.el.addClass('x-hidden');
45689 this.el.dom.setAttribute('tabIndex', -1);
45691 for (var i = 0; i < this.toolbars.length; i++) {
45692 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45693 this.toolbars[i].tb.show();
45694 this.toolbars[i].footer.show();
45698 //this.deferFocus();
45701 this.setSize(this.wrap.getSize());
45702 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45704 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45707 // private (for BoxComponent)
45708 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45710 // private (for BoxComponent)
45711 getResizeEl : function(){
45715 // private (for BoxComponent)
45716 getPositionEl : function(){
45721 initEvents : function(){
45722 this.originalValue = this.getValue();
45726 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45729 markInvalid : Roo.emptyFn,
45731 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45734 clearInvalid : Roo.emptyFn,
45736 setValue : function(v){
45737 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45738 this.editorcore.pushValue();
45743 deferFocus : function(){
45744 this.focus.defer(10, this);
45748 focus : function(){
45749 this.editorcore.focus();
45755 onDestroy : function(){
45761 for (var i =0; i < this.toolbars.length;i++) {
45762 // fixme - ask toolbars for heights?
45763 this.toolbars[i].onDestroy();
45766 this.wrap.dom.innerHTML = '';
45767 this.wrap.remove();
45772 onFirstFocus : function(){
45773 //Roo.log("onFirstFocus");
45774 this.editorcore.onFirstFocus();
45775 for (var i =0; i < this.toolbars.length;i++) {
45776 this.toolbars[i].onFirstFocus();
45782 syncValue : function()
45784 this.editorcore.syncValue();
45787 pushValue : function()
45789 this.editorcore.pushValue();
45792 setStylesheets : function(stylesheets)
45794 this.editorcore.setStylesheets(stylesheets);
45797 removeStylesheets : function()
45799 this.editorcore.removeStylesheets();
45803 // hide stuff that is not compatible
45817 * @event specialkey
45821 * @cfg {String} fieldClass @hide
45824 * @cfg {String} focusClass @hide
45827 * @cfg {String} autoCreate @hide
45830 * @cfg {String} inputType @hide
45833 * @cfg {String} invalidClass @hide
45836 * @cfg {String} invalidText @hide
45839 * @cfg {String} msgFx @hide
45842 * @cfg {String} validateOnBlur @hide
45846 // <script type="text/javascript">
45849 * Ext JS Library 1.1.1
45850 * Copyright(c) 2006-2007, Ext JS, LLC.
45856 * @class Roo.form.HtmlEditorToolbar1
45861 new Roo.form.HtmlEditor({
45864 new Roo.form.HtmlEditorToolbar1({
45865 disable : { fonts: 1 , format: 1, ..., ... , ...],
45871 * @cfg {Object} disable List of elements to disable..
45872 * @cfg {Array} btns List of additional buttons.
45876 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45879 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45882 Roo.apply(this, config);
45884 // default disabled, based on 'good practice'..
45885 this.disable = this.disable || {};
45886 Roo.applyIf(this.disable, {
45889 specialElements : true
45893 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45894 // dont call parent... till later.
45897 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45904 editorcore : false,
45906 * @cfg {Object} disable List of toolbar elements to disable
45913 * @cfg {String} createLinkText The default text for the create link prompt
45915 createLinkText : 'Please enter the URL for the link:',
45917 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45919 defaultLinkValue : 'http:/'+'/',
45923 * @cfg {Array} fontFamilies An array of available font families
45941 // "á" , ?? a acute?
45946 "°" // , // degrees
45948 // "é" , // e ecute
45949 // "ú" , // u ecute?
45952 specialElements : [
45954 text: "Insert Table",
45957 ihtml : '<table><tr><td>Cell</td></tr></table>'
45961 text: "Insert Image",
45964 ihtml : '<img src="about:blank"/>'
45973 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45974 "input:submit", "input:button", "select", "textarea", "label" ],
45977 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45979 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45988 * @cfg {String} defaultFont default font to use.
45990 defaultFont: 'tahoma',
45992 fontSelect : false,
45995 formatCombo : false,
45997 init : function(editor)
45999 this.editor = editor;
46000 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46001 var editorcore = this.editorcore;
46005 var fid = editorcore.frameId;
46007 function btn(id, toggle, handler){
46008 var xid = fid + '-'+ id ;
46012 cls : 'x-btn-icon x-edit-'+id,
46013 enableToggle:toggle !== false,
46014 scope: _t, // was editor...
46015 handler:handler||_t.relayBtnCmd,
46016 clickEvent:'mousedown',
46017 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46024 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46026 // stop form submits
46027 tb.el.on('click', function(e){
46028 e.preventDefault(); // what does this do?
46031 if(!this.disable.font) { // && !Roo.isSafari){
46032 /* why no safari for fonts
46033 editor.fontSelect = tb.el.createChild({
46036 cls:'x-font-select',
46037 html: this.createFontOptions()
46040 editor.fontSelect.on('change', function(){
46041 var font = editor.fontSelect.dom.value;
46042 editor.relayCmd('fontname', font);
46043 editor.deferFocus();
46047 editor.fontSelect.dom,
46053 if(!this.disable.formats){
46054 this.formatCombo = new Roo.form.ComboBox({
46055 store: new Roo.data.SimpleStore({
46058 data : this.formats // from states.js
46062 //autoCreate : {tag: "div", size: "20"},
46063 displayField:'tag',
46067 triggerAction: 'all',
46068 emptyText:'Add tag',
46069 selectOnFocus:true,
46072 'select': function(c, r, i) {
46073 editorcore.insertTag(r.get('tag'));
46079 tb.addField(this.formatCombo);
46083 if(!this.disable.format){
46088 btn('strikethrough')
46091 if(!this.disable.fontSize){
46096 btn('increasefontsize', false, editorcore.adjustFont),
46097 btn('decreasefontsize', false, editorcore.adjustFont)
46102 if(!this.disable.colors){
46105 id:editorcore.frameId +'-forecolor',
46106 cls:'x-btn-icon x-edit-forecolor',
46107 clickEvent:'mousedown',
46108 tooltip: this.buttonTips['forecolor'] || undefined,
46110 menu : new Roo.menu.ColorMenu({
46111 allowReselect: true,
46112 focus: Roo.emptyFn,
46115 selectHandler: function(cp, color){
46116 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46117 editor.deferFocus();
46120 clickEvent:'mousedown'
46123 id:editorcore.frameId +'backcolor',
46124 cls:'x-btn-icon x-edit-backcolor',
46125 clickEvent:'mousedown',
46126 tooltip: this.buttonTips['backcolor'] || undefined,
46128 menu : new Roo.menu.ColorMenu({
46129 focus: Roo.emptyFn,
46132 allowReselect: true,
46133 selectHandler: function(cp, color){
46135 editorcore.execCmd('useCSS', false);
46136 editorcore.execCmd('hilitecolor', color);
46137 editorcore.execCmd('useCSS', true);
46138 editor.deferFocus();
46140 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46141 Roo.isSafari || Roo.isIE ? '#'+color : color);
46142 editor.deferFocus();
46146 clickEvent:'mousedown'
46151 // now add all the items...
46154 if(!this.disable.alignments){
46157 btn('justifyleft'),
46158 btn('justifycenter'),
46159 btn('justifyright')
46163 //if(!Roo.isSafari){
46164 if(!this.disable.links){
46167 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46171 if(!this.disable.lists){
46174 btn('insertorderedlist'),
46175 btn('insertunorderedlist')
46178 if(!this.disable.sourceEdit){
46181 btn('sourceedit', true, function(btn){
46182 this.toggleSourceEdit(btn.pressed);
46189 // special menu.. - needs to be tidied up..
46190 if (!this.disable.special) {
46193 cls: 'x-edit-none',
46199 for (var i =0; i < this.specialChars.length; i++) {
46200 smenu.menu.items.push({
46202 html: this.specialChars[i],
46203 handler: function(a,b) {
46204 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46205 //editor.insertAtCursor(a.html);
46219 if (!this.disable.cleanStyles) {
46221 cls: 'x-btn-icon x-btn-clear',
46227 for (var i =0; i < this.cleanStyles.length; i++) {
46228 cmenu.menu.items.push({
46229 actiontype : this.cleanStyles[i],
46230 html: 'Remove ' + this.cleanStyles[i],
46231 handler: function(a,b) {
46234 var c = Roo.get(editorcore.doc.body);
46235 c.select('[style]').each(function(s) {
46236 s.dom.style.removeProperty(a.actiontype);
46238 editorcore.syncValue();
46243 cmenu.menu.items.push({
46244 actiontype : 'tablewidths',
46245 html: 'Remove Table Widths',
46246 handler: function(a,b) {
46247 editorcore.cleanTableWidths();
46248 editorcore.syncValue();
46252 cmenu.menu.items.push({
46253 actiontype : 'word',
46254 html: 'Remove MS Word Formating',
46255 handler: function(a,b) {
46256 editorcore.cleanWord();
46257 editorcore.syncValue();
46262 cmenu.menu.items.push({
46263 actiontype : 'all',
46264 html: 'Remove All Styles',
46265 handler: function(a,b) {
46267 var c = Roo.get(editorcore.doc.body);
46268 c.select('[style]').each(function(s) {
46269 s.dom.removeAttribute('style');
46271 editorcore.syncValue();
46276 cmenu.menu.items.push({
46277 actiontype : 'all',
46278 html: 'Remove All CSS Classes',
46279 handler: function(a,b) {
46281 var c = Roo.get(editorcore.doc.body);
46282 c.select('[class]').each(function(s) {
46283 s.dom.removeAttribute('class');
46285 editorcore.cleanWord();
46286 editorcore.syncValue();
46291 cmenu.menu.items.push({
46292 actiontype : 'tidy',
46293 html: 'Tidy HTML Source',
46294 handler: function(a,b) {
46295 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46296 editorcore.syncValue();
46305 if (!this.disable.specialElements) {
46308 cls: 'x-edit-none',
46313 for (var i =0; i < this.specialElements.length; i++) {
46314 semenu.menu.items.push(
46316 handler: function(a,b) {
46317 editor.insertAtCursor(this.ihtml);
46319 }, this.specialElements[i])
46331 for(var i =0; i< this.btns.length;i++) {
46332 var b = Roo.factory(this.btns[i],Roo.form);
46333 b.cls = 'x-edit-none';
46335 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46336 b.cls += ' x-init-enable';
46339 b.scope = editorcore;
46347 // disable everything...
46349 this.tb.items.each(function(item){
46352 item.id != editorcore.frameId+ '-sourceedit' &&
46353 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46359 this.rendered = true;
46361 // the all the btns;
46362 editor.on('editorevent', this.updateToolbar, this);
46363 // other toolbars need to implement this..
46364 //editor.on('editmodechange', this.updateToolbar, this);
46368 relayBtnCmd : function(btn) {
46369 this.editorcore.relayCmd(btn.cmd);
46371 // private used internally
46372 createLink : function(){
46373 Roo.log("create link?");
46374 var url = prompt(this.createLinkText, this.defaultLinkValue);
46375 if(url && url != 'http:/'+'/'){
46376 this.editorcore.relayCmd('createlink', url);
46382 * Protected method that will not generally be called directly. It triggers
46383 * a toolbar update by reading the markup state of the current selection in the editor.
46385 updateToolbar: function(){
46387 if(!this.editorcore.activated){
46388 this.editor.onFirstFocus();
46392 var btns = this.tb.items.map,
46393 doc = this.editorcore.doc,
46394 frameId = this.editorcore.frameId;
46396 if(!this.disable.font && !Roo.isSafari){
46398 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46399 if(name != this.fontSelect.dom.value){
46400 this.fontSelect.dom.value = name;
46404 if(!this.disable.format){
46405 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46406 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46407 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46408 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46410 if(!this.disable.alignments){
46411 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46412 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46413 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46415 if(!Roo.isSafari && !this.disable.lists){
46416 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46417 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46420 var ans = this.editorcore.getAllAncestors();
46421 if (this.formatCombo) {
46424 var store = this.formatCombo.store;
46425 this.formatCombo.setValue("");
46426 for (var i =0; i < ans.length;i++) {
46427 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46429 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46437 // hides menus... - so this cant be on a menu...
46438 Roo.menu.MenuMgr.hideAll();
46440 //this.editorsyncValue();
46444 createFontOptions : function(){
46445 var buf = [], fs = this.fontFamilies, ff, lc;
46449 for(var i = 0, len = fs.length; i< len; i++){
46451 lc = ff.toLowerCase();
46453 '<option value="',lc,'" style="font-family:',ff,';"',
46454 (this.defaultFont == lc ? ' selected="true">' : '>'),
46459 return buf.join('');
46462 toggleSourceEdit : function(sourceEditMode){
46464 Roo.log("toolbar toogle");
46465 if(sourceEditMode === undefined){
46466 sourceEditMode = !this.sourceEditMode;
46468 this.sourceEditMode = sourceEditMode === true;
46469 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46470 // just toggle the button?
46471 if(btn.pressed !== this.sourceEditMode){
46472 btn.toggle(this.sourceEditMode);
46476 if(sourceEditMode){
46477 Roo.log("disabling buttons");
46478 this.tb.items.each(function(item){
46479 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46485 Roo.log("enabling buttons");
46486 if(this.editorcore.initialized){
46487 this.tb.items.each(function(item){
46493 Roo.log("calling toggole on editor");
46494 // tell the editor that it's been pressed..
46495 this.editor.toggleSourceEdit(sourceEditMode);
46499 * Object collection of toolbar tooltips for the buttons in the editor. The key
46500 * is the command id associated with that button and the value is a valid QuickTips object.
46505 title: 'Bold (Ctrl+B)',
46506 text: 'Make the selected text bold.',
46507 cls: 'x-html-editor-tip'
46510 title: 'Italic (Ctrl+I)',
46511 text: 'Make the selected text italic.',
46512 cls: 'x-html-editor-tip'
46520 title: 'Bold (Ctrl+B)',
46521 text: 'Make the selected text bold.',
46522 cls: 'x-html-editor-tip'
46525 title: 'Italic (Ctrl+I)',
46526 text: 'Make the selected text italic.',
46527 cls: 'x-html-editor-tip'
46530 title: 'Underline (Ctrl+U)',
46531 text: 'Underline the selected text.',
46532 cls: 'x-html-editor-tip'
46535 title: 'Strikethrough',
46536 text: 'Strikethrough the selected text.',
46537 cls: 'x-html-editor-tip'
46539 increasefontsize : {
46540 title: 'Grow Text',
46541 text: 'Increase the font size.',
46542 cls: 'x-html-editor-tip'
46544 decreasefontsize : {
46545 title: 'Shrink Text',
46546 text: 'Decrease the font size.',
46547 cls: 'x-html-editor-tip'
46550 title: 'Text Highlight Color',
46551 text: 'Change the background color of the selected text.',
46552 cls: 'x-html-editor-tip'
46555 title: 'Font Color',
46556 text: 'Change the color of the selected text.',
46557 cls: 'x-html-editor-tip'
46560 title: 'Align Text Left',
46561 text: 'Align text to the left.',
46562 cls: 'x-html-editor-tip'
46565 title: 'Center Text',
46566 text: 'Center text in the editor.',
46567 cls: 'x-html-editor-tip'
46570 title: 'Align Text Right',
46571 text: 'Align text to the right.',
46572 cls: 'x-html-editor-tip'
46574 insertunorderedlist : {
46575 title: 'Bullet List',
46576 text: 'Start a bulleted list.',
46577 cls: 'x-html-editor-tip'
46579 insertorderedlist : {
46580 title: 'Numbered List',
46581 text: 'Start a numbered list.',
46582 cls: 'x-html-editor-tip'
46585 title: 'Hyperlink',
46586 text: 'Make the selected text a hyperlink.',
46587 cls: 'x-html-editor-tip'
46590 title: 'Source Edit',
46591 text: 'Switch to source editing mode.',
46592 cls: 'x-html-editor-tip'
46596 onDestroy : function(){
46599 this.tb.items.each(function(item){
46601 item.menu.removeAll();
46603 item.menu.el.destroy();
46611 onFirstFocus: function() {
46612 this.tb.items.each(function(item){
46621 // <script type="text/javascript">
46624 * Ext JS Library 1.1.1
46625 * Copyright(c) 2006-2007, Ext JS, LLC.
46632 * @class Roo.form.HtmlEditor.ToolbarContext
46637 new Roo.form.HtmlEditor({
46640 { xtype: 'ToolbarStandard', styles : {} }
46641 { xtype: 'ToolbarContext', disable : {} }
46647 * @config : {Object} disable List of elements to disable.. (not done yet.)
46648 * @config : {Object} styles Map of styles available.
46652 Roo.form.HtmlEditor.ToolbarContext = function(config)
46655 Roo.apply(this, config);
46656 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46657 // dont call parent... till later.
46658 this.styles = this.styles || {};
46663 Roo.form.HtmlEditor.ToolbarContext.types = {
46675 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46741 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46746 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46756 style : 'fontFamily',
46757 displayField: 'display',
46758 optname : 'font-family',
46807 // should we really allow this??
46808 // should this just be
46819 style : 'fontFamily',
46820 displayField: 'display',
46821 optname : 'font-family',
46828 style : 'fontFamily',
46829 displayField: 'display',
46830 optname : 'font-family',
46837 style : 'fontFamily',
46838 displayField: 'display',
46839 optname : 'font-family',
46850 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46851 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46853 Roo.form.HtmlEditor.ToolbarContext.options = {
46855 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46856 [ 'Courier New', 'Courier New'],
46857 [ 'Tahoma', 'Tahoma'],
46858 [ 'Times New Roman,serif', 'Times'],
46859 [ 'Verdana','Verdana' ]
46863 // fixme - these need to be configurable..
46866 //Roo.form.HtmlEditor.ToolbarContext.types
46869 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46876 editorcore : false,
46878 * @cfg {Object} disable List of toolbar elements to disable
46883 * @cfg {Object} styles List of styles
46884 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46886 * These must be defined in the page, so they get rendered correctly..
46897 init : function(editor)
46899 this.editor = editor;
46900 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46901 var editorcore = this.editorcore;
46903 var fid = editorcore.frameId;
46905 function btn(id, toggle, handler){
46906 var xid = fid + '-'+ id ;
46910 cls : 'x-btn-icon x-edit-'+id,
46911 enableToggle:toggle !== false,
46912 scope: editorcore, // was editor...
46913 handler:handler||editorcore.relayBtnCmd,
46914 clickEvent:'mousedown',
46915 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46919 // create a new element.
46920 var wdiv = editor.wrap.createChild({
46922 }, editor.wrap.dom.firstChild.nextSibling, true);
46924 // can we do this more than once??
46926 // stop form submits
46929 // disable everything...
46930 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46931 this.toolbars = {};
46933 for (var i in ty) {
46935 this.toolbars[i] = this.buildToolbar(ty[i],i);
46937 this.tb = this.toolbars.BODY;
46939 this.buildFooter();
46940 this.footer.show();
46941 editor.on('hide', function( ) { this.footer.hide() }, this);
46942 editor.on('show', function( ) { this.footer.show() }, this);
46945 this.rendered = true;
46947 // the all the btns;
46948 editor.on('editorevent', this.updateToolbar, this);
46949 // other toolbars need to implement this..
46950 //editor.on('editmodechange', this.updateToolbar, this);
46956 * Protected method that will not generally be called directly. It triggers
46957 * a toolbar update by reading the markup state of the current selection in the editor.
46959 * Note you can force an update by calling on('editorevent', scope, false)
46961 updateToolbar: function(editor,ev,sel){
46964 // capture mouse up - this is handy for selecting images..
46965 // perhaps should go somewhere else...
46966 if(!this.editorcore.activated){
46967 this.editor.onFirstFocus();
46973 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46974 // selectNode - might want to handle IE?
46976 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46977 ev.target && ev.target.tagName == 'IMG') {
46978 // they have click on an image...
46979 // let's see if we can change the selection...
46982 var nodeRange = sel.ownerDocument.createRange();
46984 nodeRange.selectNode(sel);
46986 nodeRange.selectNodeContents(sel);
46988 //nodeRange.collapse(true);
46989 var s = this.editorcore.win.getSelection();
46990 s.removeAllRanges();
46991 s.addRange(nodeRange);
46995 var updateFooter = sel ? false : true;
46998 var ans = this.editorcore.getAllAncestors();
47001 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47004 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47005 sel = sel ? sel : this.editorcore.doc.body;
47006 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47009 // pick a menu that exists..
47010 var tn = sel.tagName.toUpperCase();
47011 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47013 tn = sel.tagName.toUpperCase();
47015 var lastSel = this.tb.selectedNode;
47017 this.tb.selectedNode = sel;
47019 // if current menu does not match..
47021 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47024 ///console.log("show: " + tn);
47025 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47028 this.tb.items.first().el.innerHTML = tn + ': ';
47031 // update attributes
47032 if (this.tb.fields) {
47033 this.tb.fields.each(function(e) {
47035 e.setValue(sel.style[e.stylename]);
47038 e.setValue(sel.getAttribute(e.attrname));
47042 var hasStyles = false;
47043 for(var i in this.styles) {
47050 var st = this.tb.fields.item(0);
47052 st.store.removeAll();
47055 var cn = sel.className.split(/\s+/);
47058 if (this.styles['*']) {
47060 Roo.each(this.styles['*'], function(v) {
47061 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47064 if (this.styles[tn]) {
47065 Roo.each(this.styles[tn], function(v) {
47066 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47070 st.store.loadData(avs);
47074 // flag our selected Node.
47075 this.tb.selectedNode = sel;
47078 Roo.menu.MenuMgr.hideAll();
47082 if (!updateFooter) {
47083 //this.footDisp.dom.innerHTML = '';
47086 // update the footer
47090 this.footerEls = ans.reverse();
47091 Roo.each(this.footerEls, function(a,i) {
47092 if (!a) { return; }
47093 html += html.length ? ' > ' : '';
47095 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47100 var sz = this.footDisp.up('td').getSize();
47101 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47102 this.footDisp.dom.style.marginLeft = '5px';
47104 this.footDisp.dom.style.overflow = 'hidden';
47106 this.footDisp.dom.innerHTML = html;
47108 //this.editorsyncValue();
47115 onDestroy : function(){
47118 this.tb.items.each(function(item){
47120 item.menu.removeAll();
47122 item.menu.el.destroy();
47130 onFirstFocus: function() {
47131 // need to do this for all the toolbars..
47132 this.tb.items.each(function(item){
47136 buildToolbar: function(tlist, nm)
47138 var editor = this.editor;
47139 var editorcore = this.editorcore;
47140 // create a new element.
47141 var wdiv = editor.wrap.createChild({
47143 }, editor.wrap.dom.firstChild.nextSibling, true);
47146 var tb = new Roo.Toolbar(wdiv);
47149 tb.add(nm+ ": ");
47152 for(var i in this.styles) {
47157 if (styles && styles.length) {
47159 // this needs a multi-select checkbox...
47160 tb.addField( new Roo.form.ComboBox({
47161 store: new Roo.data.SimpleStore({
47163 fields: ['val', 'selected'],
47166 name : '-roo-edit-className',
47167 attrname : 'className',
47168 displayField: 'val',
47172 triggerAction: 'all',
47173 emptyText:'Select Style',
47174 selectOnFocus:true,
47177 'select': function(c, r, i) {
47178 // initial support only for on class per el..
47179 tb.selectedNode.className = r ? r.get('val') : '';
47180 editorcore.syncValue();
47187 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47188 var tbops = tbc.options;
47190 for (var i in tlist) {
47192 var item = tlist[i];
47193 tb.add(item.title + ": ");
47196 //optname == used so you can configure the options available..
47197 var opts = item.opts ? item.opts : false;
47198 if (item.optname) {
47199 opts = tbops[item.optname];
47204 // opts == pulldown..
47205 tb.addField( new Roo.form.ComboBox({
47206 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47208 fields: ['val', 'display'],
47211 name : '-roo-edit-' + i,
47213 stylename : item.style ? item.style : false,
47214 displayField: item.displayField ? item.displayField : 'val',
47215 valueField : 'val',
47217 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47219 triggerAction: 'all',
47220 emptyText:'Select',
47221 selectOnFocus:true,
47222 width: item.width ? item.width : 130,
47224 'select': function(c, r, i) {
47226 tb.selectedNode.style[c.stylename] = r.get('val');
47229 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47238 tb.addField( new Roo.form.TextField({
47241 //allowBlank:false,
47246 tb.addField( new Roo.form.TextField({
47247 name: '-roo-edit-' + i,
47254 'change' : function(f, nv, ov) {
47255 tb.selectedNode.setAttribute(f.attrname, nv);
47256 editorcore.syncValue();
47269 text: 'Stylesheets',
47272 click : function ()
47274 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47282 text: 'Remove Tag',
47285 click : function ()
47288 // undo does not work.
47290 var sn = tb.selectedNode;
47292 var pn = sn.parentNode;
47294 var stn = sn.childNodes[0];
47295 var en = sn.childNodes[sn.childNodes.length - 1 ];
47296 while (sn.childNodes.length) {
47297 var node = sn.childNodes[0];
47298 sn.removeChild(node);
47300 pn.insertBefore(node, sn);
47303 pn.removeChild(sn);
47304 var range = editorcore.createRange();
47306 range.setStart(stn,0);
47307 range.setEnd(en,0); //????
47308 //range.selectNode(sel);
47311 var selection = editorcore.getSelection();
47312 selection.removeAllRanges();
47313 selection.addRange(range);
47317 //_this.updateToolbar(null, null, pn);
47318 _this.updateToolbar(null, null, null);
47319 _this.footDisp.dom.innerHTML = '';
47329 tb.el.on('click', function(e){
47330 e.preventDefault(); // what does this do?
47332 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47335 // dont need to disable them... as they will get hidden
47340 buildFooter : function()
47343 var fel = this.editor.wrap.createChild();
47344 this.footer = new Roo.Toolbar(fel);
47345 // toolbar has scrolly on left / right?
47346 var footDisp= new Roo.Toolbar.Fill();
47352 handler : function() {
47353 _t.footDisp.scrollTo('left',0,true)
47357 this.footer.add( footDisp );
47362 handler : function() {
47364 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47368 var fel = Roo.get(footDisp.el);
47369 fel.addClass('x-editor-context');
47370 this.footDispWrap = fel;
47371 this.footDispWrap.overflow = 'hidden';
47373 this.footDisp = fel.createChild();
47374 this.footDispWrap.on('click', this.onContextClick, this)
47378 onContextClick : function (ev,dom)
47380 ev.preventDefault();
47381 var cn = dom.className;
47383 if (!cn.match(/x-ed-loc-/)) {
47386 var n = cn.split('-').pop();
47387 var ans = this.footerEls;
47391 var range = this.editorcore.createRange();
47393 range.selectNodeContents(sel);
47394 //range.selectNode(sel);
47397 var selection = this.editorcore.getSelection();
47398 selection.removeAllRanges();
47399 selection.addRange(range);
47403 this.updateToolbar(null, null, sel);
47420 * Ext JS Library 1.1.1
47421 * Copyright(c) 2006-2007, Ext JS, LLC.
47423 * Originally Released Under LGPL - original licence link has changed is not relivant.
47426 * <script type="text/javascript">
47430 * @class Roo.form.BasicForm
47431 * @extends Roo.util.Observable
47432 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47434 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47435 * @param {Object} config Configuration options
47437 Roo.form.BasicForm = function(el, config){
47438 this.allItems = [];
47439 this.childForms = [];
47440 Roo.apply(this, config);
47442 * The Roo.form.Field items in this form.
47443 * @type MixedCollection
47447 this.items = new Roo.util.MixedCollection(false, function(o){
47448 return o.id || (o.id = Roo.id());
47452 * @event beforeaction
47453 * Fires before any action is performed. Return false to cancel the action.
47454 * @param {Form} this
47455 * @param {Action} action The action to be performed
47457 beforeaction: true,
47459 * @event actionfailed
47460 * Fires when an action fails.
47461 * @param {Form} this
47462 * @param {Action} action The action that failed
47464 actionfailed : true,
47466 * @event actioncomplete
47467 * Fires when an action is completed.
47468 * @param {Form} this
47469 * @param {Action} action The action that completed
47471 actioncomplete : true
47476 Roo.form.BasicForm.superclass.constructor.call(this);
47478 Roo.form.BasicForm.popover.apply();
47481 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47483 * @cfg {String} method
47484 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47487 * @cfg {DataReader} reader
47488 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47489 * This is optional as there is built-in support for processing JSON.
47492 * @cfg {DataReader} errorReader
47493 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47494 * This is completely optional as there is built-in support for processing JSON.
47497 * @cfg {String} url
47498 * The URL to use for form actions if one isn't supplied in the action options.
47501 * @cfg {Boolean} fileUpload
47502 * Set to true if this form is a file upload.
47506 * @cfg {Object} baseParams
47507 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47512 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47517 activeAction : null,
47520 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47521 * or setValues() data instead of when the form was first created.
47523 trackResetOnLoad : false,
47527 * childForms - used for multi-tab forms
47530 childForms : false,
47533 * allItems - full list of fields.
47539 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47540 * element by passing it or its id or mask the form itself by passing in true.
47543 waitMsgTarget : false,
47548 disableMask : false,
47551 * @cfg {Boolean} errorMask (true|false) default false
47556 * @cfg {Number} maskOffset Default 100
47561 initEl : function(el){
47562 this.el = Roo.get(el);
47563 this.id = this.el.id || Roo.id();
47564 this.el.on('submit', this.onSubmit, this);
47565 this.el.addClass('x-form');
47569 onSubmit : function(e){
47574 * Returns true if client-side validation on the form is successful.
47577 isValid : function(){
47579 var target = false;
47580 this.items.each(function(f){
47587 if(!target && f.el.isVisible(true)){
47592 if(this.errorMask && !valid){
47593 Roo.form.BasicForm.popover.mask(this, target);
47599 * Returns array of invalid form fields.
47603 invalidFields : function()
47606 this.items.each(function(f){
47619 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47622 isDirty : function(){
47624 this.items.each(function(f){
47634 * Returns true if any fields in this form have changed since their original load. (New version)
47638 hasChanged : function()
47641 this.items.each(function(f){
47642 if(f.hasChanged()){
47651 * Resets all hasChanged to 'false' -
47652 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47653 * So hasChanged storage is only to be used for this purpose
47656 resetHasChanged : function()
47658 this.items.each(function(f){
47659 f.resetHasChanged();
47666 * Performs a predefined action (submit or load) or custom actions you define on this form.
47667 * @param {String} actionName The name of the action type
47668 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47669 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47670 * accept other config options):
47672 Property Type Description
47673 ---------------- --------------- ----------------------------------------------------------------------------------
47674 url String The url for the action (defaults to the form's url)
47675 method String The form method to use (defaults to the form's method, or POST if not defined)
47676 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47677 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47678 validate the form on the client (defaults to false)
47680 * @return {BasicForm} this
47682 doAction : function(action, options){
47683 if(typeof action == 'string'){
47684 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47686 if(this.fireEvent('beforeaction', this, action) !== false){
47687 this.beforeAction(action);
47688 action.run.defer(100, action);
47694 * Shortcut to do a submit action.
47695 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47696 * @return {BasicForm} this
47698 submit : function(options){
47699 this.doAction('submit', options);
47704 * Shortcut to do a load action.
47705 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47706 * @return {BasicForm} this
47708 load : function(options){
47709 this.doAction('load', options);
47714 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47715 * @param {Record} record The record to edit
47716 * @return {BasicForm} this
47718 updateRecord : function(record){
47719 record.beginEdit();
47720 var fs = record.fields;
47721 fs.each(function(f){
47722 var field = this.findField(f.name);
47724 record.set(f.name, field.getValue());
47732 * Loads an Roo.data.Record into this form.
47733 * @param {Record} record The record to load
47734 * @return {BasicForm} this
47736 loadRecord : function(record){
47737 this.setValues(record.data);
47742 beforeAction : function(action){
47743 var o = action.options;
47745 if(!this.disableMask) {
47746 if(this.waitMsgTarget === true){
47747 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47748 }else if(this.waitMsgTarget){
47749 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47750 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47752 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47760 afterAction : function(action, success){
47761 this.activeAction = null;
47762 var o = action.options;
47764 if(!this.disableMask) {
47765 if(this.waitMsgTarget === true){
47767 }else if(this.waitMsgTarget){
47768 this.waitMsgTarget.unmask();
47770 Roo.MessageBox.updateProgress(1);
47771 Roo.MessageBox.hide();
47779 Roo.callback(o.success, o.scope, [this, action]);
47780 this.fireEvent('actioncomplete', this, action);
47784 // failure condition..
47785 // we have a scenario where updates need confirming.
47786 // eg. if a locking scenario exists..
47787 // we look for { errors : { needs_confirm : true }} in the response.
47789 (typeof(action.result) != 'undefined') &&
47790 (typeof(action.result.errors) != 'undefined') &&
47791 (typeof(action.result.errors.needs_confirm) != 'undefined')
47794 Roo.MessageBox.confirm(
47795 "Change requires confirmation",
47796 action.result.errorMsg,
47801 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47811 Roo.callback(o.failure, o.scope, [this, action]);
47812 // show an error message if no failed handler is set..
47813 if (!this.hasListener('actionfailed')) {
47814 Roo.MessageBox.alert("Error",
47815 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47816 action.result.errorMsg :
47817 "Saving Failed, please check your entries or try again"
47821 this.fireEvent('actionfailed', this, action);
47827 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47828 * @param {String} id The value to search for
47831 findField : function(id){
47832 var field = this.items.get(id);
47834 this.items.each(function(f){
47835 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47841 return field || null;
47845 * Add a secondary form to this one,
47846 * Used to provide tabbed forms. One form is primary, with hidden values
47847 * which mirror the elements from the other forms.
47849 * @param {Roo.form.Form} form to add.
47852 addForm : function(form)
47855 if (this.childForms.indexOf(form) > -1) {
47859 this.childForms.push(form);
47861 Roo.each(form.allItems, function (fe) {
47863 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
47864 if (this.findField(n)) { // already added..
47867 var add = new Roo.form.Hidden({
47870 add.render(this.el);
47877 * Mark fields in this form invalid in bulk.
47878 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
47879 * @return {BasicForm} this
47881 markInvalid : function(errors){
47882 if(errors instanceof Array){
47883 for(var i = 0, len = errors.length; i < len; i++){
47884 var fieldError = errors[i];
47885 var f = this.findField(fieldError.id);
47887 f.markInvalid(fieldError.msg);
47893 if(typeof errors[id] != 'function' && (field = this.findField(id))){
47894 field.markInvalid(errors[id]);
47898 Roo.each(this.childForms || [], function (f) {
47899 f.markInvalid(errors);
47906 * Set values for fields in this form in bulk.
47907 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
47908 * @return {BasicForm} this
47910 setValues : function(values){
47911 if(values instanceof Array){ // array of objects
47912 for(var i = 0, len = values.length; i < len; i++){
47914 var f = this.findField(v.id);
47916 f.setValue(v.value);
47917 if(this.trackResetOnLoad){
47918 f.originalValue = f.getValue();
47922 }else{ // object hash
47925 if(typeof values[id] != 'function' && (field = this.findField(id))){
47927 if (field.setFromData &&
47928 field.valueField &&
47929 field.displayField &&
47930 // combos' with local stores can
47931 // be queried via setValue()
47932 // to set their value..
47933 (field.store && !field.store.isLocal)
47937 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47938 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47939 field.setFromData(sd);
47942 field.setValue(values[id]);
47946 if(this.trackResetOnLoad){
47947 field.originalValue = field.getValue();
47952 this.resetHasChanged();
47955 Roo.each(this.childForms || [], function (f) {
47956 f.setValues(values);
47957 f.resetHasChanged();
47964 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47965 * they are returned as an array.
47966 * @param {Boolean} asString
47969 getValues : function(asString){
47970 if (this.childForms) {
47971 // copy values from the child forms
47972 Roo.each(this.childForms, function (f) {
47973 this.setValues(f.getValues());
47978 if (typeof(FormData) != 'undefined' && asString !== true) {
47979 // this relies on a 'recent' version of chrome apparently...
47981 var fd = (new FormData(this.el.dom)).entries();
47983 var ent = fd.next();
47984 while (!ent.done) {
47985 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
47996 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47997 if(asString === true){
48000 return Roo.urlDecode(fs);
48004 * Returns the fields in this form as an object with key/value pairs.
48005 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48008 getFieldValues : function(with_hidden)
48010 if (this.childForms) {
48011 // copy values from the child forms
48012 // should this call getFieldValues - probably not as we do not currently copy
48013 // hidden fields when we generate..
48014 Roo.each(this.childForms, function (f) {
48015 this.setValues(f.getValues());
48020 this.items.each(function(f){
48021 if (!f.getName()) {
48024 var v = f.getValue();
48025 if (f.inputType =='radio') {
48026 if (typeof(ret[f.getName()]) == 'undefined') {
48027 ret[f.getName()] = ''; // empty..
48030 if (!f.el.dom.checked) {
48034 v = f.el.dom.value;
48038 // not sure if this supported any more..
48039 if ((typeof(v) == 'object') && f.getRawValue) {
48040 v = f.getRawValue() ; // dates..
48042 // combo boxes where name != hiddenName...
48043 if (f.name != f.getName()) {
48044 ret[f.name] = f.getRawValue();
48046 ret[f.getName()] = v;
48053 * Clears all invalid messages in this form.
48054 * @return {BasicForm} this
48056 clearInvalid : function(){
48057 this.items.each(function(f){
48061 Roo.each(this.childForms || [], function (f) {
48070 * Resets this form.
48071 * @return {BasicForm} this
48073 reset : function(){
48074 this.items.each(function(f){
48078 Roo.each(this.childForms || [], function (f) {
48081 this.resetHasChanged();
48087 * Add Roo.form components to this form.
48088 * @param {Field} field1
48089 * @param {Field} field2 (optional)
48090 * @param {Field} etc (optional)
48091 * @return {BasicForm} this
48094 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48100 * Removes a field from the items collection (does NOT remove its markup).
48101 * @param {Field} field
48102 * @return {BasicForm} this
48104 remove : function(field){
48105 this.items.remove(field);
48110 * Looks at the fields in this form, checks them for an id attribute,
48111 * and calls applyTo on the existing dom element with that id.
48112 * @return {BasicForm} this
48114 render : function(){
48115 this.items.each(function(f){
48116 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48124 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48125 * @param {Object} values
48126 * @return {BasicForm} this
48128 applyToFields : function(o){
48129 this.items.each(function(f){
48136 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48137 * @param {Object} values
48138 * @return {BasicForm} this
48140 applyIfToFields : function(o){
48141 this.items.each(function(f){
48149 Roo.BasicForm = Roo.form.BasicForm;
48151 Roo.apply(Roo.form.BasicForm, {
48165 intervalID : false,
48171 if(this.isApplied){
48176 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48177 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48178 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48179 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48182 this.maskEl.top.enableDisplayMode("block");
48183 this.maskEl.left.enableDisplayMode("block");
48184 this.maskEl.bottom.enableDisplayMode("block");
48185 this.maskEl.right.enableDisplayMode("block");
48187 Roo.get(document.body).on('click', function(){
48191 Roo.get(document.body).on('touchstart', function(){
48195 this.isApplied = true
48198 mask : function(form, target)
48202 this.target = target;
48204 if(!this.form.errorMask || !target.el){
48208 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48210 var ot = this.target.el.calcOffsetsTo(scrollable);
48212 var scrollTo = ot[1] - this.form.maskOffset;
48214 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48216 scrollable.scrollTo('top', scrollTo);
48218 var el = this.target.wrap || this.target.el;
48220 var box = el.getBox();
48222 this.maskEl.top.setStyle('position', 'absolute');
48223 this.maskEl.top.setStyle('z-index', 10000);
48224 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48225 this.maskEl.top.setLeft(0);
48226 this.maskEl.top.setTop(0);
48227 this.maskEl.top.show();
48229 this.maskEl.left.setStyle('position', 'absolute');
48230 this.maskEl.left.setStyle('z-index', 10000);
48231 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48232 this.maskEl.left.setLeft(0);
48233 this.maskEl.left.setTop(box.y - this.padding);
48234 this.maskEl.left.show();
48236 this.maskEl.bottom.setStyle('position', 'absolute');
48237 this.maskEl.bottom.setStyle('z-index', 10000);
48238 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48239 this.maskEl.bottom.setLeft(0);
48240 this.maskEl.bottom.setTop(box.bottom + this.padding);
48241 this.maskEl.bottom.show();
48243 this.maskEl.right.setStyle('position', 'absolute');
48244 this.maskEl.right.setStyle('z-index', 10000);
48245 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48246 this.maskEl.right.setLeft(box.right + this.padding);
48247 this.maskEl.right.setTop(box.y - this.padding);
48248 this.maskEl.right.show();
48250 this.intervalID = window.setInterval(function() {
48251 Roo.form.BasicForm.popover.unmask();
48254 window.onwheel = function(){ return false;};
48256 (function(){ this.isMasked = true; }).defer(500, this);
48260 unmask : function()
48262 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48266 this.maskEl.top.setStyle('position', 'absolute');
48267 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48268 this.maskEl.top.hide();
48270 this.maskEl.left.setStyle('position', 'absolute');
48271 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48272 this.maskEl.left.hide();
48274 this.maskEl.bottom.setStyle('position', 'absolute');
48275 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48276 this.maskEl.bottom.hide();
48278 this.maskEl.right.setStyle('position', 'absolute');
48279 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48280 this.maskEl.right.hide();
48282 window.onwheel = function(){ return true;};
48284 if(this.intervalID){
48285 window.clearInterval(this.intervalID);
48286 this.intervalID = false;
48289 this.isMasked = false;
48297 * Ext JS Library 1.1.1
48298 * Copyright(c) 2006-2007, Ext JS, LLC.
48300 * Originally Released Under LGPL - original licence link has changed is not relivant.
48303 * <script type="text/javascript">
48307 * @class Roo.form.Form
48308 * @extends Roo.form.BasicForm
48309 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48311 * @param {Object} config Configuration options
48313 Roo.form.Form = function(config){
48315 if (config.items) {
48316 xitems = config.items;
48317 delete config.items;
48321 Roo.form.Form.superclass.constructor.call(this, null, config);
48322 this.url = this.url || this.action;
48324 this.root = new Roo.form.Layout(Roo.applyIf({
48328 this.active = this.root;
48330 * Array of all the buttons that have been added to this form via {@link addButton}
48334 this.allItems = [];
48337 * @event clientvalidation
48338 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48339 * @param {Form} this
48340 * @param {Boolean} valid true if the form has passed client-side validation
48342 clientvalidation: true,
48345 * Fires when the form is rendered
48346 * @param {Roo.form.Form} form
48351 if (this.progressUrl) {
48352 // push a hidden field onto the list of fields..
48356 name : 'UPLOAD_IDENTIFIER'
48361 Roo.each(xitems, this.addxtype, this);
48365 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48367 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48370 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48373 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48375 buttonAlign:'center',
48378 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48383 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48384 * This property cascades to child containers if not set.
48389 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48390 * fires a looping event with that state. This is required to bind buttons to the valid
48391 * state using the config value formBind:true on the button.
48393 monitorValid : false,
48396 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48401 * @cfg {String} progressUrl - Url to return progress data
48404 progressUrl : false,
48406 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48407 * sending a formdata with extra parameters - eg uploaded elements.
48413 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48414 * fields are added and the column is closed. If no fields are passed the column remains open
48415 * until end() is called.
48416 * @param {Object} config The config to pass to the column
48417 * @param {Field} field1 (optional)
48418 * @param {Field} field2 (optional)
48419 * @param {Field} etc (optional)
48420 * @return Column The column container object
48422 column : function(c){
48423 var col = new Roo.form.Column(c);
48425 if(arguments.length > 1){ // duplicate code required because of Opera
48426 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48433 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48434 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48435 * until end() is called.
48436 * @param {Object} config The config to pass to the fieldset
48437 * @param {Field} field1 (optional)
48438 * @param {Field} field2 (optional)
48439 * @param {Field} etc (optional)
48440 * @return FieldSet The fieldset container object
48442 fieldset : function(c){
48443 var fs = new Roo.form.FieldSet(c);
48445 if(arguments.length > 1){ // duplicate code required because of Opera
48446 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48453 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48454 * fields are added and the container is closed. If no fields are passed the container remains open
48455 * until end() is called.
48456 * @param {Object} config The config to pass to the Layout
48457 * @param {Field} field1 (optional)
48458 * @param {Field} field2 (optional)
48459 * @param {Field} etc (optional)
48460 * @return Layout The container object
48462 container : function(c){
48463 var l = new Roo.form.Layout(c);
48465 if(arguments.length > 1){ // duplicate code required because of Opera
48466 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48473 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48474 * @param {Object} container A Roo.form.Layout or subclass of Layout
48475 * @return {Form} this
48477 start : function(c){
48478 // cascade label info
48479 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48480 this.active.stack.push(c);
48481 c.ownerCt = this.active;
48487 * Closes the current open container
48488 * @return {Form} this
48491 if(this.active == this.root){
48494 this.active = this.active.ownerCt;
48499 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48500 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48501 * as the label of the field.
48502 * @param {Field} field1
48503 * @param {Field} field2 (optional)
48504 * @param {Field} etc. (optional)
48505 * @return {Form} this
48508 this.active.stack.push.apply(this.active.stack, arguments);
48509 this.allItems.push.apply(this.allItems,arguments);
48511 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48512 if(a[i].isFormField){
48517 Roo.form.Form.superclass.add.apply(this, r);
48527 * Find any element that has been added to a form, using it's ID or name
48528 * This can include framesets, columns etc. along with regular fields..
48529 * @param {String} id - id or name to find.
48531 * @return {Element} e - or false if nothing found.
48533 findbyId : function(id)
48539 Roo.each(this.allItems, function(f){
48540 if (f.id == id || f.name == id ){
48551 * Render this form into the passed container. This should only be called once!
48552 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48553 * @return {Form} this
48555 render : function(ct)
48561 var o = this.autoCreate || {
48563 method : this.method || 'POST',
48564 id : this.id || Roo.id()
48566 this.initEl(ct.createChild(o));
48568 this.root.render(this.el);
48572 this.items.each(function(f){
48573 f.render('x-form-el-'+f.id);
48576 if(this.buttons.length > 0){
48577 // tables are required to maintain order and for correct IE layout
48578 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48579 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48580 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48582 var tr = tb.getElementsByTagName('tr')[0];
48583 for(var i = 0, len = this.buttons.length; i < len; i++) {
48584 var b = this.buttons[i];
48585 var td = document.createElement('td');
48586 td.className = 'x-form-btn-td';
48587 b.render(tr.appendChild(td));
48590 if(this.monitorValid){ // initialize after render
48591 this.startMonitoring();
48593 this.fireEvent('rendered', this);
48598 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48599 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48600 * object or a valid Roo.DomHelper element config
48601 * @param {Function} handler The function called when the button is clicked
48602 * @param {Object} scope (optional) The scope of the handler function
48603 * @return {Roo.Button}
48605 addButton : function(config, handler, scope){
48609 minWidth: this.minButtonWidth,
48612 if(typeof config == "string"){
48615 Roo.apply(bc, config);
48617 var btn = new Roo.Button(null, bc);
48618 this.buttons.push(btn);
48623 * Adds a series of form elements (using the xtype property as the factory method.
48624 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48625 * @param {Object} config
48628 addxtype : function()
48630 var ar = Array.prototype.slice.call(arguments, 0);
48632 for(var i = 0; i < ar.length; i++) {
48634 continue; // skip -- if this happends something invalid got sent, we
48635 // should ignore it, as basically that interface element will not show up
48636 // and that should be pretty obvious!!
48639 if (Roo.form[ar[i].xtype]) {
48641 var fe = Roo.factory(ar[i], Roo.form);
48647 fe.store.form = this;
48652 this.allItems.push(fe);
48653 if (fe.items && fe.addxtype) {
48654 fe.addxtype.apply(fe, fe.items);
48664 // console.log('adding ' + ar[i].xtype);
48666 if (ar[i].xtype == 'Button') {
48667 //console.log('adding button');
48668 //console.log(ar[i]);
48669 this.addButton(ar[i]);
48670 this.allItems.push(fe);
48674 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48675 alert('end is not supported on xtype any more, use items');
48677 // //console.log('adding end');
48685 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48686 * option "monitorValid"
48688 startMonitoring : function(){
48691 Roo.TaskMgr.start({
48692 run : this.bindHandler,
48693 interval : this.monitorPoll || 200,
48700 * Stops monitoring of the valid state of this form
48702 stopMonitoring : function(){
48703 this.bound = false;
48707 bindHandler : function(){
48709 return false; // stops binding
48712 this.items.each(function(f){
48713 if(!f.isValid(true)){
48718 for(var i = 0, len = this.buttons.length; i < len; i++){
48719 var btn = this.buttons[i];
48720 if(btn.formBind === true && btn.disabled === valid){
48721 btn.setDisabled(!valid);
48724 this.fireEvent('clientvalidation', this, valid);
48738 Roo.Form = Roo.form.Form;
48741 * Ext JS Library 1.1.1
48742 * Copyright(c) 2006-2007, Ext JS, LLC.
48744 * Originally Released Under LGPL - original licence link has changed is not relivant.
48747 * <script type="text/javascript">
48750 // as we use this in bootstrap.
48751 Roo.namespace('Roo.form');
48753 * @class Roo.form.Action
48754 * Internal Class used to handle form actions
48756 * @param {Roo.form.BasicForm} el The form element or its id
48757 * @param {Object} config Configuration options
48762 // define the action interface
48763 Roo.form.Action = function(form, options){
48765 this.options = options || {};
48768 * Client Validation Failed
48771 Roo.form.Action.CLIENT_INVALID = 'client';
48773 * Server Validation Failed
48776 Roo.form.Action.SERVER_INVALID = 'server';
48778 * Connect to Server Failed
48781 Roo.form.Action.CONNECT_FAILURE = 'connect';
48783 * Reading Data from Server Failed
48786 Roo.form.Action.LOAD_FAILURE = 'load';
48788 Roo.form.Action.prototype = {
48790 failureType : undefined,
48791 response : undefined,
48792 result : undefined,
48794 // interface method
48795 run : function(options){
48799 // interface method
48800 success : function(response){
48804 // interface method
48805 handleResponse : function(response){
48809 // default connection failure
48810 failure : function(response){
48812 this.response = response;
48813 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48814 this.form.afterAction(this, false);
48817 processResponse : function(response){
48818 this.response = response;
48819 if(!response.responseText){
48822 this.result = this.handleResponse(response);
48823 return this.result;
48826 // utility functions used internally
48827 getUrl : function(appendParams){
48828 var url = this.options.url || this.form.url || this.form.el.dom.action;
48830 var p = this.getParams();
48832 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
48838 getMethod : function(){
48839 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
48842 getParams : function(){
48843 var bp = this.form.baseParams;
48844 var p = this.options.params;
48846 if(typeof p == "object"){
48847 p = Roo.urlEncode(Roo.applyIf(p, bp));
48848 }else if(typeof p == 'string' && bp){
48849 p += '&' + Roo.urlEncode(bp);
48852 p = Roo.urlEncode(bp);
48857 createCallback : function(){
48859 success: this.success,
48860 failure: this.failure,
48862 timeout: (this.form.timeout*1000),
48863 upload: this.form.fileUpload ? this.success : undefined
48868 Roo.form.Action.Submit = function(form, options){
48869 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
48872 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
48875 haveProgress : false,
48876 uploadComplete : false,
48878 // uploadProgress indicator.
48879 uploadProgress : function()
48881 if (!this.form.progressUrl) {
48885 if (!this.haveProgress) {
48886 Roo.MessageBox.progress("Uploading", "Uploading");
48888 if (this.uploadComplete) {
48889 Roo.MessageBox.hide();
48893 this.haveProgress = true;
48895 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
48897 var c = new Roo.data.Connection();
48899 url : this.form.progressUrl,
48904 success : function(req){
48905 //console.log(data);
48909 rdata = Roo.decode(req.responseText)
48911 Roo.log("Invalid data from server..");
48915 if (!rdata || !rdata.success) {
48917 Roo.MessageBox.alert(Roo.encode(rdata));
48920 var data = rdata.data;
48922 if (this.uploadComplete) {
48923 Roo.MessageBox.hide();
48928 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
48929 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
48932 this.uploadProgress.defer(2000,this);
48935 failure: function(data) {
48936 Roo.log('progress url failed ');
48947 // run get Values on the form, so it syncs any secondary forms.
48948 this.form.getValues();
48950 var o = this.options;
48951 var method = this.getMethod();
48952 var isPost = method == 'POST';
48953 if(o.clientValidation === false || this.form.isValid()){
48955 if (this.form.progressUrl) {
48956 this.form.findField('UPLOAD_IDENTIFIER').setValue(
48957 (new Date() * 1) + '' + Math.random());
48962 Roo.Ajax.request(Roo.apply(this.createCallback(), {
48963 form:this.form.el.dom,
48964 url:this.getUrl(!isPost),
48966 params:isPost ? this.getParams() : null,
48967 isUpload: this.form.fileUpload,
48968 formData : this.form.formData
48971 this.uploadProgress();
48973 }else if (o.clientValidation !== false){ // client validation failed
48974 this.failureType = Roo.form.Action.CLIENT_INVALID;
48975 this.form.afterAction(this, false);
48979 success : function(response)
48981 this.uploadComplete= true;
48982 if (this.haveProgress) {
48983 Roo.MessageBox.hide();
48987 var result = this.processResponse(response);
48988 if(result === true || result.success){
48989 this.form.afterAction(this, true);
48993 this.form.markInvalid(result.errors);
48994 this.failureType = Roo.form.Action.SERVER_INVALID;
48996 this.form.afterAction(this, false);
48998 failure : function(response)
49000 this.uploadComplete= true;
49001 if (this.haveProgress) {
49002 Roo.MessageBox.hide();
49005 this.response = response;
49006 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49007 this.form.afterAction(this, false);
49010 handleResponse : function(response){
49011 if(this.form.errorReader){
49012 var rs = this.form.errorReader.read(response);
49015 for(var i = 0, len = rs.records.length; i < len; i++) {
49016 var r = rs.records[i];
49017 errors[i] = r.data;
49020 if(errors.length < 1){
49024 success : rs.success,
49030 ret = Roo.decode(response.responseText);
49034 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49044 Roo.form.Action.Load = function(form, options){
49045 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49046 this.reader = this.form.reader;
49049 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49054 Roo.Ajax.request(Roo.apply(
49055 this.createCallback(), {
49056 method:this.getMethod(),
49057 url:this.getUrl(false),
49058 params:this.getParams()
49062 success : function(response){
49064 var result = this.processResponse(response);
49065 if(result === true || !result.success || !result.data){
49066 this.failureType = Roo.form.Action.LOAD_FAILURE;
49067 this.form.afterAction(this, false);
49070 this.form.clearInvalid();
49071 this.form.setValues(result.data);
49072 this.form.afterAction(this, true);
49075 handleResponse : function(response){
49076 if(this.form.reader){
49077 var rs = this.form.reader.read(response);
49078 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49080 success : rs.success,
49084 return Roo.decode(response.responseText);
49088 Roo.form.Action.ACTION_TYPES = {
49089 'load' : Roo.form.Action.Load,
49090 'submit' : Roo.form.Action.Submit
49093 * Ext JS Library 1.1.1
49094 * Copyright(c) 2006-2007, Ext JS, LLC.
49096 * Originally Released Under LGPL - original licence link has changed is not relivant.
49099 * <script type="text/javascript">
49103 * @class Roo.form.Layout
49104 * @extends Roo.Component
49105 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49107 * @param {Object} config Configuration options
49109 Roo.form.Layout = function(config){
49111 if (config.items) {
49112 xitems = config.items;
49113 delete config.items;
49115 Roo.form.Layout.superclass.constructor.call(this, config);
49117 Roo.each(xitems, this.addxtype, this);
49121 Roo.extend(Roo.form.Layout, Roo.Component, {
49123 * @cfg {String/Object} autoCreate
49124 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49127 * @cfg {String/Object/Function} style
49128 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49129 * a function which returns such a specification.
49132 * @cfg {String} labelAlign
49133 * Valid values are "left," "top" and "right" (defaults to "left")
49136 * @cfg {Number} labelWidth
49137 * Fixed width in pixels of all field labels (defaults to undefined)
49140 * @cfg {Boolean} clear
49141 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49145 * @cfg {String} labelSeparator
49146 * The separator to use after field labels (defaults to ':')
49148 labelSeparator : ':',
49150 * @cfg {Boolean} hideLabels
49151 * True to suppress the display of field labels in this layout (defaults to false)
49153 hideLabels : false,
49156 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49161 onRender : function(ct, position){
49162 if(this.el){ // from markup
49163 this.el = Roo.get(this.el);
49164 }else { // generate
49165 var cfg = this.getAutoCreate();
49166 this.el = ct.createChild(cfg, position);
49169 this.el.applyStyles(this.style);
49171 if(this.labelAlign){
49172 this.el.addClass('x-form-label-'+this.labelAlign);
49174 if(this.hideLabels){
49175 this.labelStyle = "display:none";
49176 this.elementStyle = "padding-left:0;";
49178 if(typeof this.labelWidth == 'number'){
49179 this.labelStyle = "width:"+this.labelWidth+"px;";
49180 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49182 if(this.labelAlign == 'top'){
49183 this.labelStyle = "width:auto;";
49184 this.elementStyle = "padding-left:0;";
49187 var stack = this.stack;
49188 var slen = stack.length;
49190 if(!this.fieldTpl){
49191 var t = new Roo.Template(
49192 '<div class="x-form-item {5}">',
49193 '<label for="{0}" style="{2}">{1}{4}</label>',
49194 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49196 '</div><div class="x-form-clear-left"></div>'
49198 t.disableFormats = true;
49200 Roo.form.Layout.prototype.fieldTpl = t;
49202 for(var i = 0; i < slen; i++) {
49203 if(stack[i].isFormField){
49204 this.renderField(stack[i]);
49206 this.renderComponent(stack[i]);
49211 this.el.createChild({cls:'x-form-clear'});
49216 renderField : function(f){
49217 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49220 f.labelStyle||this.labelStyle||'', //2
49221 this.elementStyle||'', //3
49222 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49223 f.itemCls||this.itemCls||'' //5
49224 ], true).getPrevSibling());
49228 renderComponent : function(c){
49229 c.render(c.isLayout ? this.el : this.el.createChild());
49232 * Adds a object form elements (using the xtype property as the factory method.)
49233 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49234 * @param {Object} config
49236 addxtype : function(o)
49238 // create the lement.
49239 o.form = this.form;
49240 var fe = Roo.factory(o, Roo.form);
49241 this.form.allItems.push(fe);
49242 this.stack.push(fe);
49244 if (fe.isFormField) {
49245 this.form.items.add(fe);
49253 * @class Roo.form.Column
49254 * @extends Roo.form.Layout
49255 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49257 * @param {Object} config Configuration options
49259 Roo.form.Column = function(config){
49260 Roo.form.Column.superclass.constructor.call(this, config);
49263 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49265 * @cfg {Number/String} width
49266 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49269 * @cfg {String/Object} autoCreate
49270 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49274 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49277 onRender : function(ct, position){
49278 Roo.form.Column.superclass.onRender.call(this, ct, position);
49280 this.el.setWidth(this.width);
49287 * @class Roo.form.Row
49288 * @extends Roo.form.Layout
49289 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49291 * @param {Object} config Configuration options
49295 Roo.form.Row = function(config){
49296 Roo.form.Row.superclass.constructor.call(this, config);
49299 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49301 * @cfg {Number/String} width
49302 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49305 * @cfg {Number/String} height
49306 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49308 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49312 onRender : function(ct, position){
49313 //console.log('row render');
49315 var t = new Roo.Template(
49316 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49317 '<label for="{0}" style="{2}">{1}{4}</label>',
49318 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49322 t.disableFormats = true;
49324 Roo.form.Layout.prototype.rowTpl = t;
49326 this.fieldTpl = this.rowTpl;
49328 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49329 var labelWidth = 100;
49331 if ((this.labelAlign != 'top')) {
49332 if (typeof this.labelWidth == 'number') {
49333 labelWidth = this.labelWidth
49335 this.padWidth = 20 + labelWidth;
49339 Roo.form.Column.superclass.onRender.call(this, ct, position);
49341 this.el.setWidth(this.width);
49344 this.el.setHeight(this.height);
49349 renderField : function(f){
49350 f.fieldEl = this.fieldTpl.append(this.el, [
49351 f.id, f.fieldLabel,
49352 f.labelStyle||this.labelStyle||'',
49353 this.elementStyle||'',
49354 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49355 f.itemCls||this.itemCls||'',
49356 f.width ? f.width + this.padWidth : 160 + this.padWidth
49363 * @class Roo.form.FieldSet
49364 * @extends Roo.form.Layout
49365 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49367 * @param {Object} config Configuration options
49369 Roo.form.FieldSet = function(config){
49370 Roo.form.FieldSet.superclass.constructor.call(this, config);
49373 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49375 * @cfg {String} legend
49376 * The text to display as the legend for the FieldSet (defaults to '')
49379 * @cfg {String/Object} autoCreate
49380 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49384 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49387 onRender : function(ct, position){
49388 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49390 this.setLegend(this.legend);
49395 setLegend : function(text){
49397 this.el.child('legend').update(text);
49402 * Ext JS Library 1.1.1
49403 * Copyright(c) 2006-2007, Ext JS, LLC.
49405 * Originally Released Under LGPL - original licence link has changed is not relivant.
49408 * <script type="text/javascript">
49411 * @class Roo.form.VTypes
49412 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49415 Roo.form.VTypes = function(){
49416 // closure these in so they are only created once.
49417 var alpha = /^[a-zA-Z_]+$/;
49418 var alphanum = /^[a-zA-Z0-9_]+$/;
49419 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49420 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49422 // All these messages and functions are configurable
49425 * The function used to validate email addresses
49426 * @param {String} value The email address
49428 'email' : function(v){
49429 return email.test(v);
49432 * The error text to display when the email validation function returns false
49435 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49437 * The keystroke filter mask to be applied on email input
49440 'emailMask' : /[a-z0-9_\.\-@]/i,
49443 * The function used to validate URLs
49444 * @param {String} value The URL
49446 'url' : function(v){
49447 return url.test(v);
49450 * The error text to display when the url validation function returns false
49453 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49456 * The function used to validate alpha values
49457 * @param {String} value The value
49459 'alpha' : function(v){
49460 return alpha.test(v);
49463 * The error text to display when the alpha validation function returns false
49466 'alphaText' : 'This field should only contain letters and _',
49468 * The keystroke filter mask to be applied on alpha input
49471 'alphaMask' : /[a-z_]/i,
49474 * The function used to validate alphanumeric values
49475 * @param {String} value The value
49477 'alphanum' : function(v){
49478 return alphanum.test(v);
49481 * The error text to display when the alphanumeric validation function returns false
49484 'alphanumText' : 'This field should only contain letters, numbers and _',
49486 * The keystroke filter mask to be applied on alphanumeric input
49489 'alphanumMask' : /[a-z0-9_]/i
49491 }();//<script type="text/javascript">
49494 * @class Roo.form.FCKeditor
49495 * @extends Roo.form.TextArea
49496 * Wrapper around the FCKEditor http://www.fckeditor.net
49498 * Creates a new FCKeditor
49499 * @param {Object} config Configuration options
49501 Roo.form.FCKeditor = function(config){
49502 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49505 * @event editorinit
49506 * Fired when the editor is initialized - you can add extra handlers here..
49507 * @param {FCKeditor} this
49508 * @param {Object} the FCK object.
49515 Roo.form.FCKeditor.editors = { };
49516 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49518 //defaultAutoCreate : {
49519 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49523 * @cfg {Object} fck options - see fck manual for details.
49528 * @cfg {Object} fck toolbar set (Basic or Default)
49530 toolbarSet : 'Basic',
49532 * @cfg {Object} fck BasePath
49534 basePath : '/fckeditor/',
49542 onRender : function(ct, position)
49545 this.defaultAutoCreate = {
49547 style:"width:300px;height:60px;",
49548 autocomplete: "new-password"
49551 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49554 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49555 if(this.preventScrollbars){
49556 this.el.setStyle("overflow", "hidden");
49558 this.el.setHeight(this.growMin);
49561 //console.log('onrender' + this.getId() );
49562 Roo.form.FCKeditor.editors[this.getId()] = this;
49565 this.replaceTextarea() ;
49569 getEditor : function() {
49570 return this.fckEditor;
49573 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49574 * @param {Mixed} value The value to set
49578 setValue : function(value)
49580 //console.log('setValue: ' + value);
49582 if(typeof(value) == 'undefined') { // not sure why this is happending...
49585 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49587 //if(!this.el || !this.getEditor()) {
49588 // this.value = value;
49589 //this.setValue.defer(100,this,[value]);
49593 if(!this.getEditor()) {
49597 this.getEditor().SetData(value);
49604 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49605 * @return {Mixed} value The field value
49607 getValue : function()
49610 if (this.frame && this.frame.dom.style.display == 'none') {
49611 return Roo.form.FCKeditor.superclass.getValue.call(this);
49614 if(!this.el || !this.getEditor()) {
49616 // this.getValue.defer(100,this);
49621 var value=this.getEditor().GetData();
49622 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49623 return Roo.form.FCKeditor.superclass.getValue.call(this);
49629 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49630 * @return {Mixed} value The field value
49632 getRawValue : function()
49634 if (this.frame && this.frame.dom.style.display == 'none') {
49635 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49638 if(!this.el || !this.getEditor()) {
49639 //this.getRawValue.defer(100,this);
49646 var value=this.getEditor().GetData();
49647 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49648 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49652 setSize : function(w,h) {
49656 //if (this.frame && this.frame.dom.style.display == 'none') {
49657 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49660 //if(!this.el || !this.getEditor()) {
49661 // this.setSize.defer(100,this, [w,h]);
49667 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49669 this.frame.dom.setAttribute('width', w);
49670 this.frame.dom.setAttribute('height', h);
49671 this.frame.setSize(w,h);
49675 toggleSourceEdit : function(value) {
49679 this.el.dom.style.display = value ? '' : 'none';
49680 this.frame.dom.style.display = value ? 'none' : '';
49685 focus: function(tag)
49687 if (this.frame.dom.style.display == 'none') {
49688 return Roo.form.FCKeditor.superclass.focus.call(this);
49690 if(!this.el || !this.getEditor()) {
49691 this.focus.defer(100,this, [tag]);
49698 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49699 this.getEditor().Focus();
49701 if (!this.getEditor().Selection.GetSelection()) {
49702 this.focus.defer(100,this, [tag]);
49707 var r = this.getEditor().EditorDocument.createRange();
49708 r.setStart(tgs[0],0);
49709 r.setEnd(tgs[0],0);
49710 this.getEditor().Selection.GetSelection().removeAllRanges();
49711 this.getEditor().Selection.GetSelection().addRange(r);
49712 this.getEditor().Focus();
49719 replaceTextarea : function()
49721 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49724 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49726 // We must check the elements firstly using the Id and then the name.
49727 var oTextarea = document.getElementById( this.getId() );
49729 var colElementsByName = document.getElementsByName( this.getId() ) ;
49731 oTextarea.style.display = 'none' ;
49733 if ( oTextarea.tabIndex ) {
49734 this.TabIndex = oTextarea.tabIndex ;
49737 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49738 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49739 this.frame = Roo.get(this.getId() + '___Frame')
49742 _getConfigHtml : function()
49746 for ( var o in this.fckconfig ) {
49747 sConfig += sConfig.length > 0 ? '&' : '';
49748 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49751 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49755 _getIFrameHtml : function()
49757 var sFile = 'fckeditor.html' ;
49758 /* no idea what this is about..
49761 if ( (/fcksource=true/i).test( window.top.location.search ) )
49762 sFile = 'fckeditor.original.html' ;
49767 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49768 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49771 var html = '<iframe id="' + this.getId() +
49772 '___Frame" src="' + sLink +
49773 '" width="' + this.width +
49774 '" height="' + this.height + '"' +
49775 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
49776 ' frameborder="0" scrolling="no"></iframe>' ;
49781 _insertHtmlBefore : function( html, element )
49783 if ( element.insertAdjacentHTML ) {
49785 element.insertAdjacentHTML( 'beforeBegin', html ) ;
49787 var oRange = document.createRange() ;
49788 oRange.setStartBefore( element ) ;
49789 var oFragment = oRange.createContextualFragment( html );
49790 element.parentNode.insertBefore( oFragment, element ) ;
49803 //Roo.reg('fckeditor', Roo.form.FCKeditor);
49805 function FCKeditor_OnComplete(editorInstance){
49806 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
49807 f.fckEditor = editorInstance;
49808 //console.log("loaded");
49809 f.fireEvent('editorinit', f, editorInstance);
49829 //<script type="text/javascript">
49831 * @class Roo.form.GridField
49832 * @extends Roo.form.Field
49833 * Embed a grid (or editable grid into a form)
49836 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
49838 * xgrid.store = Roo.data.Store
49839 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
49840 * xgrid.store.reader = Roo.data.JsonReader
49844 * Creates a new GridField
49845 * @param {Object} config Configuration options
49847 Roo.form.GridField = function(config){
49848 Roo.form.GridField.superclass.constructor.call(this, config);
49852 Roo.extend(Roo.form.GridField, Roo.form.Field, {
49854 * @cfg {Number} width - used to restrict width of grid..
49858 * @cfg {Number} height - used to restrict height of grid..
49862 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
49868 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49869 * {tag: "input", type: "checkbox", autocomplete: "off"})
49871 // defaultAutoCreate : { tag: 'div' },
49872 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
49874 * @cfg {String} addTitle Text to include for adding a title.
49878 onResize : function(){
49879 Roo.form.Field.superclass.onResize.apply(this, arguments);
49882 initEvents : function(){
49883 // Roo.form.Checkbox.superclass.initEvents.call(this);
49884 // has no events...
49889 getResizeEl : function(){
49893 getPositionEl : function(){
49898 onRender : function(ct, position){
49900 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
49901 var style = this.style;
49904 Roo.form.GridField.superclass.onRender.call(this, ct, position);
49905 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
49906 this.viewEl = this.wrap.createChild({ tag: 'div' });
49908 this.viewEl.applyStyles(style);
49911 this.viewEl.setWidth(this.width);
49914 this.viewEl.setHeight(this.height);
49916 //if(this.inputValue !== undefined){
49917 //this.setValue(this.value);
49920 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
49923 this.grid.render();
49924 this.grid.getDataSource().on('remove', this.refreshValue, this);
49925 this.grid.getDataSource().on('update', this.refreshValue, this);
49926 this.grid.on('afteredit', this.refreshValue, this);
49932 * Sets the value of the item.
49933 * @param {String} either an object or a string..
49935 setValue : function(v){
49937 v = v || []; // empty set..
49938 // this does not seem smart - it really only affects memoryproxy grids..
49939 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
49940 var ds = this.grid.getDataSource();
49941 // assumes a json reader..
49943 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
49944 ds.loadData( data);
49946 // clear selection so it does not get stale.
49947 if (this.grid.sm) {
49948 this.grid.sm.clearSelections();
49951 Roo.form.GridField.superclass.setValue.call(this, v);
49952 this.refreshValue();
49953 // should load data in the grid really....
49957 refreshValue: function() {
49959 this.grid.getDataSource().each(function(r) {
49962 this.el.dom.value = Roo.encode(val);
49970 * Ext JS Library 1.1.1
49971 * Copyright(c) 2006-2007, Ext JS, LLC.
49973 * Originally Released Under LGPL - original licence link has changed is not relivant.
49976 * <script type="text/javascript">
49979 * @class Roo.form.DisplayField
49980 * @extends Roo.form.Field
49981 * A generic Field to display non-editable data.
49982 * @cfg {Boolean} closable (true|false) default false
49984 * Creates a new Display Field item.
49985 * @param {Object} config Configuration options
49987 Roo.form.DisplayField = function(config){
49988 Roo.form.DisplayField.superclass.constructor.call(this, config);
49993 * Fires after the click the close btn
49994 * @param {Roo.form.DisplayField} this
50000 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50001 inputType: 'hidden',
50007 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50009 focusClass : undefined,
50011 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50013 fieldClass: 'x-form-field',
50016 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50018 valueRenderer: undefined,
50022 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50023 * {tag: "input", type: "checkbox", autocomplete: "off"})
50026 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50030 onResize : function(){
50031 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50035 initEvents : function(){
50036 // Roo.form.Checkbox.superclass.initEvents.call(this);
50037 // has no events...
50040 this.closeEl.on('click', this.onClose, this);
50046 getResizeEl : function(){
50050 getPositionEl : function(){
50055 onRender : function(ct, position){
50057 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50058 //if(this.inputValue !== undefined){
50059 this.wrap = this.el.wrap();
50061 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50064 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50067 if (this.bodyStyle) {
50068 this.viewEl.applyStyles(this.bodyStyle);
50070 //this.viewEl.setStyle('padding', '2px');
50072 this.setValue(this.value);
50077 initValue : Roo.emptyFn,
50082 onClick : function(){
50087 * Sets the checked state of the checkbox.
50088 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50090 setValue : function(v){
50092 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50093 // this might be called before we have a dom element..
50094 if (!this.viewEl) {
50097 this.viewEl.dom.innerHTML = html;
50098 Roo.form.DisplayField.superclass.setValue.call(this, v);
50102 onClose : function(e)
50104 e.preventDefault();
50106 this.fireEvent('close', this);
50115 * @class Roo.form.DayPicker
50116 * @extends Roo.form.Field
50117 * A Day picker show [M] [T] [W] ....
50119 * Creates a new Day Picker
50120 * @param {Object} config Configuration options
50122 Roo.form.DayPicker= function(config){
50123 Roo.form.DayPicker.superclass.constructor.call(this, config);
50127 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50129 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50131 focusClass : undefined,
50133 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50135 fieldClass: "x-form-field",
50138 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50139 * {tag: "input", type: "checkbox", autocomplete: "off"})
50141 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50144 actionMode : 'viewEl',
50148 inputType : 'hidden',
50151 inputElement: false, // real input element?
50152 basedOn: false, // ????
50154 isFormField: true, // not sure where this is needed!!!!
50156 onResize : function(){
50157 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50158 if(!this.boxLabel){
50159 this.el.alignTo(this.wrap, 'c-c');
50163 initEvents : function(){
50164 Roo.form.Checkbox.superclass.initEvents.call(this);
50165 this.el.on("click", this.onClick, this);
50166 this.el.on("change", this.onClick, this);
50170 getResizeEl : function(){
50174 getPositionEl : function(){
50180 onRender : function(ct, position){
50181 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50183 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50185 var r1 = '<table><tr>';
50186 var r2 = '<tr class="x-form-daypick-icons">';
50187 for (var i=0; i < 7; i++) {
50188 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50189 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50192 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50193 viewEl.select('img').on('click', this.onClick, this);
50194 this.viewEl = viewEl;
50197 // this will not work on Chrome!!!
50198 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50199 this.el.on('propertychange', this.setFromHidden, this); //ie
50207 initValue : Roo.emptyFn,
50210 * Returns the checked state of the checkbox.
50211 * @return {Boolean} True if checked, else false
50213 getValue : function(){
50214 return this.el.dom.value;
50219 onClick : function(e){
50220 //this.setChecked(!this.checked);
50221 Roo.get(e.target).toggleClass('x-menu-item-checked');
50222 this.refreshValue();
50223 //if(this.el.dom.checked != this.checked){
50224 // this.setValue(this.el.dom.checked);
50229 refreshValue : function()
50232 this.viewEl.select('img',true).each(function(e,i,n) {
50233 val += e.is(".x-menu-item-checked") ? String(n) : '';
50235 this.setValue(val, true);
50239 * Sets the checked state of the checkbox.
50240 * On is always based on a string comparison between inputValue and the param.
50241 * @param {Boolean/String} value - the value to set
50242 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50244 setValue : function(v,suppressEvent){
50245 if (!this.el.dom) {
50248 var old = this.el.dom.value ;
50249 this.el.dom.value = v;
50250 if (suppressEvent) {
50254 // update display..
50255 this.viewEl.select('img',true).each(function(e,i,n) {
50257 var on = e.is(".x-menu-item-checked");
50258 var newv = v.indexOf(String(n)) > -1;
50260 e.toggleClass('x-menu-item-checked');
50266 this.fireEvent('change', this, v, old);
50271 // handle setting of hidden value by some other method!!?!?
50272 setFromHidden: function()
50277 //console.log("SET FROM HIDDEN");
50278 //alert('setFrom hidden');
50279 this.setValue(this.el.dom.value);
50282 onDestroy : function()
50285 Roo.get(this.viewEl).remove();
50288 Roo.form.DayPicker.superclass.onDestroy.call(this);
50292 * RooJS Library 1.1.1
50293 * Copyright(c) 2008-2011 Alan Knowles
50300 * @class Roo.form.ComboCheck
50301 * @extends Roo.form.ComboBox
50302 * A combobox for multiple select items.
50304 * FIXME - could do with a reset button..
50307 * Create a new ComboCheck
50308 * @param {Object} config Configuration options
50310 Roo.form.ComboCheck = function(config){
50311 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50312 // should verify some data...
50314 // hiddenName = required..
50315 // displayField = required
50316 // valudField == required
50317 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50319 Roo.each(req, function(e) {
50320 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50321 throw "Roo.form.ComboCheck : missing value for: " + e;
50328 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50333 selectedClass: 'x-menu-item-checked',
50336 onRender : function(ct, position){
50342 var cls = 'x-combo-list';
50345 this.tpl = new Roo.Template({
50346 html : '<div class="'+cls+'-item x-menu-check-item">' +
50347 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50348 '<span>{' + this.displayField + '}</span>' +
50355 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50356 this.view.singleSelect = false;
50357 this.view.multiSelect = true;
50358 this.view.toggleSelect = true;
50359 this.pageTb.add(new Roo.Toolbar.Fill(), {
50362 handler: function()
50369 onViewOver : function(e, t){
50375 onViewClick : function(doFocus,index){
50379 select: function () {
50380 //Roo.log("SELECT CALLED");
50383 selectByValue : function(xv, scrollIntoView){
50384 var ar = this.getValueArray();
50387 Roo.each(ar, function(v) {
50388 if(v === undefined || v === null){
50391 var r = this.findRecord(this.valueField, v);
50393 sels.push(this.store.indexOf(r))
50397 this.view.select(sels);
50403 onSelect : function(record, index){
50404 // Roo.log("onselect Called");
50405 // this is only called by the clear button now..
50406 this.view.clearSelections();
50407 this.setValue('[]');
50408 if (this.value != this.valueBefore) {
50409 this.fireEvent('change', this, this.value, this.valueBefore);
50410 this.valueBefore = this.value;
50413 getValueArray : function()
50418 //Roo.log(this.value);
50419 if (typeof(this.value) == 'undefined') {
50422 var ar = Roo.decode(this.value);
50423 return ar instanceof Array ? ar : []; //?? valid?
50426 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50431 expand : function ()
50434 Roo.form.ComboCheck.superclass.expand.call(this);
50435 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50436 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50441 collapse : function(){
50442 Roo.form.ComboCheck.superclass.collapse.call(this);
50443 var sl = this.view.getSelectedIndexes();
50444 var st = this.store;
50448 Roo.each(sl, function(i) {
50450 nv.push(r.get(this.valueField));
50452 this.setValue(Roo.encode(nv));
50453 if (this.value != this.valueBefore) {
50455 this.fireEvent('change', this, this.value, this.valueBefore);
50456 this.valueBefore = this.value;
50461 setValue : function(v){
50465 var vals = this.getValueArray();
50467 Roo.each(vals, function(k) {
50468 var r = this.findRecord(this.valueField, k);
50470 tv.push(r.data[this.displayField]);
50471 }else if(this.valueNotFoundText !== undefined){
50472 tv.push( this.valueNotFoundText );
50477 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50478 this.hiddenField.value = v;
50484 * Ext JS Library 1.1.1
50485 * Copyright(c) 2006-2007, Ext JS, LLC.
50487 * Originally Released Under LGPL - original licence link has changed is not relivant.
50490 * <script type="text/javascript">
50494 * @class Roo.form.Signature
50495 * @extends Roo.form.Field
50499 * @param {Object} config Configuration options
50502 Roo.form.Signature = function(config){
50503 Roo.form.Signature.superclass.constructor.call(this, config);
50505 this.addEvents({// not in used??
50508 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50509 * @param {Roo.form.Signature} combo This combo box
50514 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50515 * @param {Roo.form.ComboBox} combo This combo box
50516 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50522 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50524 * @cfg {Object} labels Label to use when rendering a form.
50528 * confirm : "Confirm"
50533 confirm : "Confirm"
50536 * @cfg {Number} width The signature panel width (defaults to 300)
50540 * @cfg {Number} height The signature panel height (defaults to 100)
50544 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50546 allowBlank : false,
50549 // {Object} signPanel The signature SVG panel element (defaults to {})
50551 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50552 isMouseDown : false,
50553 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50554 isConfirmed : false,
50555 // {String} signatureTmp SVG mapping string (defaults to empty string)
50559 defaultAutoCreate : { // modified by initCompnoent..
50565 onRender : function(ct, position){
50567 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50569 this.wrap = this.el.wrap({
50570 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50573 this.createToolbar(this);
50574 this.signPanel = this.wrap.createChild({
50576 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50580 this.svgID = Roo.id();
50581 this.svgEl = this.signPanel.createChild({
50582 xmlns : 'http://www.w3.org/2000/svg',
50584 id : this.svgID + "-svg",
50586 height: this.height,
50587 viewBox: '0 0 '+this.width+' '+this.height,
50591 id: this.svgID + "-svg-r",
50593 height: this.height,
50598 id: this.svgID + "-svg-l",
50600 y1: (this.height*0.8), // start set the line in 80% of height
50601 x2: this.width, // end
50602 y2: (this.height*0.8), // end set the line in 80% of height
50604 'stroke-width': "1",
50605 'stroke-dasharray': "3",
50606 'shape-rendering': "crispEdges",
50607 'pointer-events': "none"
50611 id: this.svgID + "-svg-p",
50613 'stroke-width': "3",
50615 'pointer-events': 'none'
50620 this.svgBox = this.svgEl.dom.getScreenCTM();
50622 createSVG : function(){
50623 var svg = this.signPanel;
50624 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50627 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50628 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50629 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50630 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50631 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50632 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50633 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50636 isTouchEvent : function(e){
50637 return e.type.match(/^touch/);
50639 getCoords : function (e) {
50640 var pt = this.svgEl.dom.createSVGPoint();
50643 if (this.isTouchEvent(e)) {
50644 pt.x = e.targetTouches[0].clientX;
50645 pt.y = e.targetTouches[0].clientY;
50647 var a = this.svgEl.dom.getScreenCTM();
50648 var b = a.inverse();
50649 var mx = pt.matrixTransform(b);
50650 return mx.x + ',' + mx.y;
50652 //mouse event headler
50653 down : function (e) {
50654 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50655 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50657 this.isMouseDown = true;
50659 e.preventDefault();
50661 move : function (e) {
50662 if (this.isMouseDown) {
50663 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50664 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50667 e.preventDefault();
50669 up : function (e) {
50670 this.isMouseDown = false;
50671 var sp = this.signatureTmp.split(' ');
50674 if(!sp[sp.length-2].match(/^L/)){
50678 this.signatureTmp = sp.join(" ");
50681 if(this.getValue() != this.signatureTmp){
50682 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50683 this.isConfirmed = false;
50685 e.preventDefault();
50689 * Protected method that will not generally be called directly. It
50690 * is called when the editor creates its toolbar. Override this method if you need to
50691 * add custom toolbar buttons.
50692 * @param {HtmlEditor} editor
50694 createToolbar : function(editor){
50695 function btn(id, toggle, handler){
50696 var xid = fid + '-'+ id ;
50700 cls : 'x-btn-icon x-edit-'+id,
50701 enableToggle:toggle !== false,
50702 scope: editor, // was editor...
50703 handler:handler||editor.relayBtnCmd,
50704 clickEvent:'mousedown',
50705 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50711 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50715 cls : ' x-signature-btn x-signature-'+id,
50716 scope: editor, // was editor...
50717 handler: this.reset,
50718 clickEvent:'mousedown',
50719 text: this.labels.clear
50726 cls : ' x-signature-btn x-signature-'+id,
50727 scope: editor, // was editor...
50728 handler: this.confirmHandler,
50729 clickEvent:'mousedown',
50730 text: this.labels.confirm
50737 * when user is clicked confirm then show this image.....
50739 * @return {String} Image Data URI
50741 getImageDataURI : function(){
50742 var svg = this.svgEl.dom.parentNode.innerHTML;
50743 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50748 * @return {Boolean} this.isConfirmed
50750 getConfirmed : function(){
50751 return this.isConfirmed;
50755 * @return {Number} this.width
50757 getWidth : function(){
50762 * @return {Number} this.height
50764 getHeight : function(){
50765 return this.height;
50768 getSignature : function(){
50769 return this.signatureTmp;
50772 reset : function(){
50773 this.signatureTmp = '';
50774 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50775 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
50776 this.isConfirmed = false;
50777 Roo.form.Signature.superclass.reset.call(this);
50779 setSignature : function(s){
50780 this.signatureTmp = s;
50781 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50782 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
50784 this.isConfirmed = false;
50785 Roo.form.Signature.superclass.reset.call(this);
50788 // Roo.log(this.signPanel.dom.contentWindow.up())
50791 setConfirmed : function(){
50795 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
50798 confirmHandler : function(){
50799 if(!this.getSignature()){
50803 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
50804 this.setValue(this.getSignature());
50805 this.isConfirmed = true;
50807 this.fireEvent('confirm', this);
50810 // Subclasses should provide the validation implementation by overriding this
50811 validateValue : function(value){
50812 if(this.allowBlank){
50816 if(this.isConfirmed){
50823 * Ext JS Library 1.1.1
50824 * Copyright(c) 2006-2007, Ext JS, LLC.
50826 * Originally Released Under LGPL - original licence link has changed is not relivant.
50829 * <script type="text/javascript">
50834 * @class Roo.form.ComboBox
50835 * @extends Roo.form.TriggerField
50836 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
50838 * Create a new ComboBox.
50839 * @param {Object} config Configuration options
50841 Roo.form.Select = function(config){
50842 Roo.form.Select.superclass.constructor.call(this, config);
50846 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
50848 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
50851 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
50852 * rendering into an Roo.Editor, defaults to false)
50855 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
50856 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
50859 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
50862 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
50863 * the dropdown list (defaults to undefined, with no header element)
50867 * @cfg {String/Roo.Template} tpl The template to use to render the output
50871 defaultAutoCreate : {tag: "select" },
50873 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
50875 listWidth: undefined,
50877 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
50878 * mode = 'remote' or 'text' if mode = 'local')
50880 displayField: undefined,
50882 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
50883 * mode = 'remote' or 'value' if mode = 'local').
50884 * Note: use of a valueField requires the user make a selection
50885 * in order for a value to be mapped.
50887 valueField: undefined,
50891 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
50892 * field's data value (defaults to the underlying DOM element's name)
50894 hiddenName: undefined,
50896 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
50900 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
50902 selectedClass: 'x-combo-selected',
50904 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
50905 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
50906 * which displays a downward arrow icon).
50908 triggerClass : 'x-form-arrow-trigger',
50910 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
50914 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
50915 * anchor positions (defaults to 'tl-bl')
50917 listAlign: 'tl-bl?',
50919 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
50923 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
50924 * query specified by the allQuery config option (defaults to 'query')
50926 triggerAction: 'query',
50928 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
50929 * (defaults to 4, does not apply if editable = false)
50933 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
50934 * delay (typeAheadDelay) if it matches a known value (defaults to false)
50938 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
50939 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
50943 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
50944 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
50948 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
50949 * when editable = true (defaults to false)
50951 selectOnFocus:false,
50953 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
50955 queryParam: 'query',
50957 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
50958 * when mode = 'remote' (defaults to 'Loading...')
50960 loadingText: 'Loading...',
50962 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
50966 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
50970 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
50971 * traditional select (defaults to true)
50975 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
50979 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
50983 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
50984 * listWidth has a higher value)
50988 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
50989 * allow the user to set arbitrary text into the field (defaults to false)
50991 forceSelection:false,
50993 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
50994 * if typeAhead = true (defaults to 250)
50996 typeAheadDelay : 250,
50998 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
50999 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51001 valueNotFoundText : undefined,
51004 * @cfg {String} defaultValue The value displayed after loading the store.
51009 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51011 blockFocus : false,
51014 * @cfg {Boolean} disableClear Disable showing of clear button.
51016 disableClear : false,
51018 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51020 alwaysQuery : false,
51026 // element that contains real text value.. (when hidden is used..)
51029 onRender : function(ct, position){
51030 Roo.form.Field.prototype.onRender.call(this, ct, position);
51033 this.store.on('beforeload', this.onBeforeLoad, this);
51034 this.store.on('load', this.onLoad, this);
51035 this.store.on('loadexception', this.onLoadException, this);
51036 this.store.load({});
51044 initEvents : function(){
51045 //Roo.form.ComboBox.superclass.initEvents.call(this);
51049 onDestroy : function(){
51052 this.store.un('beforeload', this.onBeforeLoad, this);
51053 this.store.un('load', this.onLoad, this);
51054 this.store.un('loadexception', this.onLoadException, this);
51056 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51060 fireKey : function(e){
51061 if(e.isNavKeyPress() && !this.list.isVisible()){
51062 this.fireEvent("specialkey", this, e);
51067 onResize: function(w, h){
51075 * Allow or prevent the user from directly editing the field text. If false is passed,
51076 * the user will only be able to select from the items defined in the dropdown list. This method
51077 * is the runtime equivalent of setting the 'editable' config option at config time.
51078 * @param {Boolean} value True to allow the user to directly edit the field text
51080 setEditable : function(value){
51085 onBeforeLoad : function(){
51087 Roo.log("Select before load");
51090 this.innerList.update(this.loadingText ?
51091 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51092 //this.restrictHeight();
51093 this.selectedIndex = -1;
51097 onLoad : function(){
51100 var dom = this.el.dom;
51101 dom.innerHTML = '';
51102 var od = dom.ownerDocument;
51104 if (this.emptyText) {
51105 var op = od.createElement('option');
51106 op.setAttribute('value', '');
51107 op.innerHTML = String.format('{0}', this.emptyText);
51108 dom.appendChild(op);
51110 if(this.store.getCount() > 0){
51112 var vf = this.valueField;
51113 var df = this.displayField;
51114 this.store.data.each(function(r) {
51115 // which colmsn to use... testing - cdoe / title..
51116 var op = od.createElement('option');
51117 op.setAttribute('value', r.data[vf]);
51118 op.innerHTML = String.format('{0}', r.data[df]);
51119 dom.appendChild(op);
51121 if (typeof(this.defaultValue != 'undefined')) {
51122 this.setValue(this.defaultValue);
51127 //this.onEmptyResults();
51132 onLoadException : function()
51134 dom.innerHTML = '';
51136 Roo.log("Select on load exception");
51140 Roo.log(this.store.reader.jsonData);
51141 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51142 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51148 onTypeAhead : function(){
51153 onSelect : function(record, index){
51154 Roo.log('on select?');
51156 if(this.fireEvent('beforeselect', this, record, index) !== false){
51157 this.setFromData(index > -1 ? record.data : false);
51159 this.fireEvent('select', this, record, index);
51164 * Returns the currently selected field value or empty string if no value is set.
51165 * @return {String} value The selected value
51167 getValue : function(){
51168 var dom = this.el.dom;
51169 this.value = dom.options[dom.selectedIndex].value;
51175 * Clears any text/value currently set in the field
51177 clearValue : function(){
51179 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51184 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51185 * will be displayed in the field. If the value does not match the data value of an existing item,
51186 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51187 * Otherwise the field will be blank (although the value will still be set).
51188 * @param {String} value The value to match
51190 setValue : function(v){
51191 var d = this.el.dom;
51192 for (var i =0; i < d.options.length;i++) {
51193 if (v == d.options[i].value) {
51194 d.selectedIndex = i;
51202 * @property {Object} the last set data for the element
51207 * Sets the value of the field based on a object which is related to the record format for the store.
51208 * @param {Object} value the value to set as. or false on reset?
51210 setFromData : function(o){
51211 Roo.log('setfrom data?');
51217 reset : function(){
51221 findRecord : function(prop, value){
51226 if(this.store.getCount() > 0){
51227 this.store.each(function(r){
51228 if(r.data[prop] == value){
51238 getName: function()
51240 // returns hidden if it's set..
51241 if (!this.rendered) {return ''};
51242 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51250 onEmptyResults : function(){
51251 Roo.log('empty results');
51256 * Returns true if the dropdown list is expanded, else false.
51258 isExpanded : function(){
51263 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51264 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51265 * @param {String} value The data value of the item to select
51266 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51267 * selected item if it is not currently in view (defaults to true)
51268 * @return {Boolean} True if the value matched an item in the list, else false
51270 selectByValue : function(v, scrollIntoView){
51271 Roo.log('select By Value');
51274 if(v !== undefined && v !== null){
51275 var r = this.findRecord(this.valueField || this.displayField, v);
51277 this.select(this.store.indexOf(r), scrollIntoView);
51285 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51286 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51287 * @param {Number} index The zero-based index of the list item to select
51288 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51289 * selected item if it is not currently in view (defaults to true)
51291 select : function(index, scrollIntoView){
51292 Roo.log('select ');
51295 this.selectedIndex = index;
51296 this.view.select(index);
51297 if(scrollIntoView !== false){
51298 var el = this.view.getNode(index);
51300 this.innerList.scrollChildIntoView(el, false);
51308 validateBlur : function(){
51315 initQuery : function(){
51316 this.doQuery(this.getRawValue());
51320 doForce : function(){
51321 if(this.el.dom.value.length > 0){
51322 this.el.dom.value =
51323 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51329 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51330 * query allowing the query action to be canceled if needed.
51331 * @param {String} query The SQL query to execute
51332 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51333 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51334 * saved in the current store (defaults to false)
51336 doQuery : function(q, forceAll){
51338 Roo.log('doQuery?');
51339 if(q === undefined || q === null){
51344 forceAll: forceAll,
51348 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51352 forceAll = qe.forceAll;
51353 if(forceAll === true || (q.length >= this.minChars)){
51354 if(this.lastQuery != q || this.alwaysQuery){
51355 this.lastQuery = q;
51356 if(this.mode == 'local'){
51357 this.selectedIndex = -1;
51359 this.store.clearFilter();
51361 this.store.filter(this.displayField, q);
51365 this.store.baseParams[this.queryParam] = q;
51367 params: this.getParams(q)
51372 this.selectedIndex = -1;
51379 getParams : function(q){
51381 //p[this.queryParam] = q;
51384 p.limit = this.pageSize;
51390 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51392 collapse : function(){
51397 collapseIf : function(e){
51402 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51404 expand : function(){
51412 * @cfg {Boolean} grow
51416 * @cfg {Number} growMin
51420 * @cfg {Number} growMax
51428 setWidth : function()
51432 getResizeEl : function(){
51435 });//<script type="text/javasscript">
51439 * @class Roo.DDView
51440 * A DnD enabled version of Roo.View.
51441 * @param {Element/String} container The Element in which to create the View.
51442 * @param {String} tpl The template string used to create the markup for each element of the View
51443 * @param {Object} config The configuration properties. These include all the config options of
51444 * {@link Roo.View} plus some specific to this class.<br>
51446 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51447 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51449 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51450 .x-view-drag-insert-above {
51451 border-top:1px dotted #3366cc;
51453 .x-view-drag-insert-below {
51454 border-bottom:1px dotted #3366cc;
51460 Roo.DDView = function(container, tpl, config) {
51461 Roo.DDView.superclass.constructor.apply(this, arguments);
51462 this.getEl().setStyle("outline", "0px none");
51463 this.getEl().unselectable();
51464 if (this.dragGroup) {
51465 this.setDraggable(this.dragGroup.split(","));
51467 if (this.dropGroup) {
51468 this.setDroppable(this.dropGroup.split(","));
51470 if (this.deletable) {
51471 this.setDeletable();
51473 this.isDirtyFlag = false;
51479 Roo.extend(Roo.DDView, Roo.View, {
51480 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51481 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51482 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51483 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51487 reset: Roo.emptyFn,
51489 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51491 validate: function() {
51495 destroy: function() {
51496 this.purgeListeners();
51497 this.getEl.removeAllListeners();
51498 this.getEl().remove();
51499 if (this.dragZone) {
51500 if (this.dragZone.destroy) {
51501 this.dragZone.destroy();
51504 if (this.dropZone) {
51505 if (this.dropZone.destroy) {
51506 this.dropZone.destroy();
51511 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51512 getName: function() {
51516 /** Loads the View from a JSON string representing the Records to put into the Store. */
51517 setValue: function(v) {
51519 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51522 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51523 this.store.proxy = new Roo.data.MemoryProxy(data);
51527 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51528 getValue: function() {
51530 this.store.each(function(rec) {
51531 result += rec.id + ',';
51533 return result.substr(0, result.length - 1) + ')';
51536 getIds: function() {
51537 var i = 0, result = new Array(this.store.getCount());
51538 this.store.each(function(rec) {
51539 result[i++] = rec.id;
51544 isDirty: function() {
51545 return this.isDirtyFlag;
51549 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51550 * whole Element becomes the target, and this causes the drop gesture to append.
51552 getTargetFromEvent : function(e) {
51553 var target = e.getTarget();
51554 while ((target !== null) && (target.parentNode != this.el.dom)) {
51555 target = target.parentNode;
51558 target = this.el.dom.lastChild || this.el.dom;
51564 * Create the drag data which consists of an object which has the property "ddel" as
51565 * the drag proxy element.
51567 getDragData : function(e) {
51568 var target = this.findItemFromChild(e.getTarget());
51570 this.handleSelection(e);
51571 var selNodes = this.getSelectedNodes();
51574 copy: this.copy || (this.allowCopy && e.ctrlKey),
51578 var selectedIndices = this.getSelectedIndexes();
51579 for (var i = 0; i < selectedIndices.length; i++) {
51580 dragData.records.push(this.store.getAt(selectedIndices[i]));
51582 if (selNodes.length == 1) {
51583 dragData.ddel = target.cloneNode(true); // the div element
51585 var div = document.createElement('div'); // create the multi element drag "ghost"
51586 div.className = 'multi-proxy';
51587 for (var i = 0, len = selNodes.length; i < len; i++) {
51588 div.appendChild(selNodes[i].cloneNode(true));
51590 dragData.ddel = div;
51592 //console.log(dragData)
51593 //console.log(dragData.ddel.innerHTML)
51596 //console.log('nodragData')
51600 /** Specify to which ddGroup items in this DDView may be dragged. */
51601 setDraggable: function(ddGroup) {
51602 if (ddGroup instanceof Array) {
51603 Roo.each(ddGroup, this.setDraggable, this);
51606 if (this.dragZone) {
51607 this.dragZone.addToGroup(ddGroup);
51609 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51610 containerScroll: true,
51614 // Draggability implies selection. DragZone's mousedown selects the element.
51615 if (!this.multiSelect) { this.singleSelect = true; }
51617 // Wire the DragZone's handlers up to methods in *this*
51618 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51622 /** Specify from which ddGroup this DDView accepts drops. */
51623 setDroppable: function(ddGroup) {
51624 if (ddGroup instanceof Array) {
51625 Roo.each(ddGroup, this.setDroppable, this);
51628 if (this.dropZone) {
51629 this.dropZone.addToGroup(ddGroup);
51631 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51632 containerScroll: true,
51636 // Wire the DropZone's handlers up to methods in *this*
51637 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51638 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51639 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51640 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51641 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51645 /** Decide whether to drop above or below a View node. */
51646 getDropPoint : function(e, n, dd){
51647 if (n == this.el.dom) { return "above"; }
51648 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51649 var c = t + (b - t) / 2;
51650 var y = Roo.lib.Event.getPageY(e);
51658 onNodeEnter : function(n, dd, e, data){
51662 onNodeOver : function(n, dd, e, data){
51663 var pt = this.getDropPoint(e, n, dd);
51664 // set the insert point style on the target node
51665 var dragElClass = this.dropNotAllowed;
51668 if (pt == "above"){
51669 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51670 targetElClass = "x-view-drag-insert-above";
51672 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51673 targetElClass = "x-view-drag-insert-below";
51675 if (this.lastInsertClass != targetElClass){
51676 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51677 this.lastInsertClass = targetElClass;
51680 return dragElClass;
51683 onNodeOut : function(n, dd, e, data){
51684 this.removeDropIndicators(n);
51687 onNodeDrop : function(n, dd, e, data){
51688 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51691 var pt = this.getDropPoint(e, n, dd);
51692 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51693 if (pt == "below") { insertAt++; }
51694 for (var i = 0; i < data.records.length; i++) {
51695 var r = data.records[i];
51696 var dup = this.store.getById(r.id);
51697 if (dup && (dd != this.dragZone)) {
51698 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51701 this.store.insert(insertAt++, r.copy());
51703 data.source.isDirtyFlag = true;
51705 this.store.insert(insertAt++, r);
51707 this.isDirtyFlag = true;
51710 this.dragZone.cachedTarget = null;
51714 removeDropIndicators : function(n){
51716 Roo.fly(n).removeClass([
51717 "x-view-drag-insert-above",
51718 "x-view-drag-insert-below"]);
51719 this.lastInsertClass = "_noclass";
51724 * Utility method. Add a delete option to the DDView's context menu.
51725 * @param {String} imageUrl The URL of the "delete" icon image.
51727 setDeletable: function(imageUrl) {
51728 if (!this.singleSelect && !this.multiSelect) {
51729 this.singleSelect = true;
51731 var c = this.getContextMenu();
51732 this.contextMenu.on("itemclick", function(item) {
51735 this.remove(this.getSelectedIndexes());
51739 this.contextMenu.add({
51746 /** Return the context menu for this DDView. */
51747 getContextMenu: function() {
51748 if (!this.contextMenu) {
51749 // Create the View's context menu
51750 this.contextMenu = new Roo.menu.Menu({
51751 id: this.id + "-contextmenu"
51753 this.el.on("contextmenu", this.showContextMenu, this);
51755 return this.contextMenu;
51758 disableContextMenu: function() {
51759 if (this.contextMenu) {
51760 this.el.un("contextmenu", this.showContextMenu, this);
51764 showContextMenu: function(e, item) {
51765 item = this.findItemFromChild(e.getTarget());
51768 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51769 this.contextMenu.showAt(e.getXY());
51774 * Remove {@link Roo.data.Record}s at the specified indices.
51775 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
51777 remove: function(selectedIndices) {
51778 selectedIndices = [].concat(selectedIndices);
51779 for (var i = 0; i < selectedIndices.length; i++) {
51780 var rec = this.store.getAt(selectedIndices[i]);
51781 this.store.remove(rec);
51786 * Double click fires the event, but also, if this is draggable, and there is only one other
51787 * related DropZone, it transfers the selected node.
51789 onDblClick : function(e){
51790 var item = this.findItemFromChild(e.getTarget());
51792 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
51795 if (this.dragGroup) {
51796 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
51797 while (targets.indexOf(this.dropZone) > -1) {
51798 targets.remove(this.dropZone);
51800 if (targets.length == 1) {
51801 this.dragZone.cachedTarget = null;
51802 var el = Roo.get(targets[0].getEl());
51803 var box = el.getBox(true);
51804 targets[0].onNodeDrop(el.dom, {
51806 xy: [box.x, box.y + box.height - 1]
51807 }, null, this.getDragData(e));
51813 handleSelection: function(e) {
51814 this.dragZone.cachedTarget = null;
51815 var item = this.findItemFromChild(e.getTarget());
51817 this.clearSelections(true);
51820 if (item && (this.multiSelect || this.singleSelect)){
51821 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
51822 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
51823 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
51824 this.unselect(item);
51826 this.select(item, this.multiSelect && e.ctrlKey);
51827 this.lastSelection = item;
51832 onItemClick : function(item, index, e){
51833 if(this.fireEvent("beforeclick", this, index, item, e) === false){
51839 unselect : function(nodeInfo, suppressEvent){
51840 var node = this.getNode(nodeInfo);
51841 if(node && this.isSelected(node)){
51842 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
51843 Roo.fly(node).removeClass(this.selectedClass);
51844 this.selections.remove(node);
51845 if(!suppressEvent){
51846 this.fireEvent("selectionchange", this, this.selections);
51854 * Ext JS Library 1.1.1
51855 * Copyright(c) 2006-2007, Ext JS, LLC.
51857 * Originally Released Under LGPL - original licence link has changed is not relivant.
51860 * <script type="text/javascript">
51864 * @class Roo.LayoutManager
51865 * @extends Roo.util.Observable
51866 * Base class for layout managers.
51868 Roo.LayoutManager = function(container, config){
51869 Roo.LayoutManager.superclass.constructor.call(this);
51870 this.el = Roo.get(container);
51871 // ie scrollbar fix
51872 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
51873 document.body.scroll = "no";
51874 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
51875 this.el.position('relative');
51877 this.id = this.el.id;
51878 this.el.addClass("x-layout-container");
51879 /** false to disable window resize monitoring @type Boolean */
51880 this.monitorWindowResize = true;
51885 * Fires when a layout is performed.
51886 * @param {Roo.LayoutManager} this
51890 * @event regionresized
51891 * Fires when the user resizes a region.
51892 * @param {Roo.LayoutRegion} region The resized region
51893 * @param {Number} newSize The new size (width for east/west, height for north/south)
51895 "regionresized" : true,
51897 * @event regioncollapsed
51898 * Fires when a region is collapsed.
51899 * @param {Roo.LayoutRegion} region The collapsed region
51901 "regioncollapsed" : true,
51903 * @event regionexpanded
51904 * Fires when a region is expanded.
51905 * @param {Roo.LayoutRegion} region The expanded region
51907 "regionexpanded" : true
51909 this.updating = false;
51910 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
51913 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
51915 * Returns true if this layout is currently being updated
51916 * @return {Boolean}
51918 isUpdating : function(){
51919 return this.updating;
51923 * Suspend the LayoutManager from doing auto-layouts while
51924 * making multiple add or remove calls
51926 beginUpdate : function(){
51927 this.updating = true;
51931 * Restore auto-layouts and optionally disable the manager from performing a layout
51932 * @param {Boolean} noLayout true to disable a layout update
51934 endUpdate : function(noLayout){
51935 this.updating = false;
51941 layout: function(){
51945 onRegionResized : function(region, newSize){
51946 this.fireEvent("regionresized", region, newSize);
51950 onRegionCollapsed : function(region){
51951 this.fireEvent("regioncollapsed", region);
51954 onRegionExpanded : function(region){
51955 this.fireEvent("regionexpanded", region);
51959 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
51960 * performs box-model adjustments.
51961 * @return {Object} The size as an object {width: (the width), height: (the height)}
51963 getViewSize : function(){
51965 if(this.el.dom != document.body){
51966 size = this.el.getSize();
51968 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
51970 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
51971 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
51976 * Returns the Element this layout is bound to.
51977 * @return {Roo.Element}
51979 getEl : function(){
51984 * Returns the specified region.
51985 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
51986 * @return {Roo.LayoutRegion}
51988 getRegion : function(target){
51989 return this.regions[target.toLowerCase()];
51992 onWindowResize : function(){
51993 if(this.monitorWindowResize){
51999 * Ext JS Library 1.1.1
52000 * Copyright(c) 2006-2007, Ext JS, LLC.
52002 * Originally Released Under LGPL - original licence link has changed is not relivant.
52005 * <script type="text/javascript">
52008 * @class Roo.BorderLayout
52009 * @extends Roo.LayoutManager
52010 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52011 * please see: <br><br>
52012 * <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>
52013 * <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>
52016 var layout = new Roo.BorderLayout(document.body, {
52050 preferredTabWidth: 150
52055 var CP = Roo.ContentPanel;
52057 layout.beginUpdate();
52058 layout.add("north", new CP("north", "North"));
52059 layout.add("south", new CP("south", {title: "South", closable: true}));
52060 layout.add("west", new CP("west", {title: "West"}));
52061 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52062 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52063 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52064 layout.getRegion("center").showPanel("center1");
52065 layout.endUpdate();
52068 <b>The container the layout is rendered into can be either the body element or any other element.
52069 If it is not the body element, the container needs to either be an absolute positioned element,
52070 or you will need to add "position:relative" to the css of the container. You will also need to specify
52071 the container size if it is not the body element.</b>
52074 * Create a new BorderLayout
52075 * @param {String/HTMLElement/Element} container The container this layout is bound to
52076 * @param {Object} config Configuration options
52078 Roo.BorderLayout = function(container, config){
52079 config = config || {};
52080 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52081 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52082 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52083 var target = this.factory.validRegions[i];
52084 if(config[target]){
52085 this.addRegion(target, config[target]);
52090 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52092 * Creates and adds a new region if it doesn't already exist.
52093 * @param {String} target The target region key (north, south, east, west or center).
52094 * @param {Object} config The regions config object
52095 * @return {BorderLayoutRegion} The new region
52097 addRegion : function(target, config){
52098 if(!this.regions[target]){
52099 var r = this.factory.create(target, this, config);
52100 this.bindRegion(target, r);
52102 return this.regions[target];
52106 bindRegion : function(name, r){
52107 this.regions[name] = r;
52108 r.on("visibilitychange", this.layout, this);
52109 r.on("paneladded", this.layout, this);
52110 r.on("panelremoved", this.layout, this);
52111 r.on("invalidated", this.layout, this);
52112 r.on("resized", this.onRegionResized, this);
52113 r.on("collapsed", this.onRegionCollapsed, this);
52114 r.on("expanded", this.onRegionExpanded, this);
52118 * Performs a layout update.
52120 layout : function(){
52121 if(this.updating) {
52124 var size = this.getViewSize();
52125 var w = size.width;
52126 var h = size.height;
52131 //var x = 0, y = 0;
52133 var rs = this.regions;
52134 var north = rs["north"];
52135 var south = rs["south"];
52136 var west = rs["west"];
52137 var east = rs["east"];
52138 var center = rs["center"];
52139 //if(this.hideOnLayout){ // not supported anymore
52140 //c.el.setStyle("display", "none");
52142 if(north && north.isVisible()){
52143 var b = north.getBox();
52144 var m = north.getMargins();
52145 b.width = w - (m.left+m.right);
52148 centerY = b.height + b.y + m.bottom;
52149 centerH -= centerY;
52150 north.updateBox(this.safeBox(b));
52152 if(south && south.isVisible()){
52153 var b = south.getBox();
52154 var m = south.getMargins();
52155 b.width = w - (m.left+m.right);
52157 var totalHeight = (b.height + m.top + m.bottom);
52158 b.y = h - totalHeight + m.top;
52159 centerH -= totalHeight;
52160 south.updateBox(this.safeBox(b));
52162 if(west && west.isVisible()){
52163 var b = west.getBox();
52164 var m = west.getMargins();
52165 b.height = centerH - (m.top+m.bottom);
52167 b.y = centerY + m.top;
52168 var totalWidth = (b.width + m.left + m.right);
52169 centerX += totalWidth;
52170 centerW -= totalWidth;
52171 west.updateBox(this.safeBox(b));
52173 if(east && east.isVisible()){
52174 var b = east.getBox();
52175 var m = east.getMargins();
52176 b.height = centerH - (m.top+m.bottom);
52177 var totalWidth = (b.width + m.left + m.right);
52178 b.x = w - totalWidth + m.left;
52179 b.y = centerY + m.top;
52180 centerW -= totalWidth;
52181 east.updateBox(this.safeBox(b));
52184 var m = center.getMargins();
52186 x: centerX + m.left,
52187 y: centerY + m.top,
52188 width: centerW - (m.left+m.right),
52189 height: centerH - (m.top+m.bottom)
52191 //if(this.hideOnLayout){
52192 //center.el.setStyle("display", "block");
52194 center.updateBox(this.safeBox(centerBox));
52197 this.fireEvent("layout", this);
52201 safeBox : function(box){
52202 box.width = Math.max(0, box.width);
52203 box.height = Math.max(0, box.height);
52208 * Adds a ContentPanel (or subclass) to this layout.
52209 * @param {String} target The target region key (north, south, east, west or center).
52210 * @param {Roo.ContentPanel} panel The panel to add
52211 * @return {Roo.ContentPanel} The added panel
52213 add : function(target, panel){
52215 target = target.toLowerCase();
52216 return this.regions[target].add(panel);
52220 * Remove a ContentPanel (or subclass) to this layout.
52221 * @param {String} target The target region key (north, south, east, west or center).
52222 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52223 * @return {Roo.ContentPanel} The removed panel
52225 remove : function(target, panel){
52226 target = target.toLowerCase();
52227 return this.regions[target].remove(panel);
52231 * Searches all regions for a panel with the specified id
52232 * @param {String} panelId
52233 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52235 findPanel : function(panelId){
52236 var rs = this.regions;
52237 for(var target in rs){
52238 if(typeof rs[target] != "function"){
52239 var p = rs[target].getPanel(panelId);
52249 * Searches all regions for a panel with the specified id and activates (shows) it.
52250 * @param {String/ContentPanel} panelId The panels id or the panel itself
52251 * @return {Roo.ContentPanel} The shown panel or null
52253 showPanel : function(panelId) {
52254 var rs = this.regions;
52255 for(var target in rs){
52256 var r = rs[target];
52257 if(typeof r != "function"){
52258 if(r.hasPanel(panelId)){
52259 return r.showPanel(panelId);
52267 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52268 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52270 restoreState : function(provider){
52272 provider = Roo.state.Manager;
52274 var sm = new Roo.LayoutStateManager();
52275 sm.init(this, provider);
52279 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52280 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52281 * a valid ContentPanel config object. Example:
52283 // Create the main layout
52284 var layout = new Roo.BorderLayout('main-ct', {
52295 // Create and add multiple ContentPanels at once via configs
52298 id: 'source-files',
52300 title:'Ext Source Files',
52313 * @param {Object} regions An object containing ContentPanel configs by region name
52315 batchAdd : function(regions){
52316 this.beginUpdate();
52317 for(var rname in regions){
52318 var lr = this.regions[rname];
52320 this.addTypedPanels(lr, regions[rname]);
52327 addTypedPanels : function(lr, ps){
52328 if(typeof ps == 'string'){
52329 lr.add(new Roo.ContentPanel(ps));
52331 else if(ps instanceof Array){
52332 for(var i =0, len = ps.length; i < len; i++){
52333 this.addTypedPanels(lr, ps[i]);
52336 else if(!ps.events){ // raw config?
52338 delete ps.el; // prevent conflict
52339 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52341 else { // panel object assumed!
52346 * Adds a xtype elements to the layout.
52350 xtype : 'ContentPanel',
52357 xtype : 'NestedLayoutPanel',
52363 items : [ ... list of content panels or nested layout panels.. ]
52367 * @param {Object} cfg Xtype definition of item to add.
52369 addxtype : function(cfg)
52371 // basically accepts a pannel...
52372 // can accept a layout region..!?!?
52373 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52375 if (!cfg.xtype.match(/Panel$/)) {
52380 if (typeof(cfg.region) == 'undefined') {
52381 Roo.log("Failed to add Panel, region was not set");
52385 var region = cfg.region;
52391 xitems = cfg.items;
52398 case 'ContentPanel': // ContentPanel (el, cfg)
52399 case 'ScrollPanel': // ContentPanel (el, cfg)
52401 if(cfg.autoCreate) {
52402 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52404 var el = this.el.createChild();
52405 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52408 this.add(region, ret);
52412 case 'TreePanel': // our new panel!
52413 cfg.el = this.el.createChild();
52414 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52415 this.add(region, ret);
52418 case 'NestedLayoutPanel':
52419 // create a new Layout (which is a Border Layout...
52420 var el = this.el.createChild();
52421 var clayout = cfg.layout;
52423 clayout.items = clayout.items || [];
52424 // replace this exitems with the clayout ones..
52425 xitems = clayout.items;
52428 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52429 cfg.background = false;
52431 var layout = new Roo.BorderLayout(el, clayout);
52433 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52434 //console.log('adding nested layout panel ' + cfg.toSource());
52435 this.add(region, ret);
52436 nb = {}; /// find first...
52441 // needs grid and region
52443 //var el = this.getRegion(region).el.createChild();
52444 var el = this.el.createChild();
52445 // create the grid first...
52447 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52449 if (region == 'center' && this.active ) {
52450 cfg.background = false;
52452 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52454 this.add(region, ret);
52455 if (cfg.background) {
52456 ret.on('activate', function(gp) {
52457 if (!gp.grid.rendered) {
52472 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52474 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52475 this.add(region, ret);
52478 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52482 // GridPanel (grid, cfg)
52485 this.beginUpdate();
52489 Roo.each(xitems, function(i) {
52490 region = nb && i.region ? i.region : false;
52492 var add = ret.addxtype(i);
52495 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52496 if (!i.background) {
52497 abn[region] = nb[region] ;
52504 // make the last non-background panel active..
52505 //if (nb) { Roo.log(abn); }
52508 for(var r in abn) {
52509 region = this.getRegion(r);
52511 // tried using nb[r], but it does not work..
52513 region.showPanel(abn[r]);
52524 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52525 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52526 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52527 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52530 var CP = Roo.ContentPanel;
52532 var layout = Roo.BorderLayout.create({
52536 panels: [new CP("north", "North")]
52545 panels: [new CP("west", {title: "West"})]
52554 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52563 panels: [new CP("south", {title: "South", closable: true})]
52570 preferredTabWidth: 150,
52572 new CP("center1", {title: "Close Me", closable: true}),
52573 new CP("center2", {title: "Center Panel", closable: false})
52578 layout.getRegion("center").showPanel("center1");
52583 Roo.BorderLayout.create = function(config, targetEl){
52584 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52585 layout.beginUpdate();
52586 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52587 for(var j = 0, jlen = regions.length; j < jlen; j++){
52588 var lr = regions[j];
52589 if(layout.regions[lr] && config[lr].panels){
52590 var r = layout.regions[lr];
52591 var ps = config[lr].panels;
52592 layout.addTypedPanels(r, ps);
52595 layout.endUpdate();
52600 Roo.BorderLayout.RegionFactory = {
52602 validRegions : ["north","south","east","west","center"],
52605 create : function(target, mgr, config){
52606 target = target.toLowerCase();
52607 if(config.lightweight || config.basic){
52608 return new Roo.BasicLayoutRegion(mgr, config, target);
52612 return new Roo.NorthLayoutRegion(mgr, config);
52614 return new Roo.SouthLayoutRegion(mgr, config);
52616 return new Roo.EastLayoutRegion(mgr, config);
52618 return new Roo.WestLayoutRegion(mgr, config);
52620 return new Roo.CenterLayoutRegion(mgr, config);
52622 throw 'Layout region "'+target+'" not supported.';
52626 * Ext JS Library 1.1.1
52627 * Copyright(c) 2006-2007, Ext JS, LLC.
52629 * Originally Released Under LGPL - original licence link has changed is not relivant.
52632 * <script type="text/javascript">
52636 * @class Roo.BasicLayoutRegion
52637 * @extends Roo.util.Observable
52638 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52639 * and does not have a titlebar, tabs or any other features. All it does is size and position
52640 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52642 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52644 this.position = pos;
52647 * @scope Roo.BasicLayoutRegion
52651 * @event beforeremove
52652 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52653 * @param {Roo.LayoutRegion} this
52654 * @param {Roo.ContentPanel} panel The panel
52655 * @param {Object} e The cancel event object
52657 "beforeremove" : true,
52659 * @event invalidated
52660 * Fires when the layout for this region is changed.
52661 * @param {Roo.LayoutRegion} this
52663 "invalidated" : true,
52665 * @event visibilitychange
52666 * Fires when this region is shown or hidden
52667 * @param {Roo.LayoutRegion} this
52668 * @param {Boolean} visibility true or false
52670 "visibilitychange" : true,
52672 * @event paneladded
52673 * Fires when a panel is added.
52674 * @param {Roo.LayoutRegion} this
52675 * @param {Roo.ContentPanel} panel The panel
52677 "paneladded" : true,
52679 * @event panelremoved
52680 * Fires when a panel is removed.
52681 * @param {Roo.LayoutRegion} this
52682 * @param {Roo.ContentPanel} panel The panel
52684 "panelremoved" : true,
52686 * @event beforecollapse
52687 * Fires when this region before collapse.
52688 * @param {Roo.LayoutRegion} this
52690 "beforecollapse" : true,
52693 * Fires when this region is collapsed.
52694 * @param {Roo.LayoutRegion} this
52696 "collapsed" : true,
52699 * Fires when this region is expanded.
52700 * @param {Roo.LayoutRegion} this
52705 * Fires when this region is slid into view.
52706 * @param {Roo.LayoutRegion} this
52708 "slideshow" : true,
52711 * Fires when this region slides out of view.
52712 * @param {Roo.LayoutRegion} this
52714 "slidehide" : true,
52716 * @event panelactivated
52717 * Fires when a panel is activated.
52718 * @param {Roo.LayoutRegion} this
52719 * @param {Roo.ContentPanel} panel The activated panel
52721 "panelactivated" : true,
52724 * Fires when the user resizes this region.
52725 * @param {Roo.LayoutRegion} this
52726 * @param {Number} newSize The new size (width for east/west, height for north/south)
52730 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52731 this.panels = new Roo.util.MixedCollection();
52732 this.panels.getKey = this.getPanelId.createDelegate(this);
52734 this.activePanel = null;
52735 // ensure listeners are added...
52737 if (config.listeners || config.events) {
52738 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52739 listeners : config.listeners || {},
52740 events : config.events || {}
52744 if(skipConfig !== true){
52745 this.applyConfig(config);
52749 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52750 getPanelId : function(p){
52754 applyConfig : function(config){
52755 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52756 this.config = config;
52761 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
52762 * the width, for horizontal (north, south) the height.
52763 * @param {Number} newSize The new width or height
52765 resizeTo : function(newSize){
52766 var el = this.el ? this.el :
52767 (this.activePanel ? this.activePanel.getEl() : null);
52769 switch(this.position){
52772 el.setWidth(newSize);
52773 this.fireEvent("resized", this, newSize);
52777 el.setHeight(newSize);
52778 this.fireEvent("resized", this, newSize);
52784 getBox : function(){
52785 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
52788 getMargins : function(){
52789 return this.margins;
52792 updateBox : function(box){
52794 var el = this.activePanel.getEl();
52795 el.dom.style.left = box.x + "px";
52796 el.dom.style.top = box.y + "px";
52797 this.activePanel.setSize(box.width, box.height);
52801 * Returns the container element for this region.
52802 * @return {Roo.Element}
52804 getEl : function(){
52805 return this.activePanel;
52809 * Returns true if this region is currently visible.
52810 * @return {Boolean}
52812 isVisible : function(){
52813 return this.activePanel ? true : false;
52816 setActivePanel : function(panel){
52817 panel = this.getPanel(panel);
52818 if(this.activePanel && this.activePanel != panel){
52819 this.activePanel.setActiveState(false);
52820 this.activePanel.getEl().setLeftTop(-10000,-10000);
52822 this.activePanel = panel;
52823 panel.setActiveState(true);
52825 panel.setSize(this.box.width, this.box.height);
52827 this.fireEvent("panelactivated", this, panel);
52828 this.fireEvent("invalidated");
52832 * Show the specified panel.
52833 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
52834 * @return {Roo.ContentPanel} The shown panel or null
52836 showPanel : function(panel){
52837 if(panel = this.getPanel(panel)){
52838 this.setActivePanel(panel);
52844 * Get the active panel for this region.
52845 * @return {Roo.ContentPanel} The active panel or null
52847 getActivePanel : function(){
52848 return this.activePanel;
52852 * Add the passed ContentPanel(s)
52853 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52854 * @return {Roo.ContentPanel} The panel added (if only one was added)
52856 add : function(panel){
52857 if(arguments.length > 1){
52858 for(var i = 0, len = arguments.length; i < len; i++) {
52859 this.add(arguments[i]);
52863 if(this.hasPanel(panel)){
52864 this.showPanel(panel);
52867 var el = panel.getEl();
52868 if(el.dom.parentNode != this.mgr.el.dom){
52869 this.mgr.el.dom.appendChild(el.dom);
52871 if(panel.setRegion){
52872 panel.setRegion(this);
52874 this.panels.add(panel);
52875 el.setStyle("position", "absolute");
52876 if(!panel.background){
52877 this.setActivePanel(panel);
52878 if(this.config.initialSize && this.panels.getCount()==1){
52879 this.resizeTo(this.config.initialSize);
52882 this.fireEvent("paneladded", this, panel);
52887 * Returns true if the panel is in this region.
52888 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52889 * @return {Boolean}
52891 hasPanel : function(panel){
52892 if(typeof panel == "object"){ // must be panel obj
52893 panel = panel.getId();
52895 return this.getPanel(panel) ? true : false;
52899 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52900 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52901 * @param {Boolean} preservePanel Overrides the config preservePanel option
52902 * @return {Roo.ContentPanel} The panel that was removed
52904 remove : function(panel, preservePanel){
52905 panel = this.getPanel(panel);
52910 this.fireEvent("beforeremove", this, panel, e);
52911 if(e.cancel === true){
52914 var panelId = panel.getId();
52915 this.panels.removeKey(panelId);
52920 * Returns the panel specified or null if it's not in this region.
52921 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52922 * @return {Roo.ContentPanel}
52924 getPanel : function(id){
52925 if(typeof id == "object"){ // must be panel obj
52928 return this.panels.get(id);
52932 * Returns this regions position (north/south/east/west/center).
52935 getPosition: function(){
52936 return this.position;
52940 * Ext JS Library 1.1.1
52941 * Copyright(c) 2006-2007, Ext JS, LLC.
52943 * Originally Released Under LGPL - original licence link has changed is not relivant.
52946 * <script type="text/javascript">
52950 * @class Roo.LayoutRegion
52951 * @extends Roo.BasicLayoutRegion
52952 * This class represents a region in a layout manager.
52953 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
52954 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
52955 * @cfg {Boolean} floatable False to disable floating (defaults to true)
52956 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
52957 * @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})
52958 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
52959 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
52960 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
52961 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
52962 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
52963 * @cfg {String} title The title for the region (overrides panel titles)
52964 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
52965 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
52966 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
52967 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
52968 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
52969 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
52970 * the space available, similar to FireFox 1.5 tabs (defaults to false)
52971 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
52972 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
52973 * @cfg {Boolean} showPin True to show a pin button
52974 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
52975 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
52976 * @cfg {Boolean} disableTabTips True to disable tab tooltips
52977 * @cfg {Number} width For East/West panels
52978 * @cfg {Number} height For North/South panels
52979 * @cfg {Boolean} split To show the splitter
52980 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
52982 Roo.LayoutRegion = function(mgr, config, pos){
52983 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
52984 var dh = Roo.DomHelper;
52985 /** This region's container element
52986 * @type Roo.Element */
52987 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
52988 /** This region's title element
52989 * @type Roo.Element */
52991 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
52992 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
52993 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
52995 this.titleEl.enableDisplayMode();
52996 /** This region's title text element
52997 * @type HTMLElement */
52998 this.titleTextEl = this.titleEl.dom.firstChild;
52999 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53000 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53001 this.closeBtn.enableDisplayMode();
53002 this.closeBtn.on("click", this.closeClicked, this);
53003 this.closeBtn.hide();
53005 this.createBody(config);
53006 this.visible = true;
53007 this.collapsed = false;
53009 if(config.hideWhenEmpty){
53011 this.on("paneladded", this.validateVisibility, this);
53012 this.on("panelremoved", this.validateVisibility, this);
53014 this.applyConfig(config);
53017 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53019 createBody : function(){
53020 /** This region's body element
53021 * @type Roo.Element */
53022 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53025 applyConfig : function(c){
53026 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53027 var dh = Roo.DomHelper;
53028 if(c.titlebar !== false){
53029 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53030 this.collapseBtn.on("click", this.collapse, this);
53031 this.collapseBtn.enableDisplayMode();
53033 if(c.showPin === true || this.showPin){
53034 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53035 this.stickBtn.enableDisplayMode();
53036 this.stickBtn.on("click", this.expand, this);
53037 this.stickBtn.hide();
53040 /** This region's collapsed element
53041 * @type Roo.Element */
53042 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53043 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53045 if(c.floatable !== false){
53046 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53047 this.collapsedEl.on("click", this.collapseClick, this);
53050 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53051 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53052 id: "message", unselectable: "on", style:{"float":"left"}});
53053 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53055 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53056 this.expandBtn.on("click", this.expand, this);
53058 if(this.collapseBtn){
53059 this.collapseBtn.setVisible(c.collapsible == true);
53061 this.cmargins = c.cmargins || this.cmargins ||
53062 (this.position == "west" || this.position == "east" ?
53063 {top: 0, left: 2, right:2, bottom: 0} :
53064 {top: 2, left: 0, right:0, bottom: 2});
53065 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53066 this.bottomTabs = c.tabPosition != "top";
53067 this.autoScroll = c.autoScroll || false;
53068 if(this.autoScroll){
53069 this.bodyEl.setStyle("overflow", "auto");
53071 this.bodyEl.setStyle("overflow", "hidden");
53073 //if(c.titlebar !== false){
53074 if((!c.titlebar && !c.title) || c.titlebar === false){
53075 this.titleEl.hide();
53077 this.titleEl.show();
53079 this.titleTextEl.innerHTML = c.title;
53083 this.duration = c.duration || .30;
53084 this.slideDuration = c.slideDuration || .45;
53087 this.collapse(true);
53094 * Returns true if this region is currently visible.
53095 * @return {Boolean}
53097 isVisible : function(){
53098 return this.visible;
53102 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53103 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53105 setCollapsedTitle : function(title){
53106 title = title || " ";
53107 if(this.collapsedTitleTextEl){
53108 this.collapsedTitleTextEl.innerHTML = title;
53112 getBox : function(){
53114 if(!this.collapsed){
53115 b = this.el.getBox(false, true);
53117 b = this.collapsedEl.getBox(false, true);
53122 getMargins : function(){
53123 return this.collapsed ? this.cmargins : this.margins;
53126 highlight : function(){
53127 this.el.addClass("x-layout-panel-dragover");
53130 unhighlight : function(){
53131 this.el.removeClass("x-layout-panel-dragover");
53134 updateBox : function(box){
53136 if(!this.collapsed){
53137 this.el.dom.style.left = box.x + "px";
53138 this.el.dom.style.top = box.y + "px";
53139 this.updateBody(box.width, box.height);
53141 this.collapsedEl.dom.style.left = box.x + "px";
53142 this.collapsedEl.dom.style.top = box.y + "px";
53143 this.collapsedEl.setSize(box.width, box.height);
53146 this.tabs.autoSizeTabs();
53150 updateBody : function(w, h){
53152 this.el.setWidth(w);
53153 w -= this.el.getBorderWidth("rl");
53154 if(this.config.adjustments){
53155 w += this.config.adjustments[0];
53159 this.el.setHeight(h);
53160 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53161 h -= this.el.getBorderWidth("tb");
53162 if(this.config.adjustments){
53163 h += this.config.adjustments[1];
53165 this.bodyEl.setHeight(h);
53167 h = this.tabs.syncHeight(h);
53170 if(this.panelSize){
53171 w = w !== null ? w : this.panelSize.width;
53172 h = h !== null ? h : this.panelSize.height;
53174 if(this.activePanel){
53175 var el = this.activePanel.getEl();
53176 w = w !== null ? w : el.getWidth();
53177 h = h !== null ? h : el.getHeight();
53178 this.panelSize = {width: w, height: h};
53179 this.activePanel.setSize(w, h);
53181 if(Roo.isIE && this.tabs){
53182 this.tabs.el.repaint();
53187 * Returns the container element for this region.
53188 * @return {Roo.Element}
53190 getEl : function(){
53195 * Hides this region.
53198 if(!this.collapsed){
53199 this.el.dom.style.left = "-2000px";
53202 this.collapsedEl.dom.style.left = "-2000px";
53203 this.collapsedEl.hide();
53205 this.visible = false;
53206 this.fireEvent("visibilitychange", this, false);
53210 * Shows this region if it was previously hidden.
53213 if(!this.collapsed){
53216 this.collapsedEl.show();
53218 this.visible = true;
53219 this.fireEvent("visibilitychange", this, true);
53222 closeClicked : function(){
53223 if(this.activePanel){
53224 this.remove(this.activePanel);
53228 collapseClick : function(e){
53230 e.stopPropagation();
53233 e.stopPropagation();
53239 * Collapses this region.
53240 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53242 collapse : function(skipAnim, skipCheck){
53243 if(this.collapsed) {
53247 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53249 this.collapsed = true;
53251 this.split.el.hide();
53253 if(this.config.animate && skipAnim !== true){
53254 this.fireEvent("invalidated", this);
53255 this.animateCollapse();
53257 this.el.setLocation(-20000,-20000);
53259 this.collapsedEl.show();
53260 this.fireEvent("collapsed", this);
53261 this.fireEvent("invalidated", this);
53267 animateCollapse : function(){
53272 * Expands this region if it was previously collapsed.
53273 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53274 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53276 expand : function(e, skipAnim){
53278 e.stopPropagation();
53280 if(!this.collapsed || this.el.hasActiveFx()) {
53284 this.afterSlideIn();
53287 this.collapsed = false;
53288 if(this.config.animate && skipAnim !== true){
53289 this.animateExpand();
53293 this.split.el.show();
53295 this.collapsedEl.setLocation(-2000,-2000);
53296 this.collapsedEl.hide();
53297 this.fireEvent("invalidated", this);
53298 this.fireEvent("expanded", this);
53302 animateExpand : function(){
53306 initTabs : function()
53308 this.bodyEl.setStyle("overflow", "hidden");
53309 var ts = new Roo.TabPanel(
53312 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53313 disableTooltips: this.config.disableTabTips,
53314 toolbar : this.config.toolbar
53317 if(this.config.hideTabs){
53318 ts.stripWrap.setDisplayed(false);
53321 ts.resizeTabs = this.config.resizeTabs === true;
53322 ts.minTabWidth = this.config.minTabWidth || 40;
53323 ts.maxTabWidth = this.config.maxTabWidth || 250;
53324 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53325 ts.monitorResize = false;
53326 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53327 ts.bodyEl.addClass('x-layout-tabs-body');
53328 this.panels.each(this.initPanelAsTab, this);
53331 initPanelAsTab : function(panel){
53332 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53333 this.config.closeOnTab && panel.isClosable());
53334 if(panel.tabTip !== undefined){
53335 ti.setTooltip(panel.tabTip);
53337 ti.on("activate", function(){
53338 this.setActivePanel(panel);
53340 if(this.config.closeOnTab){
53341 ti.on("beforeclose", function(t, e){
53343 this.remove(panel);
53349 updatePanelTitle : function(panel, title){
53350 if(this.activePanel == panel){
53351 this.updateTitle(title);
53354 var ti = this.tabs.getTab(panel.getEl().id);
53356 if(panel.tabTip !== undefined){
53357 ti.setTooltip(panel.tabTip);
53362 updateTitle : function(title){
53363 if(this.titleTextEl && !this.config.title){
53364 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53368 setActivePanel : function(panel){
53369 panel = this.getPanel(panel);
53370 if(this.activePanel && this.activePanel != panel){
53371 this.activePanel.setActiveState(false);
53373 this.activePanel = panel;
53374 panel.setActiveState(true);
53375 if(this.panelSize){
53376 panel.setSize(this.panelSize.width, this.panelSize.height);
53379 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53381 this.updateTitle(panel.getTitle());
53383 this.fireEvent("invalidated", this);
53385 this.fireEvent("panelactivated", this, panel);
53389 * Shows the specified panel.
53390 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53391 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53393 showPanel : function(panel)
53395 panel = this.getPanel(panel);
53398 var tab = this.tabs.getTab(panel.getEl().id);
53399 if(tab.isHidden()){
53400 this.tabs.unhideTab(tab.id);
53404 this.setActivePanel(panel);
53411 * Get the active panel for this region.
53412 * @return {Roo.ContentPanel} The active panel or null
53414 getActivePanel : function(){
53415 return this.activePanel;
53418 validateVisibility : function(){
53419 if(this.panels.getCount() < 1){
53420 this.updateTitle(" ");
53421 this.closeBtn.hide();
53424 if(!this.isVisible()){
53431 * Adds the passed ContentPanel(s) to this region.
53432 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53433 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53435 add : function(panel){
53436 if(arguments.length > 1){
53437 for(var i = 0, len = arguments.length; i < len; i++) {
53438 this.add(arguments[i]);
53442 if(this.hasPanel(panel)){
53443 this.showPanel(panel);
53446 panel.setRegion(this);
53447 this.panels.add(panel);
53448 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53449 this.bodyEl.dom.appendChild(panel.getEl().dom);
53450 if(panel.background !== true){
53451 this.setActivePanel(panel);
53453 this.fireEvent("paneladded", this, panel);
53459 this.initPanelAsTab(panel);
53461 if(panel.background !== true){
53462 this.tabs.activate(panel.getEl().id);
53464 this.fireEvent("paneladded", this, panel);
53469 * Hides the tab for the specified panel.
53470 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53472 hidePanel : function(panel){
53473 if(this.tabs && (panel = this.getPanel(panel))){
53474 this.tabs.hideTab(panel.getEl().id);
53479 * Unhides the tab for a previously hidden panel.
53480 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53482 unhidePanel : function(panel){
53483 if(this.tabs && (panel = this.getPanel(panel))){
53484 this.tabs.unhideTab(panel.getEl().id);
53488 clearPanels : function(){
53489 while(this.panels.getCount() > 0){
53490 this.remove(this.panels.first());
53495 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53496 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53497 * @param {Boolean} preservePanel Overrides the config preservePanel option
53498 * @return {Roo.ContentPanel} The panel that was removed
53500 remove : function(panel, preservePanel){
53501 panel = this.getPanel(panel);
53506 this.fireEvent("beforeremove", this, panel, e);
53507 if(e.cancel === true){
53510 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53511 var panelId = panel.getId();
53512 this.panels.removeKey(panelId);
53514 document.body.appendChild(panel.getEl().dom);
53517 this.tabs.removeTab(panel.getEl().id);
53518 }else if (!preservePanel){
53519 this.bodyEl.dom.removeChild(panel.getEl().dom);
53521 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53522 var p = this.panels.first();
53523 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53524 tempEl.appendChild(p.getEl().dom);
53525 this.bodyEl.update("");
53526 this.bodyEl.dom.appendChild(p.getEl().dom);
53528 this.updateTitle(p.getTitle());
53530 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53531 this.setActivePanel(p);
53533 panel.setRegion(null);
53534 if(this.activePanel == panel){
53535 this.activePanel = null;
53537 if(this.config.autoDestroy !== false && preservePanel !== true){
53538 try{panel.destroy();}catch(e){}
53540 this.fireEvent("panelremoved", this, panel);
53545 * Returns the TabPanel component used by this region
53546 * @return {Roo.TabPanel}
53548 getTabs : function(){
53552 createTool : function(parentEl, className){
53553 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53554 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53555 btn.addClassOnOver("x-layout-tools-button-over");
53560 * Ext JS Library 1.1.1
53561 * Copyright(c) 2006-2007, Ext JS, LLC.
53563 * Originally Released Under LGPL - original licence link has changed is not relivant.
53566 * <script type="text/javascript">
53572 * @class Roo.SplitLayoutRegion
53573 * @extends Roo.LayoutRegion
53574 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53576 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53577 this.cursor = cursor;
53578 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53581 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53582 splitTip : "Drag to resize.",
53583 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53584 useSplitTips : false,
53586 applyConfig : function(config){
53587 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53590 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53591 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53592 /** The SplitBar for this region
53593 * @type Roo.SplitBar */
53594 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53595 this.split.on("moved", this.onSplitMove, this);
53596 this.split.useShim = config.useShim === true;
53597 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53598 if(this.useSplitTips){
53599 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53601 if(config.collapsible){
53602 this.split.el.on("dblclick", this.collapse, this);
53605 if(typeof config.minSize != "undefined"){
53606 this.split.minSize = config.minSize;
53608 if(typeof config.maxSize != "undefined"){
53609 this.split.maxSize = config.maxSize;
53611 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53612 this.hideSplitter();
53617 getHMaxSize : function(){
53618 var cmax = this.config.maxSize || 10000;
53619 var center = this.mgr.getRegion("center");
53620 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53623 getVMaxSize : function(){
53624 var cmax = this.config.maxSize || 10000;
53625 var center = this.mgr.getRegion("center");
53626 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53629 onSplitMove : function(split, newSize){
53630 this.fireEvent("resized", this, newSize);
53634 * Returns the {@link Roo.SplitBar} for this region.
53635 * @return {Roo.SplitBar}
53637 getSplitBar : function(){
53642 this.hideSplitter();
53643 Roo.SplitLayoutRegion.superclass.hide.call(this);
53646 hideSplitter : function(){
53648 this.split.el.setLocation(-2000,-2000);
53649 this.split.el.hide();
53655 this.split.el.show();
53657 Roo.SplitLayoutRegion.superclass.show.call(this);
53660 beforeSlide: function(){
53661 if(Roo.isGecko){// firefox overflow auto bug workaround
53662 this.bodyEl.clip();
53664 this.tabs.bodyEl.clip();
53666 if(this.activePanel){
53667 this.activePanel.getEl().clip();
53669 if(this.activePanel.beforeSlide){
53670 this.activePanel.beforeSlide();
53676 afterSlide : function(){
53677 if(Roo.isGecko){// firefox overflow auto bug workaround
53678 this.bodyEl.unclip();
53680 this.tabs.bodyEl.unclip();
53682 if(this.activePanel){
53683 this.activePanel.getEl().unclip();
53684 if(this.activePanel.afterSlide){
53685 this.activePanel.afterSlide();
53691 initAutoHide : function(){
53692 if(this.autoHide !== false){
53693 if(!this.autoHideHd){
53694 var st = new Roo.util.DelayedTask(this.slideIn, this);
53695 this.autoHideHd = {
53696 "mouseout": function(e){
53697 if(!e.within(this.el, true)){
53701 "mouseover" : function(e){
53707 this.el.on(this.autoHideHd);
53711 clearAutoHide : function(){
53712 if(this.autoHide !== false){
53713 this.el.un("mouseout", this.autoHideHd.mouseout);
53714 this.el.un("mouseover", this.autoHideHd.mouseover);
53718 clearMonitor : function(){
53719 Roo.get(document).un("click", this.slideInIf, this);
53722 // these names are backwards but not changed for compat
53723 slideOut : function(){
53724 if(this.isSlid || this.el.hasActiveFx()){
53727 this.isSlid = true;
53728 if(this.collapseBtn){
53729 this.collapseBtn.hide();
53731 this.closeBtnState = this.closeBtn.getStyle('display');
53732 this.closeBtn.hide();
53734 this.stickBtn.show();
53737 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53738 this.beforeSlide();
53739 this.el.setStyle("z-index", 10001);
53740 this.el.slideIn(this.getSlideAnchor(), {
53741 callback: function(){
53743 this.initAutoHide();
53744 Roo.get(document).on("click", this.slideInIf, this);
53745 this.fireEvent("slideshow", this);
53752 afterSlideIn : function(){
53753 this.clearAutoHide();
53754 this.isSlid = false;
53755 this.clearMonitor();
53756 this.el.setStyle("z-index", "");
53757 if(this.collapseBtn){
53758 this.collapseBtn.show();
53760 this.closeBtn.setStyle('display', this.closeBtnState);
53762 this.stickBtn.hide();
53764 this.fireEvent("slidehide", this);
53767 slideIn : function(cb){
53768 if(!this.isSlid || this.el.hasActiveFx()){
53772 this.isSlid = false;
53773 this.beforeSlide();
53774 this.el.slideOut(this.getSlideAnchor(), {
53775 callback: function(){
53776 this.el.setLeftTop(-10000, -10000);
53778 this.afterSlideIn();
53786 slideInIf : function(e){
53787 if(!e.within(this.el)){
53792 animateCollapse : function(){
53793 this.beforeSlide();
53794 this.el.setStyle("z-index", 20000);
53795 var anchor = this.getSlideAnchor();
53796 this.el.slideOut(anchor, {
53797 callback : function(){
53798 this.el.setStyle("z-index", "");
53799 this.collapsedEl.slideIn(anchor, {duration:.3});
53801 this.el.setLocation(-10000,-10000);
53803 this.fireEvent("collapsed", this);
53810 animateExpand : function(){
53811 this.beforeSlide();
53812 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
53813 this.el.setStyle("z-index", 20000);
53814 this.collapsedEl.hide({
53817 this.el.slideIn(this.getSlideAnchor(), {
53818 callback : function(){
53819 this.el.setStyle("z-index", "");
53822 this.split.el.show();
53824 this.fireEvent("invalidated", this);
53825 this.fireEvent("expanded", this);
53853 getAnchor : function(){
53854 return this.anchors[this.position];
53857 getCollapseAnchor : function(){
53858 return this.canchors[this.position];
53861 getSlideAnchor : function(){
53862 return this.sanchors[this.position];
53865 getAlignAdj : function(){
53866 var cm = this.cmargins;
53867 switch(this.position){
53883 getExpandAdj : function(){
53884 var c = this.collapsedEl, cm = this.cmargins;
53885 switch(this.position){
53887 return [-(cm.right+c.getWidth()+cm.left), 0];
53890 return [cm.right+c.getWidth()+cm.left, 0];
53893 return [0, -(cm.top+cm.bottom+c.getHeight())];
53896 return [0, cm.top+cm.bottom+c.getHeight()];
53902 * Ext JS Library 1.1.1
53903 * Copyright(c) 2006-2007, Ext JS, LLC.
53905 * Originally Released Under LGPL - original licence link has changed is not relivant.
53908 * <script type="text/javascript">
53911 * These classes are private internal classes
53913 Roo.CenterLayoutRegion = function(mgr, config){
53914 Roo.LayoutRegion.call(this, mgr, config, "center");
53915 this.visible = true;
53916 this.minWidth = config.minWidth || 20;
53917 this.minHeight = config.minHeight || 20;
53920 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
53922 // center panel can't be hidden
53926 // center panel can't be hidden
53929 getMinWidth: function(){
53930 return this.minWidth;
53933 getMinHeight: function(){
53934 return this.minHeight;
53939 Roo.NorthLayoutRegion = function(mgr, config){
53940 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
53942 this.split.placement = Roo.SplitBar.TOP;
53943 this.split.orientation = Roo.SplitBar.VERTICAL;
53944 this.split.el.addClass("x-layout-split-v");
53946 var size = config.initialSize || config.height;
53947 if(typeof size != "undefined"){
53948 this.el.setHeight(size);
53951 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
53952 orientation: Roo.SplitBar.VERTICAL,
53953 getBox : function(){
53954 if(this.collapsed){
53955 return this.collapsedEl.getBox();
53957 var box = this.el.getBox();
53959 box.height += this.split.el.getHeight();
53964 updateBox : function(box){
53965 if(this.split && !this.collapsed){
53966 box.height -= this.split.el.getHeight();
53967 this.split.el.setLeft(box.x);
53968 this.split.el.setTop(box.y+box.height);
53969 this.split.el.setWidth(box.width);
53971 if(this.collapsed){
53972 this.updateBody(box.width, null);
53974 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53978 Roo.SouthLayoutRegion = function(mgr, config){
53979 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
53981 this.split.placement = Roo.SplitBar.BOTTOM;
53982 this.split.orientation = Roo.SplitBar.VERTICAL;
53983 this.split.el.addClass("x-layout-split-v");
53985 var size = config.initialSize || config.height;
53986 if(typeof size != "undefined"){
53987 this.el.setHeight(size);
53990 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
53991 orientation: Roo.SplitBar.VERTICAL,
53992 getBox : function(){
53993 if(this.collapsed){
53994 return this.collapsedEl.getBox();
53996 var box = this.el.getBox();
53998 var sh = this.split.el.getHeight();
54005 updateBox : function(box){
54006 if(this.split && !this.collapsed){
54007 var sh = this.split.el.getHeight();
54010 this.split.el.setLeft(box.x);
54011 this.split.el.setTop(box.y-sh);
54012 this.split.el.setWidth(box.width);
54014 if(this.collapsed){
54015 this.updateBody(box.width, null);
54017 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54021 Roo.EastLayoutRegion = function(mgr, config){
54022 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54024 this.split.placement = Roo.SplitBar.RIGHT;
54025 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54026 this.split.el.addClass("x-layout-split-h");
54028 var size = config.initialSize || config.width;
54029 if(typeof size != "undefined"){
54030 this.el.setWidth(size);
54033 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54034 orientation: Roo.SplitBar.HORIZONTAL,
54035 getBox : function(){
54036 if(this.collapsed){
54037 return this.collapsedEl.getBox();
54039 var box = this.el.getBox();
54041 var sw = this.split.el.getWidth();
54048 updateBox : function(box){
54049 if(this.split && !this.collapsed){
54050 var sw = this.split.el.getWidth();
54052 this.split.el.setLeft(box.x);
54053 this.split.el.setTop(box.y);
54054 this.split.el.setHeight(box.height);
54057 if(this.collapsed){
54058 this.updateBody(null, box.height);
54060 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54064 Roo.WestLayoutRegion = function(mgr, config){
54065 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54067 this.split.placement = Roo.SplitBar.LEFT;
54068 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54069 this.split.el.addClass("x-layout-split-h");
54071 var size = config.initialSize || config.width;
54072 if(typeof size != "undefined"){
54073 this.el.setWidth(size);
54076 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
54077 orientation: Roo.SplitBar.HORIZONTAL,
54078 getBox : function(){
54079 if(this.collapsed){
54080 return this.collapsedEl.getBox();
54082 var box = this.el.getBox();
54084 box.width += this.split.el.getWidth();
54089 updateBox : function(box){
54090 if(this.split && !this.collapsed){
54091 var sw = this.split.el.getWidth();
54093 this.split.el.setLeft(box.x+box.width);
54094 this.split.el.setTop(box.y);
54095 this.split.el.setHeight(box.height);
54097 if(this.collapsed){
54098 this.updateBody(null, box.height);
54100 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54105 * Ext JS Library 1.1.1
54106 * Copyright(c) 2006-2007, Ext JS, LLC.
54108 * Originally Released Under LGPL - original licence link has changed is not relivant.
54111 * <script type="text/javascript">
54116 * Private internal class for reading and applying state
54118 Roo.LayoutStateManager = function(layout){
54119 // default empty state
54128 Roo.LayoutStateManager.prototype = {
54129 init : function(layout, provider){
54130 this.provider = provider;
54131 var state = provider.get(layout.id+"-layout-state");
54133 var wasUpdating = layout.isUpdating();
54135 layout.beginUpdate();
54137 for(var key in state){
54138 if(typeof state[key] != "function"){
54139 var rstate = state[key];
54140 var r = layout.getRegion(key);
54143 r.resizeTo(rstate.size);
54145 if(rstate.collapsed == true){
54148 r.expand(null, true);
54154 layout.endUpdate();
54156 this.state = state;
54158 this.layout = layout;
54159 layout.on("regionresized", this.onRegionResized, this);
54160 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54161 layout.on("regionexpanded", this.onRegionExpanded, this);
54164 storeState : function(){
54165 this.provider.set(this.layout.id+"-layout-state", this.state);
54168 onRegionResized : function(region, newSize){
54169 this.state[region.getPosition()].size = newSize;
54173 onRegionCollapsed : function(region){
54174 this.state[region.getPosition()].collapsed = true;
54178 onRegionExpanded : function(region){
54179 this.state[region.getPosition()].collapsed = false;
54184 * Ext JS Library 1.1.1
54185 * Copyright(c) 2006-2007, Ext JS, LLC.
54187 * Originally Released Under LGPL - original licence link has changed is not relivant.
54190 * <script type="text/javascript">
54193 * @class Roo.ContentPanel
54194 * @extends Roo.util.Observable
54195 * A basic ContentPanel element.
54196 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54197 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54198 * @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
54199 * @cfg {Boolean} closable True if the panel can be closed/removed
54200 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54201 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54202 * @cfg {Toolbar} toolbar A toolbar for this panel
54203 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54204 * @cfg {String} title The title for this panel
54205 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54206 * @cfg {String} url Calls {@link #setUrl} with this value
54207 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54208 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54209 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54210 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54211 * @cfg {String} style Extra style to add to the content panel
54214 * Create a new ContentPanel.
54215 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54216 * @param {String/Object} config A string to set only the title or a config object
54217 * @param {String} content (optional) Set the HTML content for this panel
54218 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54220 Roo.ContentPanel = function(el, config, content){
54224 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54228 if (config && config.parentLayout) {
54229 el = config.parentLayout.el.createChild();
54232 if(el.autoCreate){ // xtype is available if this is called from factory
54236 this.el = Roo.get(el);
54237 if(!this.el && config && config.autoCreate){
54238 if(typeof config.autoCreate == "object"){
54239 if(!config.autoCreate.id){
54240 config.autoCreate.id = config.id||el;
54242 this.el = Roo.DomHelper.append(document.body,
54243 config.autoCreate, true);
54245 this.el = Roo.DomHelper.append(document.body,
54246 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54251 this.closable = false;
54252 this.loaded = false;
54253 this.active = false;
54254 if(typeof config == "string"){
54255 this.title = config;
54257 Roo.apply(this, config);
54260 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54261 this.wrapEl = this.el.wrap();
54262 this.toolbar.container = this.el.insertSibling(false, 'before');
54263 this.toolbar = new Roo.Toolbar(this.toolbar);
54266 // xtype created footer. - not sure if will work as we normally have to render first..
54267 if (this.footer && !this.footer.el && this.footer.xtype) {
54268 if (!this.wrapEl) {
54269 this.wrapEl = this.el.wrap();
54272 this.footer.container = this.wrapEl.createChild();
54274 this.footer = Roo.factory(this.footer, Roo);
54279 this.resizeEl = Roo.get(this.resizeEl, true);
54281 this.resizeEl = this.el;
54283 // handle view.xtype
54291 * Fires when this panel is activated.
54292 * @param {Roo.ContentPanel} this
54296 * @event deactivate
54297 * Fires when this panel is activated.
54298 * @param {Roo.ContentPanel} this
54300 "deactivate" : true,
54304 * Fires when this panel is resized if fitToFrame is true.
54305 * @param {Roo.ContentPanel} this
54306 * @param {Number} width The width after any component adjustments
54307 * @param {Number} height The height after any component adjustments
54313 * Fires when this tab is created
54314 * @param {Roo.ContentPanel} this
54324 if(this.autoScroll){
54325 this.resizeEl.setStyle("overflow", "auto");
54327 // fix randome scrolling
54328 this.el.on('scroll', function() {
54329 Roo.log('fix random scolling');
54330 this.scrollTo('top',0);
54333 content = content || this.content;
54335 this.setContent(content);
54337 if(config && config.url){
54338 this.setUrl(this.url, this.params, this.loadOnce);
54343 Roo.ContentPanel.superclass.constructor.call(this);
54345 if (this.view && typeof(this.view.xtype) != 'undefined') {
54346 this.view.el = this.el.appendChild(document.createElement("div"));
54347 this.view = Roo.factory(this.view);
54348 this.view.render && this.view.render(false, '');
54352 this.fireEvent('render', this);
54355 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54357 setRegion : function(region){
54358 this.region = region;
54360 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54362 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54367 * Returns the toolbar for this Panel if one was configured.
54368 * @return {Roo.Toolbar}
54370 getToolbar : function(){
54371 return this.toolbar;
54374 setActiveState : function(active){
54375 this.active = active;
54377 this.fireEvent("deactivate", this);
54379 this.fireEvent("activate", this);
54383 * Updates this panel's element
54384 * @param {String} content The new content
54385 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54387 setContent : function(content, loadScripts){
54388 this.el.update(content, loadScripts);
54391 ignoreResize : function(w, h){
54392 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54395 this.lastSize = {width: w, height: h};
54400 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54401 * @return {Roo.UpdateManager} The UpdateManager
54403 getUpdateManager : function(){
54404 return this.el.getUpdateManager();
54407 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54408 * @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:
54411 url: "your-url.php",
54412 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54413 callback: yourFunction,
54414 scope: yourObject, //(optional scope)
54417 text: "Loading...",
54422 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54423 * 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.
54424 * @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}
54425 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54426 * @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.
54427 * @return {Roo.ContentPanel} this
54430 var um = this.el.getUpdateManager();
54431 um.update.apply(um, arguments);
54437 * 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.
54438 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54439 * @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)
54440 * @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)
54441 * @return {Roo.UpdateManager} The UpdateManager
54443 setUrl : function(url, params, loadOnce){
54444 if(this.refreshDelegate){
54445 this.removeListener("activate", this.refreshDelegate);
54447 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54448 this.on("activate", this.refreshDelegate);
54449 return this.el.getUpdateManager();
54452 _handleRefresh : function(url, params, loadOnce){
54453 if(!loadOnce || !this.loaded){
54454 var updater = this.el.getUpdateManager();
54455 updater.update(url, params, this._setLoaded.createDelegate(this));
54459 _setLoaded : function(){
54460 this.loaded = true;
54464 * Returns this panel's id
54467 getId : function(){
54472 * Returns this panel's element - used by regiosn to add.
54473 * @return {Roo.Element}
54475 getEl : function(){
54476 return this.wrapEl || this.el;
54479 adjustForComponents : function(width, height)
54481 //Roo.log('adjustForComponents ');
54482 if(this.resizeEl != this.el){
54483 width -= this.el.getFrameWidth('lr');
54484 height -= this.el.getFrameWidth('tb');
54487 var te = this.toolbar.getEl();
54488 height -= te.getHeight();
54489 te.setWidth(width);
54492 var te = this.footer.getEl();
54493 //Roo.log("footer:" + te.getHeight());
54495 height -= te.getHeight();
54496 te.setWidth(width);
54500 if(this.adjustments){
54501 width += this.adjustments[0];
54502 height += this.adjustments[1];
54504 return {"width": width, "height": height};
54507 setSize : function(width, height){
54508 if(this.fitToFrame && !this.ignoreResize(width, height)){
54509 if(this.fitContainer && this.resizeEl != this.el){
54510 this.el.setSize(width, height);
54512 var size = this.adjustForComponents(width, height);
54513 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54514 this.fireEvent('resize', this, size.width, size.height);
54519 * Returns this panel's title
54522 getTitle : function(){
54527 * Set this panel's title
54528 * @param {String} title
54530 setTitle : function(title){
54531 this.title = title;
54533 this.region.updatePanelTitle(this, title);
54538 * Returns true is this panel was configured to be closable
54539 * @return {Boolean}
54541 isClosable : function(){
54542 return this.closable;
54545 beforeSlide : function(){
54547 this.resizeEl.clip();
54550 afterSlide : function(){
54552 this.resizeEl.unclip();
54556 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54557 * Will fail silently if the {@link #setUrl} method has not been called.
54558 * This does not activate the panel, just updates its content.
54560 refresh : function(){
54561 if(this.refreshDelegate){
54562 this.loaded = false;
54563 this.refreshDelegate();
54568 * Destroys this panel
54570 destroy : function(){
54571 this.el.removeAllListeners();
54572 var tempEl = document.createElement("span");
54573 tempEl.appendChild(this.el.dom);
54574 tempEl.innerHTML = "";
54580 * form - if the content panel contains a form - this is a reference to it.
54581 * @type {Roo.form.Form}
54585 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54586 * This contains a reference to it.
54592 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54602 * @param {Object} cfg Xtype definition of item to add.
54605 addxtype : function(cfg) {
54607 if (cfg.xtype.match(/^Form$/)) {
54610 //if (this.footer) {
54611 // el = this.footer.container.insertSibling(false, 'before');
54613 el = this.el.createChild();
54616 this.form = new Roo.form.Form(cfg);
54619 if ( this.form.allItems.length) {
54620 this.form.render(el.dom);
54624 // should only have one of theses..
54625 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54626 // views.. should not be just added - used named prop 'view''
54628 cfg.el = this.el.appendChild(document.createElement("div"));
54631 var ret = new Roo.factory(cfg);
54633 ret.render && ret.render(false, ''); // render blank..
54642 * @class Roo.GridPanel
54643 * @extends Roo.ContentPanel
54645 * Create a new GridPanel.
54646 * @param {Roo.grid.Grid} grid The grid for this panel
54647 * @param {String/Object} config A string to set only the panel's title, or a config object
54649 Roo.GridPanel = function(grid, config){
54652 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54653 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54655 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54657 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54660 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54662 // xtype created footer. - not sure if will work as we normally have to render first..
54663 if (this.footer && !this.footer.el && this.footer.xtype) {
54665 this.footer.container = this.grid.getView().getFooterPanel(true);
54666 this.footer.dataSource = this.grid.dataSource;
54667 this.footer = Roo.factory(this.footer, Roo);
54671 grid.monitorWindowResize = false; // turn off autosizing
54672 grid.autoHeight = false;
54673 grid.autoWidth = false;
54675 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54678 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54679 getId : function(){
54680 return this.grid.id;
54684 * Returns the grid for this panel
54685 * @return {Roo.grid.Grid}
54687 getGrid : function(){
54691 setSize : function(width, height){
54692 if(!this.ignoreResize(width, height)){
54693 var grid = this.grid;
54694 var size = this.adjustForComponents(width, height);
54695 grid.getGridEl().setSize(size.width, size.height);
54700 beforeSlide : function(){
54701 this.grid.getView().scroller.clip();
54704 afterSlide : function(){
54705 this.grid.getView().scroller.unclip();
54708 destroy : function(){
54709 this.grid.destroy();
54711 Roo.GridPanel.superclass.destroy.call(this);
54717 * @class Roo.NestedLayoutPanel
54718 * @extends Roo.ContentPanel
54720 * Create a new NestedLayoutPanel.
54723 * @param {Roo.BorderLayout} layout The layout for this panel
54724 * @param {String/Object} config A string to set only the title or a config object
54726 Roo.NestedLayoutPanel = function(layout, config)
54728 // construct with only one argument..
54729 /* FIXME - implement nicer consturctors
54730 if (layout.layout) {
54732 layout = config.layout;
54733 delete config.layout;
54735 if (layout.xtype && !layout.getEl) {
54736 // then layout needs constructing..
54737 layout = Roo.factory(layout, Roo);
54742 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54744 layout.monitorWindowResize = false; // turn off autosizing
54745 this.layout = layout;
54746 this.layout.getEl().addClass("x-layout-nested-layout");
54753 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
54755 setSize : function(width, height){
54756 if(!this.ignoreResize(width, height)){
54757 var size = this.adjustForComponents(width, height);
54758 var el = this.layout.getEl();
54759 el.setSize(size.width, size.height);
54760 var touch = el.dom.offsetWidth;
54761 this.layout.layout();
54762 // ie requires a double layout on the first pass
54763 if(Roo.isIE && !this.initialized){
54764 this.initialized = true;
54765 this.layout.layout();
54770 // activate all subpanels if not currently active..
54772 setActiveState : function(active){
54773 this.active = active;
54775 this.fireEvent("deactivate", this);
54779 this.fireEvent("activate", this);
54780 // not sure if this should happen before or after..
54781 if (!this.layout) {
54782 return; // should not happen..
54785 for (var r in this.layout.regions) {
54786 reg = this.layout.getRegion(r);
54787 if (reg.getActivePanel()) {
54788 //reg.showPanel(reg.getActivePanel()); // force it to activate..
54789 reg.setActivePanel(reg.getActivePanel());
54792 if (!reg.panels.length) {
54795 reg.showPanel(reg.getPanel(0));
54804 * Returns the nested BorderLayout for this panel
54805 * @return {Roo.BorderLayout}
54807 getLayout : function(){
54808 return this.layout;
54812 * Adds a xtype elements to the layout of the nested panel
54816 xtype : 'ContentPanel',
54823 xtype : 'NestedLayoutPanel',
54829 items : [ ... list of content panels or nested layout panels.. ]
54833 * @param {Object} cfg Xtype definition of item to add.
54835 addxtype : function(cfg) {
54836 return this.layout.addxtype(cfg);
54841 Roo.ScrollPanel = function(el, config, content){
54842 config = config || {};
54843 config.fitToFrame = true;
54844 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
54846 this.el.dom.style.overflow = "hidden";
54847 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
54848 this.el.removeClass("x-layout-inactive-content");
54849 this.el.on("mousewheel", this.onWheel, this);
54851 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
54852 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
54853 up.unselectable(); down.unselectable();
54854 up.on("click", this.scrollUp, this);
54855 down.on("click", this.scrollDown, this);
54856 up.addClassOnOver("x-scroller-btn-over");
54857 down.addClassOnOver("x-scroller-btn-over");
54858 up.addClassOnClick("x-scroller-btn-click");
54859 down.addClassOnClick("x-scroller-btn-click");
54860 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
54862 this.resizeEl = this.el;
54863 this.el = wrap; this.up = up; this.down = down;
54866 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
54868 wheelIncrement : 5,
54869 scrollUp : function(){
54870 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
54873 scrollDown : function(){
54874 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
54877 afterScroll : function(){
54878 var el = this.resizeEl;
54879 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
54880 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54881 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54884 setSize : function(){
54885 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
54886 this.afterScroll();
54889 onWheel : function(e){
54890 var d = e.getWheelDelta();
54891 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
54892 this.afterScroll();
54896 setContent : function(content, loadScripts){
54897 this.resizeEl.update(content, loadScripts);
54911 * @class Roo.TreePanel
54912 * @extends Roo.ContentPanel
54914 * Create a new TreePanel. - defaults to fit/scoll contents.
54915 * @param {String/Object} config A string to set only the panel's title, or a config object
54916 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
54918 Roo.TreePanel = function(config){
54919 var el = config.el;
54920 var tree = config.tree;
54921 delete config.tree;
54922 delete config.el; // hopefull!
54924 // wrapper for IE7 strict & safari scroll issue
54926 var treeEl = el.createChild();
54927 config.resizeEl = treeEl;
54931 Roo.TreePanel.superclass.constructor.call(this, el, config);
54934 this.tree = new Roo.tree.TreePanel(treeEl , tree);
54935 //console.log(tree);
54936 this.on('activate', function()
54938 if (this.tree.rendered) {
54941 //console.log('render tree');
54942 this.tree.render();
54944 // this should not be needed.. - it's actually the 'el' that resizes?
54945 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
54947 //this.on('resize', function (cp, w, h) {
54948 // this.tree.innerCt.setWidth(w);
54949 // this.tree.innerCt.setHeight(h);
54950 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
54957 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
54974 * Ext JS Library 1.1.1
54975 * Copyright(c) 2006-2007, Ext JS, LLC.
54977 * Originally Released Under LGPL - original licence link has changed is not relivant.
54980 * <script type="text/javascript">
54985 * @class Roo.ReaderLayout
54986 * @extends Roo.BorderLayout
54987 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
54988 * center region containing two nested regions (a top one for a list view and one for item preview below),
54989 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
54990 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
54991 * expedites the setup of the overall layout and regions for this common application style.
54994 var reader = new Roo.ReaderLayout();
54995 var CP = Roo.ContentPanel; // shortcut for adding
54997 reader.beginUpdate();
54998 reader.add("north", new CP("north", "North"));
54999 reader.add("west", new CP("west", {title: "West"}));
55000 reader.add("east", new CP("east", {title: "East"}));
55002 reader.regions.listView.add(new CP("listView", "List"));
55003 reader.regions.preview.add(new CP("preview", "Preview"));
55004 reader.endUpdate();
55007 * Create a new ReaderLayout
55008 * @param {Object} config Configuration options
55009 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55010 * document.body if omitted)
55012 Roo.ReaderLayout = function(config, renderTo){
55013 var c = config || {size:{}};
55014 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55015 north: c.north !== false ? Roo.apply({
55019 }, c.north) : false,
55020 west: c.west !== false ? Roo.apply({
55028 margins:{left:5,right:0,bottom:5,top:5},
55029 cmargins:{left:5,right:5,bottom:5,top:5}
55030 }, c.west) : false,
55031 east: c.east !== false ? Roo.apply({
55039 margins:{left:0,right:5,bottom:5,top:5},
55040 cmargins:{left:5,right:5,bottom:5,top:5}
55041 }, c.east) : false,
55042 center: Roo.apply({
55043 tabPosition: 'top',
55047 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55051 this.el.addClass('x-reader');
55053 this.beginUpdate();
55055 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55056 south: c.preview !== false ? Roo.apply({
55063 cmargins:{top:5,left:0, right:0, bottom:0}
55064 }, c.preview) : false,
55065 center: Roo.apply({
55071 this.add('center', new Roo.NestedLayoutPanel(inner,
55072 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55076 this.regions.preview = inner.getRegion('south');
55077 this.regions.listView = inner.getRegion('center');
55080 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55082 * Ext JS Library 1.1.1
55083 * Copyright(c) 2006-2007, Ext JS, LLC.
55085 * Originally Released Under LGPL - original licence link has changed is not relivant.
55088 * <script type="text/javascript">
55092 * @class Roo.grid.Grid
55093 * @extends Roo.util.Observable
55094 * This class represents the primary interface of a component based grid control.
55095 * <br><br>Usage:<pre><code>
55096 var grid = new Roo.grid.Grid("my-container-id", {
55099 selModel: mySelectionModel,
55100 autoSizeColumns: true,
55101 monitorWindowResize: false,
55102 trackMouseOver: true
55107 * <b>Common Problems:</b><br/>
55108 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55109 * element will correct this<br/>
55110 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55111 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55112 * are unpredictable.<br/>
55113 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55114 * grid to calculate dimensions/offsets.<br/>
55116 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55117 * The container MUST have some type of size defined for the grid to fill. The container will be
55118 * automatically set to position relative if it isn't already.
55119 * @param {Object} config A config object that sets properties on this grid.
55121 Roo.grid.Grid = function(container, config){
55122 // initialize the container
55123 this.container = Roo.get(container);
55124 this.container.update("");
55125 this.container.setStyle("overflow", "hidden");
55126 this.container.addClass('x-grid-container');
55128 this.id = this.container.id;
55130 Roo.apply(this, config);
55131 // check and correct shorthanded configs
55133 this.dataSource = this.ds;
55137 this.colModel = this.cm;
55141 this.selModel = this.sm;
55145 if (this.selModel) {
55146 this.selModel = Roo.factory(this.selModel, Roo.grid);
55147 this.sm = this.selModel;
55148 this.sm.xmodule = this.xmodule || false;
55150 if (typeof(this.colModel.config) == 'undefined') {
55151 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55152 this.cm = this.colModel;
55153 this.cm.xmodule = this.xmodule || false;
55155 if (this.dataSource) {
55156 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55157 this.ds = this.dataSource;
55158 this.ds.xmodule = this.xmodule || false;
55165 this.container.setWidth(this.width);
55169 this.container.setHeight(this.height);
55176 * The raw click event for the entire grid.
55177 * @param {Roo.EventObject} e
55182 * The raw dblclick event for the entire grid.
55183 * @param {Roo.EventObject} e
55187 * @event contextmenu
55188 * The raw contextmenu event for the entire grid.
55189 * @param {Roo.EventObject} e
55191 "contextmenu" : true,
55194 * The raw mousedown event for the entire grid.
55195 * @param {Roo.EventObject} e
55197 "mousedown" : true,
55200 * The raw mouseup event for the entire grid.
55201 * @param {Roo.EventObject} e
55206 * The raw mouseover event for the entire grid.
55207 * @param {Roo.EventObject} e
55209 "mouseover" : true,
55212 * The raw mouseout event for the entire grid.
55213 * @param {Roo.EventObject} e
55218 * The raw keypress event for the entire grid.
55219 * @param {Roo.EventObject} e
55224 * The raw keydown event for the entire grid.
55225 * @param {Roo.EventObject} e
55233 * Fires when a cell is clicked
55234 * @param {Grid} this
55235 * @param {Number} rowIndex
55236 * @param {Number} columnIndex
55237 * @param {Roo.EventObject} e
55239 "cellclick" : true,
55241 * @event celldblclick
55242 * Fires when a cell is double clicked
55243 * @param {Grid} this
55244 * @param {Number} rowIndex
55245 * @param {Number} columnIndex
55246 * @param {Roo.EventObject} e
55248 "celldblclick" : true,
55251 * Fires when a row is clicked
55252 * @param {Grid} this
55253 * @param {Number} rowIndex
55254 * @param {Roo.EventObject} e
55258 * @event rowdblclick
55259 * Fires when a row is double clicked
55260 * @param {Grid} this
55261 * @param {Number} rowIndex
55262 * @param {Roo.EventObject} e
55264 "rowdblclick" : true,
55266 * @event headerclick
55267 * Fires when a header is clicked
55268 * @param {Grid} this
55269 * @param {Number} columnIndex
55270 * @param {Roo.EventObject} e
55272 "headerclick" : true,
55274 * @event headerdblclick
55275 * Fires when a header cell is double clicked
55276 * @param {Grid} this
55277 * @param {Number} columnIndex
55278 * @param {Roo.EventObject} e
55280 "headerdblclick" : true,
55282 * @event rowcontextmenu
55283 * Fires when a row is right clicked
55284 * @param {Grid} this
55285 * @param {Number} rowIndex
55286 * @param {Roo.EventObject} e
55288 "rowcontextmenu" : true,
55290 * @event cellcontextmenu
55291 * Fires when a cell is right clicked
55292 * @param {Grid} this
55293 * @param {Number} rowIndex
55294 * @param {Number} cellIndex
55295 * @param {Roo.EventObject} e
55297 "cellcontextmenu" : true,
55299 * @event headercontextmenu
55300 * Fires when a header is right clicked
55301 * @param {Grid} this
55302 * @param {Number} columnIndex
55303 * @param {Roo.EventObject} e
55305 "headercontextmenu" : true,
55307 * @event bodyscroll
55308 * Fires when the body element is scrolled
55309 * @param {Number} scrollLeft
55310 * @param {Number} scrollTop
55312 "bodyscroll" : true,
55314 * @event columnresize
55315 * Fires when the user resizes a column
55316 * @param {Number} columnIndex
55317 * @param {Number} newSize
55319 "columnresize" : true,
55321 * @event columnmove
55322 * Fires when the user moves a column
55323 * @param {Number} oldIndex
55324 * @param {Number} newIndex
55326 "columnmove" : true,
55329 * Fires when row(s) start being dragged
55330 * @param {Grid} this
55331 * @param {Roo.GridDD} dd The drag drop object
55332 * @param {event} e The raw browser event
55334 "startdrag" : true,
55337 * Fires when a drag operation is complete
55338 * @param {Grid} this
55339 * @param {Roo.GridDD} dd The drag drop object
55340 * @param {event} e The raw browser event
55345 * Fires when dragged row(s) are dropped on a valid DD target
55346 * @param {Grid} this
55347 * @param {Roo.GridDD} dd The drag drop object
55348 * @param {String} targetId The target drag drop object
55349 * @param {event} e The raw browser event
55354 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55355 * @param {Grid} this
55356 * @param {Roo.GridDD} dd The drag drop object
55357 * @param {String} targetId The target drag drop object
55358 * @param {event} e The raw browser event
55363 * Fires when the dragged row(s) first cross another DD target while being dragged
55364 * @param {Grid} this
55365 * @param {Roo.GridDD} dd The drag drop object
55366 * @param {String} targetId The target drag drop object
55367 * @param {event} e The raw browser event
55369 "dragenter" : true,
55372 * Fires when the dragged row(s) leave another DD target while being dragged
55373 * @param {Grid} this
55374 * @param {Roo.GridDD} dd The drag drop object
55375 * @param {String} targetId The target drag drop object
55376 * @param {event} e The raw browser event
55381 * Fires when a row is rendered, so you can change add a style to it.
55382 * @param {GridView} gridview The grid view
55383 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55389 * Fires when the grid is rendered
55390 * @param {Grid} grid
55395 Roo.grid.Grid.superclass.constructor.call(this);
55397 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55400 * @cfg {String} ddGroup - drag drop group.
55404 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55406 minColumnWidth : 25,
55409 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55410 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55411 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55413 autoSizeColumns : false,
55416 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55418 autoSizeHeaders : true,
55421 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55423 monitorWindowResize : true,
55426 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55427 * rows measured to get a columns size. Default is 0 (all rows).
55429 maxRowsToMeasure : 0,
55432 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55434 trackMouseOver : true,
55437 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55441 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55443 enableDragDrop : false,
55446 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55448 enableColumnMove : true,
55451 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55453 enableColumnHide : true,
55456 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55458 enableRowHeightSync : false,
55461 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55466 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55468 autoHeight : false,
55471 * @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.
55473 autoExpandColumn : false,
55476 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55479 autoExpandMin : 50,
55482 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55484 autoExpandMax : 1000,
55487 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55492 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55496 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55506 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55507 * of a fixed width. Default is false.
55510 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55513 * Called once after all setup has been completed and the grid is ready to be rendered.
55514 * @return {Roo.grid.Grid} this
55516 render : function()
55518 var c = this.container;
55519 // try to detect autoHeight/width mode
55520 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55521 this.autoHeight = true;
55523 var view = this.getView();
55526 c.on("click", this.onClick, this);
55527 c.on("dblclick", this.onDblClick, this);
55528 c.on("contextmenu", this.onContextMenu, this);
55529 c.on("keydown", this.onKeyDown, this);
55531 c.on("touchstart", this.onTouchStart, this);
55534 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55536 this.getSelectionModel().init(this);
55541 this.loadMask = new Roo.LoadMask(this.container,
55542 Roo.apply({store:this.dataSource}, this.loadMask));
55546 if (this.toolbar && this.toolbar.xtype) {
55547 this.toolbar.container = this.getView().getHeaderPanel(true);
55548 this.toolbar = new Roo.Toolbar(this.toolbar);
55550 if (this.footer && this.footer.xtype) {
55551 this.footer.dataSource = this.getDataSource();
55552 this.footer.container = this.getView().getFooterPanel(true);
55553 this.footer = Roo.factory(this.footer, Roo);
55555 if (this.dropTarget && this.dropTarget.xtype) {
55556 delete this.dropTarget.xtype;
55557 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55561 this.rendered = true;
55562 this.fireEvent('render', this);
55567 * Reconfigures the grid to use a different Store and Column Model.
55568 * The View will be bound to the new objects and refreshed.
55569 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55570 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55572 reconfigure : function(dataSource, colModel){
55574 this.loadMask.destroy();
55575 this.loadMask = new Roo.LoadMask(this.container,
55576 Roo.apply({store:dataSource}, this.loadMask));
55578 this.view.bind(dataSource, colModel);
55579 this.dataSource = dataSource;
55580 this.colModel = colModel;
55581 this.view.refresh(true);
55585 * Add's a column, default at the end..
55587 * @param {int} position to add (default end)
55588 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55590 addColumns : function(pos, ar)
55593 for (var i =0;i< ar.length;i++) {
55595 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55596 this.cm.lookup[cfg.id] = cfg;
55600 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55601 pos = this.cm.config.length; //this.cm.config.push(cfg);
55603 pos = Math.max(0,pos);
55606 this.cm.config.splice.apply(this.cm.config, ar);
55610 this.view.generateRules(this.cm);
55611 this.view.refresh(true);
55619 onKeyDown : function(e){
55620 this.fireEvent("keydown", e);
55624 * Destroy this grid.
55625 * @param {Boolean} removeEl True to remove the element
55627 destroy : function(removeEl, keepListeners){
55629 this.loadMask.destroy();
55631 var c = this.container;
55632 c.removeAllListeners();
55633 this.view.destroy();
55634 this.colModel.purgeListeners();
55635 if(!keepListeners){
55636 this.purgeListeners();
55639 if(removeEl === true){
55645 processEvent : function(name, e){
55646 // does this fire select???
55647 //Roo.log('grid:processEvent ' + name);
55649 if (name != 'touchstart' ) {
55650 this.fireEvent(name, e);
55653 var t = e.getTarget();
55655 var header = v.findHeaderIndex(t);
55656 if(header !== false){
55657 var ename = name == 'touchstart' ? 'click' : name;
55659 this.fireEvent("header" + ename, this, header, e);
55661 var row = v.findRowIndex(t);
55662 var cell = v.findCellIndex(t);
55663 if (name == 'touchstart') {
55664 // first touch is always a click.
55665 // hopefull this happens after selection is updated.?
55668 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55669 var cs = this.selModel.getSelectedCell();
55670 if (row == cs[0] && cell == cs[1]){
55674 if (typeof(this.selModel.getSelections) != 'undefined') {
55675 var cs = this.selModel.getSelections();
55676 var ds = this.dataSource;
55677 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55688 this.fireEvent("row" + name, this, row, e);
55689 if(cell !== false){
55690 this.fireEvent("cell" + name, this, row, cell, e);
55697 onClick : function(e){
55698 this.processEvent("click", e);
55701 onTouchStart : function(e){
55702 this.processEvent("touchstart", e);
55706 onContextMenu : function(e, t){
55707 this.processEvent("contextmenu", e);
55711 onDblClick : function(e){
55712 this.processEvent("dblclick", e);
55716 walkCells : function(row, col, step, fn, scope){
55717 var cm = this.colModel, clen = cm.getColumnCount();
55718 var ds = this.dataSource, rlen = ds.getCount(), first = true;
55730 if(fn.call(scope || this, row, col, cm) === true){
55748 if(fn.call(scope || this, row, col, cm) === true){
55760 getSelections : function(){
55761 return this.selModel.getSelections();
55765 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
55766 * but if manual update is required this method will initiate it.
55768 autoSize : function(){
55770 this.view.layout();
55771 if(this.view.adjustForScroll){
55772 this.view.adjustForScroll();
55778 * Returns the grid's underlying element.
55779 * @return {Element} The element
55781 getGridEl : function(){
55782 return this.container;
55785 // private for compatibility, overridden by editor grid
55786 stopEditing : function(){},
55789 * Returns the grid's SelectionModel.
55790 * @return {SelectionModel}
55792 getSelectionModel : function(){
55793 if(!this.selModel){
55794 this.selModel = new Roo.grid.RowSelectionModel();
55796 return this.selModel;
55800 * Returns the grid's DataSource.
55801 * @return {DataSource}
55803 getDataSource : function(){
55804 return this.dataSource;
55808 * Returns the grid's ColumnModel.
55809 * @return {ColumnModel}
55811 getColumnModel : function(){
55812 return this.colModel;
55816 * Returns the grid's GridView object.
55817 * @return {GridView}
55819 getView : function(){
55821 this.view = new Roo.grid.GridView(this.viewConfig);
55826 * Called to get grid's drag proxy text, by default returns this.ddText.
55829 getDragDropText : function(){
55830 var count = this.selModel.getCount();
55831 return String.format(this.ddText, count, count == 1 ? '' : 's');
55835 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55836 * %0 is replaced with the number of selected rows.
55839 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
55841 * Ext JS Library 1.1.1
55842 * Copyright(c) 2006-2007, Ext JS, LLC.
55844 * Originally Released Under LGPL - original licence link has changed is not relivant.
55847 * <script type="text/javascript">
55850 Roo.grid.AbstractGridView = function(){
55854 "beforerowremoved" : true,
55855 "beforerowsinserted" : true,
55856 "beforerefresh" : true,
55857 "rowremoved" : true,
55858 "rowsinserted" : true,
55859 "rowupdated" : true,
55862 Roo.grid.AbstractGridView.superclass.constructor.call(this);
55865 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
55866 rowClass : "x-grid-row",
55867 cellClass : "x-grid-cell",
55868 tdClass : "x-grid-td",
55869 hdClass : "x-grid-hd",
55870 splitClass : "x-grid-hd-split",
55872 init: function(grid){
55874 var cid = this.grid.getGridEl().id;
55875 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
55876 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
55877 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
55878 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
55881 getColumnRenderers : function(){
55882 var renderers = [];
55883 var cm = this.grid.colModel;
55884 var colCount = cm.getColumnCount();
55885 for(var i = 0; i < colCount; i++){
55886 renderers[i] = cm.getRenderer(i);
55891 getColumnIds : function(){
55893 var cm = this.grid.colModel;
55894 var colCount = cm.getColumnCount();
55895 for(var i = 0; i < colCount; i++){
55896 ids[i] = cm.getColumnId(i);
55901 getDataIndexes : function(){
55902 if(!this.indexMap){
55903 this.indexMap = this.buildIndexMap();
55905 return this.indexMap.colToData;
55908 getColumnIndexByDataIndex : function(dataIndex){
55909 if(!this.indexMap){
55910 this.indexMap = this.buildIndexMap();
55912 return this.indexMap.dataToCol[dataIndex];
55916 * Set a css style for a column dynamically.
55917 * @param {Number} colIndex The index of the column
55918 * @param {String} name The css property name
55919 * @param {String} value The css value
55921 setCSSStyle : function(colIndex, name, value){
55922 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
55923 Roo.util.CSS.updateRule(selector, name, value);
55926 generateRules : function(cm){
55927 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
55928 Roo.util.CSS.removeStyleSheet(rulesId);
55929 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55930 var cid = cm.getColumnId(i);
55931 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
55932 this.tdSelector, cid, " {\n}\n",
55933 this.hdSelector, cid, " {\n}\n",
55934 this.splitSelector, cid, " {\n}\n");
55936 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55940 * Ext JS Library 1.1.1
55941 * Copyright(c) 2006-2007, Ext JS, LLC.
55943 * Originally Released Under LGPL - original licence link has changed is not relivant.
55946 * <script type="text/javascript">
55950 // This is a support class used internally by the Grid components
55951 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
55953 this.view = grid.getView();
55954 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
55955 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
55957 this.setHandleElId(Roo.id(hd));
55958 this.setOuterHandleElId(Roo.id(hd2));
55960 this.scroll = false;
55962 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
55964 getDragData : function(e){
55965 var t = Roo.lib.Event.getTarget(e);
55966 var h = this.view.findHeaderCell(t);
55968 return {ddel: h.firstChild, header:h};
55973 onInitDrag : function(e){
55974 this.view.headersDisabled = true;
55975 var clone = this.dragData.ddel.cloneNode(true);
55976 clone.id = Roo.id();
55977 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
55978 this.proxy.update(clone);
55982 afterValidDrop : function(){
55984 setTimeout(function(){
55985 v.headersDisabled = false;
55989 afterInvalidDrop : function(){
55991 setTimeout(function(){
55992 v.headersDisabled = false;
55998 * Ext JS Library 1.1.1
55999 * Copyright(c) 2006-2007, Ext JS, LLC.
56001 * Originally Released Under LGPL - original licence link has changed is not relivant.
56004 * <script type="text/javascript">
56007 // This is a support class used internally by the Grid components
56008 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56010 this.view = grid.getView();
56011 // split the proxies so they don't interfere with mouse events
56012 this.proxyTop = Roo.DomHelper.append(document.body, {
56013 cls:"col-move-top", html:" "
56015 this.proxyBottom = Roo.DomHelper.append(document.body, {
56016 cls:"col-move-bottom", html:" "
56018 this.proxyTop.hide = this.proxyBottom.hide = function(){
56019 this.setLeftTop(-100,-100);
56020 this.setStyle("visibility", "hidden");
56022 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56023 // temporarily disabled
56024 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56025 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56027 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56028 proxyOffsets : [-4, -9],
56029 fly: Roo.Element.fly,
56031 getTargetFromEvent : function(e){
56032 var t = Roo.lib.Event.getTarget(e);
56033 var cindex = this.view.findCellIndex(t);
56034 if(cindex !== false){
56035 return this.view.getHeaderCell(cindex);
56040 nextVisible : function(h){
56041 var v = this.view, cm = this.grid.colModel;
56044 if(!cm.isHidden(v.getCellIndex(h))){
56052 prevVisible : function(h){
56053 var v = this.view, cm = this.grid.colModel;
56056 if(!cm.isHidden(v.getCellIndex(h))){
56064 positionIndicator : function(h, n, e){
56065 var x = Roo.lib.Event.getPageX(e);
56066 var r = Roo.lib.Dom.getRegion(n.firstChild);
56067 var px, pt, py = r.top + this.proxyOffsets[1];
56068 if((r.right - x) <= (r.right-r.left)/2){
56069 px = r.right+this.view.borderWidth;
56075 var oldIndex = this.view.getCellIndex(h);
56076 var newIndex = this.view.getCellIndex(n);
56078 if(this.grid.colModel.isFixed(newIndex)){
56082 var locked = this.grid.colModel.isLocked(newIndex);
56087 if(oldIndex < newIndex){
56090 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56093 px += this.proxyOffsets[0];
56094 this.proxyTop.setLeftTop(px, py);
56095 this.proxyTop.show();
56096 if(!this.bottomOffset){
56097 this.bottomOffset = this.view.mainHd.getHeight();
56099 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56100 this.proxyBottom.show();
56104 onNodeEnter : function(n, dd, e, data){
56105 if(data.header != n){
56106 this.positionIndicator(data.header, n, e);
56110 onNodeOver : function(n, dd, e, data){
56111 var result = false;
56112 if(data.header != n){
56113 result = this.positionIndicator(data.header, n, e);
56116 this.proxyTop.hide();
56117 this.proxyBottom.hide();
56119 return result ? this.dropAllowed : this.dropNotAllowed;
56122 onNodeOut : function(n, dd, e, data){
56123 this.proxyTop.hide();
56124 this.proxyBottom.hide();
56127 onNodeDrop : function(n, dd, e, data){
56128 var h = data.header;
56130 var cm = this.grid.colModel;
56131 var x = Roo.lib.Event.getPageX(e);
56132 var r = Roo.lib.Dom.getRegion(n.firstChild);
56133 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56134 var oldIndex = this.view.getCellIndex(h);
56135 var newIndex = this.view.getCellIndex(n);
56136 var locked = cm.isLocked(newIndex);
56140 if(oldIndex < newIndex){
56143 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56146 cm.setLocked(oldIndex, locked, true);
56147 cm.moveColumn(oldIndex, newIndex);
56148 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56156 * Ext JS Library 1.1.1
56157 * Copyright(c) 2006-2007, Ext JS, LLC.
56159 * Originally Released Under LGPL - original licence link has changed is not relivant.
56162 * <script type="text/javascript">
56166 * @class Roo.grid.GridView
56167 * @extends Roo.util.Observable
56170 * @param {Object} config
56172 Roo.grid.GridView = function(config){
56173 Roo.grid.GridView.superclass.constructor.call(this);
56176 Roo.apply(this, config);
56179 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56181 unselectable : 'unselectable="on"',
56182 unselectableCls : 'x-unselectable',
56185 rowClass : "x-grid-row",
56187 cellClass : "x-grid-col",
56189 tdClass : "x-grid-td",
56191 hdClass : "x-grid-hd",
56193 splitClass : "x-grid-split",
56195 sortClasses : ["sort-asc", "sort-desc"],
56197 enableMoveAnim : false,
56201 dh : Roo.DomHelper,
56203 fly : Roo.Element.fly,
56205 css : Roo.util.CSS,
56211 scrollIncrement : 22,
56213 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56215 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56217 bind : function(ds, cm){
56219 this.ds.un("load", this.onLoad, this);
56220 this.ds.un("datachanged", this.onDataChange, this);
56221 this.ds.un("add", this.onAdd, this);
56222 this.ds.un("remove", this.onRemove, this);
56223 this.ds.un("update", this.onUpdate, this);
56224 this.ds.un("clear", this.onClear, this);
56227 ds.on("load", this.onLoad, this);
56228 ds.on("datachanged", this.onDataChange, this);
56229 ds.on("add", this.onAdd, this);
56230 ds.on("remove", this.onRemove, this);
56231 ds.on("update", this.onUpdate, this);
56232 ds.on("clear", this.onClear, this);
56237 this.cm.un("widthchange", this.onColWidthChange, this);
56238 this.cm.un("headerchange", this.onHeaderChange, this);
56239 this.cm.un("hiddenchange", this.onHiddenChange, this);
56240 this.cm.un("columnmoved", this.onColumnMove, this);
56241 this.cm.un("columnlockchange", this.onColumnLock, this);
56244 this.generateRules(cm);
56245 cm.on("widthchange", this.onColWidthChange, this);
56246 cm.on("headerchange", this.onHeaderChange, this);
56247 cm.on("hiddenchange", this.onHiddenChange, this);
56248 cm.on("columnmoved", this.onColumnMove, this);
56249 cm.on("columnlockchange", this.onColumnLock, this);
56254 init: function(grid){
56255 Roo.grid.GridView.superclass.init.call(this, grid);
56257 this.bind(grid.dataSource, grid.colModel);
56259 grid.on("headerclick", this.handleHeaderClick, this);
56261 if(grid.trackMouseOver){
56262 grid.on("mouseover", this.onRowOver, this);
56263 grid.on("mouseout", this.onRowOut, this);
56265 grid.cancelTextSelection = function(){};
56266 this.gridId = grid.id;
56268 var tpls = this.templates || {};
56271 tpls.master = new Roo.Template(
56272 '<div class="x-grid" hidefocus="true">',
56273 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56274 '<div class="x-grid-topbar"></div>',
56275 '<div class="x-grid-scroller"><div></div></div>',
56276 '<div class="x-grid-locked">',
56277 '<div class="x-grid-header">{lockedHeader}</div>',
56278 '<div class="x-grid-body">{lockedBody}</div>',
56280 '<div class="x-grid-viewport">',
56281 '<div class="x-grid-header">{header}</div>',
56282 '<div class="x-grid-body">{body}</div>',
56284 '<div class="x-grid-bottombar"></div>',
56286 '<div class="x-grid-resize-proxy"> </div>',
56289 tpls.master.disableformats = true;
56293 tpls.header = new Roo.Template(
56294 '<table border="0" cellspacing="0" cellpadding="0">',
56295 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56298 tpls.header.disableformats = true;
56300 tpls.header.compile();
56303 tpls.hcell = new Roo.Template(
56304 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56305 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56308 tpls.hcell.disableFormats = true;
56310 tpls.hcell.compile();
56313 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56314 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56315 tpls.hsplit.disableFormats = true;
56317 tpls.hsplit.compile();
56320 tpls.body = new Roo.Template(
56321 '<table border="0" cellspacing="0" cellpadding="0">',
56322 "<tbody>{rows}</tbody>",
56325 tpls.body.disableFormats = true;
56327 tpls.body.compile();
56330 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56331 tpls.row.disableFormats = true;
56333 tpls.row.compile();
56336 tpls.cell = new Roo.Template(
56337 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56338 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56339 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56342 tpls.cell.disableFormats = true;
56344 tpls.cell.compile();
56346 this.templates = tpls;
56349 // remap these for backwards compat
56350 onColWidthChange : function(){
56351 this.updateColumns.apply(this, arguments);
56353 onHeaderChange : function(){
56354 this.updateHeaders.apply(this, arguments);
56356 onHiddenChange : function(){
56357 this.handleHiddenChange.apply(this, arguments);
56359 onColumnMove : function(){
56360 this.handleColumnMove.apply(this, arguments);
56362 onColumnLock : function(){
56363 this.handleLockChange.apply(this, arguments);
56366 onDataChange : function(){
56368 this.updateHeaderSortState();
56371 onClear : function(){
56375 onUpdate : function(ds, record){
56376 this.refreshRow(record);
56379 refreshRow : function(record){
56380 var ds = this.ds, index;
56381 if(typeof record == 'number'){
56383 record = ds.getAt(index);
56385 index = ds.indexOf(record);
56387 this.insertRows(ds, index, index, true);
56388 this.onRemove(ds, record, index+1, true);
56389 this.syncRowHeights(index, index);
56391 this.fireEvent("rowupdated", this, index, record);
56394 onAdd : function(ds, records, index){
56395 this.insertRows(ds, index, index + (records.length-1));
56398 onRemove : function(ds, record, index, isUpdate){
56399 if(isUpdate !== true){
56400 this.fireEvent("beforerowremoved", this, index, record);
56402 var bt = this.getBodyTable(), lt = this.getLockedTable();
56403 if(bt.rows[index]){
56404 bt.firstChild.removeChild(bt.rows[index]);
56406 if(lt.rows[index]){
56407 lt.firstChild.removeChild(lt.rows[index]);
56409 if(isUpdate !== true){
56410 this.stripeRows(index);
56411 this.syncRowHeights(index, index);
56413 this.fireEvent("rowremoved", this, index, record);
56417 onLoad : function(){
56418 this.scrollToTop();
56422 * Scrolls the grid to the top
56424 scrollToTop : function(){
56426 this.scroller.dom.scrollTop = 0;
56432 * Gets a panel in the header of the grid that can be used for toolbars etc.
56433 * After modifying the contents of this panel a call to grid.autoSize() may be
56434 * required to register any changes in size.
56435 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56436 * @return Roo.Element
56438 getHeaderPanel : function(doShow){
56440 this.headerPanel.show();
56442 return this.headerPanel;
56446 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56447 * After modifying the contents of this panel a call to grid.autoSize() may be
56448 * required to register any changes in size.
56449 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56450 * @return Roo.Element
56452 getFooterPanel : function(doShow){
56454 this.footerPanel.show();
56456 return this.footerPanel;
56459 initElements : function(){
56460 var E = Roo.Element;
56461 var el = this.grid.getGridEl().dom.firstChild;
56462 var cs = el.childNodes;
56464 this.el = new E(el);
56466 this.focusEl = new E(el.firstChild);
56467 this.focusEl.swallowEvent("click", true);
56469 this.headerPanel = new E(cs[1]);
56470 this.headerPanel.enableDisplayMode("block");
56472 this.scroller = new E(cs[2]);
56473 this.scrollSizer = new E(this.scroller.dom.firstChild);
56475 this.lockedWrap = new E(cs[3]);
56476 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56477 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56479 this.mainWrap = new E(cs[4]);
56480 this.mainHd = new E(this.mainWrap.dom.firstChild);
56481 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56483 this.footerPanel = new E(cs[5]);
56484 this.footerPanel.enableDisplayMode("block");
56486 this.resizeProxy = new E(cs[6]);
56488 this.headerSelector = String.format(
56489 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56490 this.lockedHd.id, this.mainHd.id
56493 this.splitterSelector = String.format(
56494 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56495 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56498 idToCssName : function(s)
56500 return s.replace(/[^a-z0-9]+/ig, '-');
56503 getHeaderCell : function(index){
56504 return Roo.DomQuery.select(this.headerSelector)[index];
56507 getHeaderCellMeasure : function(index){
56508 return this.getHeaderCell(index).firstChild;
56511 getHeaderCellText : function(index){
56512 return this.getHeaderCell(index).firstChild.firstChild;
56515 getLockedTable : function(){
56516 return this.lockedBody.dom.firstChild;
56519 getBodyTable : function(){
56520 return this.mainBody.dom.firstChild;
56523 getLockedRow : function(index){
56524 return this.getLockedTable().rows[index];
56527 getRow : function(index){
56528 return this.getBodyTable().rows[index];
56531 getRowComposite : function(index){
56533 this.rowEl = new Roo.CompositeElementLite();
56535 var els = [], lrow, mrow;
56536 if(lrow = this.getLockedRow(index)){
56539 if(mrow = this.getRow(index)){
56542 this.rowEl.elements = els;
56546 * Gets the 'td' of the cell
56548 * @param {Integer} rowIndex row to select
56549 * @param {Integer} colIndex column to select
56553 getCell : function(rowIndex, colIndex){
56554 var locked = this.cm.getLockedCount();
56556 if(colIndex < locked){
56557 source = this.lockedBody.dom.firstChild;
56559 source = this.mainBody.dom.firstChild;
56560 colIndex -= locked;
56562 return source.rows[rowIndex].childNodes[colIndex];
56565 getCellText : function(rowIndex, colIndex){
56566 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56569 getCellBox : function(cell){
56570 var b = this.fly(cell).getBox();
56571 if(Roo.isOpera){ // opera fails to report the Y
56572 b.y = cell.offsetTop + this.mainBody.getY();
56577 getCellIndex : function(cell){
56578 var id = String(cell.className).match(this.cellRE);
56580 return parseInt(id[1], 10);
56585 findHeaderIndex : function(n){
56586 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56587 return r ? this.getCellIndex(r) : false;
56590 findHeaderCell : function(n){
56591 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56592 return r ? r : false;
56595 findRowIndex : function(n){
56599 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56600 return r ? r.rowIndex : false;
56603 findCellIndex : function(node){
56604 var stop = this.el.dom;
56605 while(node && node != stop){
56606 if(this.findRE.test(node.className)){
56607 return this.getCellIndex(node);
56609 node = node.parentNode;
56614 getColumnId : function(index){
56615 return this.cm.getColumnId(index);
56618 getSplitters : function()
56620 if(this.splitterSelector){
56621 return Roo.DomQuery.select(this.splitterSelector);
56627 getSplitter : function(index){
56628 return this.getSplitters()[index];
56631 onRowOver : function(e, t){
56633 if((row = this.findRowIndex(t)) !== false){
56634 this.getRowComposite(row).addClass("x-grid-row-over");
56638 onRowOut : function(e, t){
56640 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56641 this.getRowComposite(row).removeClass("x-grid-row-over");
56645 renderHeaders : function(){
56647 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56648 var cb = [], lb = [], sb = [], lsb = [], p = {};
56649 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56650 p.cellId = "x-grid-hd-0-" + i;
56651 p.splitId = "x-grid-csplit-0-" + i;
56652 p.id = cm.getColumnId(i);
56653 p.value = cm.getColumnHeader(i) || "";
56654 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56655 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56656 if(!cm.isLocked(i)){
56657 cb[cb.length] = ct.apply(p);
56658 sb[sb.length] = st.apply(p);
56660 lb[lb.length] = ct.apply(p);
56661 lsb[lsb.length] = st.apply(p);
56664 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56665 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56668 updateHeaders : function(){
56669 var html = this.renderHeaders();
56670 this.lockedHd.update(html[0]);
56671 this.mainHd.update(html[1]);
56675 * Focuses the specified row.
56676 * @param {Number} row The row index
56678 focusRow : function(row)
56680 //Roo.log('GridView.focusRow');
56681 var x = this.scroller.dom.scrollLeft;
56682 this.focusCell(row, 0, false);
56683 this.scroller.dom.scrollLeft = x;
56687 * Focuses the specified cell.
56688 * @param {Number} row The row index
56689 * @param {Number} col The column index
56690 * @param {Boolean} hscroll false to disable horizontal scrolling
56692 focusCell : function(row, col, hscroll)
56694 //Roo.log('GridView.focusCell');
56695 var el = this.ensureVisible(row, col, hscroll);
56696 this.focusEl.alignTo(el, "tl-tl");
56698 this.focusEl.focus();
56700 this.focusEl.focus.defer(1, this.focusEl);
56705 * Scrolls the specified cell into view
56706 * @param {Number} row The row index
56707 * @param {Number} col The column index
56708 * @param {Boolean} hscroll false to disable horizontal scrolling
56710 ensureVisible : function(row, col, hscroll)
56712 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56713 //return null; //disable for testing.
56714 if(typeof row != "number"){
56715 row = row.rowIndex;
56717 if(row < 0 && row >= this.ds.getCount()){
56720 col = (col !== undefined ? col : 0);
56721 var cm = this.grid.colModel;
56722 while(cm.isHidden(col)){
56726 var el = this.getCell(row, col);
56730 var c = this.scroller.dom;
56732 var ctop = parseInt(el.offsetTop, 10);
56733 var cleft = parseInt(el.offsetLeft, 10);
56734 var cbot = ctop + el.offsetHeight;
56735 var cright = cleft + el.offsetWidth;
56737 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
56738 var stop = parseInt(c.scrollTop, 10);
56739 var sleft = parseInt(c.scrollLeft, 10);
56740 var sbot = stop + ch;
56741 var sright = sleft + c.clientWidth;
56743 Roo.log('GridView.ensureVisible:' +
56745 ' c.clientHeight:' + c.clientHeight +
56746 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
56754 c.scrollTop = ctop;
56755 //Roo.log("set scrolltop to ctop DISABLE?");
56756 }else if(cbot > sbot){
56757 //Roo.log("set scrolltop to cbot-ch");
56758 c.scrollTop = cbot-ch;
56761 if(hscroll !== false){
56763 c.scrollLeft = cleft;
56764 }else if(cright > sright){
56765 c.scrollLeft = cright-c.clientWidth;
56772 updateColumns : function(){
56773 this.grid.stopEditing();
56774 var cm = this.grid.colModel, colIds = this.getColumnIds();
56775 //var totalWidth = cm.getTotalWidth();
56777 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56778 //if(cm.isHidden(i)) continue;
56779 var w = cm.getColumnWidth(i);
56780 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56781 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56783 this.updateSplitters();
56786 generateRules : function(cm){
56787 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
56788 Roo.util.CSS.removeStyleSheet(rulesId);
56789 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56790 var cid = cm.getColumnId(i);
56792 if(cm.config[i].align){
56793 align = 'text-align:'+cm.config[i].align+';';
56796 if(cm.isHidden(i)){
56797 hidden = 'display:none;';
56799 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
56801 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
56802 this.hdSelector, cid, " {\n", align, width, "}\n",
56803 this.tdSelector, cid, " {\n",hidden,"\n}\n",
56804 this.splitSelector, cid, " {\n", hidden , "\n}\n");
56806 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56809 updateSplitters : function(){
56810 var cm = this.cm, s = this.getSplitters();
56811 if(s){ // splitters not created yet
56812 var pos = 0, locked = true;
56813 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56814 if(cm.isHidden(i)) {
56817 var w = cm.getColumnWidth(i); // make sure it's a number
56818 if(!cm.isLocked(i) && locked){
56823 s[i].style.left = (pos-this.splitOffset) + "px";
56828 handleHiddenChange : function(colModel, colIndex, hidden){
56830 this.hideColumn(colIndex);
56832 this.unhideColumn(colIndex);
56836 hideColumn : function(colIndex){
56837 var cid = this.getColumnId(colIndex);
56838 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
56839 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
56841 this.updateHeaders();
56843 this.updateSplitters();
56847 unhideColumn : function(colIndex){
56848 var cid = this.getColumnId(colIndex);
56849 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
56850 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
56853 this.updateHeaders();
56855 this.updateSplitters();
56859 insertRows : function(dm, firstRow, lastRow, isUpdate){
56860 if(firstRow == 0 && lastRow == dm.getCount()-1){
56864 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
56866 var s = this.getScrollState();
56867 var markup = this.renderRows(firstRow, lastRow);
56868 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
56869 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
56870 this.restoreScroll(s);
56872 this.fireEvent("rowsinserted", this, firstRow, lastRow);
56873 this.syncRowHeights(firstRow, lastRow);
56874 this.stripeRows(firstRow);
56880 bufferRows : function(markup, target, index){
56881 var before = null, trows = target.rows, tbody = target.tBodies[0];
56882 if(index < trows.length){
56883 before = trows[index];
56885 var b = document.createElement("div");
56886 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
56887 var rows = b.firstChild.rows;
56888 for(var i = 0, len = rows.length; i < len; i++){
56890 tbody.insertBefore(rows[0], before);
56892 tbody.appendChild(rows[0]);
56899 deleteRows : function(dm, firstRow, lastRow){
56900 if(dm.getRowCount()<1){
56901 this.fireEvent("beforerefresh", this);
56902 this.mainBody.update("");
56903 this.lockedBody.update("");
56904 this.fireEvent("refresh", this);
56906 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
56907 var bt = this.getBodyTable();
56908 var tbody = bt.firstChild;
56909 var rows = bt.rows;
56910 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
56911 tbody.removeChild(rows[firstRow]);
56913 this.stripeRows(firstRow);
56914 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
56918 updateRows : function(dataSource, firstRow, lastRow){
56919 var s = this.getScrollState();
56921 this.restoreScroll(s);
56924 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
56928 this.updateHeaderSortState();
56931 getScrollState : function(){
56933 var sb = this.scroller.dom;
56934 return {left: sb.scrollLeft, top: sb.scrollTop};
56937 stripeRows : function(startRow){
56938 if(!this.grid.stripeRows || this.ds.getCount() < 1){
56941 startRow = startRow || 0;
56942 var rows = this.getBodyTable().rows;
56943 var lrows = this.getLockedTable().rows;
56944 var cls = ' x-grid-row-alt ';
56945 for(var i = startRow, len = rows.length; i < len; i++){
56946 var row = rows[i], lrow = lrows[i];
56947 var isAlt = ((i+1) % 2 == 0);
56948 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
56949 if(isAlt == hasAlt){
56953 row.className += " x-grid-row-alt";
56955 row.className = row.className.replace("x-grid-row-alt", "");
56958 lrow.className = row.className;
56963 restoreScroll : function(state){
56964 //Roo.log('GridView.restoreScroll');
56965 var sb = this.scroller.dom;
56966 sb.scrollLeft = state.left;
56967 sb.scrollTop = state.top;
56971 syncScroll : function(){
56972 //Roo.log('GridView.syncScroll');
56973 var sb = this.scroller.dom;
56974 var sh = this.mainHd.dom;
56975 var bs = this.mainBody.dom;
56976 var lv = this.lockedBody.dom;
56977 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
56978 lv.scrollTop = bs.scrollTop = sb.scrollTop;
56981 handleScroll : function(e){
56983 var sb = this.scroller.dom;
56984 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
56988 handleWheel : function(e){
56989 var d = e.getWheelDelta();
56990 this.scroller.dom.scrollTop -= d*22;
56991 // set this here to prevent jumpy scrolling on large tables
56992 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
56996 renderRows : function(startRow, endRow){
56997 // pull in all the crap needed to render rows
56998 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
56999 var colCount = cm.getColumnCount();
57001 if(ds.getCount() < 1){
57005 // build a map for all the columns
57007 for(var i = 0; i < colCount; i++){
57008 var name = cm.getDataIndex(i);
57010 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57011 renderer : cm.getRenderer(i),
57012 id : cm.getColumnId(i),
57013 locked : cm.isLocked(i),
57014 has_editor : cm.isCellEditable(i)
57018 startRow = startRow || 0;
57019 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57021 // records to render
57022 var rs = ds.getRange(startRow, endRow);
57024 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57027 // As much as I hate to duplicate code, this was branched because FireFox really hates
57028 // [].join("") on strings. The performance difference was substantial enough to
57029 // branch this function
57030 doRender : Roo.isGecko ?
57031 function(cs, rs, ds, startRow, colCount, stripe){
57032 var ts = this.templates, ct = ts.cell, rt = ts.row;
57034 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57036 var hasListener = this.grid.hasListener('rowclass');
57038 for(var j = 0, len = rs.length; j < len; j++){
57039 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57040 for(var i = 0; i < colCount; i++){
57042 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57044 p.css = p.attr = "";
57045 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57046 if(p.value == undefined || p.value === "") {
57047 p.value = " ";
57050 p.css += ' x-grid-editable-cell';
57052 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57053 p.css += ' x-grid-dirty-cell';
57055 var markup = ct.apply(p);
57063 if(stripe && ((rowIndex+1) % 2 == 0)){
57064 alt.push("x-grid-row-alt")
57067 alt.push( " x-grid-dirty-row");
57070 if(this.getRowClass){
57071 alt.push(this.getRowClass(r, rowIndex));
57077 rowIndex : rowIndex,
57080 this.grid.fireEvent('rowclass', this, rowcfg);
57081 alt.push(rowcfg.rowClass);
57083 rp.alt = alt.join(" ");
57084 lbuf+= rt.apply(rp);
57086 buf+= rt.apply(rp);
57088 return [lbuf, buf];
57090 function(cs, rs, ds, startRow, colCount, stripe){
57091 var ts = this.templates, ct = ts.cell, rt = ts.row;
57093 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57094 var hasListener = this.grid.hasListener('rowclass');
57097 for(var j = 0, len = rs.length; j < len; j++){
57098 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57099 for(var i = 0; i < colCount; i++){
57101 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57103 p.css = p.attr = "";
57104 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57105 if(p.value == undefined || p.value === "") {
57106 p.value = " ";
57110 p.css += ' x-grid-editable-cell';
57112 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57113 p.css += ' x-grid-dirty-cell'
57116 var markup = ct.apply(p);
57118 cb[cb.length] = markup;
57120 lcb[lcb.length] = markup;
57124 if(stripe && ((rowIndex+1) % 2 == 0)){
57125 alt.push( "x-grid-row-alt");
57128 alt.push(" x-grid-dirty-row");
57131 if(this.getRowClass){
57132 alt.push( this.getRowClass(r, rowIndex));
57138 rowIndex : rowIndex,
57141 this.grid.fireEvent('rowclass', this, rowcfg);
57142 alt.push(rowcfg.rowClass);
57145 rp.alt = alt.join(" ");
57146 rp.cells = lcb.join("");
57147 lbuf[lbuf.length] = rt.apply(rp);
57148 rp.cells = cb.join("");
57149 buf[buf.length] = rt.apply(rp);
57151 return [lbuf.join(""), buf.join("")];
57154 renderBody : function(){
57155 var markup = this.renderRows();
57156 var bt = this.templates.body;
57157 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57161 * Refreshes the grid
57162 * @param {Boolean} headersToo
57164 refresh : function(headersToo){
57165 this.fireEvent("beforerefresh", this);
57166 this.grid.stopEditing();
57167 var result = this.renderBody();
57168 this.lockedBody.update(result[0]);
57169 this.mainBody.update(result[1]);
57170 if(headersToo === true){
57171 this.updateHeaders();
57172 this.updateColumns();
57173 this.updateSplitters();
57174 this.updateHeaderSortState();
57176 this.syncRowHeights();
57178 this.fireEvent("refresh", this);
57181 handleColumnMove : function(cm, oldIndex, newIndex){
57182 this.indexMap = null;
57183 var s = this.getScrollState();
57184 this.refresh(true);
57185 this.restoreScroll(s);
57186 this.afterMove(newIndex);
57189 afterMove : function(colIndex){
57190 if(this.enableMoveAnim && Roo.enableFx){
57191 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57193 // if multisort - fix sortOrder, and reload..
57194 if (this.grid.dataSource.multiSort) {
57195 // the we can call sort again..
57196 var dm = this.grid.dataSource;
57197 var cm = this.grid.colModel;
57199 for(var i = 0; i < cm.config.length; i++ ) {
57201 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57202 continue; // dont' bother, it's not in sort list or being set.
57205 so.push(cm.config[i].dataIndex);
57208 dm.load(dm.lastOptions);
57215 updateCell : function(dm, rowIndex, dataIndex){
57216 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57217 if(typeof colIndex == "undefined"){ // not present in grid
57220 var cm = this.grid.colModel;
57221 var cell = this.getCell(rowIndex, colIndex);
57222 var cellText = this.getCellText(rowIndex, colIndex);
57225 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57226 id : cm.getColumnId(colIndex),
57227 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57229 var renderer = cm.getRenderer(colIndex);
57230 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57231 if(typeof val == "undefined" || val === "") {
57234 cellText.innerHTML = val;
57235 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57236 this.syncRowHeights(rowIndex, rowIndex);
57239 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57241 if(this.grid.autoSizeHeaders){
57242 var h = this.getHeaderCellMeasure(colIndex);
57243 maxWidth = Math.max(maxWidth, h.scrollWidth);
57246 if(this.cm.isLocked(colIndex)){
57247 tb = this.getLockedTable();
57250 tb = this.getBodyTable();
57251 index = colIndex - this.cm.getLockedCount();
57254 var rows = tb.rows;
57255 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57256 for(var i = 0; i < stopIndex; i++){
57257 var cell = rows[i].childNodes[index].firstChild;
57258 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57261 return maxWidth + /*margin for error in IE*/ 5;
57264 * Autofit a column to its content.
57265 * @param {Number} colIndex
57266 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57268 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57269 if(this.cm.isHidden(colIndex)){
57270 return; // can't calc a hidden column
57273 var cid = this.cm.getColumnId(colIndex);
57274 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57275 if(this.grid.autoSizeHeaders){
57276 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57279 var newWidth = this.calcColumnWidth(colIndex);
57280 this.cm.setColumnWidth(colIndex,
57281 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57282 if(!suppressEvent){
57283 this.grid.fireEvent("columnresize", colIndex, newWidth);
57288 * Autofits all columns to their content and then expands to fit any extra space in the grid
57290 autoSizeColumns : function(){
57291 var cm = this.grid.colModel;
57292 var colCount = cm.getColumnCount();
57293 for(var i = 0; i < colCount; i++){
57294 this.autoSizeColumn(i, true, true);
57296 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57299 this.updateColumns();
57305 * Autofits all columns to the grid's width proportionate with their current size
57306 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57308 fitColumns : function(reserveScrollSpace){
57309 var cm = this.grid.colModel;
57310 var colCount = cm.getColumnCount();
57314 for (i = 0; i < colCount; i++){
57315 if(!cm.isHidden(i) && !cm.isFixed(i)){
57316 w = cm.getColumnWidth(i);
57322 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57323 if(reserveScrollSpace){
57326 var frac = (avail - cm.getTotalWidth())/width;
57327 while (cols.length){
57330 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57332 this.updateColumns();
57336 onRowSelect : function(rowIndex){
57337 var row = this.getRowComposite(rowIndex);
57338 row.addClass("x-grid-row-selected");
57341 onRowDeselect : function(rowIndex){
57342 var row = this.getRowComposite(rowIndex);
57343 row.removeClass("x-grid-row-selected");
57346 onCellSelect : function(row, col){
57347 var cell = this.getCell(row, col);
57349 Roo.fly(cell).addClass("x-grid-cell-selected");
57353 onCellDeselect : function(row, col){
57354 var cell = this.getCell(row, col);
57356 Roo.fly(cell).removeClass("x-grid-cell-selected");
57360 updateHeaderSortState : function(){
57362 // sort state can be single { field: xxx, direction : yyy}
57363 // or { xxx=>ASC , yyy : DESC ..... }
57366 if (!this.ds.multiSort) {
57367 var state = this.ds.getSortState();
57371 mstate[state.field] = state.direction;
57372 // FIXME... - this is not used here.. but might be elsewhere..
57373 this.sortState = state;
57376 mstate = this.ds.sortToggle;
57378 //remove existing sort classes..
57380 var sc = this.sortClasses;
57381 var hds = this.el.select(this.headerSelector).removeClass(sc);
57383 for(var f in mstate) {
57385 var sortColumn = this.cm.findColumnIndex(f);
57387 if(sortColumn != -1){
57388 var sortDir = mstate[f];
57389 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57398 handleHeaderClick : function(g, index,e){
57400 Roo.log("header click");
57403 // touch events on header are handled by context
57404 this.handleHdCtx(g,index,e);
57409 if(this.headersDisabled){
57412 var dm = g.dataSource, cm = g.colModel;
57413 if(!cm.isSortable(index)){
57418 if (dm.multiSort) {
57419 // update the sortOrder
57421 for(var i = 0; i < cm.config.length; i++ ) {
57423 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57424 continue; // dont' bother, it's not in sort list or being set.
57427 so.push(cm.config[i].dataIndex);
57433 dm.sort(cm.getDataIndex(index));
57437 destroy : function(){
57439 this.colMenu.removeAll();
57440 Roo.menu.MenuMgr.unregister(this.colMenu);
57441 this.colMenu.getEl().remove();
57442 delete this.colMenu;
57445 this.hmenu.removeAll();
57446 Roo.menu.MenuMgr.unregister(this.hmenu);
57447 this.hmenu.getEl().remove();
57450 if(this.grid.enableColumnMove){
57451 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57453 for(var dd in dds){
57454 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57455 var elid = dds[dd].dragElId;
57457 Roo.get(elid).remove();
57458 } else if(dds[dd].config.isTarget){
57459 dds[dd].proxyTop.remove();
57460 dds[dd].proxyBottom.remove();
57463 if(Roo.dd.DDM.locationCache[dd]){
57464 delete Roo.dd.DDM.locationCache[dd];
57467 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57470 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57471 this.bind(null, null);
57472 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57475 handleLockChange : function(){
57476 this.refresh(true);
57479 onDenyColumnLock : function(){
57483 onDenyColumnHide : function(){
57487 handleHdMenuClick : function(item){
57488 var index = this.hdCtxIndex;
57489 var cm = this.cm, ds = this.ds;
57492 ds.sort(cm.getDataIndex(index), "ASC");
57495 ds.sort(cm.getDataIndex(index), "DESC");
57498 var lc = cm.getLockedCount();
57499 if(cm.getColumnCount(true) <= lc+1){
57500 this.onDenyColumnLock();
57504 cm.setLocked(index, true, true);
57505 cm.moveColumn(index, lc);
57506 this.grid.fireEvent("columnmove", index, lc);
57508 cm.setLocked(index, true);
57512 var lc = cm.getLockedCount();
57513 if((lc-1) != index){
57514 cm.setLocked(index, false, true);
57515 cm.moveColumn(index, lc-1);
57516 this.grid.fireEvent("columnmove", index, lc-1);
57518 cm.setLocked(index, false);
57521 case 'wider': // used to expand cols on touch..
57523 var cw = cm.getColumnWidth(index);
57524 cw += (item.id == 'wider' ? 1 : -1) * 50;
57525 cw = Math.max(0, cw);
57526 cw = Math.min(cw,4000);
57527 cm.setColumnWidth(index, cw);
57531 index = cm.getIndexById(item.id.substr(4));
57533 if(item.checked && cm.getColumnCount(true) <= 1){
57534 this.onDenyColumnHide();
57537 cm.setHidden(index, item.checked);
57543 beforeColMenuShow : function(){
57544 var cm = this.cm, colCount = cm.getColumnCount();
57545 this.colMenu.removeAll();
57546 for(var i = 0; i < colCount; i++){
57547 this.colMenu.add(new Roo.menu.CheckItem({
57548 id: "col-"+cm.getColumnId(i),
57549 text: cm.getColumnHeader(i),
57550 checked: !cm.isHidden(i),
57556 handleHdCtx : function(g, index, e){
57558 var hd = this.getHeaderCell(index);
57559 this.hdCtxIndex = index;
57560 var ms = this.hmenu.items, cm = this.cm;
57561 ms.get("asc").setDisabled(!cm.isSortable(index));
57562 ms.get("desc").setDisabled(!cm.isSortable(index));
57563 if(this.grid.enableColLock !== false){
57564 ms.get("lock").setDisabled(cm.isLocked(index));
57565 ms.get("unlock").setDisabled(!cm.isLocked(index));
57567 this.hmenu.show(hd, "tl-bl");
57570 handleHdOver : function(e){
57571 var hd = this.findHeaderCell(e.getTarget());
57572 if(hd && !this.headersDisabled){
57573 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57574 this.fly(hd).addClass("x-grid-hd-over");
57579 handleHdOut : function(e){
57580 var hd = this.findHeaderCell(e.getTarget());
57582 this.fly(hd).removeClass("x-grid-hd-over");
57586 handleSplitDblClick : function(e, t){
57587 var i = this.getCellIndex(t);
57588 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57589 this.autoSizeColumn(i, true);
57594 render : function(){
57597 var colCount = cm.getColumnCount();
57599 if(this.grid.monitorWindowResize === true){
57600 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57602 var header = this.renderHeaders();
57603 var body = this.templates.body.apply({rows:""});
57604 var html = this.templates.master.apply({
57607 lockedHeader: header[0],
57611 //this.updateColumns();
57613 this.grid.getGridEl().dom.innerHTML = html;
57615 this.initElements();
57617 // a kludge to fix the random scolling effect in webkit
57618 this.el.on("scroll", function() {
57619 this.el.dom.scrollTop=0; // hopefully not recursive..
57622 this.scroller.on("scroll", this.handleScroll, this);
57623 this.lockedBody.on("mousewheel", this.handleWheel, this);
57624 this.mainBody.on("mousewheel", this.handleWheel, this);
57626 this.mainHd.on("mouseover", this.handleHdOver, this);
57627 this.mainHd.on("mouseout", this.handleHdOut, this);
57628 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57629 {delegate: "."+this.splitClass});
57631 this.lockedHd.on("mouseover", this.handleHdOver, this);
57632 this.lockedHd.on("mouseout", this.handleHdOut, this);
57633 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57634 {delegate: "."+this.splitClass});
57636 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57637 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57640 this.updateSplitters();
57642 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57643 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57644 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57647 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57648 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57650 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57651 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57653 if(this.grid.enableColLock !== false){
57654 this.hmenu.add('-',
57655 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57656 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57660 this.hmenu.add('-',
57661 {id:"wider", text: this.columnsWiderText},
57662 {id:"narrow", text: this.columnsNarrowText }
57668 if(this.grid.enableColumnHide !== false){
57670 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57671 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57672 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57674 this.hmenu.add('-',
57675 {id:"columns", text: this.columnsText, menu: this.colMenu}
57678 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57680 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57683 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57684 this.dd = new Roo.grid.GridDragZone(this.grid, {
57685 ddGroup : this.grid.ddGroup || 'GridDD'
57691 for(var i = 0; i < colCount; i++){
57692 if(cm.isHidden(i)){
57693 this.hideColumn(i);
57695 if(cm.config[i].align){
57696 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57697 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57701 this.updateHeaderSortState();
57703 this.beforeInitialResize();
57706 // two part rendering gives faster view to the user
57707 this.renderPhase2.defer(1, this);
57710 renderPhase2 : function(){
57711 // render the rows now
57713 if(this.grid.autoSizeColumns){
57714 this.autoSizeColumns();
57718 beforeInitialResize : function(){
57722 onColumnSplitterMoved : function(i, w){
57723 this.userResized = true;
57724 var cm = this.grid.colModel;
57725 cm.setColumnWidth(i, w, true);
57726 var cid = cm.getColumnId(i);
57727 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57728 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57729 this.updateSplitters();
57731 this.grid.fireEvent("columnresize", i, w);
57734 syncRowHeights : function(startIndex, endIndex){
57735 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
57736 startIndex = startIndex || 0;
57737 var mrows = this.getBodyTable().rows;
57738 var lrows = this.getLockedTable().rows;
57739 var len = mrows.length-1;
57740 endIndex = Math.min(endIndex || len, len);
57741 for(var i = startIndex; i <= endIndex; i++){
57742 var m = mrows[i], l = lrows[i];
57743 var h = Math.max(m.offsetHeight, l.offsetHeight);
57744 m.style.height = l.style.height = h + "px";
57749 layout : function(initialRender, is2ndPass){
57751 var auto = g.autoHeight;
57752 var scrollOffset = 16;
57753 var c = g.getGridEl(), cm = this.cm,
57754 expandCol = g.autoExpandColumn,
57756 //c.beginMeasure();
57758 if(!c.dom.offsetWidth){ // display:none?
57760 this.lockedWrap.show();
57761 this.mainWrap.show();
57766 var hasLock = this.cm.isLocked(0);
57768 var tbh = this.headerPanel.getHeight();
57769 var bbh = this.footerPanel.getHeight();
57772 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
57773 var newHeight = ch + c.getBorderWidth("tb");
57775 newHeight = Math.min(g.maxHeight, newHeight);
57777 c.setHeight(newHeight);
57781 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
57784 var s = this.scroller;
57786 var csize = c.getSize(true);
57788 this.el.setSize(csize.width, csize.height);
57790 this.headerPanel.setWidth(csize.width);
57791 this.footerPanel.setWidth(csize.width);
57793 var hdHeight = this.mainHd.getHeight();
57794 var vw = csize.width;
57795 var vh = csize.height - (tbh + bbh);
57799 var bt = this.getBodyTable();
57801 if(cm.getLockedCount() == cm.config.length){
57802 bt = this.getLockedTable();
57805 var ltWidth = hasLock ?
57806 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
57808 var scrollHeight = bt.offsetHeight;
57809 var scrollWidth = ltWidth + bt.offsetWidth;
57810 var vscroll = false, hscroll = false;
57812 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
57814 var lw = this.lockedWrap, mw = this.mainWrap;
57815 var lb = this.lockedBody, mb = this.mainBody;
57817 setTimeout(function(){
57818 var t = s.dom.offsetTop;
57819 var w = s.dom.clientWidth,
57820 h = s.dom.clientHeight;
57823 lw.setSize(ltWidth, h);
57825 mw.setLeftTop(ltWidth, t);
57826 mw.setSize(w-ltWidth, h);
57828 lb.setHeight(h-hdHeight);
57829 mb.setHeight(h-hdHeight);
57831 if(is2ndPass !== true && !gv.userResized && expandCol){
57832 // high speed resize without full column calculation
57834 var ci = cm.getIndexById(expandCol);
57836 ci = cm.findColumnIndex(expandCol);
57838 ci = Math.max(0, ci); // make sure it's got at least the first col.
57839 var expandId = cm.getColumnId(ci);
57840 var tw = cm.getTotalWidth(false);
57841 var currentWidth = cm.getColumnWidth(ci);
57842 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
57843 if(currentWidth != cw){
57844 cm.setColumnWidth(ci, cw, true);
57845 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57846 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57847 gv.updateSplitters();
57848 gv.layout(false, true);
57860 onWindowResize : function(){
57861 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
57867 appendFooter : function(parentEl){
57871 sortAscText : "Sort Ascending",
57872 sortDescText : "Sort Descending",
57873 lockText : "Lock Column",
57874 unlockText : "Unlock Column",
57875 columnsText : "Columns",
57877 columnsWiderText : "Wider",
57878 columnsNarrowText : "Thinner"
57882 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
57883 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
57884 this.proxy.el.addClass('x-grid3-col-dd');
57887 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
57888 handleMouseDown : function(e){
57892 callHandleMouseDown : function(e){
57893 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
57898 * Ext JS Library 1.1.1
57899 * Copyright(c) 2006-2007, Ext JS, LLC.
57901 * Originally Released Under LGPL - original licence link has changed is not relivant.
57904 * <script type="text/javascript">
57908 // This is a support class used internally by the Grid components
57909 Roo.grid.SplitDragZone = function(grid, hd, hd2){
57911 this.view = grid.getView();
57912 this.proxy = this.view.resizeProxy;
57913 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
57914 "gridSplitters" + this.grid.getGridEl().id, {
57915 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
57917 this.setHandleElId(Roo.id(hd));
57918 this.setOuterHandleElId(Roo.id(hd2));
57919 this.scroll = false;
57921 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
57922 fly: Roo.Element.fly,
57924 b4StartDrag : function(x, y){
57925 this.view.headersDisabled = true;
57926 this.proxy.setHeight(this.view.mainWrap.getHeight());
57927 var w = this.cm.getColumnWidth(this.cellIndex);
57928 var minw = Math.max(w-this.grid.minColumnWidth, 0);
57929 this.resetConstraints();
57930 this.setXConstraint(minw, 1000);
57931 this.setYConstraint(0, 0);
57932 this.minX = x - minw;
57933 this.maxX = x + 1000;
57935 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
57939 handleMouseDown : function(e){
57940 ev = Roo.EventObject.setEvent(e);
57941 var t = this.fly(ev.getTarget());
57942 if(t.hasClass("x-grid-split")){
57943 this.cellIndex = this.view.getCellIndex(t.dom);
57944 this.split = t.dom;
57945 this.cm = this.grid.colModel;
57946 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
57947 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
57952 endDrag : function(e){
57953 this.view.headersDisabled = false;
57954 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
57955 var diff = endX - this.startPos;
57956 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
57959 autoOffset : function(){
57960 this.setDelta(0,0);
57964 * Ext JS Library 1.1.1
57965 * Copyright(c) 2006-2007, Ext JS, LLC.
57967 * Originally Released Under LGPL - original licence link has changed is not relivant.
57970 * <script type="text/javascript">
57974 // This is a support class used internally by the Grid components
57975 Roo.grid.GridDragZone = function(grid, config){
57976 this.view = grid.getView();
57977 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
57978 if(this.view.lockedBody){
57979 this.setHandleElId(Roo.id(this.view.mainBody.dom));
57980 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
57982 this.scroll = false;
57984 this.ddel = document.createElement('div');
57985 this.ddel.className = 'x-grid-dd-wrap';
57988 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
57989 ddGroup : "GridDD",
57991 getDragData : function(e){
57992 var t = Roo.lib.Event.getTarget(e);
57993 var rowIndex = this.view.findRowIndex(t);
57994 var sm = this.grid.selModel;
57996 //Roo.log(rowIndex);
57998 if (sm.getSelectedCell) {
57999 // cell selection..
58000 if (!sm.getSelectedCell()) {
58003 if (rowIndex != sm.getSelectedCell()[0]) {
58009 if(rowIndex !== false){
58014 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58016 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58019 if (e.hasModifier()){
58020 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58023 Roo.log("getDragData");
58028 rowIndex: rowIndex,
58029 selections:sm.getSelections ? sm.getSelections() : (
58030 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
58037 onInitDrag : function(e){
58038 var data = this.dragData;
58039 this.ddel.innerHTML = this.grid.getDragDropText();
58040 this.proxy.update(this.ddel);
58041 // fire start drag?
58044 afterRepair : function(){
58045 this.dragging = false;
58048 getRepairXY : function(e, data){
58052 onEndDrag : function(data, e){
58056 onValidDrop : function(dd, e, id){
58061 beforeInvalidDrop : function(e, id){
58066 * Ext JS Library 1.1.1
58067 * Copyright(c) 2006-2007, Ext JS, LLC.
58069 * Originally Released Under LGPL - original licence link has changed is not relivant.
58072 * <script type="text/javascript">
58077 * @class Roo.grid.ColumnModel
58078 * @extends Roo.util.Observable
58079 * This is the default implementation of a ColumnModel used by the Grid. It defines
58080 * the columns in the grid.
58083 var colModel = new Roo.grid.ColumnModel([
58084 {header: "Ticker", width: 60, sortable: true, locked: true},
58085 {header: "Company Name", width: 150, sortable: true},
58086 {header: "Market Cap.", width: 100, sortable: true},
58087 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58088 {header: "Employees", width: 100, sortable: true, resizable: false}
58093 * The config options listed for this class are options which may appear in each
58094 * individual column definition.
58095 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58097 * @param {Object} config An Array of column config objects. See this class's
58098 * config objects for details.
58100 Roo.grid.ColumnModel = function(config){
58102 * The config passed into the constructor
58104 this.config = config;
58107 // if no id, create one
58108 // if the column does not have a dataIndex mapping,
58109 // map it to the order it is in the config
58110 for(var i = 0, len = config.length; i < len; i++){
58112 if(typeof c.dataIndex == "undefined"){
58115 if(typeof c.renderer == "string"){
58116 c.renderer = Roo.util.Format[c.renderer];
58118 if(typeof c.id == "undefined"){
58121 if(c.editor && c.editor.xtype){
58122 c.editor = Roo.factory(c.editor, Roo.grid);
58124 if(c.editor && c.editor.isFormField){
58125 c.editor = new Roo.grid.GridEditor(c.editor);
58127 this.lookup[c.id] = c;
58131 * The width of columns which have no width specified (defaults to 100)
58134 this.defaultWidth = 100;
58137 * Default sortable of columns which have no sortable specified (defaults to false)
58140 this.defaultSortable = false;
58144 * @event widthchange
58145 * Fires when the width of a column changes.
58146 * @param {ColumnModel} this
58147 * @param {Number} columnIndex The column index
58148 * @param {Number} newWidth The new width
58150 "widthchange": true,
58152 * @event headerchange
58153 * Fires when the text of a header changes.
58154 * @param {ColumnModel} this
58155 * @param {Number} columnIndex The column index
58156 * @param {Number} newText The new header text
58158 "headerchange": true,
58160 * @event hiddenchange
58161 * Fires when a column is hidden or "unhidden".
58162 * @param {ColumnModel} this
58163 * @param {Number} columnIndex The column index
58164 * @param {Boolean} hidden true if hidden, false otherwise
58166 "hiddenchange": true,
58168 * @event columnmoved
58169 * Fires when a column is moved.
58170 * @param {ColumnModel} this
58171 * @param {Number} oldIndex
58172 * @param {Number} newIndex
58174 "columnmoved" : true,
58176 * @event columlockchange
58177 * Fires when a column's locked state is changed
58178 * @param {ColumnModel} this
58179 * @param {Number} colIndex
58180 * @param {Boolean} locked true if locked
58182 "columnlockchange" : true
58184 Roo.grid.ColumnModel.superclass.constructor.call(this);
58186 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58188 * @cfg {String} header The header text to display in the Grid view.
58191 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58192 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58193 * specified, the column's index is used as an index into the Record's data Array.
58196 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58197 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58200 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58201 * Defaults to the value of the {@link #defaultSortable} property.
58202 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58205 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58208 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58211 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58214 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58217 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58218 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58219 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58220 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58223 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58226 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58229 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58232 * @cfg {String} cursor (Optional)
58235 * @cfg {String} tooltip (Optional)
58238 * @cfg {Number} xs (Optional)
58241 * @cfg {Number} sm (Optional)
58244 * @cfg {Number} md (Optional)
58247 * @cfg {Number} lg (Optional)
58250 * Returns the id of the column at the specified index.
58251 * @param {Number} index The column index
58252 * @return {String} the id
58254 getColumnId : function(index){
58255 return this.config[index].id;
58259 * Returns the column for a specified id.
58260 * @param {String} id The column id
58261 * @return {Object} the column
58263 getColumnById : function(id){
58264 return this.lookup[id];
58269 * Returns the column for a specified dataIndex.
58270 * @param {String} dataIndex The column dataIndex
58271 * @return {Object|Boolean} the column or false if not found
58273 getColumnByDataIndex: function(dataIndex){
58274 var index = this.findColumnIndex(dataIndex);
58275 return index > -1 ? this.config[index] : false;
58279 * Returns the index for a specified column id.
58280 * @param {String} id The column id
58281 * @return {Number} the index, or -1 if not found
58283 getIndexById : function(id){
58284 for(var i = 0, len = this.config.length; i < len; i++){
58285 if(this.config[i].id == id){
58293 * Returns the index for a specified column dataIndex.
58294 * @param {String} dataIndex The column dataIndex
58295 * @return {Number} the index, or -1 if not found
58298 findColumnIndex : function(dataIndex){
58299 for(var i = 0, len = this.config.length; i < len; i++){
58300 if(this.config[i].dataIndex == dataIndex){
58308 moveColumn : function(oldIndex, newIndex){
58309 var c = this.config[oldIndex];
58310 this.config.splice(oldIndex, 1);
58311 this.config.splice(newIndex, 0, c);
58312 this.dataMap = null;
58313 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58316 isLocked : function(colIndex){
58317 return this.config[colIndex].locked === true;
58320 setLocked : function(colIndex, value, suppressEvent){
58321 if(this.isLocked(colIndex) == value){
58324 this.config[colIndex].locked = value;
58325 if(!suppressEvent){
58326 this.fireEvent("columnlockchange", this, colIndex, value);
58330 getTotalLockedWidth : function(){
58331 var totalWidth = 0;
58332 for(var i = 0; i < this.config.length; i++){
58333 if(this.isLocked(i) && !this.isHidden(i)){
58334 this.totalWidth += this.getColumnWidth(i);
58340 getLockedCount : function(){
58341 for(var i = 0, len = this.config.length; i < len; i++){
58342 if(!this.isLocked(i)){
58347 return this.config.length;
58351 * Returns the number of columns.
58354 getColumnCount : function(visibleOnly){
58355 if(visibleOnly === true){
58357 for(var i = 0, len = this.config.length; i < len; i++){
58358 if(!this.isHidden(i)){
58364 return this.config.length;
58368 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58369 * @param {Function} fn
58370 * @param {Object} scope (optional)
58371 * @return {Array} result
58373 getColumnsBy : function(fn, scope){
58375 for(var i = 0, len = this.config.length; i < len; i++){
58376 var c = this.config[i];
58377 if(fn.call(scope||this, c, i) === true){
58385 * Returns true if the specified column is sortable.
58386 * @param {Number} col The column index
58387 * @return {Boolean}
58389 isSortable : function(col){
58390 if(typeof this.config[col].sortable == "undefined"){
58391 return this.defaultSortable;
58393 return this.config[col].sortable;
58397 * Returns the rendering (formatting) function defined for the column.
58398 * @param {Number} col The column index.
58399 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58401 getRenderer : function(col){
58402 if(!this.config[col].renderer){
58403 return Roo.grid.ColumnModel.defaultRenderer;
58405 return this.config[col].renderer;
58409 * Sets the rendering (formatting) function for a column.
58410 * @param {Number} col The column index
58411 * @param {Function} fn The function to use to process the cell's raw data
58412 * to return HTML markup for the grid view. The render function is called with
58413 * the following parameters:<ul>
58414 * <li>Data value.</li>
58415 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58416 * <li>css A CSS style string to apply to the table cell.</li>
58417 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58418 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58419 * <li>Row index</li>
58420 * <li>Column index</li>
58421 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58423 setRenderer : function(col, fn){
58424 this.config[col].renderer = fn;
58428 * Returns the width for the specified column.
58429 * @param {Number} col The column index
58432 getColumnWidth : function(col){
58433 return this.config[col].width * 1 || this.defaultWidth;
58437 * Sets the width for a column.
58438 * @param {Number} col The column index
58439 * @param {Number} width The new width
58441 setColumnWidth : function(col, width, suppressEvent){
58442 this.config[col].width = width;
58443 this.totalWidth = null;
58444 if(!suppressEvent){
58445 this.fireEvent("widthchange", this, col, width);
58450 * Returns the total width of all columns.
58451 * @param {Boolean} includeHidden True to include hidden column widths
58454 getTotalWidth : function(includeHidden){
58455 if(!this.totalWidth){
58456 this.totalWidth = 0;
58457 for(var i = 0, len = this.config.length; i < len; i++){
58458 if(includeHidden || !this.isHidden(i)){
58459 this.totalWidth += this.getColumnWidth(i);
58463 return this.totalWidth;
58467 * Returns the header for the specified column.
58468 * @param {Number} col The column index
58471 getColumnHeader : function(col){
58472 return this.config[col].header;
58476 * Sets the header for a column.
58477 * @param {Number} col The column index
58478 * @param {String} header The new header
58480 setColumnHeader : function(col, header){
58481 this.config[col].header = header;
58482 this.fireEvent("headerchange", this, col, header);
58486 * Returns the tooltip for the specified column.
58487 * @param {Number} col The column index
58490 getColumnTooltip : function(col){
58491 return this.config[col].tooltip;
58494 * Sets the tooltip for a column.
58495 * @param {Number} col The column index
58496 * @param {String} tooltip The new tooltip
58498 setColumnTooltip : function(col, tooltip){
58499 this.config[col].tooltip = tooltip;
58503 * Returns the dataIndex for the specified column.
58504 * @param {Number} col The column index
58507 getDataIndex : function(col){
58508 return this.config[col].dataIndex;
58512 * Sets the dataIndex for a column.
58513 * @param {Number} col The column index
58514 * @param {Number} dataIndex The new dataIndex
58516 setDataIndex : function(col, dataIndex){
58517 this.config[col].dataIndex = dataIndex;
58523 * Returns true if the cell is editable.
58524 * @param {Number} colIndex The column index
58525 * @param {Number} rowIndex The row index - this is nto actually used..?
58526 * @return {Boolean}
58528 isCellEditable : function(colIndex, rowIndex){
58529 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58533 * Returns the editor defined for the cell/column.
58534 * return false or null to disable editing.
58535 * @param {Number} colIndex The column index
58536 * @param {Number} rowIndex The row index
58539 getCellEditor : function(colIndex, rowIndex){
58540 return this.config[colIndex].editor;
58544 * Sets if a column is editable.
58545 * @param {Number} col The column index
58546 * @param {Boolean} editable True if the column is editable
58548 setEditable : function(col, editable){
58549 this.config[col].editable = editable;
58554 * Returns true if the column is hidden.
58555 * @param {Number} colIndex The column index
58556 * @return {Boolean}
58558 isHidden : function(colIndex){
58559 return this.config[colIndex].hidden;
58564 * Returns true if the column width cannot be changed
58566 isFixed : function(colIndex){
58567 return this.config[colIndex].fixed;
58571 * Returns true if the column can be resized
58572 * @return {Boolean}
58574 isResizable : function(colIndex){
58575 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58578 * Sets if a column is hidden.
58579 * @param {Number} colIndex The column index
58580 * @param {Boolean} hidden True if the column is hidden
58582 setHidden : function(colIndex, hidden){
58583 this.config[colIndex].hidden = hidden;
58584 this.totalWidth = null;
58585 this.fireEvent("hiddenchange", this, colIndex, hidden);
58589 * Sets the editor for a column.
58590 * @param {Number} col The column index
58591 * @param {Object} editor The editor object
58593 setEditor : function(col, editor){
58594 this.config[col].editor = editor;
58598 Roo.grid.ColumnModel.defaultRenderer = function(value)
58600 if(typeof value == "object") {
58603 if(typeof value == "string" && value.length < 1){
58607 return String.format("{0}", value);
58610 // Alias for backwards compatibility
58611 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
58614 * Ext JS Library 1.1.1
58615 * Copyright(c) 2006-2007, Ext JS, LLC.
58617 * Originally Released Under LGPL - original licence link has changed is not relivant.
58620 * <script type="text/javascript">
58624 * @class Roo.grid.AbstractSelectionModel
58625 * @extends Roo.util.Observable
58626 * Abstract base class for grid SelectionModels. It provides the interface that should be
58627 * implemented by descendant classes. This class should not be directly instantiated.
58630 Roo.grid.AbstractSelectionModel = function(){
58631 this.locked = false;
58632 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
58635 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
58636 /** @ignore Called by the grid automatically. Do not call directly. */
58637 init : function(grid){
58643 * Locks the selections.
58646 this.locked = true;
58650 * Unlocks the selections.
58652 unlock : function(){
58653 this.locked = false;
58657 * Returns true if the selections are locked.
58658 * @return {Boolean}
58660 isLocked : function(){
58661 return this.locked;
58665 * Ext JS Library 1.1.1
58666 * Copyright(c) 2006-2007, Ext JS, LLC.
58668 * Originally Released Under LGPL - original licence link has changed is not relivant.
58671 * <script type="text/javascript">
58674 * @extends Roo.grid.AbstractSelectionModel
58675 * @class Roo.grid.RowSelectionModel
58676 * The default SelectionModel used by {@link Roo.grid.Grid}.
58677 * It supports multiple selections and keyboard selection/navigation.
58679 * @param {Object} config
58681 Roo.grid.RowSelectionModel = function(config){
58682 Roo.apply(this, config);
58683 this.selections = new Roo.util.MixedCollection(false, function(o){
58688 this.lastActive = false;
58692 * @event selectionchange
58693 * Fires when the selection changes
58694 * @param {SelectionModel} this
58696 "selectionchange" : true,
58698 * @event afterselectionchange
58699 * Fires after the selection changes (eg. by key press or clicking)
58700 * @param {SelectionModel} this
58702 "afterselectionchange" : true,
58704 * @event beforerowselect
58705 * Fires when a row is selected being selected, return false to cancel.
58706 * @param {SelectionModel} this
58707 * @param {Number} rowIndex The selected index
58708 * @param {Boolean} keepExisting False if other selections will be cleared
58710 "beforerowselect" : true,
58713 * Fires when a row is selected.
58714 * @param {SelectionModel} this
58715 * @param {Number} rowIndex The selected index
58716 * @param {Roo.data.Record} r The record
58718 "rowselect" : true,
58720 * @event rowdeselect
58721 * Fires when a row is deselected.
58722 * @param {SelectionModel} this
58723 * @param {Number} rowIndex The selected index
58725 "rowdeselect" : true
58727 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
58728 this.locked = false;
58731 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
58733 * @cfg {Boolean} singleSelect
58734 * True to allow selection of only one row at a time (defaults to false)
58736 singleSelect : false,
58739 initEvents : function(){
58741 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
58742 this.grid.on("mousedown", this.handleMouseDown, this);
58743 }else{ // allow click to work like normal
58744 this.grid.on("rowclick", this.handleDragableRowClick, this);
58747 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
58748 "up" : function(e){
58750 this.selectPrevious(e.shiftKey);
58751 }else if(this.last !== false && this.lastActive !== false){
58752 var last = this.last;
58753 this.selectRange(this.last, this.lastActive-1);
58754 this.grid.getView().focusRow(this.lastActive);
58755 if(last !== false){
58759 this.selectFirstRow();
58761 this.fireEvent("afterselectionchange", this);
58763 "down" : function(e){
58765 this.selectNext(e.shiftKey);
58766 }else if(this.last !== false && this.lastActive !== false){
58767 var last = this.last;
58768 this.selectRange(this.last, this.lastActive+1);
58769 this.grid.getView().focusRow(this.lastActive);
58770 if(last !== false){
58774 this.selectFirstRow();
58776 this.fireEvent("afterselectionchange", this);
58781 var view = this.grid.view;
58782 view.on("refresh", this.onRefresh, this);
58783 view.on("rowupdated", this.onRowUpdated, this);
58784 view.on("rowremoved", this.onRemove, this);
58788 onRefresh : function(){
58789 var ds = this.grid.dataSource, i, v = this.grid.view;
58790 var s = this.selections;
58791 s.each(function(r){
58792 if((i = ds.indexOfId(r.id)) != -1){
58794 s.add(ds.getAt(i)); // updating the selection relate data
58802 onRemove : function(v, index, r){
58803 this.selections.remove(r);
58807 onRowUpdated : function(v, index, r){
58808 if(this.isSelected(r)){
58809 v.onRowSelect(index);
58815 * @param {Array} records The records to select
58816 * @param {Boolean} keepExisting (optional) True to keep existing selections
58818 selectRecords : function(records, keepExisting){
58820 this.clearSelections();
58822 var ds = this.grid.dataSource;
58823 for(var i = 0, len = records.length; i < len; i++){
58824 this.selectRow(ds.indexOf(records[i]), true);
58829 * Gets the number of selected rows.
58832 getCount : function(){
58833 return this.selections.length;
58837 * Selects the first row in the grid.
58839 selectFirstRow : function(){
58844 * Select the last row.
58845 * @param {Boolean} keepExisting (optional) True to keep existing selections
58847 selectLastRow : function(keepExisting){
58848 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
58852 * Selects the row immediately following the last selected row.
58853 * @param {Boolean} keepExisting (optional) True to keep existing selections
58855 selectNext : function(keepExisting){
58856 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
58857 this.selectRow(this.last+1, keepExisting);
58858 this.grid.getView().focusRow(this.last);
58863 * Selects the row that precedes the last selected row.
58864 * @param {Boolean} keepExisting (optional) True to keep existing selections
58866 selectPrevious : function(keepExisting){
58868 this.selectRow(this.last-1, keepExisting);
58869 this.grid.getView().focusRow(this.last);
58874 * Returns the selected records
58875 * @return {Array} Array of selected records
58877 getSelections : function(){
58878 return [].concat(this.selections.items);
58882 * Returns the first selected record.
58885 getSelected : function(){
58886 return this.selections.itemAt(0);
58891 * Clears all selections.
58893 clearSelections : function(fast){
58898 var ds = this.grid.dataSource;
58899 var s = this.selections;
58900 s.each(function(r){
58901 this.deselectRow(ds.indexOfId(r.id));
58905 this.selections.clear();
58912 * Selects all rows.
58914 selectAll : function(){
58918 this.selections.clear();
58919 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
58920 this.selectRow(i, true);
58925 * Returns True if there is a selection.
58926 * @return {Boolean}
58928 hasSelection : function(){
58929 return this.selections.length > 0;
58933 * Returns True if the specified row is selected.
58934 * @param {Number/Record} record The record or index of the record to check
58935 * @return {Boolean}
58937 isSelected : function(index){
58938 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
58939 return (r && this.selections.key(r.id) ? true : false);
58943 * Returns True if the specified record id is selected.
58944 * @param {String} id The id of record to check
58945 * @return {Boolean}
58947 isIdSelected : function(id){
58948 return (this.selections.key(id) ? true : false);
58952 handleMouseDown : function(e, t){
58953 var view = this.grid.getView(), rowIndex;
58954 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
58957 if(e.shiftKey && this.last !== false){
58958 var last = this.last;
58959 this.selectRange(last, rowIndex, e.ctrlKey);
58960 this.last = last; // reset the last
58961 view.focusRow(rowIndex);
58963 var isSelected = this.isSelected(rowIndex);
58964 if(e.button !== 0 && isSelected){
58965 view.focusRow(rowIndex);
58966 }else if(e.ctrlKey && isSelected){
58967 this.deselectRow(rowIndex);
58968 }else if(!isSelected){
58969 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
58970 view.focusRow(rowIndex);
58973 this.fireEvent("afterselectionchange", this);
58976 handleDragableRowClick : function(grid, rowIndex, e)
58978 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
58979 this.selectRow(rowIndex, false);
58980 grid.view.focusRow(rowIndex);
58981 this.fireEvent("afterselectionchange", this);
58986 * Selects multiple rows.
58987 * @param {Array} rows Array of the indexes of the row to select
58988 * @param {Boolean} keepExisting (optional) True to keep existing selections
58990 selectRows : function(rows, keepExisting){
58992 this.clearSelections();
58994 for(var i = 0, len = rows.length; i < len; i++){
58995 this.selectRow(rows[i], true);
59000 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59001 * @param {Number} startRow The index of the first row in the range
59002 * @param {Number} endRow The index of the last row in the range
59003 * @param {Boolean} keepExisting (optional) True to retain existing selections
59005 selectRange : function(startRow, endRow, keepExisting){
59010 this.clearSelections();
59012 if(startRow <= endRow){
59013 for(var i = startRow; i <= endRow; i++){
59014 this.selectRow(i, true);
59017 for(var i = startRow; i >= endRow; i--){
59018 this.selectRow(i, true);
59024 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59025 * @param {Number} startRow The index of the first row in the range
59026 * @param {Number} endRow The index of the last row in the range
59028 deselectRange : function(startRow, endRow, preventViewNotify){
59032 for(var i = startRow; i <= endRow; i++){
59033 this.deselectRow(i, preventViewNotify);
59039 * @param {Number} row The index of the row to select
59040 * @param {Boolean} keepExisting (optional) True to keep existing selections
59042 selectRow : function(index, keepExisting, preventViewNotify){
59043 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
59046 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59047 if(!keepExisting || this.singleSelect){
59048 this.clearSelections();
59050 var r = this.grid.dataSource.getAt(index);
59051 this.selections.add(r);
59052 this.last = this.lastActive = index;
59053 if(!preventViewNotify){
59054 this.grid.getView().onRowSelect(index);
59056 this.fireEvent("rowselect", this, index, r);
59057 this.fireEvent("selectionchange", this);
59063 * @param {Number} row The index of the row to deselect
59065 deselectRow : function(index, preventViewNotify){
59069 if(this.last == index){
59072 if(this.lastActive == index){
59073 this.lastActive = false;
59075 var r = this.grid.dataSource.getAt(index);
59076 this.selections.remove(r);
59077 if(!preventViewNotify){
59078 this.grid.getView().onRowDeselect(index);
59080 this.fireEvent("rowdeselect", this, index);
59081 this.fireEvent("selectionchange", this);
59085 restoreLast : function(){
59087 this.last = this._last;
59092 acceptsNav : function(row, col, cm){
59093 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59097 onEditorKey : function(field, e){
59098 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59103 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59105 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59107 }else if(k == e.ENTER && !e.ctrlKey){
59111 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59113 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59115 }else if(k == e.ESC){
59119 g.startEditing(newCell[0], newCell[1]);
59124 * Ext JS Library 1.1.1
59125 * Copyright(c) 2006-2007, Ext JS, LLC.
59127 * Originally Released Under LGPL - original licence link has changed is not relivant.
59130 * <script type="text/javascript">
59133 * @class Roo.grid.CellSelectionModel
59134 * @extends Roo.grid.AbstractSelectionModel
59135 * This class provides the basic implementation for cell selection in a grid.
59137 * @param {Object} config The object containing the configuration of this model.
59138 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59140 Roo.grid.CellSelectionModel = function(config){
59141 Roo.apply(this, config);
59143 this.selection = null;
59147 * @event beforerowselect
59148 * Fires before a cell is selected.
59149 * @param {SelectionModel} this
59150 * @param {Number} rowIndex The selected row index
59151 * @param {Number} colIndex The selected cell index
59153 "beforecellselect" : true,
59155 * @event cellselect
59156 * Fires when a cell is selected.
59157 * @param {SelectionModel} this
59158 * @param {Number} rowIndex The selected row index
59159 * @param {Number} colIndex The selected cell index
59161 "cellselect" : true,
59163 * @event selectionchange
59164 * Fires when the active selection changes.
59165 * @param {SelectionModel} this
59166 * @param {Object} selection null for no selection or an object (o) with two properties
59168 <li>o.record: the record object for the row the selection is in</li>
59169 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59172 "selectionchange" : true,
59175 * Fires when the tab (or enter) was pressed on the last editable cell
59176 * You can use this to trigger add new row.
59177 * @param {SelectionModel} this
59181 * @event beforeeditnext
59182 * Fires before the next editable sell is made active
59183 * You can use this to skip to another cell or fire the tabend
59184 * if you set cell to false
59185 * @param {Object} eventdata object : { cell : [ row, col ] }
59187 "beforeeditnext" : true
59189 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59192 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59194 enter_is_tab: false,
59197 initEvents : function(){
59198 this.grid.on("mousedown", this.handleMouseDown, this);
59199 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59200 var view = this.grid.view;
59201 view.on("refresh", this.onViewChange, this);
59202 view.on("rowupdated", this.onRowUpdated, this);
59203 view.on("beforerowremoved", this.clearSelections, this);
59204 view.on("beforerowsinserted", this.clearSelections, this);
59205 if(this.grid.isEditor){
59206 this.grid.on("beforeedit", this.beforeEdit, this);
59211 beforeEdit : function(e){
59212 this.select(e.row, e.column, false, true, e.record);
59216 onRowUpdated : function(v, index, r){
59217 if(this.selection && this.selection.record == r){
59218 v.onCellSelect(index, this.selection.cell[1]);
59223 onViewChange : function(){
59224 this.clearSelections(true);
59228 * Returns the currently selected cell,.
59229 * @return {Array} The selected cell (row, column) or null if none selected.
59231 getSelectedCell : function(){
59232 return this.selection ? this.selection.cell : null;
59236 * Clears all selections.
59237 * @param {Boolean} true to prevent the gridview from being notified about the change.
59239 clearSelections : function(preventNotify){
59240 var s = this.selection;
59242 if(preventNotify !== true){
59243 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59245 this.selection = null;
59246 this.fireEvent("selectionchange", this, null);
59251 * Returns true if there is a selection.
59252 * @return {Boolean}
59254 hasSelection : function(){
59255 return this.selection ? true : false;
59259 handleMouseDown : function(e, t){
59260 var v = this.grid.getView();
59261 if(this.isLocked()){
59264 var row = v.findRowIndex(t);
59265 var cell = v.findCellIndex(t);
59266 if(row !== false && cell !== false){
59267 this.select(row, cell);
59273 * @param {Number} rowIndex
59274 * @param {Number} collIndex
59276 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59277 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59278 this.clearSelections();
59279 r = r || this.grid.dataSource.getAt(rowIndex);
59282 cell : [rowIndex, colIndex]
59284 if(!preventViewNotify){
59285 var v = this.grid.getView();
59286 v.onCellSelect(rowIndex, colIndex);
59287 if(preventFocus !== true){
59288 v.focusCell(rowIndex, colIndex);
59291 this.fireEvent("cellselect", this, rowIndex, colIndex);
59292 this.fireEvent("selectionchange", this, this.selection);
59297 isSelectable : function(rowIndex, colIndex, cm){
59298 return !cm.isHidden(colIndex);
59302 handleKeyDown : function(e){
59303 //Roo.log('Cell Sel Model handleKeyDown');
59304 if(!e.isNavKeyPress()){
59307 var g = this.grid, s = this.selection;
59310 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59312 this.select(cell[0], cell[1]);
59317 var walk = function(row, col, step){
59318 return g.walkCells(row, col, step, sm.isSelectable, sm);
59320 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59327 // handled by onEditorKey
59328 if (g.isEditor && g.editing) {
59332 newCell = walk(r, c-1, -1);
59334 newCell = walk(r, c+1, 1);
59339 newCell = walk(r+1, c, 1);
59343 newCell = walk(r-1, c, -1);
59347 newCell = walk(r, c+1, 1);
59351 newCell = walk(r, c-1, -1);
59356 if(g.isEditor && !g.editing){
59357 g.startEditing(r, c);
59366 this.select(newCell[0], newCell[1]);
59372 acceptsNav : function(row, col, cm){
59373 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59377 * @param {Number} field (not used) - as it's normally used as a listener
59378 * @param {Number} e - event - fake it by using
59380 * var e = Roo.EventObjectImpl.prototype;
59381 * e.keyCode = e.TAB
59385 onEditorKey : function(field, e){
59387 var k = e.getKey(),
59390 ed = g.activeEditor,
59392 ///Roo.log('onEditorKey' + k);
59395 if (this.enter_is_tab && k == e.ENTER) {
59401 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59403 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59409 } else if(k == e.ENTER && !e.ctrlKey){
59412 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59414 } else if(k == e.ESC){
59419 var ecall = { cell : newCell, forward : forward };
59420 this.fireEvent('beforeeditnext', ecall );
59421 newCell = ecall.cell;
59422 forward = ecall.forward;
59426 //Roo.log('next cell after edit');
59427 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59428 } else if (forward) {
59429 // tabbed past last
59430 this.fireEvent.defer(100, this, ['tabend',this]);
59435 * Ext JS Library 1.1.1
59436 * Copyright(c) 2006-2007, Ext JS, LLC.
59438 * Originally Released Under LGPL - original licence link has changed is not relivant.
59441 * <script type="text/javascript">
59445 * @class Roo.grid.EditorGrid
59446 * @extends Roo.grid.Grid
59447 * Class for creating and editable grid.
59448 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59449 * The container MUST have some type of size defined for the grid to fill. The container will be
59450 * automatically set to position relative if it isn't already.
59451 * @param {Object} dataSource The data model to bind to
59452 * @param {Object} colModel The column model with info about this grid's columns
59454 Roo.grid.EditorGrid = function(container, config){
59455 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59456 this.getGridEl().addClass("xedit-grid");
59458 if(!this.selModel){
59459 this.selModel = new Roo.grid.CellSelectionModel();
59462 this.activeEditor = null;
59466 * @event beforeedit
59467 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59468 * <ul style="padding:5px;padding-left:16px;">
59469 * <li>grid - This grid</li>
59470 * <li>record - The record being edited</li>
59471 * <li>field - The field name being edited</li>
59472 * <li>value - The value for the field being edited.</li>
59473 * <li>row - The grid row index</li>
59474 * <li>column - The grid column index</li>
59475 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59477 * @param {Object} e An edit event (see above for description)
59479 "beforeedit" : true,
59482 * Fires after a cell is edited. <br />
59483 * <ul style="padding:5px;padding-left:16px;">
59484 * <li>grid - This grid</li>
59485 * <li>record - The record being edited</li>
59486 * <li>field - The field name being edited</li>
59487 * <li>value - The value being set</li>
59488 * <li>originalValue - The original value for the field, before the edit.</li>
59489 * <li>row - The grid row index</li>
59490 * <li>column - The grid column index</li>
59492 * @param {Object} e An edit event (see above for description)
59494 "afteredit" : true,
59496 * @event validateedit
59497 * Fires after a cell is edited, but before the value is set in the record.
59498 * You can use this to modify the value being set in the field, Return false
59499 * to cancel the change. The edit event object has the following properties <br />
59500 * <ul style="padding:5px;padding-left:16px;">
59501 * <li>editor - This editor</li>
59502 * <li>grid - This grid</li>
59503 * <li>record - The record being edited</li>
59504 * <li>field - The field name being edited</li>
59505 * <li>value - The value being set</li>
59506 * <li>originalValue - The original value for the field, before the edit.</li>
59507 * <li>row - The grid row index</li>
59508 * <li>column - The grid column index</li>
59509 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59511 * @param {Object} e An edit event (see above for description)
59513 "validateedit" : true
59515 this.on("bodyscroll", this.stopEditing, this);
59516 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59519 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59521 * @cfg {Number} clicksToEdit
59522 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59529 trackMouseOver: false, // causes very odd FF errors
59531 onCellDblClick : function(g, row, col){
59532 this.startEditing(row, col);
59535 onEditComplete : function(ed, value, startValue){
59536 this.editing = false;
59537 this.activeEditor = null;
59538 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59540 var field = this.colModel.getDataIndex(ed.col);
59545 originalValue: startValue,
59552 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59555 if(String(value) !== String(startValue)){
59557 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59558 r.set(field, e.value);
59559 // if we are dealing with a combo box..
59560 // then we also set the 'name' colum to be the displayField
59561 if (ed.field.displayField && ed.field.name) {
59562 r.set(ed.field.name, ed.field.el.dom.value);
59565 delete e.cancel; //?? why!!!
59566 this.fireEvent("afteredit", e);
59569 this.fireEvent("afteredit", e); // always fire it!
59571 this.view.focusCell(ed.row, ed.col);
59575 * Starts editing the specified for the specified row/column
59576 * @param {Number} rowIndex
59577 * @param {Number} colIndex
59579 startEditing : function(row, col){
59580 this.stopEditing();
59581 if(this.colModel.isCellEditable(col, row)){
59582 this.view.ensureVisible(row, col, true);
59584 var r = this.dataSource.getAt(row);
59585 var field = this.colModel.getDataIndex(col);
59586 var cell = Roo.get(this.view.getCell(row,col));
59591 value: r.data[field],
59596 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59597 this.editing = true;
59598 var ed = this.colModel.getCellEditor(col, row);
59604 ed.render(ed.parentEl || document.body);
59610 (function(){ // complex but required for focus issues in safari, ie and opera
59614 ed.on("complete", this.onEditComplete, this, {single: true});
59615 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
59616 this.activeEditor = ed;
59617 var v = r.data[field];
59618 ed.startEdit(this.view.getCell(row, col), v);
59619 // combo's with 'displayField and name set
59620 if (ed.field.displayField && ed.field.name) {
59621 ed.field.el.dom.value = r.data[ed.field.name];
59625 }).defer(50, this);
59631 * Stops any active editing
59633 stopEditing : function(){
59634 if(this.activeEditor){
59635 this.activeEditor.completeEdit();
59637 this.activeEditor = null;
59641 * Called to get grid's drag proxy text, by default returns this.ddText.
59644 getDragDropText : function(){
59645 var count = this.selModel.getSelectedCell() ? 1 : 0;
59646 return String.format(this.ddText, count, count == 1 ? '' : 's');
59651 * Ext JS Library 1.1.1
59652 * Copyright(c) 2006-2007, Ext JS, LLC.
59654 * Originally Released Under LGPL - original licence link has changed is not relivant.
59657 * <script type="text/javascript">
59660 // private - not really -- you end up using it !
59661 // This is a support class used internally by the Grid components
59664 * @class Roo.grid.GridEditor
59665 * @extends Roo.Editor
59666 * Class for creating and editable grid elements.
59667 * @param {Object} config any settings (must include field)
59669 Roo.grid.GridEditor = function(field, config){
59670 if (!config && field.field) {
59672 field = Roo.factory(config.field, Roo.form);
59674 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
59675 field.monitorTab = false;
59678 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
59681 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
59684 alignment: "tl-tl",
59687 cls: "x-small-editor x-grid-editor",
59692 * Ext JS Library 1.1.1
59693 * Copyright(c) 2006-2007, Ext JS, LLC.
59695 * Originally Released Under LGPL - original licence link has changed is not relivant.
59698 * <script type="text/javascript">
59703 Roo.grid.PropertyRecord = Roo.data.Record.create([
59704 {name:'name',type:'string'}, 'value'
59708 Roo.grid.PropertyStore = function(grid, source){
59710 this.store = new Roo.data.Store({
59711 recordType : Roo.grid.PropertyRecord
59713 this.store.on('update', this.onUpdate, this);
59715 this.setSource(source);
59717 Roo.grid.PropertyStore.superclass.constructor.call(this);
59722 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
59723 setSource : function(o){
59725 this.store.removeAll();
59728 if(this.isEditableValue(o[k])){
59729 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
59732 this.store.loadRecords({records: data}, {}, true);
59735 onUpdate : function(ds, record, type){
59736 if(type == Roo.data.Record.EDIT){
59737 var v = record.data['value'];
59738 var oldValue = record.modified['value'];
59739 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
59740 this.source[record.id] = v;
59742 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
59749 getProperty : function(row){
59750 return this.store.getAt(row);
59753 isEditableValue: function(val){
59754 if(val && val instanceof Date){
59756 }else if(typeof val == 'object' || typeof val == 'function'){
59762 setValue : function(prop, value){
59763 this.source[prop] = value;
59764 this.store.getById(prop).set('value', value);
59767 getSource : function(){
59768 return this.source;
59772 Roo.grid.PropertyColumnModel = function(grid, store){
59775 g.PropertyColumnModel.superclass.constructor.call(this, [
59776 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
59777 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
59779 this.store = store;
59780 this.bselect = Roo.DomHelper.append(document.body, {
59781 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
59782 {tag: 'option', value: 'true', html: 'true'},
59783 {tag: 'option', value: 'false', html: 'false'}
59786 Roo.id(this.bselect);
59789 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
59790 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
59791 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
59792 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
59793 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
59795 this.renderCellDelegate = this.renderCell.createDelegate(this);
59796 this.renderPropDelegate = this.renderProp.createDelegate(this);
59799 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
59803 valueText : 'Value',
59805 dateFormat : 'm/j/Y',
59808 renderDate : function(dateVal){
59809 return dateVal.dateFormat(this.dateFormat);
59812 renderBool : function(bVal){
59813 return bVal ? 'true' : 'false';
59816 isCellEditable : function(colIndex, rowIndex){
59817 return colIndex == 1;
59820 getRenderer : function(col){
59822 this.renderCellDelegate : this.renderPropDelegate;
59825 renderProp : function(v){
59826 return this.getPropertyName(v);
59829 renderCell : function(val){
59831 if(val instanceof Date){
59832 rv = this.renderDate(val);
59833 }else if(typeof val == 'boolean'){
59834 rv = this.renderBool(val);
59836 return Roo.util.Format.htmlEncode(rv);
59839 getPropertyName : function(name){
59840 var pn = this.grid.propertyNames;
59841 return pn && pn[name] ? pn[name] : name;
59844 getCellEditor : function(colIndex, rowIndex){
59845 var p = this.store.getProperty(rowIndex);
59846 var n = p.data['name'], val = p.data['value'];
59848 if(typeof(this.grid.customEditors[n]) == 'string'){
59849 return this.editors[this.grid.customEditors[n]];
59851 if(typeof(this.grid.customEditors[n]) != 'undefined'){
59852 return this.grid.customEditors[n];
59854 if(val instanceof Date){
59855 return this.editors['date'];
59856 }else if(typeof val == 'number'){
59857 return this.editors['number'];
59858 }else if(typeof val == 'boolean'){
59859 return this.editors['boolean'];
59861 return this.editors['string'];
59867 * @class Roo.grid.PropertyGrid
59868 * @extends Roo.grid.EditorGrid
59869 * This class represents the interface of a component based property grid control.
59870 * <br><br>Usage:<pre><code>
59871 var grid = new Roo.grid.PropertyGrid("my-container-id", {
59879 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59880 * The container MUST have some type of size defined for the grid to fill. The container will be
59881 * automatically set to position relative if it isn't already.
59882 * @param {Object} config A config object that sets properties on this grid.
59884 Roo.grid.PropertyGrid = function(container, config){
59885 config = config || {};
59886 var store = new Roo.grid.PropertyStore(this);
59887 this.store = store;
59888 var cm = new Roo.grid.PropertyColumnModel(this, store);
59889 store.store.sort('name', 'ASC');
59890 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
59893 enableColLock:false,
59894 enableColumnMove:false,
59896 trackMouseOver: false,
59899 this.getGridEl().addClass('x-props-grid');
59900 this.lastEditRow = null;
59901 this.on('columnresize', this.onColumnResize, this);
59904 * @event beforepropertychange
59905 * Fires before a property changes (return false to stop?)
59906 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
59907 * @param {String} id Record Id
59908 * @param {String} newval New Value
59909 * @param {String} oldval Old Value
59911 "beforepropertychange": true,
59913 * @event propertychange
59914 * Fires after a property changes
59915 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
59916 * @param {String} id Record Id
59917 * @param {String} newval New Value
59918 * @param {String} oldval Old Value
59920 "propertychange": true
59922 this.customEditors = this.customEditors || {};
59924 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
59927 * @cfg {Object} customEditors map of colnames=> custom editors.
59928 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
59929 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
59930 * false disables editing of the field.
59934 * @cfg {Object} propertyNames map of property Names to their displayed value
59937 render : function(){
59938 Roo.grid.PropertyGrid.superclass.render.call(this);
59939 this.autoSize.defer(100, this);
59942 autoSize : function(){
59943 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
59945 this.view.fitColumns();
59949 onColumnResize : function(){
59950 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
59954 * Sets the data for the Grid
59955 * accepts a Key => Value object of all the elements avaiable.
59956 * @param {Object} data to appear in grid.
59958 setSource : function(source){
59959 this.store.setSource(source);
59963 * Gets all the data from the grid.
59964 * @return {Object} data data stored in grid
59966 getSource : function(){
59967 return this.store.getSource();
59976 * @class Roo.grid.Calendar
59977 * @extends Roo.util.Grid
59978 * This class extends the Grid to provide a calendar widget
59979 * <br><br>Usage:<pre><code>
59980 var grid = new Roo.grid.Calendar("my-container-id", {
59983 selModel: mySelectionModel,
59984 autoSizeColumns: true,
59985 monitorWindowResize: false,
59986 trackMouseOver: true
59987 eventstore : real data store..
59993 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59994 * The container MUST have some type of size defined for the grid to fill. The container will be
59995 * automatically set to position relative if it isn't already.
59996 * @param {Object} config A config object that sets properties on this grid.
59998 Roo.grid.Calendar = function(container, config){
59999 // initialize the container
60000 this.container = Roo.get(container);
60001 this.container.update("");
60002 this.container.setStyle("overflow", "hidden");
60003 this.container.addClass('x-grid-container');
60005 this.id = this.container.id;
60007 Roo.apply(this, config);
60008 // check and correct shorthanded configs
60012 for (var r = 0;r < 6;r++) {
60015 for (var c =0;c < 7;c++) {
60019 if (this.eventStore) {
60020 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60021 this.eventStore.on('load',this.onLoad, this);
60022 this.eventStore.on('beforeload',this.clearEvents, this);
60026 this.dataSource = new Roo.data.Store({
60027 proxy: new Roo.data.MemoryProxy(rows),
60028 reader: new Roo.data.ArrayReader({}, [
60029 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60032 this.dataSource.load();
60033 this.ds = this.dataSource;
60034 this.ds.xmodule = this.xmodule || false;
60037 var cellRender = function(v,x,r)
60039 return String.format(
60040 '<div class="fc-day fc-widget-content"><div>' +
60041 '<div class="fc-event-container"></div>' +
60042 '<div class="fc-day-number">{0}</div>'+
60044 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60045 '</div></div>', v);
60050 this.colModel = new Roo.grid.ColumnModel( [
60052 xtype: 'ColumnModel',
60054 dataIndex : 'weekday0',
60056 renderer : cellRender
60059 xtype: 'ColumnModel',
60061 dataIndex : 'weekday1',
60063 renderer : cellRender
60066 xtype: 'ColumnModel',
60068 dataIndex : 'weekday2',
60069 header : 'Tuesday',
60070 renderer : cellRender
60073 xtype: 'ColumnModel',
60075 dataIndex : 'weekday3',
60076 header : 'Wednesday',
60077 renderer : cellRender
60080 xtype: 'ColumnModel',
60082 dataIndex : 'weekday4',
60083 header : 'Thursday',
60084 renderer : cellRender
60087 xtype: 'ColumnModel',
60089 dataIndex : 'weekday5',
60091 renderer : cellRender
60094 xtype: 'ColumnModel',
60096 dataIndex : 'weekday6',
60097 header : 'Saturday',
60098 renderer : cellRender
60101 this.cm = this.colModel;
60102 this.cm.xmodule = this.xmodule || false;
60106 //this.selModel = new Roo.grid.CellSelectionModel();
60107 //this.sm = this.selModel;
60108 //this.selModel.init(this);
60112 this.container.setWidth(this.width);
60116 this.container.setHeight(this.height);
60123 * The raw click event for the entire grid.
60124 * @param {Roo.EventObject} e
60129 * The raw dblclick event for the entire grid.
60130 * @param {Roo.EventObject} e
60134 * @event contextmenu
60135 * The raw contextmenu event for the entire grid.
60136 * @param {Roo.EventObject} e
60138 "contextmenu" : true,
60141 * The raw mousedown event for the entire grid.
60142 * @param {Roo.EventObject} e
60144 "mousedown" : true,
60147 * The raw mouseup event for the entire grid.
60148 * @param {Roo.EventObject} e
60153 * The raw mouseover event for the entire grid.
60154 * @param {Roo.EventObject} e
60156 "mouseover" : true,
60159 * The raw mouseout event for the entire grid.
60160 * @param {Roo.EventObject} e
60165 * The raw keypress event for the entire grid.
60166 * @param {Roo.EventObject} e
60171 * The raw keydown event for the entire grid.
60172 * @param {Roo.EventObject} e
60180 * Fires when a cell is clicked
60181 * @param {Grid} this
60182 * @param {Number} rowIndex
60183 * @param {Number} columnIndex
60184 * @param {Roo.EventObject} e
60186 "cellclick" : true,
60188 * @event celldblclick
60189 * Fires when a cell is double clicked
60190 * @param {Grid} this
60191 * @param {Number} rowIndex
60192 * @param {Number} columnIndex
60193 * @param {Roo.EventObject} e
60195 "celldblclick" : true,
60198 * Fires when a row is clicked
60199 * @param {Grid} this
60200 * @param {Number} rowIndex
60201 * @param {Roo.EventObject} e
60205 * @event rowdblclick
60206 * Fires when a row is double clicked
60207 * @param {Grid} this
60208 * @param {Number} rowIndex
60209 * @param {Roo.EventObject} e
60211 "rowdblclick" : true,
60213 * @event headerclick
60214 * Fires when a header is clicked
60215 * @param {Grid} this
60216 * @param {Number} columnIndex
60217 * @param {Roo.EventObject} e
60219 "headerclick" : true,
60221 * @event headerdblclick
60222 * Fires when a header cell is double clicked
60223 * @param {Grid} this
60224 * @param {Number} columnIndex
60225 * @param {Roo.EventObject} e
60227 "headerdblclick" : true,
60229 * @event rowcontextmenu
60230 * Fires when a row is right clicked
60231 * @param {Grid} this
60232 * @param {Number} rowIndex
60233 * @param {Roo.EventObject} e
60235 "rowcontextmenu" : true,
60237 * @event cellcontextmenu
60238 * Fires when a cell is right clicked
60239 * @param {Grid} this
60240 * @param {Number} rowIndex
60241 * @param {Number} cellIndex
60242 * @param {Roo.EventObject} e
60244 "cellcontextmenu" : true,
60246 * @event headercontextmenu
60247 * Fires when a header is right clicked
60248 * @param {Grid} this
60249 * @param {Number} columnIndex
60250 * @param {Roo.EventObject} e
60252 "headercontextmenu" : true,
60254 * @event bodyscroll
60255 * Fires when the body element is scrolled
60256 * @param {Number} scrollLeft
60257 * @param {Number} scrollTop
60259 "bodyscroll" : true,
60261 * @event columnresize
60262 * Fires when the user resizes a column
60263 * @param {Number} columnIndex
60264 * @param {Number} newSize
60266 "columnresize" : true,
60268 * @event columnmove
60269 * Fires when the user moves a column
60270 * @param {Number} oldIndex
60271 * @param {Number} newIndex
60273 "columnmove" : true,
60276 * Fires when row(s) start being dragged
60277 * @param {Grid} this
60278 * @param {Roo.GridDD} dd The drag drop object
60279 * @param {event} e The raw browser event
60281 "startdrag" : true,
60284 * Fires when a drag operation is complete
60285 * @param {Grid} this
60286 * @param {Roo.GridDD} dd The drag drop object
60287 * @param {event} e The raw browser event
60292 * Fires when dragged row(s) are dropped on a valid DD target
60293 * @param {Grid} this
60294 * @param {Roo.GridDD} dd The drag drop object
60295 * @param {String} targetId The target drag drop object
60296 * @param {event} e The raw browser event
60301 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60302 * @param {Grid} this
60303 * @param {Roo.GridDD} dd The drag drop object
60304 * @param {String} targetId The target drag drop object
60305 * @param {event} e The raw browser event
60310 * Fires when the dragged row(s) first cross another DD target while being dragged
60311 * @param {Grid} this
60312 * @param {Roo.GridDD} dd The drag drop object
60313 * @param {String} targetId The target drag drop object
60314 * @param {event} e The raw browser event
60316 "dragenter" : true,
60319 * Fires when the dragged row(s) leave another DD target while being dragged
60320 * @param {Grid} this
60321 * @param {Roo.GridDD} dd The drag drop object
60322 * @param {String} targetId The target drag drop object
60323 * @param {event} e The raw browser event
60328 * Fires when a row is rendered, so you can change add a style to it.
60329 * @param {GridView} gridview The grid view
60330 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60336 * Fires when the grid is rendered
60337 * @param {Grid} grid
60342 * Fires when a date is selected
60343 * @param {DatePicker} this
60344 * @param {Date} date The selected date
60348 * @event monthchange
60349 * Fires when the displayed month changes
60350 * @param {DatePicker} this
60351 * @param {Date} date The selected month
60353 'monthchange': true,
60355 * @event evententer
60356 * Fires when mouse over an event
60357 * @param {Calendar} this
60358 * @param {event} Event
60360 'evententer': true,
60362 * @event eventleave
60363 * Fires when the mouse leaves an
60364 * @param {Calendar} this
60367 'eventleave': true,
60369 * @event eventclick
60370 * Fires when the mouse click an
60371 * @param {Calendar} this
60374 'eventclick': true,
60376 * @event eventrender
60377 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60378 * @param {Calendar} this
60379 * @param {data} data to be modified
60381 'eventrender': true
60385 Roo.grid.Grid.superclass.constructor.call(this);
60386 this.on('render', function() {
60387 this.view.el.addClass('x-grid-cal');
60389 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60393 if (!Roo.grid.Calendar.style) {
60394 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60397 '.x-grid-cal .x-grid-col' : {
60398 height: 'auto !important',
60399 'vertical-align': 'top'
60401 '.x-grid-cal .fc-event-hori' : {
60412 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60414 * @cfg {Store} eventStore The store that loads events.
60419 activeDate : false,
60422 monitorWindowResize : false,
60425 resizeColumns : function() {
60426 var col = (this.view.el.getWidth() / 7) - 3;
60427 // loop through cols, and setWidth
60428 for(var i =0 ; i < 7 ; i++){
60429 this.cm.setColumnWidth(i, col);
60432 setDate :function(date) {
60434 Roo.log('setDate?');
60436 this.resizeColumns();
60437 var vd = this.activeDate;
60438 this.activeDate = date;
60439 // if(vd && this.el){
60440 // var t = date.getTime();
60441 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60442 // Roo.log('using add remove');
60444 // this.fireEvent('monthchange', this, date);
60446 // this.cells.removeClass("fc-state-highlight");
60447 // this.cells.each(function(c){
60448 // if(c.dateValue == t){
60449 // c.addClass("fc-state-highlight");
60450 // setTimeout(function(){
60451 // try{c.dom.firstChild.focus();}catch(e){}
60461 var days = date.getDaysInMonth();
60463 var firstOfMonth = date.getFirstDateOfMonth();
60464 var startingPos = firstOfMonth.getDay()-this.startDay;
60466 if(startingPos < this.startDay){
60470 var pm = date.add(Date.MONTH, -1);
60471 var prevStart = pm.getDaysInMonth()-startingPos;
60475 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60477 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60478 //this.cells.addClassOnOver('fc-state-hover');
60480 var cells = this.cells.elements;
60481 var textEls = this.textNodes;
60483 //Roo.each(cells, function(cell){
60484 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60487 days += startingPos;
60489 // convert everything to numbers so it's fast
60490 var day = 86400000;
60491 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60494 //Roo.log(prevStart);
60496 var today = new Date().clearTime().getTime();
60497 var sel = date.clearTime().getTime();
60498 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60499 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60500 var ddMatch = this.disabledDatesRE;
60501 var ddText = this.disabledDatesText;
60502 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60503 var ddaysText = this.disabledDaysText;
60504 var format = this.format;
60506 var setCellClass = function(cal, cell){
60508 //Roo.log('set Cell Class');
60510 var t = d.getTime();
60515 cell.dateValue = t;
60517 cell.className += " fc-today";
60518 cell.className += " fc-state-highlight";
60519 cell.title = cal.todayText;
60522 // disable highlight in other month..
60523 cell.className += " fc-state-highlight";
60528 //cell.className = " fc-state-disabled";
60529 cell.title = cal.minText;
60533 //cell.className = " fc-state-disabled";
60534 cell.title = cal.maxText;
60538 if(ddays.indexOf(d.getDay()) != -1){
60539 // cell.title = ddaysText;
60540 // cell.className = " fc-state-disabled";
60543 if(ddMatch && format){
60544 var fvalue = d.dateFormat(format);
60545 if(ddMatch.test(fvalue)){
60546 cell.title = ddText.replace("%0", fvalue);
60547 cell.className = " fc-state-disabled";
60551 if (!cell.initialClassName) {
60552 cell.initialClassName = cell.dom.className;
60555 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60560 for(; i < startingPos; i++) {
60561 cells[i].dayName = (++prevStart);
60562 Roo.log(textEls[i]);
60563 d.setDate(d.getDate()+1);
60565 //cells[i].className = "fc-past fc-other-month";
60566 setCellClass(this, cells[i]);
60571 for(; i < days; i++){
60572 intDay = i - startingPos + 1;
60573 cells[i].dayName = (intDay);
60574 d.setDate(d.getDate()+1);
60576 cells[i].className = ''; // "x-date-active";
60577 setCellClass(this, cells[i]);
60581 for(; i < 42; i++) {
60582 //textEls[i].innerHTML = (++extraDays);
60584 d.setDate(d.getDate()+1);
60585 cells[i].dayName = (++extraDays);
60586 cells[i].className = "fc-future fc-other-month";
60587 setCellClass(this, cells[i]);
60590 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60592 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60594 // this will cause all the cells to mis
60597 for (var r = 0;r < 6;r++) {
60598 for (var c =0;c < 7;c++) {
60599 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60603 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60604 for(i=0;i<cells.length;i++) {
60606 this.cells.elements[i].dayName = cells[i].dayName ;
60607 this.cells.elements[i].className = cells[i].className;
60608 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
60609 this.cells.elements[i].title = cells[i].title ;
60610 this.cells.elements[i].dateValue = cells[i].dateValue ;
60616 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
60617 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
60619 ////if(totalRows != 6){
60620 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
60621 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
60624 this.fireEvent('monthchange', this, date);
60629 * Returns the grid's SelectionModel.
60630 * @return {SelectionModel}
60632 getSelectionModel : function(){
60633 if(!this.selModel){
60634 this.selModel = new Roo.grid.CellSelectionModel();
60636 return this.selModel;
60640 this.eventStore.load()
60646 findCell : function(dt) {
60647 dt = dt.clearTime().getTime();
60649 this.cells.each(function(c){
60650 //Roo.log("check " +c.dateValue + '?=' + dt);
60651 if(c.dateValue == dt){
60661 findCells : function(rec) {
60662 var s = rec.data.start_dt.clone().clearTime().getTime();
60664 var e= rec.data.end_dt.clone().clearTime().getTime();
60667 this.cells.each(function(c){
60668 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
60670 if(c.dateValue > e){
60673 if(c.dateValue < s){
60682 findBestRow: function(cells)
60686 for (var i =0 ; i < cells.length;i++) {
60687 ret = Math.max(cells[i].rows || 0,ret);
60694 addItem : function(rec)
60696 // look for vertical location slot in
60697 var cells = this.findCells(rec);
60699 rec.row = this.findBestRow(cells);
60701 // work out the location.
60705 for(var i =0; i < cells.length; i++) {
60713 if (crow.start.getY() == cells[i].getY()) {
60715 crow.end = cells[i];
60731 for (var i = 0; i < cells.length;i++) {
60732 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
60739 clearEvents: function() {
60741 if (!this.eventStore.getCount()) {
60744 // reset number of rows in cells.
60745 Roo.each(this.cells.elements, function(c){
60749 this.eventStore.each(function(e) {
60750 this.clearEvent(e);
60755 clearEvent : function(ev)
60758 Roo.each(ev.els, function(el) {
60759 el.un('mouseenter' ,this.onEventEnter, this);
60760 el.un('mouseleave' ,this.onEventLeave, this);
60768 renderEvent : function(ev,ctr) {
60770 ctr = this.view.el.select('.fc-event-container',true).first();
60774 this.clearEvent(ev);
60780 var cells = ev.cells;
60781 var rows = ev.rows;
60782 this.fireEvent('eventrender', this, ev);
60784 for(var i =0; i < rows.length; i++) {
60788 cls += ' fc-event-start';
60790 if ((i+1) == rows.length) {
60791 cls += ' fc-event-end';
60794 //Roo.log(ev.data);
60795 // how many rows should it span..
60796 var cg = this.eventTmpl.append(ctr,Roo.apply({
60799 }, ev.data) , true);
60802 cg.on('mouseenter' ,this.onEventEnter, this, ev);
60803 cg.on('mouseleave' ,this.onEventLeave, this, ev);
60804 cg.on('click', this.onEventClick, this, ev);
60808 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
60809 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
60812 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
60813 cg.setWidth(ebox.right - sbox.x -2);
60817 renderEvents: function()
60819 // first make sure there is enough space..
60821 if (!this.eventTmpl) {
60822 this.eventTmpl = new Roo.Template(
60823 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
60824 '<div class="fc-event-inner">' +
60825 '<span class="fc-event-time">{time}</span>' +
60826 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
60828 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
60836 this.cells.each(function(c) {
60837 //Roo.log(c.select('.fc-day-content div',true).first());
60838 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
60841 var ctr = this.view.el.select('.fc-event-container',true).first();
60844 this.eventStore.each(function(ev){
60846 this.renderEvent(ev);
60850 this.view.layout();
60854 onEventEnter: function (e, el,event,d) {
60855 this.fireEvent('evententer', this, el, event);
60858 onEventLeave: function (e, el,event,d) {
60859 this.fireEvent('eventleave', this, el, event);
60862 onEventClick: function (e, el,event,d) {
60863 this.fireEvent('eventclick', this, el, event);
60866 onMonthChange: function () {
60870 onLoad: function () {
60872 //Roo.log('calendar onload');
60874 if(this.eventStore.getCount() > 0){
60878 this.eventStore.each(function(d){
60883 if (typeof(add.end_dt) == 'undefined') {
60884 Roo.log("Missing End time in calendar data: ");
60888 if (typeof(add.start_dt) == 'undefined') {
60889 Roo.log("Missing Start time in calendar data: ");
60893 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
60894 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
60895 add.id = add.id || d.id;
60896 add.title = add.title || '??';
60904 this.renderEvents();
60914 render : function ()
60918 if (!this.view.el.hasClass('course-timesheet')) {
60919 this.view.el.addClass('course-timesheet');
60921 if (this.tsStyle) {
60926 Roo.log(_this.grid.view.el.getWidth());
60929 this.tsStyle = Roo.util.CSS.createStyleSheet({
60930 '.course-timesheet .x-grid-row' : {
60933 '.x-grid-row td' : {
60934 'vertical-align' : 0
60936 '.course-edit-link' : {
60938 'text-overflow' : 'ellipsis',
60939 'overflow' : 'hidden',
60940 'white-space' : 'nowrap',
60941 'cursor' : 'pointer'
60946 '.de-act-sup-link' : {
60947 'color' : 'purple',
60948 'text-decoration' : 'line-through'
60952 'text-decoration' : 'line-through'
60954 '.course-timesheet .course-highlight' : {
60955 'border-top-style': 'dashed !important',
60956 'border-bottom-bottom': 'dashed !important'
60958 '.course-timesheet .course-item' : {
60959 'font-family' : 'tahoma, arial, helvetica',
60960 'font-size' : '11px',
60961 'overflow' : 'hidden',
60962 'padding-left' : '10px',
60963 'padding-right' : '10px',
60964 'padding-top' : '10px'
60972 monitorWindowResize : false,
60973 cellrenderer : function(v,x,r)
60978 xtype: 'CellSelectionModel',
60985 beforeload : function (_self, options)
60987 options.params = options.params || {};
60988 options.params._month = _this.monthField.getValue();
60989 options.params.limit = 9999;
60990 options.params['sort'] = 'when_dt';
60991 options.params['dir'] = 'ASC';
60992 this.proxy.loadResponse = this.loadResponse;
60994 //this.addColumns();
60996 load : function (_self, records, options)
60998 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
60999 // if you click on the translation.. you can edit it...
61000 var el = Roo.get(this);
61001 var id = el.dom.getAttribute('data-id');
61002 var d = el.dom.getAttribute('data-date');
61003 var t = el.dom.getAttribute('data-time');
61004 //var id = this.child('span').dom.textContent;
61007 Pman.Dialog.CourseCalendar.show({
61011 productitem_active : id ? 1 : 0
61013 _this.grid.ds.load({});
61018 _this.panel.fireEvent('resize', [ '', '' ]);
61021 loadResponse : function(o, success, response){
61022 // this is overridden on before load..
61024 Roo.log("our code?");
61025 //Roo.log(success);
61026 //Roo.log(response)
61027 delete this.activeRequest;
61029 this.fireEvent("loadexception", this, o, response);
61030 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61035 result = o.reader.read(response);
61037 Roo.log("load exception?");
61038 this.fireEvent("loadexception", this, o, response, e);
61039 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61042 Roo.log("ready...");
61043 // loop through result.records;
61044 // and set this.tdate[date] = [] << array of records..
61046 Roo.each(result.records, function(r){
61048 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61049 _this.tdata[r.data.when_dt.format('j')] = [];
61051 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61054 //Roo.log(_this.tdata);
61056 result.records = [];
61057 result.totalRecords = 6;
61059 // let's generate some duumy records for the rows.
61060 //var st = _this.dateField.getValue();
61062 // work out monday..
61063 //st = st.add(Date.DAY, -1 * st.format('w'));
61065 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61067 var firstOfMonth = date.getFirstDayOfMonth();
61068 var days = date.getDaysInMonth();
61070 var firstAdded = false;
61071 for (var i = 0; i < result.totalRecords ; i++) {
61072 //var d= st.add(Date.DAY, i);
61075 for(var w = 0 ; w < 7 ; w++){
61076 if(!firstAdded && firstOfMonth != w){
61083 var dd = (d > 0 && d < 10) ? "0"+d : d;
61084 row['weekday'+w] = String.format(
61085 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61086 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61088 date.format('Y-m-')+dd
61091 if(typeof(_this.tdata[d]) != 'undefined'){
61092 Roo.each(_this.tdata[d], function(r){
61096 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61097 if(r.parent_id*1>0){
61098 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61101 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61102 deactive = 'de-act-link';
61105 row['weekday'+w] += String.format(
61106 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61108 r.product_id_name, //1
61109 r.when_dt.format('h:ia'), //2
61119 // only do this if something added..
61121 result.records.push(_this.grid.dataSource.reader.newRow(row));
61125 // push it twice. (second one with an hour..
61129 this.fireEvent("load", this, o, o.request.arg);
61130 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61132 sortInfo : {field: 'when_dt', direction : 'ASC' },
61134 xtype: 'HttpProxy',
61137 url : baseURL + '/Roo/Shop_course.php'
61140 xtype: 'JsonReader',
61157 'name': 'parent_id',
61161 'name': 'product_id',
61165 'name': 'productitem_id',
61183 click : function (_self, e)
61185 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61186 sd.setMonth(sd.getMonth()-1);
61187 _this.monthField.setValue(sd.format('Y-m-d'));
61188 _this.grid.ds.load({});
61194 xtype: 'Separator',
61198 xtype: 'MonthField',
61201 render : function (_self)
61203 _this.monthField = _self;
61204 // _this.monthField.set today
61206 select : function (combo, date)
61208 _this.grid.ds.load({});
61211 value : (function() { return new Date(); })()
61214 xtype: 'Separator',
61220 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61230 click : function (_self, e)
61232 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61233 sd.setMonth(sd.getMonth()+1);
61234 _this.monthField.setValue(sd.format('Y-m-d'));
61235 _this.grid.ds.load({});
61248 * Ext JS Library 1.1.1
61249 * Copyright(c) 2006-2007, Ext JS, LLC.
61251 * Originally Released Under LGPL - original licence link has changed is not relivant.
61254 * <script type="text/javascript">
61258 * @class Roo.LoadMask
61259 * A simple utility class for generically masking elements while loading data. If the element being masked has
61260 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61261 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61262 * element's UpdateManager load indicator and will be destroyed after the initial load.
61264 * Create a new LoadMask
61265 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61266 * @param {Object} config The config object
61268 Roo.LoadMask = function(el, config){
61269 this.el = Roo.get(el);
61270 Roo.apply(this, config);
61272 this.store.on('beforeload', this.onBeforeLoad, this);
61273 this.store.on('load', this.onLoad, this);
61274 this.store.on('loadexception', this.onLoadException, this);
61275 this.removeMask = false;
61277 var um = this.el.getUpdateManager();
61278 um.showLoadIndicator = false; // disable the default indicator
61279 um.on('beforeupdate', this.onBeforeLoad, this);
61280 um.on('update', this.onLoad, this);
61281 um.on('failure', this.onLoad, this);
61282 this.removeMask = true;
61286 Roo.LoadMask.prototype = {
61288 * @cfg {Boolean} removeMask
61289 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61290 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61293 * @cfg {String} msg
61294 * The text to display in a centered loading message box (defaults to 'Loading...')
61296 msg : 'Loading...',
61298 * @cfg {String} msgCls
61299 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61301 msgCls : 'x-mask-loading',
61304 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61310 * Disables the mask to prevent it from being displayed
61312 disable : function(){
61313 this.disabled = true;
61317 * Enables the mask so that it can be displayed
61319 enable : function(){
61320 this.disabled = false;
61323 onLoadException : function()
61325 Roo.log(arguments);
61327 if (typeof(arguments[3]) != 'undefined') {
61328 Roo.MessageBox.alert("Error loading",arguments[3]);
61332 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61333 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61340 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61343 onLoad : function()
61345 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61349 onBeforeLoad : function(){
61350 if(!this.disabled){
61351 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61356 destroy : function(){
61358 this.store.un('beforeload', this.onBeforeLoad, this);
61359 this.store.un('load', this.onLoad, this);
61360 this.store.un('loadexception', this.onLoadException, this);
61362 var um = this.el.getUpdateManager();
61363 um.un('beforeupdate', this.onBeforeLoad, this);
61364 um.un('update', this.onLoad, this);
61365 um.un('failure', this.onLoad, this);
61370 * Ext JS Library 1.1.1
61371 * Copyright(c) 2006-2007, Ext JS, LLC.
61373 * Originally Released Under LGPL - original licence link has changed is not relivant.
61376 * <script type="text/javascript">
61381 * @class Roo.XTemplate
61382 * @extends Roo.Template
61383 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61385 var t = new Roo.XTemplate(
61386 '<select name="{name}">',
61387 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61391 // then append, applying the master template values
61394 * Supported features:
61399 {a_variable} - output encoded.
61400 {a_variable.format:("Y-m-d")} - call a method on the variable
61401 {a_variable:raw} - unencoded output
61402 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61403 {a_variable:this.method_on_template(...)} - call a method on the template object.
61408 <tpl for="a_variable or condition.."></tpl>
61409 <tpl if="a_variable or condition"></tpl>
61410 <tpl exec="some javascript"></tpl>
61411 <tpl name="named_template"></tpl> (experimental)
61413 <tpl for="."></tpl> - just iterate the property..
61414 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61418 Roo.XTemplate = function()
61420 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61427 Roo.extend(Roo.XTemplate, Roo.Template, {
61430 * The various sub templates
61435 * basic tag replacing syntax
61438 * // you can fake an object call by doing this
61442 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61445 * compile the template
61447 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61450 compile: function()
61454 s = ['<tpl>', s, '</tpl>'].join('');
61456 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61457 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61458 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61459 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61460 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61465 while(true == !!(m = s.match(re))){
61466 var forMatch = m[0].match(nameRe),
61467 ifMatch = m[0].match(ifRe),
61468 execMatch = m[0].match(execRe),
61469 namedMatch = m[0].match(namedRe),
61474 name = forMatch && forMatch[1] ? forMatch[1] : '';
61477 // if - puts fn into test..
61478 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61480 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61485 // exec - calls a function... returns empty if true is returned.
61486 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61488 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61496 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61497 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61498 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61501 var uid = namedMatch ? namedMatch[1] : id;
61505 id: namedMatch ? namedMatch[1] : id,
61512 s = s.replace(m[0], '');
61514 s = s.replace(m[0], '{xtpl'+ id + '}');
61519 for(var i = tpls.length-1; i >= 0; --i){
61520 this.compileTpl(tpls[i]);
61521 this.tpls[tpls[i].id] = tpls[i];
61523 this.master = tpls[tpls.length-1];
61527 * same as applyTemplate, except it's done to one of the subTemplates
61528 * when using named templates, you can do:
61530 * var str = pl.applySubTemplate('your-name', values);
61533 * @param {Number} id of the template
61534 * @param {Object} values to apply to template
61535 * @param {Object} parent (normaly the instance of this object)
61537 applySubTemplate : function(id, values, parent)
61541 var t = this.tpls[id];
61545 if(t.test && !t.test.call(this, values, parent)){
61549 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61550 Roo.log(e.toString());
61556 if(t.exec && t.exec.call(this, values, parent)){
61560 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61561 Roo.log(e.toString());
61566 var vs = t.target ? t.target.call(this, values, parent) : values;
61567 parent = t.target ? values : parent;
61568 if(t.target && vs instanceof Array){
61570 for(var i = 0, len = vs.length; i < len; i++){
61571 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61573 return buf.join('');
61575 return t.compiled.call(this, vs, parent);
61577 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61578 Roo.log(e.toString());
61579 Roo.log(t.compiled);
61584 compileTpl : function(tpl)
61586 var fm = Roo.util.Format;
61587 var useF = this.disableFormats !== true;
61588 var sep = Roo.isGecko ? "+" : ",";
61589 var undef = function(str) {
61590 Roo.log("Property not found :" + str);
61594 var fn = function(m, name, format, args)
61596 //Roo.log(arguments);
61597 args = args ? args.replace(/\\'/g,"'") : args;
61598 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61599 if (typeof(format) == 'undefined') {
61600 format= 'htmlEncode';
61602 if (format == 'raw' ) {
61606 if(name.substr(0, 4) == 'xtpl'){
61607 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
61610 // build an array of options to determine if value is undefined..
61612 // basically get 'xxxx.yyyy' then do
61613 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
61614 // (function () { Roo.log("Property not found"); return ''; })() :
61619 Roo.each(name.split('.'), function(st) {
61620 lookfor += (lookfor.length ? '.': '') + st;
61621 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
61624 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
61627 if(format && useF){
61629 args = args ? ',' + args : "";
61631 if(format.substr(0, 5) != "this."){
61632 format = "fm." + format + '(';
61634 format = 'this.call("'+ format.substr(5) + '", ';
61638 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
61642 // called with xxyx.yuu:(test,test)
61644 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
61646 // raw.. - :raw modifier..
61647 return "'"+ sep + udef_st + name + ")"+sep+"'";
61651 // branched to use + in gecko and [].join() in others
61653 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
61654 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
61657 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
61658 body.push(tpl.body.replace(/(\r\n|\n)/g,
61659 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
61660 body.push("'].join('');};};");
61661 body = body.join('');
61664 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
61666 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
61672 applyTemplate : function(values){
61673 return this.master.compiled.call(this, values, {});
61674 //var s = this.subs;
61677 apply : function(){
61678 return this.applyTemplate.apply(this, arguments);
61683 Roo.XTemplate.from = function(el){
61684 el = Roo.getDom(el);
61685 return new Roo.XTemplate(el.value || el.innerHTML);