4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
678 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
679 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
682 "Roo.bootstrap.dash");
685 * Ext JS Library 1.1.1
686 * Copyright(c) 2006-2007, Ext JS, LLC.
688 * Originally Released Under LGPL - original licence link has changed is not relivant.
691 * <script type="text/javascript">
695 // wrappedn so fnCleanup is not in global scope...
697 function fnCleanUp() {
698 var p = Function.prototype;
699 delete p.createSequence;
701 delete p.createDelegate;
702 delete p.createCallback;
703 delete p.createInterceptor;
705 window.detachEvent("onunload", fnCleanUp);
707 window.attachEvent("onunload", fnCleanUp);
714 * These functions are available on every Function object (any JavaScript function).
716 Roo.apply(Function.prototype, {
718 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
719 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
720 * Will create a function that is bound to those 2 args.
721 * @return {Function} The new function
723 createCallback : function(/*args...*/){
724 // make args available, in function below
725 var args = arguments;
728 return method.apply(window, args);
733 * Creates a delegate (callback) that sets the scope to obj.
734 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
735 * Will create a function that is automatically scoped to this.
736 * @param {Object} obj (optional) The object for which the scope is set
737 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
738 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
739 * if a number the args are inserted at the specified position
740 * @return {Function} The new function
742 createDelegate : function(obj, args, appendArgs){
745 var callArgs = args || arguments;
746 if(appendArgs === true){
747 callArgs = Array.prototype.slice.call(arguments, 0);
748 callArgs = callArgs.concat(args);
749 }else if(typeof appendArgs == "number"){
750 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
751 var applyArgs = [appendArgs, 0].concat(args); // create method call params
752 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
754 return method.apply(obj || window, callArgs);
759 * Calls this function after the number of millseconds specified.
760 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
761 * @param {Object} obj (optional) The object for which the scope is set
762 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764 * if a number the args are inserted at the specified position
765 * @return {Number} The timeout id that can be used with clearTimeout
767 defer : function(millis, obj, args, appendArgs){
768 var fn = this.createDelegate(obj, args, appendArgs);
770 return setTimeout(fn, millis);
776 * Create a combined function call sequence of the original function + the passed function.
777 * The resulting function returns the results of the original function.
778 * The passed fcn is called with the parameters of the original function
779 * @param {Function} fcn The function to sequence
780 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
781 * @return {Function} The new function
783 createSequence : function(fcn, scope){
784 if(typeof fcn != "function"){
789 var retval = method.apply(this || window, arguments);
790 fcn.apply(scope || this || window, arguments);
796 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
797 * The resulting function returns the results of the original function.
798 * The passed fcn is called with the parameters of the original function.
800 * @param {Function} fcn The function to call before the original
801 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
802 * @return {Function} The new function
804 createInterceptor : function(fcn, scope){
805 if(typeof fcn != "function"){
812 if(fcn.apply(scope || this || window, arguments) === false){
815 return method.apply(this || window, arguments);
821 * Ext JS Library 1.1.1
822 * Copyright(c) 2006-2007, Ext JS, LLC.
824 * Originally Released Under LGPL - original licence link has changed is not relivant.
827 * <script type="text/javascript">
830 Roo.applyIf(String, {
835 * Escapes the passed string for ' and \
836 * @param {String} string The string to escape
837 * @return {String} The escaped string
840 escape : function(string) {
841 return string.replace(/('|\\)/g, "\\$1");
845 * Pads the left side of a string with a specified character. This is especially useful
846 * for normalizing number and date strings. Example usage:
848 var s = String.leftPad('123', 5, '0');
849 // s now contains the string: '00123'
851 * @param {String} string The original string
852 * @param {Number} size The total length of the output string
853 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
854 * @return {String} The padded string
857 leftPad : function (val, size, ch) {
858 var result = new String(val);
859 if(ch === null || ch === undefined || ch === '') {
862 while (result.length < size) {
863 result = ch + result;
869 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
870 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
872 var cls = 'my-class', text = 'Some text';
873 var s = String.format('<div class="{0}">{1}</div>', cls, text);
874 // s now contains the string: '<div class="my-class">Some text</div>'
876 * @param {String} string The tokenized string to be formatted
877 * @param {String} value1 The value to replace token {0}
878 * @param {String} value2 Etc...
879 * @return {String} The formatted string
882 format : function(format){
883 var args = Array.prototype.slice.call(arguments, 1);
884 return format.replace(/\{(\d+)\}/g, function(m, i){
885 return Roo.util.Format.htmlEncode(args[i]);
893 * Utility function that allows you to easily switch a string between two alternating values. The passed value
894 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
895 * they are already different, the first value passed in is returned. Note that this method returns the new value
896 * but does not change the current string.
898 // alternate sort directions
899 sort = sort.toggle('ASC', 'DESC');
901 // instead of conditional logic:
902 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
904 * @param {String} value The value to compare to the current string
905 * @param {String} other The new value to use if the string already equals the first value passed in
906 * @return {String} The new value
909 String.prototype.toggle = function(value, other){
910 return this == value ? other : value;
915 * Remove invalid unicode characters from a string
917 * @return {String} The clean string
919 String.prototype.unicodeClean = function () {
920 return this.replace(/[\s\S]/g,
921 function(character) {
922 if (character.charCodeAt()< 256) {
926 encodeURIComponent(character);
937 * Ext JS Library 1.1.1
938 * Copyright(c) 2006-2007, Ext JS, LLC.
940 * Originally Released Under LGPL - original licence link has changed is not relivant.
943 * <script type="text/javascript">
949 Roo.applyIf(Number.prototype, {
951 * Checks whether or not the current number is within a desired range. If the number is already within the
952 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
953 * exceeded. Note that this method returns the constrained value but does not change the current number.
954 * @param {Number} min The minimum number in the range
955 * @param {Number} max The maximum number in the range
956 * @return {Number} The constrained value if outside the range, otherwise the current value
958 constrain : function(min, max){
959 return Math.min(Math.max(this, min), max);
963 * Ext JS Library 1.1.1
964 * Copyright(c) 2006-2007, Ext JS, LLC.
966 * Originally Released Under LGPL - original licence link has changed is not relivant.
969 * <script type="text/javascript">
974 Roo.applyIf(Array.prototype, {
977 * Checks whether or not the specified object exists in the array.
978 * @param {Object} o The object to check for
979 * @return {Number} The index of o in the array (or -1 if it is not found)
981 indexOf : function(o){
982 for (var i = 0, len = this.length; i < len; i++){
983 if(this[i] == o) { return i; }
989 * Removes the specified object from the array. If the object is not found nothing happens.
990 * @param {Object} o The object to remove
992 remove : function(o){
993 var index = this.indexOf(o);
995 this.splice(index, 1);
999 * Map (JS 1.6 compatibility)
1000 * @param {Function} function to call
1002 map : function(fun )
1004 var len = this.length >>> 0;
1005 if (typeof fun != "function") {
1006 throw new TypeError();
1008 var res = new Array(len);
1009 var thisp = arguments[1];
1010 for (var i = 0; i < len; i++)
1013 res[i] = fun.call(thisp, this[i], i, this);
1021 * @param {Array} o The array to compare to
1022 * @returns {Boolean} true if the same
1024 equals : function(b)
1026 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1033 if (this.length !== b.length) {
1037 // sort?? a.sort().equals(b.sort());
1039 for (var i = 0; i < this.length; ++i) {
1040 if (this[i] !== b[i]) {
1052 * Ext JS Library 1.1.1
1053 * Copyright(c) 2006-2007, Ext JS, LLC.
1055 * Originally Released Under LGPL - original licence link has changed is not relivant.
1058 * <script type="text/javascript">
1064 * The date parsing and format syntax is a subset of
1065 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1066 * supported will provide results equivalent to their PHP versions.
1068 * Following is the list of all currently supported formats:
1071 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1073 Format Output Description
1074 ------ ---------- --------------------------------------------------------------
1075 d 10 Day of the month, 2 digits with leading zeros
1076 D Wed A textual representation of a day, three letters
1077 j 10 Day of the month without leading zeros
1078 l Wednesday A full textual representation of the day of the week
1079 S th English ordinal day of month suffix, 2 chars (use with j)
1080 w 3 Numeric representation of the day of the week
1081 z 9 The julian date, or day of the year (0-365)
1082 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1083 F January A full textual representation of the month
1084 m 01 Numeric representation of a month, with leading zeros
1085 M Jan Month name abbreviation, three letters
1086 n 1 Numeric representation of a month, without leading zeros
1087 t 31 Number of days in the given month
1088 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1089 Y 2007 A full numeric representation of a year, 4 digits
1090 y 07 A two digit representation of a year
1091 a pm Lowercase Ante meridiem and Post meridiem
1092 A PM Uppercase Ante meridiem and Post meridiem
1093 g 3 12-hour format of an hour without leading zeros
1094 G 15 24-hour format of an hour without leading zeros
1095 h 03 12-hour format of an hour with leading zeros
1096 H 15 24-hour format of an hour with leading zeros
1097 i 05 Minutes with leading zeros
1098 s 01 Seconds, with leading zeros
1099 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1100 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1101 T CST Timezone setting of the machine running the code
1102 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1105 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1107 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1108 document.write(dt.format('Y-m-d')); //2007-01-10
1109 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1110 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1113 * Here are some standard date/time patterns that you might find helpful. They
1114 * are not part of the source of Date.js, but to use them you can simply copy this
1115 * block of code into any script that is included after Date.js and they will also become
1116 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1119 ISO8601Long:"Y-m-d H:i:s",
1120 ISO8601Short:"Y-m-d",
1122 LongDate: "l, F d, Y",
1123 FullDateTime: "l, F d, Y g:i:s A",
1126 LongTime: "g:i:s A",
1127 SortableDateTime: "Y-m-d\\TH:i:s",
1128 UniversalSortableDateTime: "Y-m-d H:i:sO",
1135 var dt = new Date();
1136 document.write(dt.format(Date.patterns.ShortDate));
1141 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1142 * They generate precompiled functions from date formats instead of parsing and
1143 * processing the pattern every time you format a date. These functions are available
1144 * on every Date object (any javascript function).
1146 * The original article and download are here:
1147 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1154 Returns the number of milliseconds between this date and date
1155 @param {Date} date (optional) Defaults to now
1156 @return {Number} The diff in milliseconds
1157 @member Date getElapsed
1159 Date.prototype.getElapsed = function(date) {
1160 return Math.abs((date || new Date()).getTime()-this.getTime());
1162 // was in date file..
1166 Date.parseFunctions = {count:0};
1168 Date.parseRegexes = [];
1170 Date.formatFunctions = {count:0};
1173 Date.prototype.dateFormat = function(format) {
1174 if (Date.formatFunctions[format] == null) {
1175 Date.createNewFormat(format);
1177 var func = Date.formatFunctions[format];
1178 return this[func]();
1183 * Formats a date given the supplied format string
1184 * @param {String} format The format string
1185 * @return {String} The formatted date
1188 Date.prototype.format = Date.prototype.dateFormat;
1191 Date.createNewFormat = function(format) {
1192 var funcName = "format" + Date.formatFunctions.count++;
1193 Date.formatFunctions[format] = funcName;
1194 var code = "Date.prototype." + funcName + " = function(){return ";
1195 var special = false;
1197 for (var i = 0; i < format.length; ++i) {
1198 ch = format.charAt(i);
1199 if (!special && ch == "\\") {
1204 code += "'" + String.escape(ch) + "' + ";
1207 code += Date.getFormatCode(ch);
1210 /** eval:var:zzzzzzzzzzzzz */
1211 eval(code.substring(0, code.length - 3) + ";}");
1215 Date.getFormatCode = function(character) {
1216 switch (character) {
1218 return "String.leftPad(this.getDate(), 2, '0') + ";
1220 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1222 return "this.getDate() + ";
1224 return "Date.dayNames[this.getDay()] + ";
1226 return "this.getSuffix() + ";
1228 return "this.getDay() + ";
1230 return "this.getDayOfYear() + ";
1232 return "this.getWeekOfYear() + ";
1234 return "Date.monthNames[this.getMonth()] + ";
1236 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1238 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1240 return "(this.getMonth() + 1) + ";
1242 return "this.getDaysInMonth() + ";
1244 return "(this.isLeapYear() ? 1 : 0) + ";
1246 return "this.getFullYear() + ";
1248 return "('' + this.getFullYear()).substring(2, 4) + ";
1250 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1252 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1254 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1256 return "this.getHours() + ";
1258 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1260 return "String.leftPad(this.getHours(), 2, '0') + ";
1262 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1264 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1266 return "this.getGMTOffset() + ";
1268 return "this.getGMTColonOffset() + ";
1270 return "this.getTimezone() + ";
1272 return "(this.getTimezoneOffset() * -60) + ";
1274 return "'" + String.escape(character) + "' + ";
1279 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1280 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1281 * the date format that is not specified will default to the current date value for that part. Time parts can also
1282 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1283 * string or the parse operation will fail.
1286 //dt = Fri May 25 2007 (current date)
1287 var dt = new Date();
1289 //dt = Thu May 25 2006 (today's month/day in 2006)
1290 dt = Date.parseDate("2006", "Y");
1292 //dt = Sun Jan 15 2006 (all date parts specified)
1293 dt = Date.parseDate("2006-1-15", "Y-m-d");
1295 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1296 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1298 * @param {String} input The unparsed date as a string
1299 * @param {String} format The format the date is in
1300 * @return {Date} The parsed date
1303 Date.parseDate = function(input, format) {
1304 if (Date.parseFunctions[format] == null) {
1305 Date.createParser(format);
1307 var func = Date.parseFunctions[format];
1308 return Date[func](input);
1314 Date.createParser = function(format) {
1315 var funcName = "parse" + Date.parseFunctions.count++;
1316 var regexNum = Date.parseRegexes.length;
1317 var currentGroup = 1;
1318 Date.parseFunctions[format] = funcName;
1320 var code = "Date." + funcName + " = function(input){\n"
1321 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1322 + "var d = new Date();\n"
1323 + "y = d.getFullYear();\n"
1324 + "m = d.getMonth();\n"
1325 + "d = d.getDate();\n"
1326 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1327 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1328 + "if (results && results.length > 0) {";
1331 var special = false;
1333 for (var i = 0; i < format.length; ++i) {
1334 ch = format.charAt(i);
1335 if (!special && ch == "\\") {
1340 regex += String.escape(ch);
1343 var obj = Date.formatCodeToRegex(ch, currentGroup);
1344 currentGroup += obj.g;
1346 if (obj.g && obj.c) {
1352 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1353 + "{v = new Date(y, m, d, h, i, s);}\n"
1354 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1355 + "{v = new Date(y, m, d, h, i);}\n"
1356 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1357 + "{v = new Date(y, m, d, h);}\n"
1358 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1359 + "{v = new Date(y, m, d);}\n"
1360 + "else if (y >= 0 && m >= 0)\n"
1361 + "{v = new Date(y, m);}\n"
1362 + "else if (y >= 0)\n"
1363 + "{v = new Date(y);}\n"
1364 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1365 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1366 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1369 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1370 /** eval:var:zzzzzzzzzzzzz */
1375 Date.formatCodeToRegex = function(character, currentGroup) {
1376 switch (character) {
1380 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1383 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1384 s:"(\\d{1,2})"}; // day of month without leading zeroes
1387 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1388 s:"(\\d{2})"}; // day of month with leading zeroes
1392 s:"(?:" + Date.dayNames.join("|") + ")"};
1396 s:"(?:st|nd|rd|th)"};
1411 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1412 s:"(" + Date.monthNames.join("|") + ")"};
1415 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1416 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1419 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1420 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1423 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1424 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1435 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1439 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1440 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1444 c:"if (results[" + currentGroup + "] == 'am') {\n"
1445 + "if (h == 12) { h = 0; }\n"
1446 + "} else { if (h < 12) { h += 12; }}",
1450 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1451 + "if (h == 12) { h = 0; }\n"
1452 + "} else { if (h < 12) { h += 12; }}",
1457 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1458 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1462 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1463 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1466 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1470 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1475 "o = results[", currentGroup, "];\n",
1476 "var sn = o.substring(0,1);\n", // get + / - sign
1477 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1478 "var mn = o.substring(3,5) % 60;\n", // get minutes
1479 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1480 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1482 s:"([+\-]\\d{2,4})"};
1488 "o = results[", currentGroup, "];\n",
1489 "var sn = o.substring(0,1);\n",
1490 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1491 "var mn = o.substring(4,6) % 60;\n",
1492 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1493 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1499 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1502 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1503 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1504 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1508 s:String.escape(character)};
1513 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1514 * @return {String} The abbreviated timezone name (e.g. 'CST')
1516 Date.prototype.getTimezone = function() {
1517 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1521 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1522 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1524 Date.prototype.getGMTOffset = function() {
1525 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1526 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1527 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1531 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1532 * @return {String} 2-characters representing hours and 2-characters representing minutes
1533 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1535 Date.prototype.getGMTColonOffset = function() {
1536 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1537 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1539 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1543 * Get the numeric day number of the year, adjusted for leap year.
1544 * @return {Number} 0 through 364 (365 in leap years)
1546 Date.prototype.getDayOfYear = function() {
1548 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1549 for (var i = 0; i < this.getMonth(); ++i) {
1550 num += Date.daysInMonth[i];
1552 return num + this.getDate() - 1;
1556 * Get the string representation of the numeric week number of the year
1557 * (equivalent to the format specifier 'W').
1558 * @return {String} '00' through '52'
1560 Date.prototype.getWeekOfYear = function() {
1561 // Skip to Thursday of this week
1562 var now = this.getDayOfYear() + (4 - this.getDay());
1563 // Find the first Thursday of the year
1564 var jan1 = new Date(this.getFullYear(), 0, 1);
1565 var then = (7 - jan1.getDay() + 4);
1566 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1570 * Whether or not the current date is in a leap year.
1571 * @return {Boolean} True if the current date is in a leap year, else false
1573 Date.prototype.isLeapYear = function() {
1574 var year = this.getFullYear();
1575 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1579 * Get the first day of the current month, adjusted for leap year. The returned value
1580 * is the numeric day index within the week (0-6) which can be used in conjunction with
1581 * the {@link #monthNames} array to retrieve the textual day name.
1584 var dt = new Date('1/10/2007');
1585 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1587 * @return {Number} The day number (0-6)
1589 Date.prototype.getFirstDayOfMonth = function() {
1590 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1591 return (day < 0) ? (day + 7) : day;
1595 * Get the last day of the current month, adjusted for leap year. The returned value
1596 * is the numeric day index within the week (0-6) which can be used in conjunction with
1597 * the {@link #monthNames} array to retrieve the textual day name.
1600 var dt = new Date('1/10/2007');
1601 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1603 * @return {Number} The day number (0-6)
1605 Date.prototype.getLastDayOfMonth = function() {
1606 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1607 return (day < 0) ? (day + 7) : day;
1612 * Get the first date of this date's month
1615 Date.prototype.getFirstDateOfMonth = function() {
1616 return new Date(this.getFullYear(), this.getMonth(), 1);
1620 * Get the last date of this date's month
1623 Date.prototype.getLastDateOfMonth = function() {
1624 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1627 * Get the number of days in the current month, adjusted for leap year.
1628 * @return {Number} The number of days in the month
1630 Date.prototype.getDaysInMonth = function() {
1631 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1632 return Date.daysInMonth[this.getMonth()];
1636 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1637 * @return {String} 'st, 'nd', 'rd' or 'th'
1639 Date.prototype.getSuffix = function() {
1640 switch (this.getDate()) {
1657 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1660 * An array of textual month names.
1661 * Override these values for international dates, for example...
1662 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1681 * An array of textual day names.
1682 * Override these values for international dates, for example...
1683 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1699 Date.monthNumbers = {
1714 * Creates and returns a new Date instance with the exact same date value as the called instance.
1715 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1716 * variable will also be changed. When the intention is to create a new variable that will not
1717 * modify the original instance, you should create a clone.
1719 * Example of correctly cloning a date:
1722 var orig = new Date('10/1/2006');
1725 document.write(orig); //returns 'Thu Oct 05 2006'!
1728 var orig = new Date('10/1/2006');
1729 var copy = orig.clone();
1731 document.write(orig); //returns 'Thu Oct 01 2006'
1733 * @return {Date} The new Date instance
1735 Date.prototype.clone = function() {
1736 return new Date(this.getTime());
1740 * Clears any time information from this date
1741 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1742 @return {Date} this or the clone
1744 Date.prototype.clearTime = function(clone){
1746 return this.clone().clearTime();
1751 this.setMilliseconds(0);
1756 // safari setMonth is broken -- check that this is only donw once...
1757 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1758 Date.brokenSetMonth = Date.prototype.setMonth;
1759 Date.prototype.setMonth = function(num){
1761 var n = Math.ceil(-num);
1762 var back_year = Math.ceil(n/12);
1763 var month = (n % 12) ? 12 - n % 12 : 0 ;
1764 this.setFullYear(this.getFullYear() - back_year);
1765 return Date.brokenSetMonth.call(this, month);
1767 return Date.brokenSetMonth.apply(this, arguments);
1772 /** Date interval constant
1776 /** Date interval constant
1780 /** Date interval constant
1784 /** Date interval constant
1788 /** Date interval constant
1792 /** Date interval constant
1796 /** Date interval constant
1802 * Provides a convenient method of performing basic date arithmetic. This method
1803 * does not modify the Date instance being called - it creates and returns
1804 * a new Date instance containing the resulting date value.
1809 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1810 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1812 //Negative values will subtract correctly:
1813 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1814 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1816 //You can even chain several calls together in one line!
1817 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1818 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1821 * @param {String} interval A valid date interval enum value
1822 * @param {Number} value The amount to add to the current date
1823 * @return {Date} The new Date instance
1825 Date.prototype.add = function(interval, value){
1826 var d = this.clone();
1827 if (!interval || value === 0) { return d; }
1828 switch(interval.toLowerCase()){
1830 d.setMilliseconds(this.getMilliseconds() + value);
1833 d.setSeconds(this.getSeconds() + value);
1836 d.setMinutes(this.getMinutes() + value);
1839 d.setHours(this.getHours() + value);
1842 d.setDate(this.getDate() + value);
1845 var day = this.getDate();
1847 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1850 d.setMonth(this.getMonth() + value);
1853 d.setFullYear(this.getFullYear() + value);
1860 * Ext JS Library 1.1.1
1861 * Copyright(c) 2006-2007, Ext JS, LLC.
1863 * Originally Released Under LGPL - original licence link has changed is not relivant.
1866 * <script type="text/javascript">
1870 * @class Roo.lib.Dom
1873 * Dom utils (from YIU afaik)
1878 * Get the view width
1879 * @param {Boolean} full True will get the full document, otherwise it's the view width
1880 * @return {Number} The width
1883 getViewWidth : function(full) {
1884 return full ? this.getDocumentWidth() : this.getViewportWidth();
1887 * Get the view height
1888 * @param {Boolean} full True will get the full document, otherwise it's the view height
1889 * @return {Number} The height
1891 getViewHeight : function(full) {
1892 return full ? this.getDocumentHeight() : this.getViewportHeight();
1895 getDocumentHeight: function() {
1896 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1897 return Math.max(scrollHeight, this.getViewportHeight());
1900 getDocumentWidth: function() {
1901 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1902 return Math.max(scrollWidth, this.getViewportWidth());
1905 getViewportHeight: function() {
1906 var height = self.innerHeight;
1907 var mode = document.compatMode;
1909 if ((mode || Roo.isIE) && !Roo.isOpera) {
1910 height = (mode == "CSS1Compat") ?
1911 document.documentElement.clientHeight :
1912 document.body.clientHeight;
1918 getViewportWidth: function() {
1919 var width = self.innerWidth;
1920 var mode = document.compatMode;
1922 if (mode || Roo.isIE) {
1923 width = (mode == "CSS1Compat") ?
1924 document.documentElement.clientWidth :
1925 document.body.clientWidth;
1930 isAncestor : function(p, c) {
1937 if (p.contains && !Roo.isSafari) {
1938 return p.contains(c);
1939 } else if (p.compareDocumentPosition) {
1940 return !!(p.compareDocumentPosition(c) & 16);
1942 var parent = c.parentNode;
1947 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1950 parent = parent.parentNode;
1956 getRegion : function(el) {
1957 return Roo.lib.Region.getRegion(el);
1960 getY : function(el) {
1961 return this.getXY(el)[1];
1964 getX : function(el) {
1965 return this.getXY(el)[0];
1968 getXY : function(el) {
1969 var p, pe, b, scroll, bd = document.body;
1970 el = Roo.getDom(el);
1971 var fly = Roo.lib.AnimBase.fly;
1972 if (el.getBoundingClientRect) {
1973 b = el.getBoundingClientRect();
1974 scroll = fly(document).getScroll();
1975 return [b.left + scroll.left, b.top + scroll.top];
1981 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1988 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1995 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1996 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2003 if (p != el && pe.getStyle('overflow') != 'visible') {
2011 if (Roo.isSafari && hasAbsolute) {
2016 if (Roo.isGecko && !hasAbsolute) {
2018 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2019 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2023 while (p && p != bd) {
2024 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2036 setXY : function(el, xy) {
2037 el = Roo.fly(el, '_setXY');
2039 var pts = el.translatePoints(xy);
2040 if (xy[0] !== false) {
2041 el.dom.style.left = pts.left + "px";
2043 if (xy[1] !== false) {
2044 el.dom.style.top = pts.top + "px";
2048 setX : function(el, x) {
2049 this.setXY(el, [x, false]);
2052 setY : function(el, y) {
2053 this.setXY(el, [false, y]);
2057 * Portions of this file are based on pieces of Yahoo User Interface Library
2058 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2059 * YUI licensed under the BSD License:
2060 * http://developer.yahoo.net/yui/license.txt
2061 * <script type="text/javascript">
2065 Roo.lib.Event = function() {
2066 var loadComplete = false;
2068 var unloadListeners = [];
2070 var onAvailStack = [];
2072 var lastError = null;
2085 startInterval: function() {
2086 if (!this._interval) {
2088 var callback = function() {
2089 self._tryPreloadAttach();
2091 this._interval = setInterval(callback, this.POLL_INTERVAL);
2096 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2097 onAvailStack.push({ id: p_id,
2100 override: p_override,
2101 checkReady: false });
2103 retryCount = this.POLL_RETRYS;
2104 this.startInterval();
2108 addListener: function(el, eventName, fn) {
2109 el = Roo.getDom(el);
2114 if ("unload" == eventName) {
2115 unloadListeners[unloadListeners.length] =
2116 [el, eventName, fn];
2120 var wrappedFn = function(e) {
2121 return fn(Roo.lib.Event.getEvent(e));
2124 var li = [el, eventName, fn, wrappedFn];
2126 var index = listeners.length;
2127 listeners[index] = li;
2129 this.doAdd(el, eventName, wrappedFn, false);
2135 removeListener: function(el, eventName, fn) {
2138 el = Roo.getDom(el);
2141 return this.purgeElement(el, false, eventName);
2145 if ("unload" == eventName) {
2147 for (i = 0,len = unloadListeners.length; i < len; i++) {
2148 var li = unloadListeners[i];
2151 li[1] == eventName &&
2153 unloadListeners.splice(i, 1);
2161 var cacheItem = null;
2164 var index = arguments[3];
2166 if ("undefined" == typeof index) {
2167 index = this._getCacheIndex(el, eventName, fn);
2171 cacheItem = listeners[index];
2174 if (!el || !cacheItem) {
2178 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2180 delete listeners[index][this.WFN];
2181 delete listeners[index][this.FN];
2182 listeners.splice(index, 1);
2189 getTarget: function(ev, resolveTextNode) {
2190 ev = ev.browserEvent || ev;
2191 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2192 var t = ev.target || ev.srcElement;
2193 return this.resolveTextNode(t);
2197 resolveTextNode: function(node) {
2198 if (Roo.isSafari && node && 3 == node.nodeType) {
2199 return node.parentNode;
2206 getPageX: function(ev) {
2207 ev = ev.browserEvent || ev;
2208 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2210 if (!x && 0 !== x) {
2211 x = ev.clientX || 0;
2214 x += this.getScroll()[1];
2222 getPageY: function(ev) {
2223 ev = ev.browserEvent || ev;
2224 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2226 if (!y && 0 !== y) {
2227 y = ev.clientY || 0;
2230 y += this.getScroll()[0];
2239 getXY: function(ev) {
2240 ev = ev.browserEvent || ev;
2241 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2242 return [this.getPageX(ev), this.getPageY(ev)];
2246 getRelatedTarget: function(ev) {
2247 ev = ev.browserEvent || ev;
2248 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2249 var t = ev.relatedTarget;
2251 if (ev.type == "mouseout") {
2253 } else if (ev.type == "mouseover") {
2258 return this.resolveTextNode(t);
2262 getTime: function(ev) {
2263 ev = ev.browserEvent || ev;
2264 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2266 var t = new Date().getTime();
2270 this.lastError = ex;
2279 stopEvent: function(ev) {
2280 this.stopPropagation(ev);
2281 this.preventDefault(ev);
2285 stopPropagation: function(ev) {
2286 ev = ev.browserEvent || ev;
2287 if (ev.stopPropagation) {
2288 ev.stopPropagation();
2290 ev.cancelBubble = true;
2295 preventDefault: function(ev) {
2296 ev = ev.browserEvent || ev;
2297 if(ev.preventDefault) {
2298 ev.preventDefault();
2300 ev.returnValue = false;
2305 getEvent: function(e) {
2306 var ev = e || window.event;
2308 var c = this.getEvent.caller;
2310 ev = c.arguments[0];
2311 if (ev && Event == ev.constructor) {
2321 getCharCode: function(ev) {
2322 ev = ev.browserEvent || ev;
2323 return ev.charCode || ev.keyCode || 0;
2327 _getCacheIndex: function(el, eventName, fn) {
2328 for (var i = 0,len = listeners.length; i < len; ++i) {
2329 var li = listeners[i];
2331 li[this.FN] == fn &&
2332 li[this.EL] == el &&
2333 li[this.TYPE] == eventName) {
2345 getEl: function(id) {
2346 return document.getElementById(id);
2350 clearCache: function() {
2354 _load: function(e) {
2355 loadComplete = true;
2356 var EU = Roo.lib.Event;
2360 EU.doRemove(window, "load", EU._load);
2365 _tryPreloadAttach: function() {
2374 var tryAgain = !loadComplete;
2376 tryAgain = (retryCount > 0);
2381 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2382 var item = onAvailStack[i];
2384 var el = this.getEl(item.id);
2387 if (!item.checkReady ||
2390 (document && document.body)) {
2393 if (item.override) {
2394 if (item.override === true) {
2397 scope = item.override;
2400 item.fn.call(scope, item.obj);
2401 onAvailStack[i] = null;
2404 notAvail.push(item);
2409 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2413 this.startInterval();
2415 clearInterval(this._interval);
2416 this._interval = null;
2419 this.locked = false;
2426 purgeElement: function(el, recurse, eventName) {
2427 var elListeners = this.getListeners(el, eventName);
2429 for (var i = 0,len = elListeners.length; i < len; ++i) {
2430 var l = elListeners[i];
2431 this.removeListener(el, l.type, l.fn);
2435 if (recurse && el && el.childNodes) {
2436 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2437 this.purgeElement(el.childNodes[i], recurse, eventName);
2443 getListeners: function(el, eventName) {
2444 var results = [], searchLists;
2446 searchLists = [listeners, unloadListeners];
2447 } else if (eventName == "unload") {
2448 searchLists = [unloadListeners];
2450 searchLists = [listeners];
2453 for (var j = 0; j < searchLists.length; ++j) {
2454 var searchList = searchLists[j];
2455 if (searchList && searchList.length > 0) {
2456 for (var i = 0,len = searchList.length; i < len; ++i) {
2457 var l = searchList[i];
2458 if (l && l[this.EL] === el &&
2459 (!eventName || eventName === l[this.TYPE])) {
2464 adjust: l[this.ADJ_SCOPE],
2472 return (results.length) ? results : null;
2476 _unload: function(e) {
2478 var EU = Roo.lib.Event, i, j, l, len, index;
2480 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2481 l = unloadListeners[i];
2484 if (l[EU.ADJ_SCOPE]) {
2485 if (l[EU.ADJ_SCOPE] === true) {
2488 scope = l[EU.ADJ_SCOPE];
2491 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2492 unloadListeners[i] = null;
2498 unloadListeners = null;
2500 if (listeners && listeners.length > 0) {
2501 j = listeners.length;
2504 l = listeners[index];
2506 EU.removeListener(l[EU.EL], l[EU.TYPE],
2516 EU.doRemove(window, "unload", EU._unload);
2521 getScroll: function() {
2522 var dd = document.documentElement, db = document.body;
2523 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2524 return [dd.scrollTop, dd.scrollLeft];
2526 return [db.scrollTop, db.scrollLeft];
2533 doAdd: function () {
2534 if (window.addEventListener) {
2535 return function(el, eventName, fn, capture) {
2536 el.addEventListener(eventName, fn, (capture));
2538 } else if (window.attachEvent) {
2539 return function(el, eventName, fn, capture) {
2540 el.attachEvent("on" + eventName, fn);
2549 doRemove: function() {
2550 if (window.removeEventListener) {
2551 return function (el, eventName, fn, capture) {
2552 el.removeEventListener(eventName, fn, (capture));
2554 } else if (window.detachEvent) {
2555 return function (el, eventName, fn) {
2556 el.detachEvent("on" + eventName, fn);
2568 var E = Roo.lib.Event;
2569 E.on = E.addListener;
2570 E.un = E.removeListener;
2572 if (document && document.body) {
2575 E.doAdd(window, "load", E._load);
2577 E.doAdd(window, "unload", E._unload);
2578 E._tryPreloadAttach();
2582 * Portions of this file are based on pieces of Yahoo User Interface Library
2583 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2584 * YUI licensed under the BSD License:
2585 * http://developer.yahoo.net/yui/license.txt
2586 * <script type="text/javascript">
2592 * @class Roo.lib.Ajax
2599 request : function(method, uri, cb, data, options) {
2601 var hs = options.headers;
2604 if(hs.hasOwnProperty(h)){
2605 this.initHeader(h, hs[h], false);
2609 if(options.xmlData){
2610 this.initHeader('Content-Type', 'text/xml', false);
2612 data = options.xmlData;
2616 return this.asyncRequest(method, uri, cb, data);
2619 serializeForm : function(form) {
2620 if(typeof form == 'string') {
2621 form = (document.getElementById(form) || document.forms[form]);
2624 var el, name, val, disabled, data = '', hasSubmit = false;
2625 for (var i = 0; i < form.elements.length; i++) {
2626 el = form.elements[i];
2627 disabled = form.elements[i].disabled;
2628 name = form.elements[i].name;
2629 val = form.elements[i].value;
2631 if (!disabled && name){
2635 case 'select-multiple':
2636 for (var j = 0; j < el.options.length; j++) {
2637 if (el.options[j].selected) {
2639 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2642 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2650 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2663 if(hasSubmit == false) {
2664 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2669 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2674 data = data.substr(0, data.length - 1);
2682 useDefaultHeader:true,
2684 defaultPostHeader:'application/x-www-form-urlencoded',
2686 useDefaultXhrHeader:true,
2688 defaultXhrHeader:'XMLHttpRequest',
2690 hasDefaultHeaders:true,
2702 setProgId:function(id)
2704 this.activeX.unshift(id);
2707 setDefaultPostHeader:function(b)
2709 this.useDefaultHeader = b;
2712 setDefaultXhrHeader:function(b)
2714 this.useDefaultXhrHeader = b;
2717 setPollingInterval:function(i)
2719 if (typeof i == 'number' && isFinite(i)) {
2720 this.pollInterval = i;
2724 createXhrObject:function(transactionId)
2730 http = new XMLHttpRequest();
2732 obj = { conn:http, tId:transactionId };
2736 for (var i = 0; i < this.activeX.length; ++i) {
2740 http = new ActiveXObject(this.activeX[i]);
2742 obj = { conn:http, tId:transactionId };
2755 getConnectionObject:function()
2758 var tId = this.transactionId;
2762 o = this.createXhrObject(tId);
2764 this.transactionId++;
2775 asyncRequest:function(method, uri, callback, postData)
2777 var o = this.getConnectionObject();
2783 o.conn.open(method, uri, true);
2785 if (this.useDefaultXhrHeader) {
2786 if (!this.defaultHeaders['X-Requested-With']) {
2787 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2791 if(postData && this.useDefaultHeader){
2792 this.initHeader('Content-Type', this.defaultPostHeader);
2795 if (this.hasDefaultHeaders || this.hasHeaders) {
2799 this.handleReadyState(o, callback);
2800 o.conn.send(postData || null);
2806 handleReadyState:function(o, callback)
2810 if (callback && callback.timeout) {
2812 this.timeout[o.tId] = window.setTimeout(function() {
2813 oConn.abort(o, callback, true);
2814 }, callback.timeout);
2817 this.poll[o.tId] = window.setInterval(
2819 if (o.conn && o.conn.readyState == 4) {
2820 window.clearInterval(oConn.poll[o.tId]);
2821 delete oConn.poll[o.tId];
2823 if(callback && callback.timeout) {
2824 window.clearTimeout(oConn.timeout[o.tId]);
2825 delete oConn.timeout[o.tId];
2828 oConn.handleTransactionResponse(o, callback);
2831 , this.pollInterval);
2834 handleTransactionResponse:function(o, callback, isAbort)
2838 this.releaseObject(o);
2842 var httpStatus, responseObject;
2846 if (o.conn.status !== undefined && o.conn.status != 0) {
2847 httpStatus = o.conn.status;
2859 if (httpStatus >= 200 && httpStatus < 300) {
2860 responseObject = this.createResponseObject(o, callback.argument);
2861 if (callback.success) {
2862 if (!callback.scope) {
2863 callback.success(responseObject);
2868 callback.success.apply(callback.scope, [responseObject]);
2873 switch (httpStatus) {
2881 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2882 if (callback.failure) {
2883 if (!callback.scope) {
2884 callback.failure(responseObject);
2887 callback.failure.apply(callback.scope, [responseObject]);
2892 responseObject = this.createResponseObject(o, callback.argument);
2893 if (callback.failure) {
2894 if (!callback.scope) {
2895 callback.failure(responseObject);
2898 callback.failure.apply(callback.scope, [responseObject]);
2904 this.releaseObject(o);
2905 responseObject = null;
2908 createResponseObject:function(o, callbackArg)
2915 var headerStr = o.conn.getAllResponseHeaders();
2916 var header = headerStr.split('\n');
2917 for (var i = 0; i < header.length; i++) {
2918 var delimitPos = header[i].indexOf(':');
2919 if (delimitPos != -1) {
2920 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2928 obj.status = o.conn.status;
2929 obj.statusText = o.conn.statusText;
2930 obj.getResponseHeader = headerObj;
2931 obj.getAllResponseHeaders = headerStr;
2932 obj.responseText = o.conn.responseText;
2933 obj.responseXML = o.conn.responseXML;
2935 if (typeof callbackArg !== undefined) {
2936 obj.argument = callbackArg;
2942 createExceptionObject:function(tId, callbackArg, isAbort)
2945 var COMM_ERROR = 'communication failure';
2946 var ABORT_CODE = -1;
2947 var ABORT_ERROR = 'transaction aborted';
2953 obj.status = ABORT_CODE;
2954 obj.statusText = ABORT_ERROR;
2957 obj.status = COMM_CODE;
2958 obj.statusText = COMM_ERROR;
2962 obj.argument = callbackArg;
2968 initHeader:function(label, value, isDefault)
2970 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2972 if (headerObj[label] === undefined) {
2973 headerObj[label] = value;
2978 headerObj[label] = value + "," + headerObj[label];
2982 this.hasDefaultHeaders = true;
2985 this.hasHeaders = true;
2990 setHeader:function(o)
2992 if (this.hasDefaultHeaders) {
2993 for (var prop in this.defaultHeaders) {
2994 if (this.defaultHeaders.hasOwnProperty(prop)) {
2995 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3000 if (this.hasHeaders) {
3001 for (var prop in this.headers) {
3002 if (this.headers.hasOwnProperty(prop)) {
3003 o.conn.setRequestHeader(prop, this.headers[prop]);
3007 this.hasHeaders = false;
3011 resetDefaultHeaders:function() {
3012 delete this.defaultHeaders;
3013 this.defaultHeaders = {};
3014 this.hasDefaultHeaders = false;
3017 abort:function(o, callback, isTimeout)
3019 if(this.isCallInProgress(o)) {
3021 window.clearInterval(this.poll[o.tId]);
3022 delete this.poll[o.tId];
3024 delete this.timeout[o.tId];
3027 this.handleTransactionResponse(o, callback, true);
3037 isCallInProgress:function(o)
3040 return o.conn.readyState != 4 && o.conn.readyState != 0;
3049 releaseObject:function(o)
3058 'MSXML2.XMLHTTP.3.0',
3066 * Portions of this file are based on pieces of Yahoo User Interface Library
3067 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3068 * YUI licensed under the BSD License:
3069 * http://developer.yahoo.net/yui/license.txt
3070 * <script type="text/javascript">
3074 Roo.lib.Region = function(t, r, b, l) {
3084 Roo.lib.Region.prototype = {
3085 contains : function(region) {
3086 return ( region.left >= this.left &&
3087 region.right <= this.right &&
3088 region.top >= this.top &&
3089 region.bottom <= this.bottom );
3093 getArea : function() {
3094 return ( (this.bottom - this.top) * (this.right - this.left) );
3097 intersect : function(region) {
3098 var t = Math.max(this.top, region.top);
3099 var r = Math.min(this.right, region.right);
3100 var b = Math.min(this.bottom, region.bottom);
3101 var l = Math.max(this.left, region.left);
3103 if (b >= t && r >= l) {
3104 return new Roo.lib.Region(t, r, b, l);
3109 union : function(region) {
3110 var t = Math.min(this.top, region.top);
3111 var r = Math.max(this.right, region.right);
3112 var b = Math.max(this.bottom, region.bottom);
3113 var l = Math.min(this.left, region.left);
3115 return new Roo.lib.Region(t, r, b, l);
3118 adjust : function(t, l, b, r) {
3127 Roo.lib.Region.getRegion = function(el) {
3128 var p = Roo.lib.Dom.getXY(el);
3131 var r = p[0] + el.offsetWidth;
3132 var b = p[1] + el.offsetHeight;
3135 return new Roo.lib.Region(t, r, b, l);
3138 * Portions of this file are based on pieces of Yahoo User Interface Library
3139 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3140 * YUI licensed under the BSD License:
3141 * http://developer.yahoo.net/yui/license.txt
3142 * <script type="text/javascript">
3145 //@@dep Roo.lib.Region
3148 Roo.lib.Point = function(x, y) {
3149 if (x instanceof Array) {
3153 this.x = this.right = this.left = this[0] = x;
3154 this.y = this.top = this.bottom = this[1] = y;
3157 Roo.lib.Point.prototype = new Roo.lib.Region();
3159 * Portions of this file are based on pieces of Yahoo User Interface Library
3160 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3161 * YUI licensed under the BSD License:
3162 * http://developer.yahoo.net/yui/license.txt
3163 * <script type="text/javascript">
3170 scroll : function(el, args, duration, easing, cb, scope) {
3171 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3174 motion : function(el, args, duration, easing, cb, scope) {
3175 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3178 color : function(el, args, duration, easing, cb, scope) {
3179 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3182 run : function(el, args, duration, easing, cb, scope, type) {
3183 type = type || Roo.lib.AnimBase;
3184 if (typeof easing == "string") {
3185 easing = Roo.lib.Easing[easing];
3187 var anim = new type(el, args, duration, easing);
3188 anim.animateX(function() {
3189 Roo.callback(cb, scope);
3195 * Portions of this file are based on pieces of Yahoo User Interface Library
3196 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3197 * YUI licensed under the BSD License:
3198 * http://developer.yahoo.net/yui/license.txt
3199 * <script type="text/javascript">
3207 if (!libFlyweight) {
3208 libFlyweight = new Roo.Element.Flyweight();
3210 libFlyweight.dom = el;
3211 return libFlyweight;
3214 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3218 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3220 this.init(el, attributes, duration, method);
3224 Roo.lib.AnimBase.fly = fly;
3228 Roo.lib.AnimBase.prototype = {
3230 toString: function() {
3231 var el = this.getEl();
3232 var id = el.id || el.tagName;
3233 return ("Anim " + id);
3237 noNegatives: /width|height|opacity|padding/i,
3238 offsetAttribute: /^((width|height)|(top|left))$/,
3239 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3240 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3244 doMethod: function(attr, start, end) {
3245 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3249 setAttribute: function(attr, val, unit) {
3250 if (this.patterns.noNegatives.test(attr)) {
3251 val = (val > 0) ? val : 0;
3254 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3258 getAttribute: function(attr) {
3259 var el = this.getEl();
3260 var val = fly(el).getStyle(attr);
3262 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3263 return parseFloat(val);
3266 var a = this.patterns.offsetAttribute.exec(attr) || [];
3267 var pos = !!( a[3] );
3268 var box = !!( a[2] );
3271 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3272 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3281 getDefaultUnit: function(attr) {
3282 if (this.patterns.defaultUnit.test(attr)) {
3289 animateX : function(callback, scope) {
3290 var f = function() {
3291 this.onComplete.removeListener(f);
3292 if (typeof callback == "function") {
3293 callback.call(scope || this, this);
3296 this.onComplete.addListener(f, this);
3301 setRuntimeAttribute: function(attr) {
3304 var attributes = this.attributes;
3306 this.runtimeAttributes[attr] = {};
3308 var isset = function(prop) {
3309 return (typeof prop !== 'undefined');
3312 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3316 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3319 if (isset(attributes[attr]['to'])) {
3320 end = attributes[attr]['to'];
3321 } else if (isset(attributes[attr]['by'])) {
3322 if (start.constructor == Array) {
3324 for (var i = 0, len = start.length; i < len; ++i) {
3325 end[i] = start[i] + attributes[attr]['by'][i];
3328 end = start + attributes[attr]['by'];
3332 this.runtimeAttributes[attr].start = start;
3333 this.runtimeAttributes[attr].end = end;
3336 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3340 init: function(el, attributes, duration, method) {
3342 var isAnimated = false;
3345 var startTime = null;
3348 var actualFrames = 0;
3351 el = Roo.getDom(el);
3354 this.attributes = attributes || {};
3357 this.duration = duration || 1;
3360 this.method = method || Roo.lib.Easing.easeNone;
3363 this.useSeconds = true;
3366 this.currentFrame = 0;
3369 this.totalFrames = Roo.lib.AnimMgr.fps;
3372 this.getEl = function() {
3377 this.isAnimated = function() {
3382 this.getStartTime = function() {
3386 this.runtimeAttributes = {};
3389 this.animate = function() {
3390 if (this.isAnimated()) {
3394 this.currentFrame = 0;
3396 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3398 Roo.lib.AnimMgr.registerElement(this);
3402 this.stop = function(finish) {
3404 this.currentFrame = this.totalFrames;
3405 this._onTween.fire();
3407 Roo.lib.AnimMgr.stop(this);
3410 var onStart = function() {
3411 this.onStart.fire();
3413 this.runtimeAttributes = {};
3414 for (var attr in this.attributes) {
3415 this.setRuntimeAttribute(attr);
3420 startTime = new Date();
3424 var onTween = function() {
3426 duration: new Date() - this.getStartTime(),
3427 currentFrame: this.currentFrame
3430 data.toString = function() {
3432 'duration: ' + data.duration +
3433 ', currentFrame: ' + data.currentFrame
3437 this.onTween.fire(data);
3439 var runtimeAttributes = this.runtimeAttributes;
3441 for (var attr in runtimeAttributes) {
3442 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3448 var onComplete = function() {
3449 var actual_duration = (new Date() - startTime) / 1000 ;
3452 duration: actual_duration,
3453 frames: actualFrames,
3454 fps: actualFrames / actual_duration
3457 data.toString = function() {
3459 'duration: ' + data.duration +
3460 ', frames: ' + data.frames +
3461 ', fps: ' + data.fps
3467 this.onComplete.fire(data);
3471 this._onStart = new Roo.util.Event(this);
3472 this.onStart = new Roo.util.Event(this);
3473 this.onTween = new Roo.util.Event(this);
3474 this._onTween = new Roo.util.Event(this);
3475 this.onComplete = new Roo.util.Event(this);
3476 this._onComplete = new Roo.util.Event(this);
3477 this._onStart.addListener(onStart);
3478 this._onTween.addListener(onTween);
3479 this._onComplete.addListener(onComplete);
3484 * Portions of this file are based on pieces of Yahoo User Interface Library
3485 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3486 * YUI licensed under the BSD License:
3487 * http://developer.yahoo.net/yui/license.txt
3488 * <script type="text/javascript">
3492 Roo.lib.AnimMgr = new function() {
3509 this.registerElement = function(tween) {
3510 queue[queue.length] = tween;
3512 tween._onStart.fire();
3517 this.unRegister = function(tween, index) {
3518 tween._onComplete.fire();
3519 index = index || getIndex(tween);
3521 queue.splice(index, 1);
3525 if (tweenCount <= 0) {
3531 this.start = function() {
3532 if (thread === null) {
3533 thread = setInterval(this.run, this.delay);
3538 this.stop = function(tween) {
3540 clearInterval(thread);
3542 for (var i = 0, len = queue.length; i < len; ++i) {
3543 if (queue[0].isAnimated()) {
3544 this.unRegister(queue[0], 0);
3553 this.unRegister(tween);
3558 this.run = function() {
3559 for (var i = 0, len = queue.length; i < len; ++i) {
3560 var tween = queue[i];
3561 if (!tween || !tween.isAnimated()) {
3565 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3567 tween.currentFrame += 1;
3569 if (tween.useSeconds) {
3570 correctFrame(tween);
3572 tween._onTween.fire();
3575 Roo.lib.AnimMgr.stop(tween, i);
3580 var getIndex = function(anim) {
3581 for (var i = 0, len = queue.length; i < len; ++i) {
3582 if (queue[i] == anim) {
3590 var correctFrame = function(tween) {
3591 var frames = tween.totalFrames;
3592 var frame = tween.currentFrame;
3593 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3594 var elapsed = (new Date() - tween.getStartTime());
3597 if (elapsed < tween.duration * 1000) {
3598 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3600 tweak = frames - (frame + 1);
3602 if (tweak > 0 && isFinite(tweak)) {
3603 if (tween.currentFrame + tweak >= frames) {
3604 tweak = frames - (frame + 1);
3607 tween.currentFrame += tweak;
3613 * Portions of this file are based on pieces of Yahoo User Interface Library
3614 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3615 * YUI licensed under the BSD License:
3616 * http://developer.yahoo.net/yui/license.txt
3617 * <script type="text/javascript">
3620 Roo.lib.Bezier = new function() {
3622 this.getPosition = function(points, t) {
3623 var n = points.length;
3626 for (var i = 0; i < n; ++i) {
3627 tmp[i] = [points[i][0], points[i][1]];
3630 for (var j = 1; j < n; ++j) {
3631 for (i = 0; i < n - j; ++i) {
3632 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3633 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3637 return [ tmp[0][0], tmp[0][1] ];
3641 * Portions of this file are based on pieces of Yahoo User Interface Library
3642 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3643 * YUI licensed under the BSD License:
3644 * http://developer.yahoo.net/yui/license.txt
3645 * <script type="text/javascript">
3650 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3651 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3654 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3656 var fly = Roo.lib.AnimBase.fly;
3658 var superclass = Y.ColorAnim.superclass;
3659 var proto = Y.ColorAnim.prototype;
3661 proto.toString = function() {
3662 var el = this.getEl();
3663 var id = el.id || el.tagName;
3664 return ("ColorAnim " + id);
3667 proto.patterns.color = /color$/i;
3668 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3669 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3670 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3671 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3674 proto.parseColor = function(s) {
3675 if (s.length == 3) {
3679 var c = this.patterns.hex.exec(s);
3680 if (c && c.length == 4) {
3681 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3684 c = this.patterns.rgb.exec(s);
3685 if (c && c.length == 4) {
3686 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3689 c = this.patterns.hex3.exec(s);
3690 if (c && c.length == 4) {
3691 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3696 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3697 proto.getAttribute = function(attr) {
3698 var el = this.getEl();
3699 if (this.patterns.color.test(attr)) {
3700 var val = fly(el).getStyle(attr);
3702 if (this.patterns.transparent.test(val)) {
3703 var parent = el.parentNode;
3704 val = fly(parent).getStyle(attr);
3706 while (parent && this.patterns.transparent.test(val)) {
3707 parent = parent.parentNode;
3708 val = fly(parent).getStyle(attr);
3709 if (parent.tagName.toUpperCase() == 'HTML') {
3715 val = superclass.getAttribute.call(this, attr);
3720 proto.getAttribute = function(attr) {
3721 var el = this.getEl();
3722 if (this.patterns.color.test(attr)) {
3723 var val = fly(el).getStyle(attr);
3725 if (this.patterns.transparent.test(val)) {
3726 var parent = el.parentNode;
3727 val = fly(parent).getStyle(attr);
3729 while (parent && this.patterns.transparent.test(val)) {
3730 parent = parent.parentNode;
3731 val = fly(parent).getStyle(attr);
3732 if (parent.tagName.toUpperCase() == 'HTML') {
3738 val = superclass.getAttribute.call(this, attr);
3744 proto.doMethod = function(attr, start, end) {
3747 if (this.patterns.color.test(attr)) {
3749 for (var i = 0, len = start.length; i < len; ++i) {
3750 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3753 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3756 val = superclass.doMethod.call(this, attr, start, end);
3762 proto.setRuntimeAttribute = function(attr) {
3763 superclass.setRuntimeAttribute.call(this, attr);
3765 if (this.patterns.color.test(attr)) {
3766 var attributes = this.attributes;
3767 var start = this.parseColor(this.runtimeAttributes[attr].start);
3768 var end = this.parseColor(this.runtimeAttributes[attr].end);
3770 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3771 end = this.parseColor(attributes[attr].by);
3773 for (var i = 0, len = start.length; i < len; ++i) {
3774 end[i] = start[i] + end[i];
3778 this.runtimeAttributes[attr].start = start;
3779 this.runtimeAttributes[attr].end = end;
3785 * Portions of this file are based on pieces of Yahoo User Interface Library
3786 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3787 * YUI licensed under the BSD License:
3788 * http://developer.yahoo.net/yui/license.txt
3789 * <script type="text/javascript">
3795 easeNone: function (t, b, c, d) {
3796 return c * t / d + b;
3800 easeIn: function (t, b, c, d) {
3801 return c * (t /= d) * t + b;
3805 easeOut: function (t, b, c, d) {
3806 return -c * (t /= d) * (t - 2) + b;
3810 easeBoth: function (t, b, c, d) {
3811 if ((t /= d / 2) < 1) {
3812 return c / 2 * t * t + b;
3815 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3819 easeInStrong: function (t, b, c, d) {
3820 return c * (t /= d) * t * t * t + b;
3824 easeOutStrong: function (t, b, c, d) {
3825 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3829 easeBothStrong: function (t, b, c, d) {
3830 if ((t /= d / 2) < 1) {
3831 return c / 2 * t * t * t * t + b;
3834 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3839 elasticIn: function (t, b, c, d, a, p) {
3843 if ((t /= d) == 1) {
3850 if (!a || a < Math.abs(c)) {
3855 var s = p / (2 * Math.PI) * Math.asin(c / a);
3858 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3862 elasticOut: function (t, b, c, d, a, p) {
3866 if ((t /= d) == 1) {
3873 if (!a || a < Math.abs(c)) {
3878 var s = p / (2 * Math.PI) * Math.asin(c / a);
3881 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3885 elasticBoth: function (t, b, c, d, a, p) {
3890 if ((t /= d / 2) == 2) {
3898 if (!a || a < Math.abs(c)) {
3903 var s = p / (2 * Math.PI) * Math.asin(c / a);
3907 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3908 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3910 return a * Math.pow(2, -10 * (t -= 1)) *
3911 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3916 backIn: function (t, b, c, d, s) {
3917 if (typeof s == 'undefined') {
3920 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3924 backOut: function (t, b, c, d, s) {
3925 if (typeof s == 'undefined') {
3928 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3932 backBoth: function (t, b, c, d, s) {
3933 if (typeof s == 'undefined') {
3937 if ((t /= d / 2 ) < 1) {
3938 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3940 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3944 bounceIn: function (t, b, c, d) {
3945 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3949 bounceOut: function (t, b, c, d) {
3950 if ((t /= d) < (1 / 2.75)) {
3951 return c * (7.5625 * t * t) + b;
3952 } else if (t < (2 / 2.75)) {
3953 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3954 } else if (t < (2.5 / 2.75)) {
3955 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3957 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3961 bounceBoth: function (t, b, c, d) {
3963 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3965 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3968 * Portions of this file are based on pieces of Yahoo User Interface Library
3969 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3970 * YUI licensed under the BSD License:
3971 * http://developer.yahoo.net/yui/license.txt
3972 * <script type="text/javascript">
3976 Roo.lib.Motion = function(el, attributes, duration, method) {
3978 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3982 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3986 var superclass = Y.Motion.superclass;
3987 var proto = Y.Motion.prototype;
3989 proto.toString = function() {
3990 var el = this.getEl();
3991 var id = el.id || el.tagName;
3992 return ("Motion " + id);
3995 proto.patterns.points = /^points$/i;
3997 proto.setAttribute = function(attr, val, unit) {
3998 if (this.patterns.points.test(attr)) {
3999 unit = unit || 'px';
4000 superclass.setAttribute.call(this, 'left', val[0], unit);
4001 superclass.setAttribute.call(this, 'top', val[1], unit);
4003 superclass.setAttribute.call(this, attr, val, unit);
4007 proto.getAttribute = function(attr) {
4008 if (this.patterns.points.test(attr)) {
4010 superclass.getAttribute.call(this, 'left'),
4011 superclass.getAttribute.call(this, 'top')
4014 val = superclass.getAttribute.call(this, attr);
4020 proto.doMethod = function(attr, start, end) {
4023 if (this.patterns.points.test(attr)) {
4024 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4025 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4027 val = superclass.doMethod.call(this, attr, start, end);
4032 proto.setRuntimeAttribute = function(attr) {
4033 if (this.patterns.points.test(attr)) {
4034 var el = this.getEl();
4035 var attributes = this.attributes;
4037 var control = attributes['points']['control'] || [];
4041 if (control.length > 0 && !(control[0] instanceof Array)) {
4042 control = [control];
4045 for (i = 0,len = control.length; i < len; ++i) {
4046 tmp[i] = control[i];
4051 Roo.fly(el).position();
4053 if (isset(attributes['points']['from'])) {
4054 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4057 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4060 start = this.getAttribute('points');
4063 if (isset(attributes['points']['to'])) {
4064 end = translateValues.call(this, attributes['points']['to'], start);
4066 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4067 for (i = 0,len = control.length; i < len; ++i) {
4068 control[i] = translateValues.call(this, control[i], start);
4072 } else if (isset(attributes['points']['by'])) {
4073 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4075 for (i = 0,len = control.length; i < len; ++i) {
4076 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4080 this.runtimeAttributes[attr] = [start];
4082 if (control.length > 0) {
4083 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4086 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4089 superclass.setRuntimeAttribute.call(this, attr);
4093 var translateValues = function(val, start) {
4094 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4095 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4100 var isset = function(prop) {
4101 return (typeof prop !== 'undefined');
4105 * Portions of this file are based on pieces of Yahoo User Interface Library
4106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4107 * YUI licensed under the BSD License:
4108 * http://developer.yahoo.net/yui/license.txt
4109 * <script type="text/javascript">
4113 Roo.lib.Scroll = function(el, attributes, duration, method) {
4115 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4119 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4123 var superclass = Y.Scroll.superclass;
4124 var proto = Y.Scroll.prototype;
4126 proto.toString = function() {
4127 var el = this.getEl();
4128 var id = el.id || el.tagName;
4129 return ("Scroll " + id);
4132 proto.doMethod = function(attr, start, end) {
4135 if (attr == 'scroll') {
4137 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4138 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4142 val = superclass.doMethod.call(this, attr, start, end);
4147 proto.getAttribute = function(attr) {
4149 var el = this.getEl();
4151 if (attr == 'scroll') {
4152 val = [ el.scrollLeft, el.scrollTop ];
4154 val = superclass.getAttribute.call(this, attr);
4160 proto.setAttribute = function(attr, val, unit) {
4161 var el = this.getEl();
4163 if (attr == 'scroll') {
4164 el.scrollLeft = val[0];
4165 el.scrollTop = val[1];
4167 superclass.setAttribute.call(this, attr, val, unit);
4173 * Ext JS Library 1.1.1
4174 * Copyright(c) 2006-2007, Ext JS, LLC.
4176 * Originally Released Under LGPL - original licence link has changed is not relivant.
4179 * <script type="text/javascript">
4183 // nasty IE9 hack - what a pile of crap that is..
4185 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4186 Range.prototype.createContextualFragment = function (html) {
4187 var doc = window.document;
4188 var container = doc.createElement("div");
4189 container.innerHTML = html;
4190 var frag = doc.createDocumentFragment(), n;
4191 while ((n = container.firstChild)) {
4192 frag.appendChild(n);
4199 * @class Roo.DomHelper
4200 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4201 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4204 Roo.DomHelper = function(){
4205 var tempTableEl = null;
4206 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4207 var tableRe = /^table|tbody|tr|td$/i;
4209 // build as innerHTML where available
4211 var createHtml = function(o){
4212 if(typeof o == 'string'){
4221 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4222 if(attr == "style"){
4224 if(typeof s == "function"){
4227 if(typeof s == "string"){
4228 b += ' style="' + s + '"';
4229 }else if(typeof s == "object"){
4232 if(typeof s[key] != "function"){
4233 b += key + ":" + s[key] + ";";
4240 b += ' class="' + o["cls"] + '"';
4241 }else if(attr == "htmlFor"){
4242 b += ' for="' + o["htmlFor"] + '"';
4244 b += " " + attr + '="' + o[attr] + '"';
4248 if(emptyTags.test(o.tag)){
4252 var cn = o.children || o.cn;
4254 //http://bugs.kde.org/show_bug.cgi?id=71506
4255 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4256 for(var i = 0, len = cn.length; i < len; i++) {
4257 b += createHtml(cn[i], b);
4260 b += createHtml(cn, b);
4266 b += "</" + o.tag + ">";
4273 var createDom = function(o, parentNode){
4275 // defininition craeted..
4277 if (o.ns && o.ns != 'html') {
4279 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4280 xmlns[o.ns] = o.xmlns;
4283 if (typeof(xmlns[o.ns]) == 'undefined') {
4284 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4290 if (typeof(o) == 'string') {
4291 return parentNode.appendChild(document.createTextNode(o));
4293 o.tag = o.tag || div;
4294 if (o.ns && Roo.isIE) {
4296 o.tag = o.ns + ':' + o.tag;
4299 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4300 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4303 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4304 attr == "style" || typeof o[attr] == "function") { continue; }
4306 if(attr=="cls" && Roo.isIE){
4307 el.className = o["cls"];
4309 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4315 Roo.DomHelper.applyStyles(el, o.style);
4316 var cn = o.children || o.cn;
4318 //http://bugs.kde.org/show_bug.cgi?id=71506
4319 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4320 for(var i = 0, len = cn.length; i < len; i++) {
4321 createDom(cn[i], el);
4328 el.innerHTML = o.html;
4331 parentNode.appendChild(el);
4336 var ieTable = function(depth, s, h, e){
4337 tempTableEl.innerHTML = [s, h, e].join('');
4338 var i = -1, el = tempTableEl;
4345 // kill repeat to save bytes
4349 tbe = '</tbody>'+te,
4355 * Nasty code for IE's broken table implementation
4357 var insertIntoTable = function(tag, where, el, html){
4359 tempTableEl = document.createElement('div');
4364 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4367 if(where == 'beforebegin'){
4371 before = el.nextSibling;
4374 node = ieTable(4, trs, html, tre);
4376 else if(tag == 'tr'){
4377 if(where == 'beforebegin'){
4380 node = ieTable(3, tbs, html, tbe);
4381 } else if(where == 'afterend'){
4382 before = el.nextSibling;
4384 node = ieTable(3, tbs, html, tbe);
4385 } else{ // INTO a TR
4386 if(where == 'afterbegin'){
4387 before = el.firstChild;
4389 node = ieTable(4, trs, html, tre);
4391 } else if(tag == 'tbody'){
4392 if(where == 'beforebegin'){
4395 node = ieTable(2, ts, html, te);
4396 } else if(where == 'afterend'){
4397 before = el.nextSibling;
4399 node = ieTable(2, ts, html, te);
4401 if(where == 'afterbegin'){
4402 before = el.firstChild;
4404 node = ieTable(3, tbs, html, tbe);
4407 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4410 if(where == 'afterbegin'){
4411 before = el.firstChild;
4413 node = ieTable(2, ts, html, te);
4415 el.insertBefore(node, before);
4420 /** True to force the use of DOM instead of html fragments @type Boolean */
4424 * Returns the markup for the passed Element(s) config
4425 * @param {Object} o The Dom object spec (and children)
4428 markup : function(o){
4429 return createHtml(o);
4433 * Applies a style specification to an element
4434 * @param {String/HTMLElement} el The element to apply styles to
4435 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4436 * a function which returns such a specification.
4438 applyStyles : function(el, styles){
4441 if(typeof styles == "string"){
4442 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4444 while ((matches = re.exec(styles)) != null){
4445 el.setStyle(matches[1], matches[2]);
4447 }else if (typeof styles == "object"){
4448 for (var style in styles){
4449 el.setStyle(style, styles[style]);
4451 }else if (typeof styles == "function"){
4452 Roo.DomHelper.applyStyles(el, styles.call());
4458 * Inserts an HTML fragment into the Dom
4459 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4460 * @param {HTMLElement} el The context element
4461 * @param {String} html The HTML fragmenet
4462 * @return {HTMLElement} The new node
4464 insertHtml : function(where, el, html){
4465 where = where.toLowerCase();
4466 if(el.insertAdjacentHTML){
4467 if(tableRe.test(el.tagName)){
4469 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4475 el.insertAdjacentHTML('BeforeBegin', html);
4476 return el.previousSibling;
4478 el.insertAdjacentHTML('AfterBegin', html);
4479 return el.firstChild;
4481 el.insertAdjacentHTML('BeforeEnd', html);
4482 return el.lastChild;
4484 el.insertAdjacentHTML('AfterEnd', html);
4485 return el.nextSibling;
4487 throw 'Illegal insertion point -> "' + where + '"';
4489 var range = el.ownerDocument.createRange();
4493 range.setStartBefore(el);
4494 frag = range.createContextualFragment(html);
4495 el.parentNode.insertBefore(frag, el);
4496 return el.previousSibling;
4499 range.setStartBefore(el.firstChild);
4500 frag = range.createContextualFragment(html);
4501 el.insertBefore(frag, el.firstChild);
4502 return el.firstChild;
4504 el.innerHTML = html;
4505 return el.firstChild;
4509 range.setStartAfter(el.lastChild);
4510 frag = range.createContextualFragment(html);
4511 el.appendChild(frag);
4512 return el.lastChild;
4514 el.innerHTML = html;
4515 return el.lastChild;
4518 range.setStartAfter(el);
4519 frag = range.createContextualFragment(html);
4520 el.parentNode.insertBefore(frag, el.nextSibling);
4521 return el.nextSibling;
4523 throw 'Illegal insertion point -> "' + where + '"';
4527 * Creates new Dom element(s) and inserts them before el
4528 * @param {String/HTMLElement/Element} el The context element
4529 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531 * @return {HTMLElement/Roo.Element} The new node
4533 insertBefore : function(el, o, returnElement){
4534 return this.doInsert(el, o, returnElement, "beforeBegin");
4538 * Creates new Dom element(s) and inserts them after el
4539 * @param {String/HTMLElement/Element} el The context element
4540 * @param {Object} o The Dom object spec (and children)
4541 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4542 * @return {HTMLElement/Roo.Element} The new node
4544 insertAfter : function(el, o, returnElement){
4545 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4549 * Creates new Dom element(s) and inserts them as the first child of el
4550 * @param {String/HTMLElement/Element} el The context element
4551 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4552 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4553 * @return {HTMLElement/Roo.Element} The new node
4555 insertFirst : function(el, o, returnElement){
4556 return this.doInsert(el, o, returnElement, "afterBegin");
4560 doInsert : function(el, o, returnElement, pos, sibling){
4561 el = Roo.getDom(el);
4563 if(this.useDom || o.ns){
4564 newNode = createDom(o, null);
4565 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4567 var html = createHtml(o);
4568 newNode = this.insertHtml(pos, el, html);
4570 return returnElement ? Roo.get(newNode, true) : newNode;
4574 * Creates new Dom element(s) and appends them to el
4575 * @param {String/HTMLElement/Element} el The context element
4576 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4577 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4578 * @return {HTMLElement/Roo.Element} The new node
4580 append : function(el, o, returnElement){
4581 el = Roo.getDom(el);
4583 if(this.useDom || o.ns){
4584 newNode = createDom(o, null);
4585 el.appendChild(newNode);
4587 var html = createHtml(o);
4588 newNode = this.insertHtml("beforeEnd", el, html);
4590 return returnElement ? Roo.get(newNode, true) : newNode;
4594 * Creates new Dom element(s) and overwrites the contents of el with them
4595 * @param {String/HTMLElement/Element} el The context element
4596 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4597 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4598 * @return {HTMLElement/Roo.Element} The new node
4600 overwrite : function(el, o, returnElement){
4601 el = Roo.getDom(el);
4604 while (el.childNodes.length) {
4605 el.removeChild(el.firstChild);
4609 el.innerHTML = createHtml(o);
4612 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4616 * Creates a new Roo.DomHelper.Template from the Dom object spec
4617 * @param {Object} o The Dom object spec (and children)
4618 * @return {Roo.DomHelper.Template} The new template
4620 createTemplate : function(o){
4621 var html = createHtml(o);
4622 return new Roo.Template(html);
4628 * Ext JS Library 1.1.1
4629 * Copyright(c) 2006-2007, Ext JS, LLC.
4631 * Originally Released Under LGPL - original licence link has changed is not relivant.
4634 * <script type="text/javascript">
4638 * @class Roo.Template
4639 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4640 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4643 var t = new Roo.Template({
4644 html : '<div name="{id}">' +
4645 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4647 myformat: function (value, allValues) {
4648 return 'XX' + value;
4651 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4653 * For more information see this blog post with examples:
4654 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4655 - Create Elements using DOM, HTML fragments and Templates</a>.
4657 * @param {Object} cfg - Configuration object.
4659 Roo.Template = function(cfg){
4661 if(cfg instanceof Array){
4663 }else if(arguments.length > 1){
4664 cfg = Array.prototype.join.call(arguments, "");
4668 if (typeof(cfg) == 'object') {
4679 Roo.Template.prototype = {
4682 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
4688 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4689 * it should be fixed so that template is observable...
4693 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4701 * Returns an HTML fragment of this template with the specified values applied.
4702 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4703 * @return {String} The HTML fragment
4708 applyTemplate : function(values){
4709 //Roo.log(["applyTemplate", values]);
4713 return this.compiled(values);
4715 var useF = this.disableFormats !== true;
4716 var fm = Roo.util.Format, tpl = this;
4717 var fn = function(m, name, format, args){
4719 if(format.substr(0, 5) == "this."){
4720 return tpl.call(format.substr(5), values[name], values);
4723 // quoted values are required for strings in compiled templates,
4724 // but for non compiled we need to strip them
4725 // quoted reversed for jsmin
4726 var re = /^\s*['"](.*)["']\s*$/;
4727 args = args.split(',');
4728 for(var i = 0, len = args.length; i < len; i++){
4729 args[i] = args[i].replace(re, "$1");
4731 args = [values[name]].concat(args);
4733 args = [values[name]];
4735 return fm[format].apply(fm, args);
4738 return values[name] !== undefined ? values[name] : "";
4741 return this.html.replace(this.re, fn);
4759 this.loading = true;
4760 this.compiled = false;
4762 var cx = new Roo.data.Connection();
4766 success : function (response) {
4770 _t.set(response.responseText,true);
4776 failure : function(response) {
4777 Roo.log("Template failed to load from " + _t.url);
4784 * Sets the HTML used as the template and optionally compiles it.
4785 * @param {String} html
4786 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4787 * @return {Roo.Template} this
4789 set : function(html, compile){
4791 this.compiled = false;
4799 * True to disable format functions (defaults to false)
4802 disableFormats : false,
4805 * The regular expression used to match template variables
4809 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4812 * Compiles the template into an internal function, eliminating the RegEx overhead.
4813 * @return {Roo.Template} this
4815 compile : function(){
4816 var fm = Roo.util.Format;
4817 var useF = this.disableFormats !== true;
4818 var sep = Roo.isGecko ? "+" : ",";
4819 var fn = function(m, name, format, args){
4821 args = args ? ',' + args : "";
4822 if(format.substr(0, 5) != "this."){
4823 format = "fm." + format + '(';
4825 format = 'this.call("'+ format.substr(5) + '", ';
4829 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4831 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4834 // branched to use + in gecko and [].join() in others
4836 body = "this.compiled = function(values){ return '" +
4837 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4840 body = ["this.compiled = function(values){ return ['"];
4841 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4842 body.push("'].join('');};");
4843 body = body.join('');
4853 // private function used to call members
4854 call : function(fnName, value, allValues){
4855 return this[fnName](value, allValues);
4859 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4860 * @param {String/HTMLElement/Roo.Element} el The context element
4861 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4862 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4863 * @return {HTMLElement/Roo.Element} The new node or Element
4865 insertFirst: function(el, values, returnElement){
4866 return this.doInsert('afterBegin', el, values, returnElement);
4870 * Applies the supplied values to the template and inserts the new node(s) before el.
4871 * @param {String/HTMLElement/Roo.Element} el The context element
4872 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4873 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4874 * @return {HTMLElement/Roo.Element} The new node or Element
4876 insertBefore: function(el, values, returnElement){
4877 return this.doInsert('beforeBegin', el, values, returnElement);
4881 * Applies the supplied values to the template and inserts the new node(s) after el.
4882 * @param {String/HTMLElement/Roo.Element} el The context element
4883 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4884 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4885 * @return {HTMLElement/Roo.Element} The new node or Element
4887 insertAfter : function(el, values, returnElement){
4888 return this.doInsert('afterEnd', el, values, returnElement);
4892 * Applies the supplied values to the template and appends the new node(s) to el.
4893 * @param {String/HTMLElement/Roo.Element} el The context element
4894 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4895 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4896 * @return {HTMLElement/Roo.Element} The new node or Element
4898 append : function(el, values, returnElement){
4899 return this.doInsert('beforeEnd', el, values, returnElement);
4902 doInsert : function(where, el, values, returnEl){
4903 el = Roo.getDom(el);
4904 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4905 return returnEl ? Roo.get(newNode, true) : newNode;
4909 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4910 * @param {String/HTMLElement/Roo.Element} el The context element
4911 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4912 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4913 * @return {HTMLElement/Roo.Element} The new node or Element
4915 overwrite : function(el, values, returnElement){
4916 el = Roo.getDom(el);
4917 el.innerHTML = this.applyTemplate(values);
4918 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4922 * Alias for {@link #applyTemplate}
4925 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4928 Roo.DomHelper.Template = Roo.Template;
4931 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4932 * @param {String/HTMLElement} el A DOM element or its id
4933 * @returns {Roo.Template} The created template
4936 Roo.Template.from = function(el){
4937 el = Roo.getDom(el);
4938 return new Roo.Template(el.value || el.innerHTML);
4941 * Ext JS Library 1.1.1
4942 * Copyright(c) 2006-2007, Ext JS, LLC.
4944 * Originally Released Under LGPL - original licence link has changed is not relivant.
4947 * <script type="text/javascript">
4952 * This is code is also distributed under MIT license for use
4953 * with jQuery and prototype JavaScript libraries.
4956 * @class Roo.DomQuery
4957 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4959 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4962 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4964 <h4>Element Selectors:</h4>
4966 <li> <b>*</b> any element</li>
4967 <li> <b>E</b> an element with the tag E</li>
4968 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4969 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4970 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4971 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4973 <h4>Attribute Selectors:</h4>
4974 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4976 <li> <b>E[foo]</b> has an attribute "foo"</li>
4977 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4978 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4979 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4980 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4981 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4982 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4984 <h4>Pseudo Classes:</h4>
4986 <li> <b>E:first-child</b> E is the first child of its parent</li>
4987 <li> <b>E:last-child</b> E is the last child of its parent</li>
4988 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4989 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4990 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4991 <li> <b>E:only-child</b> E is the only child of its parent</li>
4992 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4993 <li> <b>E:first</b> the first E in the resultset</li>
4994 <li> <b>E:last</b> the last E in the resultset</li>
4995 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4996 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4997 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4998 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4999 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5000 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5001 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5002 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5003 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5005 <h4>CSS Value Selectors:</h4>
5007 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5008 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5009 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5010 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5011 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5012 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5016 Roo.DomQuery = function(){
5017 var cache = {}, simpleCache = {}, valueCache = {};
5018 var nonSpace = /\S/;
5019 var trimRe = /^\s+|\s+$/g;
5020 var tplRe = /\{(\d+)\}/g;
5021 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5022 var tagTokenRe = /^(#)?([\w-\*]+)/;
5023 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5025 function child(p, index){
5027 var n = p.firstChild;
5029 if(n.nodeType == 1){
5040 while((n = n.nextSibling) && n.nodeType != 1);
5045 while((n = n.previousSibling) && n.nodeType != 1);
5049 function children(d){
5050 var n = d.firstChild, ni = -1;
5052 var nx = n.nextSibling;
5053 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5063 function byClassName(c, a, v){
5067 var r = [], ri = -1, cn;
5068 for(var i = 0, ci; ci = c[i]; i++){
5069 if((' '+ci.className+' ').indexOf(v) != -1){
5076 function attrValue(n, attr){
5077 if(!n.tagName && typeof n.length != "undefined"){
5086 if(attr == "class" || attr == "className"){
5089 return n.getAttribute(attr) || n[attr];
5093 function getNodes(ns, mode, tagName){
5094 var result = [], ri = -1, cs;
5098 tagName = tagName || "*";
5099 if(typeof ns.getElementsByTagName != "undefined"){
5103 for(var i = 0, ni; ni = ns[i]; i++){
5104 cs = ni.getElementsByTagName(tagName);
5105 for(var j = 0, ci; ci = cs[j]; j++){
5109 }else if(mode == "/" || mode == ">"){
5110 var utag = tagName.toUpperCase();
5111 for(var i = 0, ni, cn; ni = ns[i]; i++){
5112 cn = ni.children || ni.childNodes;
5113 for(var j = 0, cj; cj = cn[j]; j++){
5114 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5119 }else if(mode == "+"){
5120 var utag = tagName.toUpperCase();
5121 for(var i = 0, n; n = ns[i]; i++){
5122 while((n = n.nextSibling) && n.nodeType != 1);
5123 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5127 }else if(mode == "~"){
5128 for(var i = 0, n; n = ns[i]; i++){
5129 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5138 function concat(a, b){
5142 for(var i = 0, l = b.length; i < l; i++){
5148 function byTag(cs, tagName){
5149 if(cs.tagName || cs == document){
5155 var r = [], ri = -1;
5156 tagName = tagName.toLowerCase();
5157 for(var i = 0, ci; ci = cs[i]; i++){
5158 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5165 function byId(cs, attr, id){
5166 if(cs.tagName || cs == document){
5172 var r = [], ri = -1;
5173 for(var i = 0,ci; ci = cs[i]; i++){
5174 if(ci && ci.id == id){
5182 function byAttribute(cs, attr, value, op, custom){
5183 var r = [], ri = -1, st = custom=="{";
5184 var f = Roo.DomQuery.operators[op];
5185 for(var i = 0, ci; ci = cs[i]; i++){
5188 a = Roo.DomQuery.getStyle(ci, attr);
5190 else if(attr == "class" || attr == "className"){
5192 }else if(attr == "for"){
5194 }else if(attr == "href"){
5195 a = ci.getAttribute("href", 2);
5197 a = ci.getAttribute(attr);
5199 if((f && f(a, value)) || (!f && a)){
5206 function byPseudo(cs, name, value){
5207 return Roo.DomQuery.pseudos[name](cs, value);
5210 // This is for IE MSXML which does not support expandos.
5211 // IE runs the same speed using setAttribute, however FF slows way down
5212 // and Safari completely fails so they need to continue to use expandos.
5213 var isIE = window.ActiveXObject ? true : false;
5215 // this eval is stop the compressor from
5216 // renaming the variable to something shorter
5218 /** eval:var:batch */
5223 function nodupIEXml(cs){
5225 cs[0].setAttribute("_nodup", d);
5227 for(var i = 1, len = cs.length; i < len; i++){
5229 if(!c.getAttribute("_nodup") != d){
5230 c.setAttribute("_nodup", d);
5234 for(var i = 0, len = cs.length; i < len; i++){
5235 cs[i].removeAttribute("_nodup");
5244 var len = cs.length, c, i, r = cs, cj, ri = -1;
5245 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5248 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5249 return nodupIEXml(cs);
5253 for(i = 1; c = cs[i]; i++){
5258 for(var j = 0; j < i; j++){
5261 for(j = i+1; cj = cs[j]; j++){
5273 function quickDiffIEXml(c1, c2){
5275 for(var i = 0, len = c1.length; i < len; i++){
5276 c1[i].setAttribute("_qdiff", d);
5279 for(var i = 0, len = c2.length; i < len; i++){
5280 if(c2[i].getAttribute("_qdiff") != d){
5281 r[r.length] = c2[i];
5284 for(var i = 0, len = c1.length; i < len; i++){
5285 c1[i].removeAttribute("_qdiff");
5290 function quickDiff(c1, c2){
5291 var len1 = c1.length;
5295 if(isIE && c1[0].selectSingleNode){
5296 return quickDiffIEXml(c1, c2);
5299 for(var i = 0; i < len1; i++){
5303 for(var i = 0, len = c2.length; i < len; i++){
5304 if(c2[i]._qdiff != d){
5305 r[r.length] = c2[i];
5311 function quickId(ns, mode, root, id){
5313 var d = root.ownerDocument || root;
5314 return d.getElementById(id);
5316 ns = getNodes(ns, mode, "*");
5317 return byId(ns, null, id);
5321 getStyle : function(el, name){
5322 return Roo.fly(el).getStyle(name);
5325 * Compiles a selector/xpath query into a reusable function. The returned function
5326 * takes one parameter "root" (optional), which is the context node from where the query should start.
5327 * @param {String} selector The selector/xpath query
5328 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5329 * @return {Function}
5331 compile : function(path, type){
5332 type = type || "select";
5334 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5335 var q = path, mode, lq;
5336 var tk = Roo.DomQuery.matchers;
5337 var tklen = tk.length;
5340 // accept leading mode switch
5341 var lmode = q.match(modeRe);
5342 if(lmode && lmode[1]){
5343 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5344 q = q.replace(lmode[1], "");
5346 // strip leading slashes
5347 while(path.substr(0, 1)=="/"){
5348 path = path.substr(1);
5351 while(q && lq != q){
5353 var tm = q.match(tagTokenRe);
5354 if(type == "select"){
5357 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5359 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5361 q = q.replace(tm[0], "");
5362 }else if(q.substr(0, 1) != '@'){
5363 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5368 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5370 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5372 q = q.replace(tm[0], "");
5375 while(!(mm = q.match(modeRe))){
5376 var matched = false;
5377 for(var j = 0; j < tklen; j++){
5379 var m = q.match(t.re);
5381 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5384 q = q.replace(m[0], "");
5389 // prevent infinite loop on bad selector
5391 throw 'Error parsing selector, parsing failed at "' + q + '"';
5395 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5396 q = q.replace(mm[1], "");
5399 fn[fn.length] = "return nodup(n);\n}";
5402 * list of variables that need from compression as they are used by eval.
5412 * eval:var:byClassName
5414 * eval:var:byAttribute
5415 * eval:var:attrValue
5423 * Selects a group of elements.
5424 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5425 * @param {Node} root (optional) The start of the query (defaults to document).
5428 select : function(path, root, type){
5429 if(!root || root == document){
5432 if(typeof root == "string"){
5433 root = document.getElementById(root);
5435 var paths = path.split(",");
5437 for(var i = 0, len = paths.length; i < len; i++){
5438 var p = paths[i].replace(trimRe, "");
5440 cache[p] = Roo.DomQuery.compile(p);
5442 throw p + " is not a valid selector";
5445 var result = cache[p](root);
5446 if(result && result != document){
5447 results = results.concat(result);
5450 if(paths.length > 1){
5451 return nodup(results);
5457 * Selects a single element.
5458 * @param {String} selector The selector/xpath query
5459 * @param {Node} root (optional) The start of the query (defaults to document).
5462 selectNode : function(path, root){
5463 return Roo.DomQuery.select(path, root)[0];
5467 * Selects the value of a node, optionally replacing null with the defaultValue.
5468 * @param {String} selector The selector/xpath query
5469 * @param {Node} root (optional) The start of the query (defaults to document).
5470 * @param {String} defaultValue
5472 selectValue : function(path, root, defaultValue){
5473 path = path.replace(trimRe, "");
5474 if(!valueCache[path]){
5475 valueCache[path] = Roo.DomQuery.compile(path, "select");
5477 var n = valueCache[path](root);
5478 n = n[0] ? n[0] : n;
5479 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5480 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5484 * Selects the value of a node, parsing integers and floats.
5485 * @param {String} selector The selector/xpath query
5486 * @param {Node} root (optional) The start of the query (defaults to document).
5487 * @param {Number} defaultValue
5490 selectNumber : function(path, root, defaultValue){
5491 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5492 return parseFloat(v);
5496 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5497 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5498 * @param {String} selector The simple selector to test
5501 is : function(el, ss){
5502 if(typeof el == "string"){
5503 el = document.getElementById(el);
5505 var isArray = (el instanceof Array);
5506 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5507 return isArray ? (result.length == el.length) : (result.length > 0);
5511 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5512 * @param {Array} el An array of elements to filter
5513 * @param {String} selector The simple selector to test
5514 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5515 * the selector instead of the ones that match
5518 filter : function(els, ss, nonMatches){
5519 ss = ss.replace(trimRe, "");
5520 if(!simpleCache[ss]){
5521 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5523 var result = simpleCache[ss](els);
5524 return nonMatches ? quickDiff(result, els) : result;
5528 * Collection of matching regular expressions and code snippets.
5532 select: 'n = byClassName(n, null, " {1} ");'
5534 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5535 select: 'n = byPseudo(n, "{1}", "{2}");'
5537 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5538 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5541 select: 'n = byId(n, null, "{1}");'
5544 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5549 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5550 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5553 "=" : function(a, v){
5556 "!=" : function(a, v){
5559 "^=" : function(a, v){
5560 return a && a.substr(0, v.length) == v;
5562 "$=" : function(a, v){
5563 return a && a.substr(a.length-v.length) == v;
5565 "*=" : function(a, v){
5566 return a && a.indexOf(v) !== -1;
5568 "%=" : function(a, v){
5569 return (a % v) == 0;
5571 "|=" : function(a, v){
5572 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5574 "~=" : function(a, v){
5575 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5580 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5581 * and the argument (if any) supplied in the selector.
5584 "first-child" : function(c){
5585 var r = [], ri = -1, n;
5586 for(var i = 0, ci; ci = n = c[i]; i++){
5587 while((n = n.previousSibling) && n.nodeType != 1);
5595 "last-child" : function(c){
5596 var r = [], ri = -1, n;
5597 for(var i = 0, ci; ci = n = c[i]; i++){
5598 while((n = n.nextSibling) && n.nodeType != 1);
5606 "nth-child" : function(c, a) {
5607 var r = [], ri = -1;
5608 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5609 var f = (m[1] || 1) - 0, l = m[2] - 0;
5610 for(var i = 0, n; n = c[i]; i++){
5611 var pn = n.parentNode;
5612 if (batch != pn._batch) {
5614 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5615 if(cn.nodeType == 1){
5622 if (l == 0 || n.nodeIndex == l){
5625 } else if ((n.nodeIndex + l) % f == 0){
5633 "only-child" : function(c){
5634 var r = [], ri = -1;;
5635 for(var i = 0, ci; ci = c[i]; i++){
5636 if(!prev(ci) && !next(ci)){
5643 "empty" : function(c){
5644 var r = [], ri = -1;
5645 for(var i = 0, ci; ci = c[i]; i++){
5646 var cns = ci.childNodes, j = 0, cn, empty = true;
5649 if(cn.nodeType == 1 || cn.nodeType == 3){
5661 "contains" : function(c, v){
5662 var r = [], ri = -1;
5663 for(var i = 0, ci; ci = c[i]; i++){
5664 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5671 "nodeValue" : function(c, v){
5672 var r = [], ri = -1;
5673 for(var i = 0, ci; ci = c[i]; i++){
5674 if(ci.firstChild && ci.firstChild.nodeValue == v){
5681 "checked" : function(c){
5682 var r = [], ri = -1;
5683 for(var i = 0, ci; ci = c[i]; i++){
5684 if(ci.checked == true){
5691 "not" : function(c, ss){
5692 return Roo.DomQuery.filter(c, ss, true);
5695 "odd" : function(c){
5696 return this["nth-child"](c, "odd");
5699 "even" : function(c){
5700 return this["nth-child"](c, "even");
5703 "nth" : function(c, a){
5704 return c[a-1] || [];
5707 "first" : function(c){
5711 "last" : function(c){
5712 return c[c.length-1] || [];
5715 "has" : function(c, ss){
5716 var s = Roo.DomQuery.select;
5717 var r = [], ri = -1;
5718 for(var i = 0, ci; ci = c[i]; i++){
5719 if(s(ss, ci).length > 0){
5726 "next" : function(c, ss){
5727 var is = Roo.DomQuery.is;
5728 var r = [], ri = -1;
5729 for(var i = 0, ci; ci = c[i]; i++){
5738 "prev" : function(c, ss){
5739 var is = Roo.DomQuery.is;
5740 var r = [], ri = -1;
5741 for(var i = 0, ci; ci = c[i]; i++){
5754 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5755 * @param {String} path The selector/xpath query
5756 * @param {Node} root (optional) The start of the query (defaults to document).
5761 Roo.query = Roo.DomQuery.select;
5764 * Ext JS Library 1.1.1
5765 * Copyright(c) 2006-2007, Ext JS, LLC.
5767 * Originally Released Under LGPL - original licence link has changed is not relivant.
5770 * <script type="text/javascript">
5774 * @class Roo.util.Observable
5775 * Base class that provides a common interface for publishing events. Subclasses are expected to
5776 * to have a property "events" with all the events defined.<br>
5779 Employee = function(name){
5786 Roo.extend(Employee, Roo.util.Observable);
5788 * @param {Object} config properties to use (incuding events / listeners)
5791 Roo.util.Observable = function(cfg){
5794 this.addEvents(cfg.events || {});
5796 delete cfg.events; // make sure
5799 Roo.apply(this, cfg);
5802 this.on(this.listeners);
5803 delete this.listeners;
5806 Roo.util.Observable.prototype = {
5808 * @cfg {Object} listeners list of events and functions to call for this object,
5812 'click' : function(e) {
5822 * Fires the specified event with the passed parameters (minus the event name).
5823 * @param {String} eventName
5824 * @param {Object...} args Variable number of parameters are passed to handlers
5825 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5827 fireEvent : function(){
5828 var ce = this.events[arguments[0].toLowerCase()];
5829 if(typeof ce == "object"){
5830 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5837 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5840 * Appends an event handler to this component
5841 * @param {String} eventName The type of event to listen for
5842 * @param {Function} handler The method the event invokes
5843 * @param {Object} scope (optional) The scope in which to execute the handler
5844 * function. The handler function's "this" context.
5845 * @param {Object} options (optional) An object containing handler configuration
5846 * properties. This may contain any of the following properties:<ul>
5847 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5848 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5849 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5850 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5851 * by the specified number of milliseconds. If the event fires again within that time, the original
5852 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5855 * <b>Combining Options</b><br>
5856 * Using the options argument, it is possible to combine different types of listeners:<br>
5858 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5860 el.on('click', this.onClick, this, {
5867 * <b>Attaching multiple handlers in 1 call</b><br>
5868 * The method also allows for a single argument to be passed which is a config object containing properties
5869 * which specify multiple handlers.
5878 fn: this.onMouseOver,
5882 fn: this.onMouseOut,
5888 * Or a shorthand syntax which passes the same scope object to all handlers:
5891 'click': this.onClick,
5892 'mouseover': this.onMouseOver,
5893 'mouseout': this.onMouseOut,
5898 addListener : function(eventName, fn, scope, o){
5899 if(typeof eventName == "object"){
5902 if(this.filterOptRe.test(e)){
5905 if(typeof o[e] == "function"){
5907 this.addListener(e, o[e], o.scope, o);
5909 // individual options
5910 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5915 o = (!o || typeof o == "boolean") ? {} : o;
5916 eventName = eventName.toLowerCase();
5917 var ce = this.events[eventName] || true;
5918 if(typeof ce == "boolean"){
5919 ce = new Roo.util.Event(this, eventName);
5920 this.events[eventName] = ce;
5922 ce.addListener(fn, scope, o);
5926 * Removes a listener
5927 * @param {String} eventName The type of event to listen for
5928 * @param {Function} handler The handler to remove
5929 * @param {Object} scope (optional) The scope (this object) for the handler
5931 removeListener : function(eventName, fn, scope){
5932 var ce = this.events[eventName.toLowerCase()];
5933 if(typeof ce == "object"){
5934 ce.removeListener(fn, scope);
5939 * Removes all listeners for this object
5941 purgeListeners : function(){
5942 for(var evt in this.events){
5943 if(typeof this.events[evt] == "object"){
5944 this.events[evt].clearListeners();
5949 relayEvents : function(o, events){
5950 var createHandler = function(ename){
5952 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5955 for(var i = 0, len = events.length; i < len; i++){
5956 var ename = events[i];
5957 if(!this.events[ename]){ this.events[ename] = true; };
5958 o.on(ename, createHandler(ename), this);
5963 * Used to define events on this Observable
5964 * @param {Object} object The object with the events defined
5966 addEvents : function(o){
5970 Roo.applyIf(this.events, o);
5974 * Checks to see if this object has any listeners for a specified event
5975 * @param {String} eventName The name of the event to check for
5976 * @return {Boolean} True if the event is being listened for, else false
5978 hasListener : function(eventName){
5979 var e = this.events[eventName];
5980 return typeof e == "object" && e.listeners.length > 0;
5984 * Appends an event handler to this element (shorthand for addListener)
5985 * @param {String} eventName The type of event to listen for
5986 * @param {Function} handler The method the event invokes
5987 * @param {Object} scope (optional) The scope in which to execute the handler
5988 * function. The handler function's "this" context.
5989 * @param {Object} options (optional)
5992 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5994 * Removes a listener (shorthand for removeListener)
5995 * @param {String} eventName The type of event to listen for
5996 * @param {Function} handler The handler to remove
5997 * @param {Object} scope (optional) The scope (this object) for the handler
6000 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6003 * Starts capture on the specified Observable. All events will be passed
6004 * to the supplied function with the event name + standard signature of the event
6005 * <b>before</b> the event is fired. If the supplied function returns false,
6006 * the event will not fire.
6007 * @param {Observable} o The Observable to capture
6008 * @param {Function} fn The function to call
6009 * @param {Object} scope (optional) The scope (this object) for the fn
6012 Roo.util.Observable.capture = function(o, fn, scope){
6013 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6017 * Removes <b>all</b> added captures from the Observable.
6018 * @param {Observable} o The Observable to release
6021 Roo.util.Observable.releaseCapture = function(o){
6022 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6027 var createBuffered = function(h, o, scope){
6028 var task = new Roo.util.DelayedTask();
6030 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6034 var createSingle = function(h, e, fn, scope){
6036 e.removeListener(fn, scope);
6037 return h.apply(scope, arguments);
6041 var createDelayed = function(h, o, scope){
6043 var args = Array.prototype.slice.call(arguments, 0);
6044 setTimeout(function(){
6045 h.apply(scope, args);
6050 Roo.util.Event = function(obj, name){
6053 this.listeners = [];
6056 Roo.util.Event.prototype = {
6057 addListener : function(fn, scope, options){
6058 var o = options || {};
6059 scope = scope || this.obj;
6060 if(!this.isListening(fn, scope)){
6061 var l = {fn: fn, scope: scope, options: o};
6064 h = createDelayed(h, o, scope);
6067 h = createSingle(h, this, fn, scope);
6070 h = createBuffered(h, o, scope);
6073 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6074 this.listeners.push(l);
6076 this.listeners = this.listeners.slice(0);
6077 this.listeners.push(l);
6082 findListener : function(fn, scope){
6083 scope = scope || this.obj;
6084 var ls = this.listeners;
6085 for(var i = 0, len = ls.length; i < len; i++){
6087 if(l.fn == fn && l.scope == scope){
6094 isListening : function(fn, scope){
6095 return this.findListener(fn, scope) != -1;
6098 removeListener : function(fn, scope){
6100 if((index = this.findListener(fn, scope)) != -1){
6102 this.listeners.splice(index, 1);
6104 this.listeners = this.listeners.slice(0);
6105 this.listeners.splice(index, 1);
6112 clearListeners : function(){
6113 this.listeners = [];
6117 var ls = this.listeners, scope, len = ls.length;
6120 var args = Array.prototype.slice.call(arguments, 0);
6121 for(var i = 0; i < len; i++){
6123 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6124 this.firing = false;
6128 this.firing = false;
6135 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6142 * @class Roo.Document
6143 * @extends Roo.util.Observable
6144 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6146 * @param {Object} config the methods and properties of the 'base' class for the application.
6148 * Generic Page handler - implement this to start your app..
6151 * MyProject = new Roo.Document({
6153 'load' : true // your events..
6156 'ready' : function() {
6157 // fired on Roo.onReady()
6162 Roo.Document = function(cfg) {
6167 Roo.util.Observable.call(this,cfg);
6171 Roo.onReady(function() {
6172 _this.fireEvent('ready');
6178 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6180 * Ext JS Library 1.1.1
6181 * Copyright(c) 2006-2007, Ext JS, LLC.
6183 * Originally Released Under LGPL - original licence link has changed is not relivant.
6186 * <script type="text/javascript">
6190 * @class Roo.EventManager
6191 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6192 * several useful events directly.
6193 * See {@link Roo.EventObject} for more details on normalized event objects.
6196 Roo.EventManager = function(){
6197 var docReadyEvent, docReadyProcId, docReadyState = false;
6198 var resizeEvent, resizeTask, textEvent, textSize;
6199 var E = Roo.lib.Event;
6200 var D = Roo.lib.Dom;
6205 var fireDocReady = function(){
6207 docReadyState = true;
6210 clearInterval(docReadyProcId);
6212 if(Roo.isGecko || Roo.isOpera) {
6213 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6216 var defer = document.getElementById("ie-deferred-loader");
6218 defer.onreadystatechange = null;
6219 defer.parentNode.removeChild(defer);
6223 docReadyEvent.fire();
6224 docReadyEvent.clearListeners();
6229 var initDocReady = function(){
6230 docReadyEvent = new Roo.util.Event();
6231 if(Roo.isGecko || Roo.isOpera) {
6232 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6234 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6235 var defer = document.getElementById("ie-deferred-loader");
6236 defer.onreadystatechange = function(){
6237 if(this.readyState == "complete"){
6241 }else if(Roo.isSafari){
6242 docReadyProcId = setInterval(function(){
6243 var rs = document.readyState;
6244 if(rs == "complete") {
6249 // no matter what, make sure it fires on load
6250 E.on(window, "load", fireDocReady);
6253 var createBuffered = function(h, o){
6254 var task = new Roo.util.DelayedTask(h);
6256 // create new event object impl so new events don't wipe out properties
6257 e = new Roo.EventObjectImpl(e);
6258 task.delay(o.buffer, h, null, [e]);
6262 var createSingle = function(h, el, ename, fn){
6264 Roo.EventManager.removeListener(el, ename, fn);
6269 var createDelayed = function(h, o){
6271 // create new event object impl so new events don't wipe out properties
6272 e = new Roo.EventObjectImpl(e);
6273 setTimeout(function(){
6278 var transitionEndVal = false;
6280 var transitionEnd = function()
6282 if (transitionEndVal) {
6283 return transitionEndVal;
6285 var el = document.createElement('div');
6287 var transEndEventNames = {
6288 WebkitTransition : 'webkitTransitionEnd',
6289 MozTransition : 'transitionend',
6290 OTransition : 'oTransitionEnd otransitionend',
6291 transition : 'transitionend'
6294 for (var name in transEndEventNames) {
6295 if (el.style[name] !== undefined) {
6296 transitionEndVal = transEndEventNames[name];
6297 return transitionEndVal ;
6303 var listen = function(element, ename, opt, fn, scope){
6304 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6305 fn = fn || o.fn; scope = scope || o.scope;
6306 var el = Roo.getDom(element);
6310 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6313 if (ename == 'transitionend') {
6314 ename = transitionEnd();
6316 var h = function(e){
6317 e = Roo.EventObject.setEvent(e);
6320 t = e.getTarget(o.delegate, el);
6327 if(o.stopEvent === true){
6330 if(o.preventDefault === true){
6333 if(o.stopPropagation === true){
6334 e.stopPropagation();
6337 if(o.normalized === false){
6341 fn.call(scope || el, e, t, o);
6344 h = createDelayed(h, o);
6347 h = createSingle(h, el, ename, fn);
6350 h = createBuffered(h, o);
6353 fn._handlers = fn._handlers || [];
6356 fn._handlers.push([Roo.id(el), ename, h]);
6361 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6362 el.addEventListener("DOMMouseScroll", h, false);
6363 E.on(window, 'unload', function(){
6364 el.removeEventListener("DOMMouseScroll", h, false);
6367 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6368 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6373 var stopListening = function(el, ename, fn){
6374 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6376 for(var i = 0, len = hds.length; i < len; i++){
6378 if(h[0] == id && h[1] == ename){
6385 E.un(el, ename, hd);
6386 el = Roo.getDom(el);
6387 if(ename == "mousewheel" && el.addEventListener){
6388 el.removeEventListener("DOMMouseScroll", hd, false);
6390 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6391 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6395 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6402 * @scope Roo.EventManager
6407 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6408 * object with a Roo.EventObject
6409 * @param {Function} fn The method the event invokes
6410 * @param {Object} scope An object that becomes the scope of the handler
6411 * @param {boolean} override If true, the obj passed in becomes
6412 * the execution scope of the listener
6413 * @return {Function} The wrapped function
6416 wrap : function(fn, scope, override){
6418 Roo.EventObject.setEvent(e);
6419 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6424 * Appends an event handler to an element (shorthand for addListener)
6425 * @param {String/HTMLElement} element The html element or id to assign the
6426 * @param {String} eventName The type of event to listen for
6427 * @param {Function} handler The method the event invokes
6428 * @param {Object} scope (optional) The scope in which to execute the handler
6429 * function. The handler function's "this" context.
6430 * @param {Object} options (optional) An object containing handler configuration
6431 * properties. This may contain any of the following properties:<ul>
6432 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6433 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6434 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6435 * <li>preventDefault {Boolean} True to prevent the default action</li>
6436 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6437 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6438 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6439 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6440 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6441 * by the specified number of milliseconds. If the event fires again within that time, the original
6442 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6445 * <b>Combining Options</b><br>
6446 * Using the options argument, it is possible to combine different types of listeners:<br>
6448 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6450 el.on('click', this.onClick, this, {
6457 * <b>Attaching multiple handlers in 1 call</b><br>
6458 * The method also allows for a single argument to be passed which is a config object containing properties
6459 * which specify multiple handlers.
6469 fn: this.onMouseOver
6478 * Or a shorthand syntax:<br>
6481 'click' : this.onClick,
6482 'mouseover' : this.onMouseOver,
6483 'mouseout' : this.onMouseOut
6487 addListener : function(element, eventName, fn, scope, options){
6488 if(typeof eventName == "object"){
6494 if(typeof o[e] == "function"){
6496 listen(element, e, o, o[e], o.scope);
6498 // individual options
6499 listen(element, e, o[e]);
6504 return listen(element, eventName, options, fn, scope);
6508 * Removes an event handler
6510 * @param {String/HTMLElement} element The id or html element to remove the
6512 * @param {String} eventName The type of event
6513 * @param {Function} fn
6514 * @return {Boolean} True if a listener was actually removed
6516 removeListener : function(element, eventName, fn){
6517 return stopListening(element, eventName, fn);
6521 * Fires when the document is ready (before onload and before images are loaded). Can be
6522 * accessed shorthanded Roo.onReady().
6523 * @param {Function} fn The method the event invokes
6524 * @param {Object} scope An object that becomes the scope of the handler
6525 * @param {boolean} options
6527 onDocumentReady : function(fn, scope, options){
6528 if(docReadyState){ // if it already fired
6529 docReadyEvent.addListener(fn, scope, options);
6530 docReadyEvent.fire();
6531 docReadyEvent.clearListeners();
6537 docReadyEvent.addListener(fn, scope, options);
6541 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6542 * @param {Function} fn The method the event invokes
6543 * @param {Object} scope An object that becomes the scope of the handler
6544 * @param {boolean} options
6546 onWindowResize : function(fn, scope, options){
6548 resizeEvent = new Roo.util.Event();
6549 resizeTask = new Roo.util.DelayedTask(function(){
6550 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6552 E.on(window, "resize", function(){
6554 resizeTask.delay(50);
6556 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6560 resizeEvent.addListener(fn, scope, options);
6564 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6565 * @param {Function} fn The method the event invokes
6566 * @param {Object} scope An object that becomes the scope of the handler
6567 * @param {boolean} options
6569 onTextResize : function(fn, scope, options){
6571 textEvent = new Roo.util.Event();
6572 var textEl = new Roo.Element(document.createElement('div'));
6573 textEl.dom.className = 'x-text-resize';
6574 textEl.dom.innerHTML = 'X';
6575 textEl.appendTo(document.body);
6576 textSize = textEl.dom.offsetHeight;
6577 setInterval(function(){
6578 if(textEl.dom.offsetHeight != textSize){
6579 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6581 }, this.textResizeInterval);
6583 textEvent.addListener(fn, scope, options);
6587 * Removes the passed window resize listener.
6588 * @param {Function} fn The method the event invokes
6589 * @param {Object} scope The scope of handler
6591 removeResizeListener : function(fn, scope){
6593 resizeEvent.removeListener(fn, scope);
6598 fireResize : function(){
6600 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6604 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6608 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6610 textResizeInterval : 50
6615 * @scopeAlias pub=Roo.EventManager
6619 * Appends an event handler to an element (shorthand for addListener)
6620 * @param {String/HTMLElement} element The html element or id to assign the
6621 * @param {String} eventName The type of event to listen for
6622 * @param {Function} handler The method the event invokes
6623 * @param {Object} scope (optional) The scope in which to execute the handler
6624 * function. The handler function's "this" context.
6625 * @param {Object} options (optional) An object containing handler configuration
6626 * properties. This may contain any of the following properties:<ul>
6627 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6628 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6629 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6630 * <li>preventDefault {Boolean} True to prevent the default action</li>
6631 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6632 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6633 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6634 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6635 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6636 * by the specified number of milliseconds. If the event fires again within that time, the original
6637 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6640 * <b>Combining Options</b><br>
6641 * Using the options argument, it is possible to combine different types of listeners:<br>
6643 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6645 el.on('click', this.onClick, this, {
6652 * <b>Attaching multiple handlers in 1 call</b><br>
6653 * The method also allows for a single argument to be passed which is a config object containing properties
6654 * which specify multiple handlers.
6664 fn: this.onMouseOver
6673 * Or a shorthand syntax:<br>
6676 'click' : this.onClick,
6677 'mouseover' : this.onMouseOver,
6678 'mouseout' : this.onMouseOut
6682 pub.on = pub.addListener;
6683 pub.un = pub.removeListener;
6685 pub.stoppedMouseDownEvent = new Roo.util.Event();
6689 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6690 * @param {Function} fn The method the event invokes
6691 * @param {Object} scope An object that becomes the scope of the handler
6692 * @param {boolean} override If true, the obj passed in becomes
6693 * the execution scope of the listener
6697 Roo.onReady = Roo.EventManager.onDocumentReady;
6699 Roo.onReady(function(){
6700 var bd = Roo.get(document.body);
6705 : Roo.isIE11 ? "roo-ie11"
6706 : Roo.isEdge ? "roo-edge"
6707 : Roo.isGecko ? "roo-gecko"
6708 : Roo.isOpera ? "roo-opera"
6709 : Roo.isSafari ? "roo-safari" : ""];
6712 cls.push("roo-mac");
6715 cls.push("roo-linux");
6718 cls.push("roo-ios");
6721 cls.push("roo-touch");
6723 if(Roo.isBorderBox){
6724 cls.push('roo-border-box');
6726 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6727 var p = bd.dom.parentNode;
6729 p.className += ' roo-strict';
6732 bd.addClass(cls.join(' '));
6736 * @class Roo.EventObject
6737 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6738 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6741 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6743 var target = e.getTarget();
6746 var myDiv = Roo.get("myDiv");
6747 myDiv.on("click", handleClick);
6749 Roo.EventManager.on("myDiv", 'click', handleClick);
6750 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6754 Roo.EventObject = function(){
6756 var E = Roo.lib.Event;
6758 // safari keypress events for special keys return bad keycodes
6761 63235 : 39, // right
6764 63276 : 33, // page up
6765 63277 : 34, // page down
6766 63272 : 46, // delete
6771 // normalize button clicks
6772 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6773 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6775 Roo.EventObjectImpl = function(e){
6777 this.setEvent(e.browserEvent || e);
6780 Roo.EventObjectImpl.prototype = {
6782 * Used to fix doc tools.
6783 * @scope Roo.EventObject.prototype
6789 /** The normal browser event */
6790 browserEvent : null,
6791 /** The button pressed in a mouse event */
6793 /** True if the shift key was down during the event */
6795 /** True if the control key was down during the event */
6797 /** True if the alt key was down during the event */
6856 setEvent : function(e){
6857 if(e == this || (e && e.browserEvent)){ // already wrapped
6860 this.browserEvent = e;
6862 // normalize buttons
6863 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6864 if(e.type == 'click' && this.button == -1){
6868 this.shiftKey = e.shiftKey;
6869 // mac metaKey behaves like ctrlKey
6870 this.ctrlKey = e.ctrlKey || e.metaKey;
6871 this.altKey = e.altKey;
6872 // in getKey these will be normalized for the mac
6873 this.keyCode = e.keyCode;
6874 // keyup warnings on firefox.
6875 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6876 // cache the target for the delayed and or buffered events
6877 this.target = E.getTarget(e);
6879 this.xy = E.getXY(e);
6882 this.shiftKey = false;
6883 this.ctrlKey = false;
6884 this.altKey = false;
6894 * Stop the event (preventDefault and stopPropagation)
6896 stopEvent : function(){
6897 if(this.browserEvent){
6898 if(this.browserEvent.type == 'mousedown'){
6899 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6901 E.stopEvent(this.browserEvent);
6906 * Prevents the browsers default handling of the event.
6908 preventDefault : function(){
6909 if(this.browserEvent){
6910 E.preventDefault(this.browserEvent);
6915 isNavKeyPress : function(){
6916 var k = this.keyCode;
6917 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6918 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6921 isSpecialKey : function(){
6922 var k = this.keyCode;
6923 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6924 (k == 16) || (k == 17) ||
6925 (k >= 18 && k <= 20) ||
6926 (k >= 33 && k <= 35) ||
6927 (k >= 36 && k <= 39) ||
6928 (k >= 44 && k <= 45);
6931 * Cancels bubbling of the event.
6933 stopPropagation : function(){
6934 if(this.browserEvent){
6935 if(this.type == 'mousedown'){
6936 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6938 E.stopPropagation(this.browserEvent);
6943 * Gets the key code for the event.
6946 getCharCode : function(){
6947 return this.charCode || this.keyCode;
6951 * Returns a normalized keyCode for the event.
6952 * @return {Number} The key code
6954 getKey : function(){
6955 var k = this.keyCode || this.charCode;
6956 return Roo.isSafari ? (safariKeys[k] || k) : k;
6960 * Gets the x coordinate of the event.
6963 getPageX : function(){
6968 * Gets the y coordinate of the event.
6971 getPageY : function(){
6976 * Gets the time of the event.
6979 getTime : function(){
6980 if(this.browserEvent){
6981 return E.getTime(this.browserEvent);
6987 * Gets the page coordinates of the event.
6988 * @return {Array} The xy values like [x, y]
6995 * Gets the target for the event.
6996 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6997 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6998 search as a number or element (defaults to 10 || document.body)
6999 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7000 * @return {HTMLelement}
7002 getTarget : function(selector, maxDepth, returnEl){
7003 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7006 * Gets the related target.
7007 * @return {HTMLElement}
7009 getRelatedTarget : function(){
7010 if(this.browserEvent){
7011 return E.getRelatedTarget(this.browserEvent);
7017 * Normalizes mouse wheel delta across browsers
7018 * @return {Number} The delta
7020 getWheelDelta : function(){
7021 var e = this.browserEvent;
7023 if(e.wheelDelta){ /* IE/Opera. */
7024 delta = e.wheelDelta/120;
7025 }else if(e.detail){ /* Mozilla case. */
7026 delta = -e.detail/3;
7032 * Returns true if the control, meta, shift or alt key was pressed during this event.
7035 hasModifier : function(){
7036 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7040 * Returns true if the target of this event equals el or is a child of el
7041 * @param {String/HTMLElement/Element} el
7042 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7045 within : function(el, related){
7046 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7047 return t && Roo.fly(el).contains(t);
7050 getPoint : function(){
7051 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7055 return new Roo.EventObjectImpl();
7060 * Ext JS Library 1.1.1
7061 * Copyright(c) 2006-2007, Ext JS, LLC.
7063 * Originally Released Under LGPL - original licence link has changed is not relivant.
7066 * <script type="text/javascript">
7070 // was in Composite Element!??!?!
7073 var D = Roo.lib.Dom;
7074 var E = Roo.lib.Event;
7075 var A = Roo.lib.Anim;
7077 // local style camelizing for speed
7079 var camelRe = /(-[a-z])/gi;
7080 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7081 var view = document.defaultView;
7084 * @class Roo.Element
7085 * Represents an Element in the DOM.<br><br>
7088 var el = Roo.get("my-div");
7091 var el = getEl("my-div");
7093 // or with a DOM element
7094 var el = Roo.get(myDivElement);
7096 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7097 * each call instead of constructing a new one.<br><br>
7098 * <b>Animations</b><br />
7099 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7100 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7102 Option Default Description
7103 --------- -------- ---------------------------------------------
7104 duration .35 The duration of the animation in seconds
7105 easing easeOut The YUI easing method
7106 callback none A function to execute when the anim completes
7107 scope this The scope (this) of the callback function
7109 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7110 * manipulate the animation. Here's an example:
7112 var el = Roo.get("my-div");
7117 // default animation
7118 el.setWidth(100, true);
7120 // animation with some options set
7127 // using the "anim" property to get the Anim object
7133 el.setWidth(100, opt);
7135 if(opt.anim.isAnimated()){
7139 * <b> Composite (Collections of) Elements</b><br />
7140 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7141 * @constructor Create a new Element directly.
7142 * @param {String/HTMLElement} element
7143 * @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).
7145 Roo.Element = function(element, forceNew){
7146 var dom = typeof element == "string" ?
7147 document.getElementById(element) : element;
7148 if(!dom){ // invalid id/element
7152 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7153 return Roo.Element.cache[id];
7163 * The DOM element ID
7166 this.id = id || Roo.id(dom);
7169 var El = Roo.Element;
7173 * The element's default display mode (defaults to "")
7176 originalDisplay : "",
7179 // note this is overridden in BS version..
7182 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7188 * Sets the element's visibility mode. When setVisible() is called it
7189 * will use this to determine whether to set the visibility or the display property.
7190 * @param visMode Element.VISIBILITY or Element.DISPLAY
7191 * @return {Roo.Element} this
7193 setVisibilityMode : function(visMode){
7194 this.visibilityMode = visMode;
7198 * Convenience method for setVisibilityMode(Element.DISPLAY)
7199 * @param {String} display (optional) What to set display to when visible
7200 * @return {Roo.Element} this
7202 enableDisplayMode : function(display){
7203 this.setVisibilityMode(El.DISPLAY);
7204 if(typeof display != "undefined") { this.originalDisplay = display; }
7209 * 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)
7210 * @param {String} selector The simple selector to test
7211 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7212 search as a number or element (defaults to 10 || document.body)
7213 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7214 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7216 findParent : function(simpleSelector, maxDepth, returnEl){
7217 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7218 maxDepth = maxDepth || 50;
7219 if(typeof maxDepth != "number"){
7220 stopEl = Roo.getDom(maxDepth);
7223 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7224 if(dq.is(p, simpleSelector)){
7225 return returnEl ? Roo.get(p) : p;
7235 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7236 * @param {String} selector The simple selector to test
7237 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7238 search as a number or element (defaults to 10 || document.body)
7239 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7240 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7242 findParentNode : function(simpleSelector, maxDepth, returnEl){
7243 var p = Roo.fly(this.dom.parentNode, '_internal');
7244 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7248 * Looks at the scrollable parent element
7250 findScrollableParent : function()
7252 var overflowRegex = /(auto|scroll)/;
7254 if(this.getStyle('position') === 'fixed'){
7255 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7258 var excludeStaticParent = this.getStyle('position') === "absolute";
7260 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7262 if (excludeStaticParent && parent.getStyle('position') === "static") {
7266 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7270 if(parent.dom.nodeName.toLowerCase() == 'body'){
7271 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7275 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7279 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7280 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7281 * @param {String} selector The simple selector to test
7282 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7283 search as a number or element (defaults to 10 || document.body)
7284 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7286 up : function(simpleSelector, maxDepth){
7287 return this.findParentNode(simpleSelector, maxDepth, true);
7293 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7294 * @param {String} selector The simple selector to test
7295 * @return {Boolean} True if this element matches the selector, else false
7297 is : function(simpleSelector){
7298 return Roo.DomQuery.is(this.dom, simpleSelector);
7302 * Perform animation on this element.
7303 * @param {Object} args The YUI animation control args
7304 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7305 * @param {Function} onComplete (optional) Function to call when animation completes
7306 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7307 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7308 * @return {Roo.Element} this
7310 animate : function(args, duration, onComplete, easing, animType){
7311 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7316 * @private Internal animation call
7318 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7319 animType = animType || 'run';
7321 var anim = Roo.lib.Anim[animType](
7323 (opt.duration || defaultDur) || .35,
7324 (opt.easing || defaultEase) || 'easeOut',
7326 Roo.callback(cb, this);
7327 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7335 // private legacy anim prep
7336 preanim : function(a, i){
7337 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7341 * Removes worthless text nodes
7342 * @param {Boolean} forceReclean (optional) By default the element
7343 * keeps track if it has been cleaned already so
7344 * you can call this over and over. However, if you update the element and
7345 * need to force a reclean, you can pass true.
7347 clean : function(forceReclean){
7348 if(this.isCleaned && forceReclean !== true){
7352 var d = this.dom, n = d.firstChild, ni = -1;
7354 var nx = n.nextSibling;
7355 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7362 this.isCleaned = true;
7367 calcOffsetsTo : function(el){
7370 var restorePos = false;
7371 if(el.getStyle('position') == 'static'){
7372 el.position('relative');
7377 while(op && op != d && op.tagName != 'HTML'){
7380 op = op.offsetParent;
7383 el.position('static');
7389 * Scrolls this element into view within the passed container.
7390 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7391 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7392 * @return {Roo.Element} this
7394 scrollIntoView : function(container, hscroll){
7395 var c = Roo.getDom(container) || document.body;
7398 var o = this.calcOffsetsTo(c),
7401 b = t+el.offsetHeight,
7402 r = l+el.offsetWidth;
7404 var ch = c.clientHeight;
7405 var ct = parseInt(c.scrollTop, 10);
7406 var cl = parseInt(c.scrollLeft, 10);
7408 var cr = cl + c.clientWidth;
7416 if(hscroll !== false){
7420 c.scrollLeft = r-c.clientWidth;
7427 scrollChildIntoView : function(child, hscroll){
7428 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7432 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7433 * the new height may not be available immediately.
7434 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7435 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7436 * @param {Function} onComplete (optional) Function to call when animation completes
7437 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7438 * @return {Roo.Element} this
7440 autoHeight : function(animate, duration, onComplete, easing){
7441 var oldHeight = this.getHeight();
7443 this.setHeight(1); // force clipping
7444 setTimeout(function(){
7445 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7447 this.setHeight(height);
7449 if(typeof onComplete == "function"){
7453 this.setHeight(oldHeight); // restore original height
7454 this.setHeight(height, animate, duration, function(){
7456 if(typeof onComplete == "function") { onComplete(); }
7457 }.createDelegate(this), easing);
7459 }.createDelegate(this), 0);
7464 * Returns true if this element is an ancestor of the passed element
7465 * @param {HTMLElement/String} el The element to check
7466 * @return {Boolean} True if this element is an ancestor of el, else false
7468 contains : function(el){
7469 if(!el){return false;}
7470 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7474 * Checks whether the element is currently visible using both visibility and display properties.
7475 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7476 * @return {Boolean} True if the element is currently visible, else false
7478 isVisible : function(deep) {
7479 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7480 if(deep !== true || !vis){
7483 var p = this.dom.parentNode;
7484 while(p && p.tagName.toLowerCase() != "body"){
7485 if(!Roo.fly(p, '_isVisible').isVisible()){
7494 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7495 * @param {String} selector The CSS selector
7496 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7497 * @return {CompositeElement/CompositeElementLite} The composite element
7499 select : function(selector, unique){
7500 return El.select(selector, unique, this.dom);
7504 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7505 * @param {String} selector The CSS selector
7506 * @return {Array} An array of the matched nodes
7508 query : function(selector, unique){
7509 return Roo.DomQuery.select(selector, this.dom);
7513 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7514 * @param {String} selector The CSS selector
7515 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7516 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7518 child : function(selector, returnDom){
7519 var n = Roo.DomQuery.selectNode(selector, this.dom);
7520 return returnDom ? n : Roo.get(n);
7524 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7525 * @param {String} selector The CSS selector
7526 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7527 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7529 down : function(selector, returnDom){
7530 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7531 return returnDom ? n : Roo.get(n);
7535 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7536 * @param {String} group The group the DD object is member of
7537 * @param {Object} config The DD config object
7538 * @param {Object} overrides An object containing methods to override/implement on the DD object
7539 * @return {Roo.dd.DD} The DD object
7541 initDD : function(group, config, overrides){
7542 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7543 return Roo.apply(dd, overrides);
7547 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7548 * @param {String} group The group the DDProxy object is member of
7549 * @param {Object} config The DDProxy config object
7550 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7551 * @return {Roo.dd.DDProxy} The DDProxy object
7553 initDDProxy : function(group, config, overrides){
7554 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7555 return Roo.apply(dd, overrides);
7559 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7560 * @param {String} group The group the DDTarget object is member of
7561 * @param {Object} config The DDTarget config object
7562 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7563 * @return {Roo.dd.DDTarget} The DDTarget object
7565 initDDTarget : function(group, config, overrides){
7566 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7567 return Roo.apply(dd, overrides);
7571 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7572 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7573 * @param {Boolean} visible Whether the element is visible
7574 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7575 * @return {Roo.Element} this
7577 setVisible : function(visible, animate){
7579 if(this.visibilityMode == El.DISPLAY){
7580 this.setDisplayed(visible);
7583 this.dom.style.visibility = visible ? "visible" : "hidden";
7586 // closure for composites
7588 var visMode = this.visibilityMode;
7590 this.setOpacity(.01);
7591 this.setVisible(true);
7593 this.anim({opacity: { to: (visible?1:0) }},
7594 this.preanim(arguments, 1),
7595 null, .35, 'easeIn', function(){
7597 if(visMode == El.DISPLAY){
7598 dom.style.display = "none";
7600 dom.style.visibility = "hidden";
7602 Roo.get(dom).setOpacity(1);
7610 * Returns true if display is not "none"
7613 isDisplayed : function() {
7614 return this.getStyle("display") != "none";
7618 * Toggles the element's visibility or display, depending on visibility mode.
7619 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7620 * @return {Roo.Element} this
7622 toggle : function(animate){
7623 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7628 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7629 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7630 * @return {Roo.Element} this
7632 setDisplayed : function(value) {
7633 if(typeof value == "boolean"){
7634 value = value ? this.originalDisplay : "none";
7636 this.setStyle("display", value);
7641 * Tries to focus the element. Any exceptions are caught and ignored.
7642 * @return {Roo.Element} this
7644 focus : function() {
7652 * Tries to blur the element. Any exceptions are caught and ignored.
7653 * @return {Roo.Element} this
7663 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7664 * @param {String/Array} className The CSS class to add, or an array of classes
7665 * @return {Roo.Element} this
7667 addClass : function(className){
7668 if(className instanceof Array){
7669 for(var i = 0, len = className.length; i < len; i++) {
7670 this.addClass(className[i]);
7673 if(className && !this.hasClass(className)){
7674 this.dom.className = this.dom.className + " " + className;
7681 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7682 * @param {String/Array} className The CSS class to add, or an array of classes
7683 * @return {Roo.Element} this
7685 radioClass : function(className){
7686 var siblings = this.dom.parentNode.childNodes;
7687 for(var i = 0; i < siblings.length; i++) {
7688 var s = siblings[i];
7689 if(s.nodeType == 1){
7690 Roo.get(s).removeClass(className);
7693 this.addClass(className);
7698 * Removes one or more CSS classes from the element.
7699 * @param {String/Array} className The CSS class to remove, or an array of classes
7700 * @return {Roo.Element} this
7702 removeClass : function(className){
7703 if(!className || !this.dom.className){
7706 if(className instanceof Array){
7707 for(var i = 0, len = className.length; i < len; i++) {
7708 this.removeClass(className[i]);
7711 if(this.hasClass(className)){
7712 var re = this.classReCache[className];
7714 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7715 this.classReCache[className] = re;
7717 this.dom.className =
7718 this.dom.className.replace(re, " ");
7728 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7729 * @param {String} className The CSS class to toggle
7730 * @return {Roo.Element} this
7732 toggleClass : function(className){
7733 if(this.hasClass(className)){
7734 this.removeClass(className);
7736 this.addClass(className);
7742 * Checks if the specified CSS class exists on this element's DOM node.
7743 * @param {String} className The CSS class to check for
7744 * @return {Boolean} True if the class exists, else false
7746 hasClass : function(className){
7747 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7751 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7752 * @param {String} oldClassName The CSS class to replace
7753 * @param {String} newClassName The replacement CSS class
7754 * @return {Roo.Element} this
7756 replaceClass : function(oldClassName, newClassName){
7757 this.removeClass(oldClassName);
7758 this.addClass(newClassName);
7763 * Returns an object with properties matching the styles requested.
7764 * For example, el.getStyles('color', 'font-size', 'width') might return
7765 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7766 * @param {String} style1 A style name
7767 * @param {String} style2 A style name
7768 * @param {String} etc.
7769 * @return {Object} The style object
7771 getStyles : function(){
7772 var a = arguments, len = a.length, r = {};
7773 for(var i = 0; i < len; i++){
7774 r[a[i]] = this.getStyle(a[i]);
7780 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7781 * @param {String} property The style property whose value is returned.
7782 * @return {String} The current value of the style property for this element.
7784 getStyle : function(){
7785 return view && view.getComputedStyle ?
7787 var el = this.dom, v, cs, camel;
7788 if(prop == 'float'){
7791 if(el.style && (v = el.style[prop])){
7794 if(cs = view.getComputedStyle(el, "")){
7795 if(!(camel = propCache[prop])){
7796 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7803 var el = this.dom, v, cs, camel;
7804 if(prop == 'opacity'){
7805 if(typeof el.style.filter == 'string'){
7806 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7808 var fv = parseFloat(m[1]);
7810 return fv ? fv / 100 : 0;
7815 }else if(prop == 'float'){
7816 prop = "styleFloat";
7818 if(!(camel = propCache[prop])){
7819 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7821 if(v = el.style[camel]){
7824 if(cs = el.currentStyle){
7832 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7833 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7834 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7835 * @return {Roo.Element} this
7837 setStyle : function(prop, value){
7838 if(typeof prop == "string"){
7840 if (prop == 'float') {
7841 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7846 if(!(camel = propCache[prop])){
7847 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7850 if(camel == 'opacity') {
7851 this.setOpacity(value);
7853 this.dom.style[camel] = value;
7856 for(var style in prop){
7857 if(typeof prop[style] != "function"){
7858 this.setStyle(style, prop[style]);
7866 * More flexible version of {@link #setStyle} for setting style properties.
7867 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7868 * a function which returns such a specification.
7869 * @return {Roo.Element} this
7871 applyStyles : function(style){
7872 Roo.DomHelper.applyStyles(this.dom, style);
7877 * 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).
7878 * @return {Number} The X position of the element
7881 return D.getX(this.dom);
7885 * 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).
7886 * @return {Number} The Y position of the element
7889 return D.getY(this.dom);
7893 * 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).
7894 * @return {Array} The XY position of the element
7897 return D.getXY(this.dom);
7901 * 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).
7902 * @param {Number} The X position of the element
7903 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7904 * @return {Roo.Element} this
7906 setX : function(x, animate){
7908 D.setX(this.dom, x);
7910 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7916 * 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).
7917 * @param {Number} The Y position of the element
7918 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7919 * @return {Roo.Element} this
7921 setY : function(y, animate){
7923 D.setY(this.dom, y);
7925 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7931 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7932 * @param {String} left The left CSS property value
7933 * @return {Roo.Element} this
7935 setLeft : function(left){
7936 this.setStyle("left", this.addUnits(left));
7941 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7942 * @param {String} top The top CSS property value
7943 * @return {Roo.Element} this
7945 setTop : function(top){
7946 this.setStyle("top", this.addUnits(top));
7951 * Sets the element's CSS right style.
7952 * @param {String} right The right CSS property value
7953 * @return {Roo.Element} this
7955 setRight : function(right){
7956 this.setStyle("right", this.addUnits(right));
7961 * Sets the element's CSS bottom style.
7962 * @param {String} bottom The bottom CSS property value
7963 * @return {Roo.Element} this
7965 setBottom : function(bottom){
7966 this.setStyle("bottom", this.addUnits(bottom));
7971 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7972 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7973 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7974 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7975 * @return {Roo.Element} this
7977 setXY : function(pos, animate){
7979 D.setXY(this.dom, pos);
7981 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7987 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7988 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7989 * @param {Number} x X value for new position (coordinates are page-based)
7990 * @param {Number} y Y value for new position (coordinates are page-based)
7991 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7992 * @return {Roo.Element} this
7994 setLocation : function(x, y, animate){
7995 this.setXY([x, y], this.preanim(arguments, 2));
8000 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8001 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8002 * @param {Number} x X value for new position (coordinates are page-based)
8003 * @param {Number} y Y value for new position (coordinates are page-based)
8004 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8005 * @return {Roo.Element} this
8007 moveTo : function(x, y, animate){
8008 this.setXY([x, y], this.preanim(arguments, 2));
8013 * Returns the region of the given element.
8014 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8015 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8017 getRegion : function(){
8018 return D.getRegion(this.dom);
8022 * Returns the offset height of the element
8023 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8024 * @return {Number} The element's height
8026 getHeight : function(contentHeight){
8027 var h = this.dom.offsetHeight || 0;
8028 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8032 * Returns the offset width of the element
8033 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8034 * @return {Number} The element's width
8036 getWidth : function(contentWidth){
8037 var w = this.dom.offsetWidth || 0;
8038 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8042 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8043 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8044 * if a height has not been set using CSS.
8047 getComputedHeight : function(){
8048 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8050 h = parseInt(this.getStyle('height'), 10) || 0;
8051 if(!this.isBorderBox()){
8052 h += this.getFrameWidth('tb');
8059 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8060 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8061 * if a width has not been set using CSS.
8064 getComputedWidth : function(){
8065 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8067 w = parseInt(this.getStyle('width'), 10) || 0;
8068 if(!this.isBorderBox()){
8069 w += this.getFrameWidth('lr');
8076 * Returns the size of the element.
8077 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8078 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8080 getSize : function(contentSize){
8081 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8085 * Returns the width and height of the viewport.
8086 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8088 getViewSize : function(){
8089 var d = this.dom, doc = document, aw = 0, ah = 0;
8090 if(d == doc || d == doc.body){
8091 return {width : D.getViewWidth(), height: D.getViewHeight()};
8094 width : d.clientWidth,
8095 height: d.clientHeight
8101 * Returns the value of the "value" attribute
8102 * @param {Boolean} asNumber true to parse the value as a number
8103 * @return {String/Number}
8105 getValue : function(asNumber){
8106 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8110 adjustWidth : function(width){
8111 if(typeof width == "number"){
8112 if(this.autoBoxAdjust && !this.isBorderBox()){
8113 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8123 adjustHeight : function(height){
8124 if(typeof height == "number"){
8125 if(this.autoBoxAdjust && !this.isBorderBox()){
8126 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8136 * Set the width of the element
8137 * @param {Number} width The new width
8138 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8139 * @return {Roo.Element} this
8141 setWidth : function(width, animate){
8142 width = this.adjustWidth(width);
8144 this.dom.style.width = this.addUnits(width);
8146 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8152 * Set the height of the element
8153 * @param {Number} height The new height
8154 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8155 * @return {Roo.Element} this
8157 setHeight : function(height, animate){
8158 height = this.adjustHeight(height);
8160 this.dom.style.height = this.addUnits(height);
8162 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8168 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8169 * @param {Number} width The new width
8170 * @param {Number} height The new height
8171 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8172 * @return {Roo.Element} this
8174 setSize : function(width, height, animate){
8175 if(typeof width == "object"){ // in case of object from getSize()
8176 height = width.height; width = width.width;
8178 width = this.adjustWidth(width); height = this.adjustHeight(height);
8180 this.dom.style.width = this.addUnits(width);
8181 this.dom.style.height = this.addUnits(height);
8183 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8189 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8190 * @param {Number} x X value for new position (coordinates are page-based)
8191 * @param {Number} y Y value for new position (coordinates are page-based)
8192 * @param {Number} width The new width
8193 * @param {Number} height The new height
8194 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8195 * @return {Roo.Element} this
8197 setBounds : function(x, y, width, height, animate){
8199 this.setSize(width, height);
8200 this.setLocation(x, y);
8202 width = this.adjustWidth(width); height = this.adjustHeight(height);
8203 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8204 this.preanim(arguments, 4), 'motion');
8210 * 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.
8211 * @param {Roo.lib.Region} region The region to fill
8212 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8213 * @return {Roo.Element} this
8215 setRegion : function(region, animate){
8216 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8221 * Appends an event handler
8223 * @param {String} eventName The type of event to append
8224 * @param {Function} fn The method the event invokes
8225 * @param {Object} scope (optional) The scope (this object) of the fn
8226 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8228 addListener : function(eventName, fn, scope, options){
8230 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8235 * Removes an event handler from this element
8236 * @param {String} eventName the type of event to remove
8237 * @param {Function} fn the method the event invokes
8238 * @return {Roo.Element} this
8240 removeListener : function(eventName, fn){
8241 Roo.EventManager.removeListener(this.dom, eventName, fn);
8246 * Removes all previous added listeners from this element
8247 * @return {Roo.Element} this
8249 removeAllListeners : function(){
8250 E.purgeElement(this.dom);
8254 relayEvent : function(eventName, observable){
8255 this.on(eventName, function(e){
8256 observable.fireEvent(eventName, e);
8261 * Set the opacity of the element
8262 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8263 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8264 * @return {Roo.Element} this
8266 setOpacity : function(opacity, animate){
8268 var s = this.dom.style;
8271 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8272 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8274 s.opacity = opacity;
8277 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8283 * Gets the left X coordinate
8284 * @param {Boolean} local True to get the local css position instead of page coordinate
8287 getLeft : function(local){
8291 return parseInt(this.getStyle("left"), 10) || 0;
8296 * Gets the right X coordinate of the element (element X position + element width)
8297 * @param {Boolean} local True to get the local css position instead of page coordinate
8300 getRight : function(local){
8302 return this.getX() + this.getWidth();
8304 return (this.getLeft(true) + this.getWidth()) || 0;
8309 * Gets the top Y coordinate
8310 * @param {Boolean} local True to get the local css position instead of page coordinate
8313 getTop : function(local) {
8317 return parseInt(this.getStyle("top"), 10) || 0;
8322 * Gets the bottom Y coordinate of the element (element Y position + element height)
8323 * @param {Boolean} local True to get the local css position instead of page coordinate
8326 getBottom : function(local){
8328 return this.getY() + this.getHeight();
8330 return (this.getTop(true) + this.getHeight()) || 0;
8335 * Initializes positioning on this element. If a desired position is not passed, it will make the
8336 * the element positioned relative IF it is not already positioned.
8337 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8338 * @param {Number} zIndex (optional) The zIndex to apply
8339 * @param {Number} x (optional) Set the page X position
8340 * @param {Number} y (optional) Set the page Y position
8342 position : function(pos, zIndex, x, y){
8344 if(this.getStyle('position') == 'static'){
8345 this.setStyle('position', 'relative');
8348 this.setStyle("position", pos);
8351 this.setStyle("z-index", zIndex);
8353 if(x !== undefined && y !== undefined){
8355 }else if(x !== undefined){
8357 }else if(y !== undefined){
8363 * Clear positioning back to the default when the document was loaded
8364 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8365 * @return {Roo.Element} this
8367 clearPositioning : function(value){
8375 "position" : "static"
8381 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8382 * snapshot before performing an update and then restoring the element.
8385 getPositioning : function(){
8386 var l = this.getStyle("left");
8387 var t = this.getStyle("top");
8389 "position" : this.getStyle("position"),
8391 "right" : l ? "" : this.getStyle("right"),
8393 "bottom" : t ? "" : this.getStyle("bottom"),
8394 "z-index" : this.getStyle("z-index")
8399 * Gets the width of the border(s) for the specified side(s)
8400 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8401 * passing lr would get the border (l)eft width + the border (r)ight width.
8402 * @return {Number} The width of the sides passed added together
8404 getBorderWidth : function(side){
8405 return this.addStyles(side, El.borders);
8409 * Gets the width of the padding(s) for the specified side(s)
8410 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8411 * passing lr would get the padding (l)eft + the padding (r)ight.
8412 * @return {Number} The padding of the sides passed added together
8414 getPadding : function(side){
8415 return this.addStyles(side, El.paddings);
8419 * Set positioning with an object returned by getPositioning().
8420 * @param {Object} posCfg
8421 * @return {Roo.Element} this
8423 setPositioning : function(pc){
8424 this.applyStyles(pc);
8425 if(pc.right == "auto"){
8426 this.dom.style.right = "";
8428 if(pc.bottom == "auto"){
8429 this.dom.style.bottom = "";
8435 fixDisplay : function(){
8436 if(this.getStyle("display") == "none"){
8437 this.setStyle("visibility", "hidden");
8438 this.setStyle("display", this.originalDisplay); // first try reverting to default
8439 if(this.getStyle("display") == "none"){ // if that fails, default to block
8440 this.setStyle("display", "block");
8446 * Quick set left and top adding default units
8447 * @param {String} left The left CSS property value
8448 * @param {String} top The top CSS property value
8449 * @return {Roo.Element} this
8451 setLeftTop : function(left, top){
8452 this.dom.style.left = this.addUnits(left);
8453 this.dom.style.top = this.addUnits(top);
8458 * Move this element relative to its current position.
8459 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8460 * @param {Number} distance How far to move the element in pixels
8461 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8462 * @return {Roo.Element} this
8464 move : function(direction, distance, animate){
8465 var xy = this.getXY();
8466 direction = direction.toLowerCase();
8470 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8474 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8479 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8484 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8491 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8492 * @return {Roo.Element} this
8495 if(!this.isClipped){
8496 this.isClipped = true;
8497 this.originalClip = {
8498 "o": this.getStyle("overflow"),
8499 "x": this.getStyle("overflow-x"),
8500 "y": this.getStyle("overflow-y")
8502 this.setStyle("overflow", "hidden");
8503 this.setStyle("overflow-x", "hidden");
8504 this.setStyle("overflow-y", "hidden");
8510 * Return clipping (overflow) to original clipping before clip() was called
8511 * @return {Roo.Element} this
8513 unclip : function(){
8515 this.isClipped = false;
8516 var o = this.originalClip;
8517 if(o.o){this.setStyle("overflow", o.o);}
8518 if(o.x){this.setStyle("overflow-x", o.x);}
8519 if(o.y){this.setStyle("overflow-y", o.y);}
8526 * Gets the x,y coordinates specified by the anchor position on the element.
8527 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8528 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8529 * {width: (target width), height: (target height)} (defaults to the element's current size)
8530 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8531 * @return {Array} [x, y] An array containing the element's x and y coordinates
8533 getAnchorXY : function(anchor, local, s){
8534 //Passing a different size is useful for pre-calculating anchors,
8535 //especially for anchored animations that change the el size.
8537 var w, h, vp = false;
8540 if(d == document.body || d == document){
8542 w = D.getViewWidth(); h = D.getViewHeight();
8544 w = this.getWidth(); h = this.getHeight();
8547 w = s.width; h = s.height;
8549 var x = 0, y = 0, r = Math.round;
8550 switch((anchor || "tl").toLowerCase()){
8592 var sc = this.getScroll();
8593 return [x + sc.left, y + sc.top];
8595 //Add the element's offset xy
8596 var o = this.getXY();
8597 return [x+o[0], y+o[1]];
8601 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8602 * supported position values.
8603 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8604 * @param {String} position The position to align to.
8605 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8606 * @return {Array} [x, y]
8608 getAlignToXY : function(el, p, o)
8613 throw "Element.alignTo with an element that doesn't exist";
8615 var c = false; //constrain to viewport
8616 var p1 = "", p2 = "";
8623 }else if(p.indexOf("-") == -1){
8626 p = p.toLowerCase();
8627 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8629 throw "Element.alignTo with an invalid alignment " + p;
8631 p1 = m[1]; p2 = m[2]; c = !!m[3];
8633 //Subtract the aligned el's internal xy from the target's offset xy
8634 //plus custom offset to get the aligned el's new offset xy
8635 var a1 = this.getAnchorXY(p1, true);
8636 var a2 = el.getAnchorXY(p2, false);
8637 var x = a2[0] - a1[0] + o[0];
8638 var y = a2[1] - a1[1] + o[1];
8640 //constrain the aligned el to viewport if necessary
8641 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8642 // 5px of margin for ie
8643 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8645 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8646 //perpendicular to the vp border, allow the aligned el to slide on that border,
8647 //otherwise swap the aligned el to the opposite border of the target.
8648 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8649 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8650 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8651 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8654 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8655 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8657 if((x+w) > dw + scrollX){
8658 x = swapX ? r.left-w : dw+scrollX-w;
8661 x = swapX ? r.right : scrollX;
8663 if((y+h) > dh + scrollY){
8664 y = swapY ? r.top-h : dh+scrollY-h;
8667 y = swapY ? r.bottom : scrollY;
8674 getConstrainToXY : function(){
8675 var os = {top:0, left:0, bottom:0, right: 0};
8677 return function(el, local, offsets, proposedXY){
8679 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8681 var vw, vh, vx = 0, vy = 0;
8682 if(el.dom == document.body || el.dom == document){
8683 vw = Roo.lib.Dom.getViewWidth();
8684 vh = Roo.lib.Dom.getViewHeight();
8686 vw = el.dom.clientWidth;
8687 vh = el.dom.clientHeight;
8689 var vxy = el.getXY();
8695 var s = el.getScroll();
8697 vx += offsets.left + s.left;
8698 vy += offsets.top + s.top;
8700 vw -= offsets.right;
8701 vh -= offsets.bottom;
8706 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8707 var x = xy[0], y = xy[1];
8708 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8710 // only move it if it needs it
8713 // first validate right/bottom
8722 // then make sure top/left isn't negative
8731 return moved ? [x, y] : false;
8736 adjustForConstraints : function(xy, parent, offsets){
8737 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8741 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8742 * document it aligns it to the viewport.
8743 * The position parameter is optional, and can be specified in any one of the following formats:
8745 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8746 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8747 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8748 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8749 * <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
8750 * element's anchor point, and the second value is used as the target's anchor point.</li>
8752 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8753 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8754 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8755 * that specified in order to enforce the viewport constraints.
8756 * Following are all of the supported anchor positions:
8759 ----- -----------------------------
8760 tl The top left corner (default)
8761 t The center of the top edge
8762 tr The top right corner
8763 l The center of the left edge
8764 c In the center of the element
8765 r The center of the right edge
8766 bl The bottom left corner
8767 b The center of the bottom edge
8768 br The bottom right corner
8772 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8773 el.alignTo("other-el");
8775 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8776 el.alignTo("other-el", "tr?");
8778 // align the bottom right corner of el with the center left edge of other-el
8779 el.alignTo("other-el", "br-l?");
8781 // align the center of el with the bottom left corner of other-el and
8782 // adjust the x position by -6 pixels (and the y position by 0)
8783 el.alignTo("other-el", "c-bl", [-6, 0]);
8785 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8786 * @param {String} position The position to align to.
8787 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8788 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8789 * @return {Roo.Element} this
8791 alignTo : function(element, position, offsets, animate){
8792 var xy = this.getAlignToXY(element, position, offsets);
8793 this.setXY(xy, this.preanim(arguments, 3));
8798 * Anchors an element to another element and realigns it when the window is resized.
8799 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8800 * @param {String} position The position to align to.
8801 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8802 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8803 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8804 * is a number, it is used as the buffer delay (defaults to 50ms).
8805 * @param {Function} callback The function to call after the animation finishes
8806 * @return {Roo.Element} this
8808 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8809 var action = function(){
8810 this.alignTo(el, alignment, offsets, animate);
8811 Roo.callback(callback, this);
8813 Roo.EventManager.onWindowResize(action, this);
8814 var tm = typeof monitorScroll;
8815 if(tm != 'undefined'){
8816 Roo.EventManager.on(window, 'scroll', action, this,
8817 {buffer: tm == 'number' ? monitorScroll : 50});
8819 action.call(this); // align immediately
8823 * Clears any opacity settings from this element. Required in some cases for IE.
8824 * @return {Roo.Element} this
8826 clearOpacity : function(){
8827 if (window.ActiveXObject) {
8828 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8829 this.dom.style.filter = "";
8832 this.dom.style.opacity = "";
8833 this.dom.style["-moz-opacity"] = "";
8834 this.dom.style["-khtml-opacity"] = "";
8840 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8841 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8842 * @return {Roo.Element} this
8844 hide : function(animate){
8845 this.setVisible(false, this.preanim(arguments, 0));
8850 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8851 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8852 * @return {Roo.Element} this
8854 show : function(animate){
8855 this.setVisible(true, this.preanim(arguments, 0));
8860 * @private Test if size has a unit, otherwise appends the default
8862 addUnits : function(size){
8863 return Roo.Element.addUnits(size, this.defaultUnit);
8867 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8868 * @return {Roo.Element} this
8870 beginMeasure : function(){
8872 if(el.offsetWidth || el.offsetHeight){
8873 return this; // offsets work already
8876 var p = this.dom, b = document.body; // start with this element
8877 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8878 var pe = Roo.get(p);
8879 if(pe.getStyle('display') == 'none'){
8880 changed.push({el: p, visibility: pe.getStyle("visibility")});
8881 p.style.visibility = "hidden";
8882 p.style.display = "block";
8886 this._measureChanged = changed;
8892 * Restores displays to before beginMeasure was called
8893 * @return {Roo.Element} this
8895 endMeasure : function(){
8896 var changed = this._measureChanged;
8898 for(var i = 0, len = changed.length; i < len; i++) {
8900 r.el.style.visibility = r.visibility;
8901 r.el.style.display = "none";
8903 this._measureChanged = null;
8909 * Update the innerHTML of this element, optionally searching for and processing scripts
8910 * @param {String} html The new HTML
8911 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8912 * @param {Function} callback For async script loading you can be noticed when the update completes
8913 * @return {Roo.Element} this
8915 update : function(html, loadScripts, callback){
8916 if(typeof html == "undefined"){
8919 if(loadScripts !== true){
8920 this.dom.innerHTML = html;
8921 if(typeof callback == "function"){
8929 html += '<span id="' + id + '"></span>';
8931 E.onAvailable(id, function(){
8932 var hd = document.getElementsByTagName("head")[0];
8933 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8934 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8935 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8938 while(match = re.exec(html)){
8939 var attrs = match[1];
8940 var srcMatch = attrs ? attrs.match(srcRe) : false;
8941 if(srcMatch && srcMatch[2]){
8942 var s = document.createElement("script");
8943 s.src = srcMatch[2];
8944 var typeMatch = attrs.match(typeRe);
8945 if(typeMatch && typeMatch[2]){
8946 s.type = typeMatch[2];
8949 }else if(match[2] && match[2].length > 0){
8950 if(window.execScript) {
8951 window.execScript(match[2]);
8959 window.eval(match[2]);
8963 var el = document.getElementById(id);
8964 if(el){el.parentNode.removeChild(el);}
8965 if(typeof callback == "function"){
8969 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8974 * Direct access to the UpdateManager update() method (takes the same parameters).
8975 * @param {String/Function} url The url for this request or a function to call to get the url
8976 * @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}
8977 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8978 * @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.
8979 * @return {Roo.Element} this
8982 var um = this.getUpdateManager();
8983 um.update.apply(um, arguments);
8988 * Gets this element's UpdateManager
8989 * @return {Roo.UpdateManager} The UpdateManager
8991 getUpdateManager : function(){
8992 if(!this.updateManager){
8993 this.updateManager = new Roo.UpdateManager(this);
8995 return this.updateManager;
8999 * Disables text selection for this element (normalized across browsers)
9000 * @return {Roo.Element} this
9002 unselectable : function(){
9003 this.dom.unselectable = "on";
9004 this.swallowEvent("selectstart", true);
9005 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9006 this.addClass("x-unselectable");
9011 * Calculates the x, y to center this element on the screen
9012 * @return {Array} The x, y values [x, y]
9014 getCenterXY : function(){
9015 return this.getAlignToXY(document, 'c-c');
9019 * Centers the Element in either the viewport, or another Element.
9020 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9022 center : function(centerIn){
9023 this.alignTo(centerIn || document, 'c-c');
9028 * Tests various css rules/browsers to determine if this element uses a border box
9031 isBorderBox : function(){
9032 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9036 * Return a box {x, y, width, height} that can be used to set another elements
9037 * size/location to match this element.
9038 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9039 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9040 * @return {Object} box An object in the format {x, y, width, height}
9042 getBox : function(contentBox, local){
9047 var left = parseInt(this.getStyle("left"), 10) || 0;
9048 var top = parseInt(this.getStyle("top"), 10) || 0;
9051 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9053 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9055 var l = this.getBorderWidth("l")+this.getPadding("l");
9056 var r = this.getBorderWidth("r")+this.getPadding("r");
9057 var t = this.getBorderWidth("t")+this.getPadding("t");
9058 var b = this.getBorderWidth("b")+this.getPadding("b");
9059 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)};
9061 bx.right = bx.x + bx.width;
9062 bx.bottom = bx.y + bx.height;
9067 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9068 for more information about the sides.
9069 * @param {String} sides
9072 getFrameWidth : function(sides, onlyContentBox){
9073 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9077 * 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.
9078 * @param {Object} box The box to fill {x, y, width, height}
9079 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9080 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9081 * @return {Roo.Element} this
9083 setBox : function(box, adjust, animate){
9084 var w = box.width, h = box.height;
9085 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9086 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9087 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9089 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9094 * Forces the browser to repaint this element
9095 * @return {Roo.Element} this
9097 repaint : function(){
9099 this.addClass("x-repaint");
9100 setTimeout(function(){
9101 Roo.get(dom).removeClass("x-repaint");
9107 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9108 * then it returns the calculated width of the sides (see getPadding)
9109 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9110 * @return {Object/Number}
9112 getMargins : function(side){
9115 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9116 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9117 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9118 right: parseInt(this.getStyle("margin-right"), 10) || 0
9121 return this.addStyles(side, El.margins);
9126 addStyles : function(sides, styles){
9128 for(var i = 0, len = sides.length; i < len; i++){
9129 v = this.getStyle(styles[sides.charAt(i)]);
9131 w = parseInt(v, 10);
9139 * Creates a proxy element of this element
9140 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9141 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9142 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9143 * @return {Roo.Element} The new proxy element
9145 createProxy : function(config, renderTo, matchBox){
9147 renderTo = Roo.getDom(renderTo);
9149 renderTo = document.body;
9151 config = typeof config == "object" ?
9152 config : {tag : "div", cls: config};
9153 var proxy = Roo.DomHelper.append(renderTo, config, true);
9155 proxy.setBox(this.getBox());
9161 * Puts a mask over this element to disable user interaction. Requires core.css.
9162 * This method can only be applied to elements which accept child nodes.
9163 * @param {String} msg (optional) A message to display in the mask
9164 * @param {String} msgCls (optional) A css class to apply to the msg element
9165 * @return {Element} The mask element
9167 mask : function(msg, msgCls)
9169 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9170 this.setStyle("position", "relative");
9173 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9176 this.addClass("x-masked");
9177 this._mask.setDisplayed(true);
9182 while (dom && dom.style) {
9183 if (!isNaN(parseInt(dom.style.zIndex))) {
9184 z = Math.max(z, parseInt(dom.style.zIndex));
9186 dom = dom.parentNode;
9188 // if we are masking the body - then it hides everything..
9189 if (this.dom == document.body) {
9191 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9192 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9195 if(typeof msg == 'string'){
9197 this._maskMsg = Roo.DomHelper.append(this.dom, {
9198 cls: "roo-el-mask-msg",
9202 cls: 'fa fa-spinner fa-spin'
9210 var mm = this._maskMsg;
9211 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9212 if (mm.dom.lastChild) { // weird IE issue?
9213 mm.dom.lastChild.innerHTML = msg;
9215 mm.setDisplayed(true);
9217 mm.setStyle('z-index', z + 102);
9219 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9220 this._mask.setHeight(this.getHeight());
9222 this._mask.setStyle('z-index', z + 100);
9228 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9229 * it is cached for reuse.
9231 unmask : function(removeEl){
9233 if(removeEl === true){
9234 this._mask.remove();
9237 this._maskMsg.remove();
9238 delete this._maskMsg;
9241 this._mask.setDisplayed(false);
9243 this._maskMsg.setDisplayed(false);
9247 this.removeClass("x-masked");
9251 * Returns true if this element is masked
9254 isMasked : function(){
9255 return this._mask && this._mask.isVisible();
9259 * Creates an iframe shim for this element to keep selects and other windowed objects from
9261 * @return {Roo.Element} The new shim element
9263 createShim : function(){
9264 var el = document.createElement('iframe');
9265 el.frameBorder = 'no';
9266 el.className = 'roo-shim';
9267 if(Roo.isIE && Roo.isSecure){
9268 el.src = Roo.SSL_SECURE_URL;
9270 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9271 shim.autoBoxAdjust = false;
9276 * Removes this element from the DOM and deletes it from the cache
9278 remove : function(){
9279 if(this.dom.parentNode){
9280 this.dom.parentNode.removeChild(this.dom);
9282 delete El.cache[this.dom.id];
9286 * Sets up event handlers to add and remove a css class when the mouse is over this element
9287 * @param {String} className
9288 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9289 * mouseout events for children elements
9290 * @return {Roo.Element} this
9292 addClassOnOver : function(className, preventFlicker){
9293 this.on("mouseover", function(){
9294 Roo.fly(this, '_internal').addClass(className);
9296 var removeFn = function(e){
9297 if(preventFlicker !== true || !e.within(this, true)){
9298 Roo.fly(this, '_internal').removeClass(className);
9301 this.on("mouseout", removeFn, this.dom);
9306 * Sets up event handlers to add and remove a css class when this element has the focus
9307 * @param {String} className
9308 * @return {Roo.Element} this
9310 addClassOnFocus : function(className){
9311 this.on("focus", function(){
9312 Roo.fly(this, '_internal').addClass(className);
9314 this.on("blur", function(){
9315 Roo.fly(this, '_internal').removeClass(className);
9320 * 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)
9321 * @param {String} className
9322 * @return {Roo.Element} this
9324 addClassOnClick : function(className){
9326 this.on("mousedown", function(){
9327 Roo.fly(dom, '_internal').addClass(className);
9328 var d = Roo.get(document);
9329 var fn = function(){
9330 Roo.fly(dom, '_internal').removeClass(className);
9331 d.removeListener("mouseup", fn);
9333 d.on("mouseup", fn);
9339 * Stops the specified event from bubbling and optionally prevents the default action
9340 * @param {String} eventName
9341 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9342 * @return {Roo.Element} this
9344 swallowEvent : function(eventName, preventDefault){
9345 var fn = function(e){
9346 e.stopPropagation();
9351 if(eventName instanceof Array){
9352 for(var i = 0, len = eventName.length; i < len; i++){
9353 this.on(eventName[i], fn);
9357 this.on(eventName, fn);
9364 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9367 * Sizes this element to its parent element's dimensions performing
9368 * neccessary box adjustments.
9369 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9370 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9371 * @return {Roo.Element} this
9373 fitToParent : function(monitorResize, targetParent) {
9374 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9375 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9376 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9379 var p = Roo.get(targetParent || this.dom.parentNode);
9380 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9381 if (monitorResize === true) {
9382 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9383 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9389 * Gets the next sibling, skipping text nodes
9390 * @return {HTMLElement} The next sibling or null
9392 getNextSibling : function(){
9393 var n = this.dom.nextSibling;
9394 while(n && n.nodeType != 1){
9401 * Gets the previous sibling, skipping text nodes
9402 * @return {HTMLElement} The previous sibling or null
9404 getPrevSibling : function(){
9405 var n = this.dom.previousSibling;
9406 while(n && n.nodeType != 1){
9407 n = n.previousSibling;
9414 * Appends the passed element(s) to this element
9415 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9416 * @return {Roo.Element} this
9418 appendChild: function(el){
9425 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9426 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9427 * automatically generated with the specified attributes.
9428 * @param {HTMLElement} insertBefore (optional) a child element of this element
9429 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9430 * @return {Roo.Element} The new child element
9432 createChild: function(config, insertBefore, returnDom){
9433 config = config || {tag:'div'};
9435 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9437 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9441 * Appends this element to the passed element
9442 * @param {String/HTMLElement/Element} el The new parent element
9443 * @return {Roo.Element} this
9445 appendTo: function(el){
9446 el = Roo.getDom(el);
9447 el.appendChild(this.dom);
9452 * Inserts this element before the passed element in the DOM
9453 * @param {String/HTMLElement/Element} el The element to insert before
9454 * @return {Roo.Element} this
9456 insertBefore: function(el){
9457 el = Roo.getDom(el);
9458 el.parentNode.insertBefore(this.dom, el);
9463 * Inserts this element after the passed element in the DOM
9464 * @param {String/HTMLElement/Element} el The element to insert after
9465 * @return {Roo.Element} this
9467 insertAfter: function(el){
9468 el = Roo.getDom(el);
9469 el.parentNode.insertBefore(this.dom, el.nextSibling);
9474 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9475 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9476 * @return {Roo.Element} The new child
9478 insertFirst: function(el, returnDom){
9480 if(typeof el == 'object' && !el.nodeType){ // dh config
9481 return this.createChild(el, this.dom.firstChild, returnDom);
9483 el = Roo.getDom(el);
9484 this.dom.insertBefore(el, this.dom.firstChild);
9485 return !returnDom ? Roo.get(el) : el;
9490 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9491 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9492 * @param {String} where (optional) 'before' or 'after' defaults to before
9493 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9494 * @return {Roo.Element} the inserted Element
9496 insertSibling: function(el, where, returnDom){
9497 where = where ? where.toLowerCase() : 'before';
9499 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9501 if(typeof el == 'object' && !el.nodeType){ // dh config
9502 if(where == 'after' && !this.dom.nextSibling){
9503 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9505 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9509 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9510 where == 'before' ? this.dom : this.dom.nextSibling);
9519 * Creates and wraps this element with another element
9520 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9521 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9522 * @return {HTMLElement/Element} The newly created wrapper element
9524 wrap: function(config, returnDom){
9526 config = {tag: "div"};
9528 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9529 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9534 * Replaces the passed element with this element
9535 * @param {String/HTMLElement/Element} el The element to replace
9536 * @return {Roo.Element} this
9538 replace: function(el){
9540 this.insertBefore(el);
9546 * Inserts an html fragment into this element
9547 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9548 * @param {String} html The HTML fragment
9549 * @param {Boolean} returnEl True to return an Roo.Element
9550 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9552 insertHtml : function(where, html, returnEl){
9553 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9554 return returnEl ? Roo.get(el) : el;
9558 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9559 * @param {Object} o The object with the attributes
9560 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9561 * @return {Roo.Element} this
9563 set : function(o, useSet){
9565 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9567 if(attr == "style" || typeof o[attr] == "function") { continue; }
9569 el.className = o["cls"];
9572 el.setAttribute(attr, o[attr]);
9579 Roo.DomHelper.applyStyles(el, o.style);
9585 * Convenience method for constructing a KeyMap
9586 * @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:
9587 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9588 * @param {Function} fn The function to call
9589 * @param {Object} scope (optional) The scope of the function
9590 * @return {Roo.KeyMap} The KeyMap created
9592 addKeyListener : function(key, fn, scope){
9594 if(typeof key != "object" || key instanceof Array){
9610 return new Roo.KeyMap(this, config);
9614 * Creates a KeyMap for this element
9615 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9616 * @return {Roo.KeyMap} The KeyMap created
9618 addKeyMap : function(config){
9619 return new Roo.KeyMap(this, config);
9623 * Returns true if this element is scrollable.
9626 isScrollable : function(){
9628 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9632 * 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().
9633 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9634 * @param {Number} value The new scroll value
9635 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9636 * @return {Element} this
9639 scrollTo : function(side, value, animate){
9640 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9642 this.dom[prop] = value;
9644 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9645 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9651 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9652 * within this element's scrollable range.
9653 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9654 * @param {Number} distance How far to scroll the element in pixels
9655 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9656 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9657 * was scrolled as far as it could go.
9659 scroll : function(direction, distance, animate){
9660 if(!this.isScrollable()){
9664 var l = el.scrollLeft, t = el.scrollTop;
9665 var w = el.scrollWidth, h = el.scrollHeight;
9666 var cw = el.clientWidth, ch = el.clientHeight;
9667 direction = direction.toLowerCase();
9668 var scrolled = false;
9669 var a = this.preanim(arguments, 2);
9674 var v = Math.min(l + distance, w-cw);
9675 this.scrollTo("left", v, a);
9682 var v = Math.max(l - distance, 0);
9683 this.scrollTo("left", v, a);
9691 var v = Math.max(t - distance, 0);
9692 this.scrollTo("top", v, a);
9700 var v = Math.min(t + distance, h-ch);
9701 this.scrollTo("top", v, a);
9710 * Translates the passed page coordinates into left/top css values for this element
9711 * @param {Number/Array} x The page x or an array containing [x, y]
9712 * @param {Number} y The page y
9713 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9715 translatePoints : function(x, y){
9716 if(typeof x == 'object' || x instanceof Array){
9719 var p = this.getStyle('position');
9720 var o = this.getXY();
9722 var l = parseInt(this.getStyle('left'), 10);
9723 var t = parseInt(this.getStyle('top'), 10);
9726 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9729 t = (p == "relative") ? 0 : this.dom.offsetTop;
9732 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9736 * Returns the current scroll position of the element.
9737 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9739 getScroll : function(){
9740 var d = this.dom, doc = document;
9741 if(d == doc || d == doc.body){
9742 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9743 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9744 return {left: l, top: t};
9746 return {left: d.scrollLeft, top: d.scrollTop};
9751 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9752 * are convert to standard 6 digit hex color.
9753 * @param {String} attr The css attribute
9754 * @param {String} defaultValue The default value to use when a valid color isn't found
9755 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9758 getColor : function(attr, defaultValue, prefix){
9759 var v = this.getStyle(attr);
9760 if(!v || v == "transparent" || v == "inherit") {
9761 return defaultValue;
9763 var color = typeof prefix == "undefined" ? "#" : prefix;
9764 if(v.substr(0, 4) == "rgb("){
9765 var rvs = v.slice(4, v.length -1).split(",");
9766 for(var i = 0; i < 3; i++){
9767 var h = parseInt(rvs[i]).toString(16);
9774 if(v.substr(0, 1) == "#"){
9776 for(var i = 1; i < 4; i++){
9777 var c = v.charAt(i);
9780 }else if(v.length == 7){
9781 color += v.substr(1);
9785 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9789 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9790 * gradient background, rounded corners and a 4-way shadow.
9791 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9792 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9793 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9794 * @return {Roo.Element} this
9796 boxWrap : function(cls){
9797 cls = cls || 'x-box';
9798 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9799 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9804 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9805 * @param {String} namespace The namespace in which to look for the attribute
9806 * @param {String} name The attribute name
9807 * @return {String} The attribute value
9809 getAttributeNS : Roo.isIE ? function(ns, name){
9811 var type = typeof d[ns+":"+name];
9812 if(type != 'undefined' && type != 'unknown'){
9813 return d[ns+":"+name];
9816 } : function(ns, name){
9818 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9823 * Sets or Returns the value the dom attribute value
9824 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9825 * @param {String} value (optional) The value to set the attribute to
9826 * @return {String} The attribute value
9828 attr : function(name){
9829 if (arguments.length > 1) {
9830 this.dom.setAttribute(name, arguments[1]);
9831 return arguments[1];
9833 if (typeof(name) == 'object') {
9834 for(var i in name) {
9835 this.attr(i, name[i]);
9841 if (!this.dom.hasAttribute(name)) {
9844 return this.dom.getAttribute(name);
9851 var ep = El.prototype;
9854 * Appends an event handler (Shorthand for addListener)
9855 * @param {String} eventName The type of event to append
9856 * @param {Function} fn The method the event invokes
9857 * @param {Object} scope (optional) The scope (this object) of the fn
9858 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9861 ep.on = ep.addListener;
9863 ep.mon = ep.addListener;
9866 * Removes an event handler from this element (shorthand for removeListener)
9867 * @param {String} eventName the type of event to remove
9868 * @param {Function} fn the method the event invokes
9869 * @return {Roo.Element} this
9872 ep.un = ep.removeListener;
9875 * true to automatically adjust width and height settings for box-model issues (default to true)
9877 ep.autoBoxAdjust = true;
9880 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9883 El.addUnits = function(v, defaultUnit){
9884 if(v === "" || v == "auto"){
9887 if(v === undefined){
9890 if(typeof v == "number" || !El.unitPattern.test(v)){
9891 return v + (defaultUnit || 'px');
9896 // special markup used throughout Roo when box wrapping elements
9897 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>';
9899 * Visibility mode constant - Use visibility to hide element
9905 * Visibility mode constant - Use display to hide element
9911 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9912 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9913 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9925 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9926 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9927 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9928 * @return {Element} The Element object
9931 El.get = function(el){
9933 if(!el){ return null; }
9934 if(typeof el == "string"){ // element id
9935 if(!(elm = document.getElementById(el))){
9938 if(ex = El.cache[el]){
9941 ex = El.cache[el] = new El(elm);
9944 }else if(el.tagName){ // dom element
9948 if(ex = El.cache[id]){
9951 ex = El.cache[id] = new El(el);
9954 }else if(el instanceof El){
9956 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9957 // catch case where it hasn't been appended
9958 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9961 }else if(el.isComposite){
9963 }else if(el instanceof Array){
9964 return El.select(el);
9965 }else if(el == document){
9966 // create a bogus element object representing the document object
9968 var f = function(){};
9969 f.prototype = El.prototype;
9971 docEl.dom = document;
9979 El.uncache = function(el){
9980 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9982 delete El.cache[a[i].id || a[i]];
9988 // Garbage collection - uncache elements/purge listeners on orphaned elements
9989 // so we don't hold a reference and cause the browser to retain them
9990 El.garbageCollect = function(){
9991 if(!Roo.enableGarbageCollector){
9992 clearInterval(El.collectorThread);
9995 for(var eid in El.cache){
9996 var el = El.cache[eid], d = el.dom;
9997 // -------------------------------------------------------
9998 // Determining what is garbage:
9999 // -------------------------------------------------------
10001 // dom node is null, definitely garbage
10002 // -------------------------------------------------------
10004 // no parentNode == direct orphan, definitely garbage
10005 // -------------------------------------------------------
10006 // !d.offsetParent && !document.getElementById(eid)
10007 // display none elements have no offsetParent so we will
10008 // also try to look it up by it's id. However, check
10009 // offsetParent first so we don't do unneeded lookups.
10010 // This enables collection of elements that are not orphans
10011 // directly, but somewhere up the line they have an orphan
10013 // -------------------------------------------------------
10014 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10015 delete El.cache[eid];
10016 if(d && Roo.enableListenerCollection){
10022 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10026 El.Flyweight = function(dom){
10029 El.Flyweight.prototype = El.prototype;
10031 El._flyweights = {};
10033 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10034 * the dom node can be overwritten by other code.
10035 * @param {String/HTMLElement} el The dom node or id
10036 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10037 * prevent conflicts (e.g. internally Roo uses "_internal")
10039 * @return {Element} The shared Element object
10041 El.fly = function(el, named){
10042 named = named || '_global';
10043 el = Roo.getDom(el);
10047 if(!El._flyweights[named]){
10048 El._flyweights[named] = new El.Flyweight();
10050 El._flyweights[named].dom = el;
10051 return El._flyweights[named];
10055 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10056 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10057 * Shorthand of {@link Roo.Element#get}
10058 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10059 * @return {Element} The Element object
10065 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10066 * the dom node can be overwritten by other code.
10067 * Shorthand of {@link Roo.Element#fly}
10068 * @param {String/HTMLElement} el The dom node or id
10069 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10070 * prevent conflicts (e.g. internally Roo uses "_internal")
10072 * @return {Element} The shared Element object
10078 // speedy lookup for elements never to box adjust
10079 var noBoxAdjust = Roo.isStrict ? {
10082 input:1, select:1, textarea:1
10084 if(Roo.isIE || Roo.isGecko){
10085 noBoxAdjust['button'] = 1;
10089 Roo.EventManager.on(window, 'unload', function(){
10091 delete El._flyweights;
10099 Roo.Element.selectorFunction = Roo.DomQuery.select;
10102 Roo.Element.select = function(selector, unique, root){
10104 if(typeof selector == "string"){
10105 els = Roo.Element.selectorFunction(selector, root);
10106 }else if(selector.length !== undefined){
10109 throw "Invalid selector";
10111 if(unique === true){
10112 return new Roo.CompositeElement(els);
10114 return new Roo.CompositeElementLite(els);
10118 * Selects elements based on the passed CSS selector to enable working on them as 1.
10119 * @param {String/Array} selector The CSS selector or an array of elements
10120 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10121 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10122 * @return {CompositeElementLite/CompositeElement}
10126 Roo.select = Roo.Element.select;
10143 * Ext JS Library 1.1.1
10144 * Copyright(c) 2006-2007, Ext JS, LLC.
10146 * Originally Released Under LGPL - original licence link has changed is not relivant.
10149 * <script type="text/javascript">
10154 //Notifies Element that fx methods are available
10155 Roo.enableFx = true;
10159 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10160 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10161 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10162 * Element effects to work.</p><br/>
10164 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10165 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10166 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10167 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10168 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10169 * expected results and should be done with care.</p><br/>
10171 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10172 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10175 ----- -----------------------------
10176 tl The top left corner
10177 t The center of the top edge
10178 tr The top right corner
10179 l The center of the left edge
10180 r The center of the right edge
10181 bl The bottom left corner
10182 b The center of the bottom edge
10183 br The bottom right corner
10185 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10186 * below are common options that can be passed to any Fx method.</b>
10187 * @cfg {Function} callback A function called when the effect is finished
10188 * @cfg {Object} scope The scope of the effect function
10189 * @cfg {String} easing A valid Easing value for the effect
10190 * @cfg {String} afterCls A css class to apply after the effect
10191 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10192 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10193 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10194 * effects that end with the element being visually hidden, ignored otherwise)
10195 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10196 * a function which returns such a specification that will be applied to the Element after the effect finishes
10197 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10198 * @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
10199 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10203 * Slides the element into view. An anchor point can be optionally passed to set the point of
10204 * origin for the slide effect. This function automatically handles wrapping the element with
10205 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10208 // default: slide the element in from the top
10211 // custom: slide the element in from the right with a 2-second duration
10212 el.slideIn('r', { duration: 2 });
10214 // common config options shown with default values
10220 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10221 * @param {Object} options (optional) Object literal with any of the Fx config options
10222 * @return {Roo.Element} The Element
10224 slideIn : function(anchor, o){
10225 var el = this.getFxEl();
10228 el.queueFx(o, function(){
10230 anchor = anchor || "t";
10232 // fix display to visibility
10235 // restore values after effect
10236 var r = this.getFxRestore();
10237 var b = this.getBox();
10238 // fixed size for slide
10242 var wrap = this.fxWrap(r.pos, o, "hidden");
10244 var st = this.dom.style;
10245 st.visibility = "visible";
10246 st.position = "absolute";
10248 // clear out temp styles after slide and unwrap
10249 var after = function(){
10250 el.fxUnwrap(wrap, r.pos, o);
10251 st.width = r.width;
10252 st.height = r.height;
10255 // time to calc the positions
10256 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10258 switch(anchor.toLowerCase()){
10260 wrap.setSize(b.width, 0);
10261 st.left = st.bottom = "0";
10265 wrap.setSize(0, b.height);
10266 st.right = st.top = "0";
10270 wrap.setSize(0, b.height);
10271 wrap.setX(b.right);
10272 st.left = st.top = "0";
10273 a = {width: bw, points: pt};
10276 wrap.setSize(b.width, 0);
10277 wrap.setY(b.bottom);
10278 st.left = st.top = "0";
10279 a = {height: bh, points: pt};
10282 wrap.setSize(0, 0);
10283 st.right = st.bottom = "0";
10284 a = {width: bw, height: bh};
10287 wrap.setSize(0, 0);
10288 wrap.setY(b.y+b.height);
10289 st.right = st.top = "0";
10290 a = {width: bw, height: bh, points: pt};
10293 wrap.setSize(0, 0);
10294 wrap.setXY([b.right, b.bottom]);
10295 st.left = st.top = "0";
10296 a = {width: bw, height: bh, points: pt};
10299 wrap.setSize(0, 0);
10300 wrap.setX(b.x+b.width);
10301 st.left = st.bottom = "0";
10302 a = {width: bw, height: bh, points: pt};
10305 this.dom.style.visibility = "visible";
10308 arguments.callee.anim = wrap.fxanim(a,
10318 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10319 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10320 * 'hidden') but block elements will still take up space in the document. The element must be removed
10321 * from the DOM using the 'remove' config option if desired. This function automatically handles
10322 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10325 // default: slide the element out to the top
10328 // custom: slide the element out to the right with a 2-second duration
10329 el.slideOut('r', { duration: 2 });
10331 // common config options shown with default values
10339 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10340 * @param {Object} options (optional) Object literal with any of the Fx config options
10341 * @return {Roo.Element} The Element
10343 slideOut : function(anchor, o){
10344 var el = this.getFxEl();
10347 el.queueFx(o, function(){
10349 anchor = anchor || "t";
10351 // restore values after effect
10352 var r = this.getFxRestore();
10354 var b = this.getBox();
10355 // fixed size for slide
10359 var wrap = this.fxWrap(r.pos, o, "visible");
10361 var st = this.dom.style;
10362 st.visibility = "visible";
10363 st.position = "absolute";
10367 var after = function(){
10369 el.setDisplayed(false);
10374 el.fxUnwrap(wrap, r.pos, o);
10376 st.width = r.width;
10377 st.height = r.height;
10382 var a, zero = {to: 0};
10383 switch(anchor.toLowerCase()){
10385 st.left = st.bottom = "0";
10386 a = {height: zero};
10389 st.right = st.top = "0";
10393 st.left = st.top = "0";
10394 a = {width: zero, points: {to:[b.right, b.y]}};
10397 st.left = st.top = "0";
10398 a = {height: zero, points: {to:[b.x, b.bottom]}};
10401 st.right = st.bottom = "0";
10402 a = {width: zero, height: zero};
10405 st.right = st.top = "0";
10406 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10409 st.left = st.top = "0";
10410 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10413 st.left = st.bottom = "0";
10414 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10418 arguments.callee.anim = wrap.fxanim(a,
10428 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10429 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10430 * The element must be removed from the DOM using the 'remove' config option if desired.
10436 // common config options shown with default values
10444 * @param {Object} options (optional) Object literal with any of the Fx config options
10445 * @return {Roo.Element} The Element
10447 puff : function(o){
10448 var el = this.getFxEl();
10451 el.queueFx(o, function(){
10452 this.clearOpacity();
10455 // restore values after effect
10456 var r = this.getFxRestore();
10457 var st = this.dom.style;
10459 var after = function(){
10461 el.setDisplayed(false);
10468 el.setPositioning(r.pos);
10469 st.width = r.width;
10470 st.height = r.height;
10475 var width = this.getWidth();
10476 var height = this.getHeight();
10478 arguments.callee.anim = this.fxanim({
10479 width : {to: this.adjustWidth(width * 2)},
10480 height : {to: this.adjustHeight(height * 2)},
10481 points : {by: [-(width * .5), -(height * .5)]},
10483 fontSize: {to:200, unit: "%"}
10494 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10495 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10496 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10502 // all config options shown with default values
10510 * @param {Object} options (optional) Object literal with any of the Fx config options
10511 * @return {Roo.Element} The Element
10513 switchOff : function(o){
10514 var el = this.getFxEl();
10517 el.queueFx(o, function(){
10518 this.clearOpacity();
10521 // restore values after effect
10522 var r = this.getFxRestore();
10523 var st = this.dom.style;
10525 var after = function(){
10527 el.setDisplayed(false);
10533 el.setPositioning(r.pos);
10534 st.width = r.width;
10535 st.height = r.height;
10540 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10541 this.clearOpacity();
10545 points:{by:[0, this.getHeight() * .5]}
10546 }, o, 'motion', 0.3, 'easeIn', after);
10547 }).defer(100, this);
10554 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10555 * changed using the "attr" config option) and then fading back to the original color. If no original
10556 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10559 // default: highlight background to yellow
10562 // custom: highlight foreground text to blue for 2 seconds
10563 el.highlight("0000ff", { attr: 'color', duration: 2 });
10565 // common config options shown with default values
10566 el.highlight("ffff9c", {
10567 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10568 endColor: (current color) or "ffffff",
10573 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10574 * @param {Object} options (optional) Object literal with any of the Fx config options
10575 * @return {Roo.Element} The Element
10577 highlight : function(color, o){
10578 var el = this.getFxEl();
10581 el.queueFx(o, function(){
10582 color = color || "ffff9c";
10583 attr = o.attr || "backgroundColor";
10585 this.clearOpacity();
10588 var origColor = this.getColor(attr);
10589 var restoreColor = this.dom.style[attr];
10590 endColor = (o.endColor || origColor) || "ffffff";
10592 var after = function(){
10593 el.dom.style[attr] = restoreColor;
10598 a[attr] = {from: color, to: endColor};
10599 arguments.callee.anim = this.fxanim(a,
10609 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10612 // default: a single light blue ripple
10615 // custom: 3 red ripples lasting 3 seconds total
10616 el.frame("ff0000", 3, { duration: 3 });
10618 // common config options shown with default values
10619 el.frame("C3DAF9", 1, {
10620 duration: 1 //duration of entire animation (not each individual ripple)
10621 // Note: Easing is not configurable and will be ignored if included
10624 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10625 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10626 * @param {Object} options (optional) Object literal with any of the Fx config options
10627 * @return {Roo.Element} The Element
10629 frame : function(color, count, o){
10630 var el = this.getFxEl();
10633 el.queueFx(o, function(){
10634 color = color || "#C3DAF9";
10635 if(color.length == 6){
10636 color = "#" + color;
10638 count = count || 1;
10639 duration = o.duration || 1;
10642 var b = this.getBox();
10643 var animFn = function(){
10644 var proxy = this.createProxy({
10647 visbility:"hidden",
10648 position:"absolute",
10649 "z-index":"35000", // yee haw
10650 border:"0px solid " + color
10653 var scale = Roo.isBorderBox ? 2 : 1;
10655 top:{from:b.y, to:b.y - 20},
10656 left:{from:b.x, to:b.x - 20},
10657 borderWidth:{from:0, to:10},
10658 opacity:{from:1, to:0},
10659 height:{from:b.height, to:(b.height + (20*scale))},
10660 width:{from:b.width, to:(b.width + (20*scale))}
10661 }, duration, function(){
10665 animFn.defer((duration/2)*1000, this);
10676 * Creates a pause before any subsequent queued effects begin. If there are
10677 * no effects queued after the pause it will have no effect.
10682 * @param {Number} seconds The length of time to pause (in seconds)
10683 * @return {Roo.Element} The Element
10685 pause : function(seconds){
10686 var el = this.getFxEl();
10689 el.queueFx(o, function(){
10690 setTimeout(function(){
10692 }, seconds * 1000);
10698 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10699 * using the "endOpacity" config option.
10702 // default: fade in from opacity 0 to 100%
10705 // custom: fade in from opacity 0 to 75% over 2 seconds
10706 el.fadeIn({ endOpacity: .75, duration: 2});
10708 // common config options shown with default values
10710 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10715 * @param {Object} options (optional) Object literal with any of the Fx config options
10716 * @return {Roo.Element} The Element
10718 fadeIn : function(o){
10719 var el = this.getFxEl();
10721 el.queueFx(o, function(){
10722 this.setOpacity(0);
10724 this.dom.style.visibility = 'visible';
10725 var to = o.endOpacity || 1;
10726 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10727 o, null, .5, "easeOut", function(){
10729 this.clearOpacity();
10738 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10739 * using the "endOpacity" config option.
10742 // default: fade out from the element's current opacity to 0
10745 // custom: fade out from the element's current opacity to 25% over 2 seconds
10746 el.fadeOut({ endOpacity: .25, duration: 2});
10748 // common config options shown with default values
10750 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10757 * @param {Object} options (optional) Object literal with any of the Fx config options
10758 * @return {Roo.Element} The Element
10760 fadeOut : function(o){
10761 var el = this.getFxEl();
10763 el.queueFx(o, function(){
10764 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10765 o, null, .5, "easeOut", function(){
10766 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10767 this.dom.style.display = "none";
10769 this.dom.style.visibility = "hidden";
10771 this.clearOpacity();
10779 * Animates the transition of an element's dimensions from a starting height/width
10780 * to an ending height/width.
10783 // change height and width to 100x100 pixels
10784 el.scale(100, 100);
10786 // common config options shown with default values. The height and width will default to
10787 // the element's existing values if passed as null.
10790 [element's height], {
10795 * @param {Number} width The new width (pass undefined to keep the original width)
10796 * @param {Number} height The new height (pass undefined to keep the original height)
10797 * @param {Object} options (optional) Object literal with any of the Fx config options
10798 * @return {Roo.Element} The Element
10800 scale : function(w, h, o){
10801 this.shift(Roo.apply({}, o, {
10809 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10810 * Any of these properties not specified in the config object will not be changed. This effect
10811 * requires that at least one new dimension, position or opacity setting must be passed in on
10812 * the config object in order for the function to have any effect.
10815 // slide the element horizontally to x position 200 while changing the height and opacity
10816 el.shift({ x: 200, height: 50, opacity: .8 });
10818 // common config options shown with default values.
10820 width: [element's width],
10821 height: [element's height],
10822 x: [element's x position],
10823 y: [element's y position],
10824 opacity: [element's opacity],
10829 * @param {Object} options Object literal with any of the Fx config options
10830 * @return {Roo.Element} The Element
10832 shift : function(o){
10833 var el = this.getFxEl();
10835 el.queueFx(o, function(){
10836 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10837 if(w !== undefined){
10838 a.width = {to: this.adjustWidth(w)};
10840 if(h !== undefined){
10841 a.height = {to: this.adjustHeight(h)};
10843 if(x !== undefined || y !== undefined){
10845 x !== undefined ? x : this.getX(),
10846 y !== undefined ? y : this.getY()
10849 if(op !== undefined){
10850 a.opacity = {to: op};
10852 if(o.xy !== undefined){
10853 a.points = {to: o.xy};
10855 arguments.callee.anim = this.fxanim(a,
10856 o, 'motion', .35, "easeOut", function(){
10864 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10865 * ending point of the effect.
10868 // default: slide the element downward while fading out
10871 // custom: slide the element out to the right with a 2-second duration
10872 el.ghost('r', { duration: 2 });
10874 // common config options shown with default values
10882 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10883 * @param {Object} options (optional) Object literal with any of the Fx config options
10884 * @return {Roo.Element} The Element
10886 ghost : function(anchor, o){
10887 var el = this.getFxEl();
10890 el.queueFx(o, function(){
10891 anchor = anchor || "b";
10893 // restore values after effect
10894 var r = this.getFxRestore();
10895 var w = this.getWidth(),
10896 h = this.getHeight();
10898 var st = this.dom.style;
10900 var after = function(){
10902 el.setDisplayed(false);
10908 el.setPositioning(r.pos);
10909 st.width = r.width;
10910 st.height = r.height;
10915 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10916 switch(anchor.toLowerCase()){
10943 arguments.callee.anim = this.fxanim(a,
10953 * Ensures that all effects queued after syncFx is called on the element are
10954 * run concurrently. This is the opposite of {@link #sequenceFx}.
10955 * @return {Roo.Element} The Element
10957 syncFx : function(){
10958 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10967 * Ensures that all effects queued after sequenceFx is called on the element are
10968 * run in sequence. This is the opposite of {@link #syncFx}.
10969 * @return {Roo.Element} The Element
10971 sequenceFx : function(){
10972 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10974 concurrent : false,
10981 nextFx : function(){
10982 var ef = this.fxQueue[0];
10989 * Returns true if the element has any effects actively running or queued, else returns false.
10990 * @return {Boolean} True if element has active effects, else false
10992 hasActiveFx : function(){
10993 return this.fxQueue && this.fxQueue[0];
10997 * Stops any running effects and clears the element's internal effects queue if it contains
10998 * any additional effects that haven't started yet.
10999 * @return {Roo.Element} The Element
11001 stopFx : function(){
11002 if(this.hasActiveFx()){
11003 var cur = this.fxQueue[0];
11004 if(cur && cur.anim && cur.anim.isAnimated()){
11005 this.fxQueue = [cur]; // clear out others
11006 cur.anim.stop(true);
11013 beforeFx : function(o){
11014 if(this.hasActiveFx() && !o.concurrent){
11025 * Returns true if the element is currently blocking so that no other effect can be queued
11026 * until this effect is finished, else returns false if blocking is not set. This is commonly
11027 * used to ensure that an effect initiated by a user action runs to completion prior to the
11028 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11029 * @return {Boolean} True if blocking, else false
11031 hasFxBlock : function(){
11032 var q = this.fxQueue;
11033 return q && q[0] && q[0].block;
11037 queueFx : function(o, fn){
11041 if(!this.hasFxBlock()){
11042 Roo.applyIf(o, this.fxDefaults);
11044 var run = this.beforeFx(o);
11045 fn.block = o.block;
11046 this.fxQueue.push(fn);
11058 fxWrap : function(pos, o, vis){
11060 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11063 wrapXY = this.getXY();
11065 var div = document.createElement("div");
11066 div.style.visibility = vis;
11067 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11068 wrap.setPositioning(pos);
11069 if(wrap.getStyle("position") == "static"){
11070 wrap.position("relative");
11072 this.clearPositioning('auto');
11074 wrap.dom.appendChild(this.dom);
11076 wrap.setXY(wrapXY);
11083 fxUnwrap : function(wrap, pos, o){
11084 this.clearPositioning();
11085 this.setPositioning(pos);
11087 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11093 getFxRestore : function(){
11094 var st = this.dom.style;
11095 return {pos: this.getPositioning(), width: st.width, height : st.height};
11099 afterFx : function(o){
11101 this.applyStyles(o.afterStyle);
11104 this.addClass(o.afterCls);
11106 if(o.remove === true){
11109 Roo.callback(o.callback, o.scope, [this]);
11111 this.fxQueue.shift();
11117 getFxEl : function(){ // support for composite element fx
11118 return Roo.get(this.dom);
11122 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11123 animType = animType || 'run';
11125 var anim = Roo.lib.Anim[animType](
11127 (opt.duration || defaultDur) || .35,
11128 (opt.easing || defaultEase) || 'easeOut',
11130 Roo.callback(cb, this);
11139 // backwords compat
11140 Roo.Fx.resize = Roo.Fx.scale;
11142 //When included, Roo.Fx is automatically applied to Element so that all basic
11143 //effects are available directly via the Element API
11144 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11146 * Ext JS Library 1.1.1
11147 * Copyright(c) 2006-2007, Ext JS, LLC.
11149 * Originally Released Under LGPL - original licence link has changed is not relivant.
11152 * <script type="text/javascript">
11157 * @class Roo.CompositeElement
11158 * Standard composite class. Creates a Roo.Element for every element in the collection.
11160 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11161 * actions will be performed on all the elements in this collection.</b>
11163 * All methods return <i>this</i> and can be chained.
11165 var els = Roo.select("#some-el div.some-class", true);
11166 // or select directly from an existing element
11167 var el = Roo.get('some-el');
11168 el.select('div.some-class', true);
11170 els.setWidth(100); // all elements become 100 width
11171 els.hide(true); // all elements fade out and hide
11173 els.setWidth(100).hide(true);
11176 Roo.CompositeElement = function(els){
11177 this.elements = [];
11178 this.addElements(els);
11180 Roo.CompositeElement.prototype = {
11182 addElements : function(els){
11186 if(typeof els == "string"){
11187 els = Roo.Element.selectorFunction(els);
11189 var yels = this.elements;
11190 var index = yels.length-1;
11191 for(var i = 0, len = els.length; i < len; i++) {
11192 yels[++index] = Roo.get(els[i]);
11198 * Clears this composite and adds the elements returned by the passed selector.
11199 * @param {String/Array} els A string CSS selector, an array of elements or an element
11200 * @return {CompositeElement} this
11202 fill : function(els){
11203 this.elements = [];
11209 * Filters this composite to only elements that match the passed selector.
11210 * @param {String} selector A string CSS selector
11211 * @param {Boolean} inverse return inverse filter (not matches)
11212 * @return {CompositeElement} this
11214 filter : function(selector, inverse){
11216 inverse = inverse || false;
11217 this.each(function(el){
11218 var match = inverse ? !el.is(selector) : el.is(selector);
11220 els[els.length] = el.dom;
11227 invoke : function(fn, args){
11228 var els = this.elements;
11229 for(var i = 0, len = els.length; i < len; i++) {
11230 Roo.Element.prototype[fn].apply(els[i], args);
11235 * Adds elements to this composite.
11236 * @param {String/Array} els A string CSS selector, an array of elements or an element
11237 * @return {CompositeElement} this
11239 add : function(els){
11240 if(typeof els == "string"){
11241 this.addElements(Roo.Element.selectorFunction(els));
11242 }else if(els.length !== undefined){
11243 this.addElements(els);
11245 this.addElements([els]);
11250 * Calls the passed function passing (el, this, index) for each element in this composite.
11251 * @param {Function} fn The function to call
11252 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11253 * @return {CompositeElement} this
11255 each : function(fn, scope){
11256 var els = this.elements;
11257 for(var i = 0, len = els.length; i < len; i++){
11258 if(fn.call(scope || els[i], els[i], this, i) === false) {
11266 * Returns the Element object at the specified index
11267 * @param {Number} index
11268 * @return {Roo.Element}
11270 item : function(index){
11271 return this.elements[index] || null;
11275 * Returns the first Element
11276 * @return {Roo.Element}
11278 first : function(){
11279 return this.item(0);
11283 * Returns the last Element
11284 * @return {Roo.Element}
11287 return this.item(this.elements.length-1);
11291 * Returns the number of elements in this composite
11294 getCount : function(){
11295 return this.elements.length;
11299 * Returns true if this composite contains the passed element
11302 contains : function(el){
11303 return this.indexOf(el) !== -1;
11307 * Returns true if this composite contains the passed element
11310 indexOf : function(el){
11311 return this.elements.indexOf(Roo.get(el));
11316 * Removes the specified element(s).
11317 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11318 * or an array of any of those.
11319 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11320 * @return {CompositeElement} this
11322 removeElement : function(el, removeDom){
11323 if(el instanceof Array){
11324 for(var i = 0, len = el.length; i < len; i++){
11325 this.removeElement(el[i]);
11329 var index = typeof el == 'number' ? el : this.indexOf(el);
11332 var d = this.elements[index];
11336 d.parentNode.removeChild(d);
11339 this.elements.splice(index, 1);
11345 * Replaces the specified element with the passed element.
11346 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11348 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11349 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11350 * @return {CompositeElement} this
11352 replaceElement : function(el, replacement, domReplace){
11353 var index = typeof el == 'number' ? el : this.indexOf(el);
11356 this.elements[index].replaceWith(replacement);
11358 this.elements.splice(index, 1, Roo.get(replacement))
11365 * Removes all elements.
11367 clear : function(){
11368 this.elements = [];
11372 Roo.CompositeElement.createCall = function(proto, fnName){
11373 if(!proto[fnName]){
11374 proto[fnName] = function(){
11375 return this.invoke(fnName, arguments);
11379 for(var fnName in Roo.Element.prototype){
11380 if(typeof Roo.Element.prototype[fnName] == "function"){
11381 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11387 * Ext JS Library 1.1.1
11388 * Copyright(c) 2006-2007, Ext JS, LLC.
11390 * Originally Released Under LGPL - original licence link has changed is not relivant.
11393 * <script type="text/javascript">
11397 * @class Roo.CompositeElementLite
11398 * @extends Roo.CompositeElement
11399 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11401 var els = Roo.select("#some-el div.some-class");
11402 // or select directly from an existing element
11403 var el = Roo.get('some-el');
11404 el.select('div.some-class');
11406 els.setWidth(100); // all elements become 100 width
11407 els.hide(true); // all elements fade out and hide
11409 els.setWidth(100).hide(true);
11410 </code></pre><br><br>
11411 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11412 * actions will be performed on all the elements in this collection.</b>
11414 Roo.CompositeElementLite = function(els){
11415 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11416 this.el = new Roo.Element.Flyweight();
11418 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11419 addElements : function(els){
11421 if(els instanceof Array){
11422 this.elements = this.elements.concat(els);
11424 var yels = this.elements;
11425 var index = yels.length-1;
11426 for(var i = 0, len = els.length; i < len; i++) {
11427 yels[++index] = els[i];
11433 invoke : function(fn, args){
11434 var els = this.elements;
11436 for(var i = 0, len = els.length; i < len; i++) {
11438 Roo.Element.prototype[fn].apply(el, args);
11443 * Returns a flyweight Element of the dom element object at the specified index
11444 * @param {Number} index
11445 * @return {Roo.Element}
11447 item : function(index){
11448 if(!this.elements[index]){
11451 this.el.dom = this.elements[index];
11455 // fixes scope with flyweight
11456 addListener : function(eventName, handler, scope, opt){
11457 var els = this.elements;
11458 for(var i = 0, len = els.length; i < len; i++) {
11459 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11465 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11466 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11467 * a reference to the dom node, use el.dom.</b>
11468 * @param {Function} fn The function to call
11469 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11470 * @return {CompositeElement} this
11472 each : function(fn, scope){
11473 var els = this.elements;
11475 for(var i = 0, len = els.length; i < len; i++){
11477 if(fn.call(scope || el, el, this, i) === false){
11484 indexOf : function(el){
11485 return this.elements.indexOf(Roo.getDom(el));
11488 replaceElement : function(el, replacement, domReplace){
11489 var index = typeof el == 'number' ? el : this.indexOf(el);
11491 replacement = Roo.getDom(replacement);
11493 var d = this.elements[index];
11494 d.parentNode.insertBefore(replacement, d);
11495 d.parentNode.removeChild(d);
11497 this.elements.splice(index, 1, replacement);
11502 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11506 * Ext JS Library 1.1.1
11507 * Copyright(c) 2006-2007, Ext JS, LLC.
11509 * Originally Released Under LGPL - original licence link has changed is not relivant.
11512 * <script type="text/javascript">
11518 * @class Roo.data.Connection
11519 * @extends Roo.util.Observable
11520 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11521 * either to a configured URL, or to a URL specified at request time.
11523 * Requests made by this class are asynchronous, and will return immediately. No data from
11524 * the server will be available to the statement immediately following the {@link #request} call.
11525 * To process returned data, use a callback in the request options object, or an event listener.
11527 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11528 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11529 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11530 * property and, if present, the IFRAME's XML document as the responseXML property.
11532 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11533 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11534 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11535 * standard DOM methods.
11537 * @param {Object} config a configuration object.
11539 Roo.data.Connection = function(config){
11540 Roo.apply(this, config);
11543 * @event beforerequest
11544 * Fires before a network request is made to retrieve a data object.
11545 * @param {Connection} conn This Connection object.
11546 * @param {Object} options The options config object passed to the {@link #request} method.
11548 "beforerequest" : true,
11550 * @event requestcomplete
11551 * Fires if the request was successfully completed.
11552 * @param {Connection} conn This Connection object.
11553 * @param {Object} response The XHR object containing the response data.
11554 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11555 * @param {Object} options The options config object passed to the {@link #request} method.
11557 "requestcomplete" : true,
11559 * @event requestexception
11560 * Fires if an error HTTP status was returned from the server.
11561 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11562 * @param {Connection} conn This Connection object.
11563 * @param {Object} response The XHR object containing the response data.
11564 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11565 * @param {Object} options The options config object passed to the {@link #request} method.
11567 "requestexception" : true
11569 Roo.data.Connection.superclass.constructor.call(this);
11572 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11574 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11577 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11578 * extra parameters to each request made by this object. (defaults to undefined)
11581 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11582 * to each request made by this object. (defaults to undefined)
11585 * @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)
11588 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11592 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11598 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11601 disableCaching: true,
11604 * Sends an HTTP request to a remote server.
11605 * @param {Object} options An object which may contain the following properties:<ul>
11606 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11607 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11608 * request, a url encoded string or a function to call to get either.</li>
11609 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11610 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11611 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11612 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11613 * <li>options {Object} The parameter to the request call.</li>
11614 * <li>success {Boolean} True if the request succeeded.</li>
11615 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11617 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11618 * The callback is passed the following parameters:<ul>
11619 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11620 * <li>options {Object} The parameter to the request call.</li>
11622 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11623 * The callback is passed the following parameters:<ul>
11624 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11625 * <li>options {Object} The parameter to the request call.</li>
11627 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11628 * for the callback function. Defaults to the browser window.</li>
11629 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11630 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11631 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11632 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11633 * params for the post data. Any params will be appended to the URL.</li>
11634 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11636 * @return {Number} transactionId
11638 request : function(o){
11639 if(this.fireEvent("beforerequest", this, o) !== false){
11642 if(typeof p == "function"){
11643 p = p.call(o.scope||window, o);
11645 if(typeof p == "object"){
11646 p = Roo.urlEncode(o.params);
11648 if(this.extraParams){
11649 var extras = Roo.urlEncode(this.extraParams);
11650 p = p ? (p + '&' + extras) : extras;
11653 var url = o.url || this.url;
11654 if(typeof url == 'function'){
11655 url = url.call(o.scope||window, o);
11659 var form = Roo.getDom(o.form);
11660 url = url || form.action;
11662 var enctype = form.getAttribute("enctype");
11665 return this.doFormDataUpload(o, url);
11668 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11669 return this.doFormUpload(o, p, url);
11671 var f = Roo.lib.Ajax.serializeForm(form);
11672 p = p ? (p + '&' + f) : f;
11675 if (!o.form && o.formData) {
11676 o.formData = o.formData === true ? new FormData() : o.formData;
11677 for (var k in o.params) {
11678 o.formData.append(k,o.params[k]);
11681 return this.doFormDataUpload(o, url);
11685 var hs = o.headers;
11686 if(this.defaultHeaders){
11687 hs = Roo.apply(hs || {}, this.defaultHeaders);
11694 success: this.handleResponse,
11695 failure: this.handleFailure,
11697 argument: {options: o},
11698 timeout : o.timeout || this.timeout
11701 var method = o.method||this.method||(p ? "POST" : "GET");
11703 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11704 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11707 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11711 }else if(this.autoAbort !== false){
11715 if((method == 'GET' && p) || o.xmlData){
11716 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11719 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11720 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11721 Roo.lib.Ajax.useDefaultHeader == true;
11722 return this.transId;
11724 Roo.callback(o.callback, o.scope, [o, null, null]);
11730 * Determine whether this object has a request outstanding.
11731 * @param {Number} transactionId (Optional) defaults to the last transaction
11732 * @return {Boolean} True if there is an outstanding request.
11734 isLoading : function(transId){
11736 return Roo.lib.Ajax.isCallInProgress(transId);
11738 return this.transId ? true : false;
11743 * Aborts any outstanding request.
11744 * @param {Number} transactionId (Optional) defaults to the last transaction
11746 abort : function(transId){
11747 if(transId || this.isLoading()){
11748 Roo.lib.Ajax.abort(transId || this.transId);
11753 handleResponse : function(response){
11754 this.transId = false;
11755 var options = response.argument.options;
11756 response.argument = options ? options.argument : null;
11757 this.fireEvent("requestcomplete", this, response, options);
11758 Roo.callback(options.success, options.scope, [response, options]);
11759 Roo.callback(options.callback, options.scope, [options, true, response]);
11763 handleFailure : function(response, e){
11764 this.transId = false;
11765 var options = response.argument.options;
11766 response.argument = options ? options.argument : null;
11767 this.fireEvent("requestexception", this, response, options, e);
11768 Roo.callback(options.failure, options.scope, [response, options]);
11769 Roo.callback(options.callback, options.scope, [options, false, response]);
11773 doFormUpload : function(o, ps, url){
11775 var frame = document.createElement('iframe');
11778 frame.className = 'x-hidden';
11780 frame.src = Roo.SSL_SECURE_URL;
11782 document.body.appendChild(frame);
11785 document.frames[id].name = id;
11788 var form = Roo.getDom(o.form);
11790 form.method = 'POST';
11791 form.enctype = form.encoding = 'multipart/form-data';
11797 if(ps){ // add dynamic params
11799 ps = Roo.urlDecode(ps, false);
11801 if(ps.hasOwnProperty(k)){
11802 hd = document.createElement('input');
11803 hd.type = 'hidden';
11806 form.appendChild(hd);
11813 var r = { // bogus response object
11818 r.argument = o ? o.argument : null;
11823 doc = frame.contentWindow.document;
11825 doc = (frame.contentDocument || window.frames[id].document);
11827 if(doc && doc.body){
11828 r.responseText = doc.body.innerHTML;
11830 if(doc && doc.XMLDocument){
11831 r.responseXML = doc.XMLDocument;
11833 r.responseXML = doc;
11840 Roo.EventManager.removeListener(frame, 'load', cb, this);
11842 this.fireEvent("requestcomplete", this, r, o);
11843 Roo.callback(o.success, o.scope, [r, o]);
11844 Roo.callback(o.callback, o.scope, [o, true, r]);
11846 setTimeout(function(){document.body.removeChild(frame);}, 100);
11849 Roo.EventManager.on(frame, 'load', cb, this);
11852 if(hiddens){ // remove dynamic params
11853 for(var i = 0, len = hiddens.length; i < len; i++){
11854 form.removeChild(hiddens[i]);
11858 // this is a 'formdata version???'
11861 doFormDataUpload : function(o, url)
11865 var form = Roo.getDom(o.form);
11866 form.enctype = form.encoding = 'multipart/form-data';
11867 formData = o.formData === true ? new FormData(form) : o.formData;
11869 formData = o.formData === true ? new FormData() : o.formData;
11874 success: this.handleResponse,
11875 failure: this.handleFailure,
11877 argument: {options: o},
11878 timeout : o.timeout || this.timeout
11881 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11885 }else if(this.autoAbort !== false){
11889 //Roo.lib.Ajax.defaultPostHeader = null;
11890 Roo.lib.Ajax.useDefaultHeader = false;
11891 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11892 Roo.lib.Ajax.useDefaultHeader = true;
11900 * Ext JS Library 1.1.1
11901 * Copyright(c) 2006-2007, Ext JS, LLC.
11903 * Originally Released Under LGPL - original licence link has changed is not relivant.
11906 * <script type="text/javascript">
11910 * Global Ajax request class.
11913 * @extends Roo.data.Connection
11916 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11917 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11918 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11919 * @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)
11920 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11921 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11922 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11924 Roo.Ajax = new Roo.data.Connection({
11933 * Serialize the passed form into a url encoded string
11935 * @param {String/HTMLElement} form
11938 serializeForm : function(form){
11939 return Roo.lib.Ajax.serializeForm(form);
11943 * Ext JS Library 1.1.1
11944 * Copyright(c) 2006-2007, Ext JS, LLC.
11946 * Originally Released Under LGPL - original licence link has changed is not relivant.
11949 * <script type="text/javascript">
11954 * @class Roo.UpdateManager
11955 * @extends Roo.util.Observable
11956 * Provides AJAX-style update for Element object.<br><br>
11959 * // Get it from a Roo.Element object
11960 * var el = Roo.get("foo");
11961 * var mgr = el.getUpdateManager();
11962 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11964 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11966 * // or directly (returns the same UpdateManager instance)
11967 * var mgr = new Roo.UpdateManager("myElementId");
11968 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11969 * mgr.on("update", myFcnNeedsToKnow);
11971 // short handed call directly from the element object
11972 Roo.get("foo").load({
11976 text: "Loading Foo..."
11980 * Create new UpdateManager directly.
11981 * @param {String/HTMLElement/Roo.Element} el The element to update
11982 * @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).
11984 Roo.UpdateManager = function(el, forceNew){
11986 if(!forceNew && el.updateManager){
11987 return el.updateManager;
11990 * The Element object
11991 * @type Roo.Element
11995 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11998 this.defaultUrl = null;
12002 * @event beforeupdate
12003 * Fired before an update is made, return false from your handler and the update is cancelled.
12004 * @param {Roo.Element} el
12005 * @param {String/Object/Function} url
12006 * @param {String/Object} params
12008 "beforeupdate": true,
12011 * Fired after successful update is made.
12012 * @param {Roo.Element} el
12013 * @param {Object} oResponseObject The response Object
12018 * Fired on update failure.
12019 * @param {Roo.Element} el
12020 * @param {Object} oResponseObject The response Object
12024 var d = Roo.UpdateManager.defaults;
12026 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12029 this.sslBlankUrl = d.sslBlankUrl;
12031 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12034 this.disableCaching = d.disableCaching;
12036 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12039 this.indicatorText = d.indicatorText;
12041 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12044 this.showLoadIndicator = d.showLoadIndicator;
12046 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12049 this.timeout = d.timeout;
12052 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12055 this.loadScripts = d.loadScripts;
12058 * Transaction object of current executing transaction
12060 this.transaction = null;
12065 this.autoRefreshProcId = null;
12067 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12070 this.refreshDelegate = this.refresh.createDelegate(this);
12072 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12075 this.updateDelegate = this.update.createDelegate(this);
12077 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12080 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12084 this.successDelegate = this.processSuccess.createDelegate(this);
12088 this.failureDelegate = this.processFailure.createDelegate(this);
12090 if(!this.renderer){
12092 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12094 this.renderer = new Roo.UpdateManager.BasicRenderer();
12097 Roo.UpdateManager.superclass.constructor.call(this);
12100 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12102 * Get the Element this UpdateManager is bound to
12103 * @return {Roo.Element} The element
12105 getEl : function(){
12109 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12110 * @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:
12113 url: "your-url.php",<br/>
12114 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12115 callback: yourFunction,<br/>
12116 scope: yourObject, //(optional scope) <br/>
12117 discardUrl: false, <br/>
12118 nocache: false,<br/>
12119 text: "Loading...",<br/>
12121 scripts: false<br/>
12124 * The only required property is url. The optional properties nocache, text and scripts
12125 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12126 * @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}
12127 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12128 * @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.
12130 update : function(url, params, callback, discardUrl){
12131 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12132 var method = this.method,
12134 if(typeof url == "object"){ // must be config object
12137 params = params || cfg.params;
12138 callback = callback || cfg.callback;
12139 discardUrl = discardUrl || cfg.discardUrl;
12140 if(callback && cfg.scope){
12141 callback = callback.createDelegate(cfg.scope);
12143 if(typeof cfg.method != "undefined"){method = cfg.method;};
12144 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12145 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12146 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12147 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12149 this.showLoading();
12151 this.defaultUrl = url;
12153 if(typeof url == "function"){
12154 url = url.call(this);
12157 method = method || (params ? "POST" : "GET");
12158 if(method == "GET"){
12159 url = this.prepareUrl(url);
12162 var o = Roo.apply(cfg ||{}, {
12165 success: this.successDelegate,
12166 failure: this.failureDelegate,
12167 callback: undefined,
12168 timeout: (this.timeout*1000),
12169 argument: {"url": url, "form": null, "callback": callback, "params": params}
12171 Roo.log("updated manager called with timeout of " + o.timeout);
12172 this.transaction = Roo.Ajax.request(o);
12177 * 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.
12178 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12179 * @param {String/HTMLElement} form The form Id or form element
12180 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12181 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12182 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12184 formUpdate : function(form, url, reset, callback){
12185 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12186 if(typeof url == "function"){
12187 url = url.call(this);
12189 form = Roo.getDom(form);
12190 this.transaction = Roo.Ajax.request({
12193 success: this.successDelegate,
12194 failure: this.failureDelegate,
12195 timeout: (this.timeout*1000),
12196 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12198 this.showLoading.defer(1, this);
12203 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12204 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12206 refresh : function(callback){
12207 if(this.defaultUrl == null){
12210 this.update(this.defaultUrl, null, callback, true);
12214 * Set this element to auto refresh.
12215 * @param {Number} interval How often to update (in seconds).
12216 * @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)
12217 * @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}
12218 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12219 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12221 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12223 this.update(url || this.defaultUrl, params, callback, true);
12225 if(this.autoRefreshProcId){
12226 clearInterval(this.autoRefreshProcId);
12228 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12232 * Stop auto refresh on this element.
12234 stopAutoRefresh : function(){
12235 if(this.autoRefreshProcId){
12236 clearInterval(this.autoRefreshProcId);
12237 delete this.autoRefreshProcId;
12241 isAutoRefreshing : function(){
12242 return this.autoRefreshProcId ? true : false;
12245 * Called to update the element to "Loading" state. Override to perform custom action.
12247 showLoading : function(){
12248 if(this.showLoadIndicator){
12249 this.el.update(this.indicatorText);
12254 * Adds unique parameter to query string if disableCaching = true
12257 prepareUrl : function(url){
12258 if(this.disableCaching){
12259 var append = "_dc=" + (new Date().getTime());
12260 if(url.indexOf("?") !== -1){
12261 url += "&" + append;
12263 url += "?" + append;
12272 processSuccess : function(response){
12273 this.transaction = null;
12274 if(response.argument.form && response.argument.reset){
12275 try{ // put in try/catch since some older FF releases had problems with this
12276 response.argument.form.reset();
12279 if(this.loadScripts){
12280 this.renderer.render(this.el, response, this,
12281 this.updateComplete.createDelegate(this, [response]));
12283 this.renderer.render(this.el, response, this);
12284 this.updateComplete(response);
12288 updateComplete : function(response){
12289 this.fireEvent("update", this.el, response);
12290 if(typeof response.argument.callback == "function"){
12291 response.argument.callback(this.el, true, response);
12298 processFailure : function(response){
12299 this.transaction = null;
12300 this.fireEvent("failure", this.el, response);
12301 if(typeof response.argument.callback == "function"){
12302 response.argument.callback(this.el, false, response);
12307 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12308 * @param {Object} renderer The object implementing the render() method
12310 setRenderer : function(renderer){
12311 this.renderer = renderer;
12314 getRenderer : function(){
12315 return this.renderer;
12319 * Set the defaultUrl used for updates
12320 * @param {String/Function} defaultUrl The url or a function to call to get the url
12322 setDefaultUrl : function(defaultUrl){
12323 this.defaultUrl = defaultUrl;
12327 * Aborts the executing transaction
12329 abort : function(){
12330 if(this.transaction){
12331 Roo.Ajax.abort(this.transaction);
12336 * Returns true if an update is in progress
12337 * @return {Boolean}
12339 isUpdating : function(){
12340 if(this.transaction){
12341 return Roo.Ajax.isLoading(this.transaction);
12348 * @class Roo.UpdateManager.defaults
12349 * @static (not really - but it helps the doc tool)
12350 * The defaults collection enables customizing the default properties of UpdateManager
12352 Roo.UpdateManager.defaults = {
12354 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12360 * True to process scripts by default (Defaults to false).
12363 loadScripts : false,
12366 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12369 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12371 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12374 disableCaching : false,
12376 * Whether to show indicatorText when loading (Defaults to true).
12379 showLoadIndicator : true,
12381 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12384 indicatorText : '<div class="loading-indicator">Loading...</div>'
12388 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12390 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12391 * @param {String/HTMLElement/Roo.Element} el The element to update
12392 * @param {String} url The url
12393 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12394 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12397 * @member Roo.UpdateManager
12399 Roo.UpdateManager.updateElement = function(el, url, params, options){
12400 var um = Roo.get(el, true).getUpdateManager();
12401 Roo.apply(um, options);
12402 um.update(url, params, options ? options.callback : null);
12404 // alias for backwards compat
12405 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12407 * @class Roo.UpdateManager.BasicRenderer
12408 * Default Content renderer. Updates the elements innerHTML with the responseText.
12410 Roo.UpdateManager.BasicRenderer = function(){};
12412 Roo.UpdateManager.BasicRenderer.prototype = {
12414 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12415 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12416 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12417 * @param {Roo.Element} el The element being rendered
12418 * @param {Object} response The YUI Connect response object
12419 * @param {UpdateManager} updateManager The calling update manager
12420 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12422 render : function(el, response, updateManager, callback){
12423 el.update(response.responseText, updateManager.loadScripts, callback);
12429 * (c)) Alan Knowles
12435 * @class Roo.DomTemplate
12436 * @extends Roo.Template
12437 * An effort at a dom based template engine..
12439 * Similar to XTemplate, except it uses dom parsing to create the template..
12441 * Supported features:
12446 {a_variable} - output encoded.
12447 {a_variable.format:("Y-m-d")} - call a method on the variable
12448 {a_variable:raw} - unencoded output
12449 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12450 {a_variable:this.method_on_template(...)} - call a method on the template object.
12455 <div roo-for="a_variable or condition.."></div>
12456 <div roo-if="a_variable or condition"></div>
12457 <div roo-exec="some javascript"></div>
12458 <div roo-name="named_template"></div>
12463 Roo.DomTemplate = function()
12465 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12472 Roo.extend(Roo.DomTemplate, Roo.Template, {
12474 * id counter for sub templates.
12478 * flag to indicate if dom parser is inside a pre,
12479 * it will strip whitespace if not.
12484 * The various sub templates
12492 * basic tag replacing syntax
12495 * // you can fake an object call by doing this
12499 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12500 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12502 iterChild : function (node, method) {
12504 var oldPre = this.inPre;
12505 if (node.tagName == 'PRE') {
12508 for( var i = 0; i < node.childNodes.length; i++) {
12509 method.call(this, node.childNodes[i]);
12511 this.inPre = oldPre;
12517 * compile the template
12519 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12522 compile: function()
12526 // covert the html into DOM...
12530 doc = document.implementation.createHTMLDocument("");
12531 doc.documentElement.innerHTML = this.html ;
12532 div = doc.documentElement;
12534 // old IE... - nasty -- it causes all sorts of issues.. with
12535 // images getting pulled from server..
12536 div = document.createElement('div');
12537 div.innerHTML = this.html;
12539 //doc.documentElement.innerHTML = htmlBody
12545 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12547 var tpls = this.tpls;
12549 // create a top level template from the snippet..
12551 //Roo.log(div.innerHTML);
12558 body : div.innerHTML,
12571 Roo.each(tpls, function(tp){
12572 this.compileTpl(tp);
12573 this.tpls[tp.id] = tp;
12576 this.master = tpls[0];
12582 compileNode : function(node, istop) {
12587 // skip anything not a tag..
12588 if (node.nodeType != 1) {
12589 if (node.nodeType == 3 && !this.inPre) {
12590 // reduce white space..
12591 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12614 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12615 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12616 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12617 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12623 // just itterate children..
12624 this.iterChild(node,this.compileNode);
12627 tpl.uid = this.id++;
12628 tpl.value = node.getAttribute('roo-' + tpl.attr);
12629 node.removeAttribute('roo-'+ tpl.attr);
12630 if (tpl.attr != 'name') {
12631 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12632 node.parentNode.replaceChild(placeholder, node);
12635 var placeholder = document.createElement('span');
12636 placeholder.className = 'roo-tpl-' + tpl.value;
12637 node.parentNode.replaceChild(placeholder, node);
12640 // parent now sees '{domtplXXXX}
12641 this.iterChild(node,this.compileNode);
12643 // we should now have node body...
12644 var div = document.createElement('div');
12645 div.appendChild(node);
12647 // this has the unfortunate side effect of converting tagged attributes
12648 // eg. href="{...}" into %7C...%7D
12649 // this has been fixed by searching for those combo's although it's a bit hacky..
12652 tpl.body = div.innerHTML;
12659 switch (tpl.value) {
12660 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12661 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12662 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12667 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12671 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12675 tpl.id = tpl.value; // replace non characters???
12681 this.tpls.push(tpl);
12691 * Compile a segment of the template into a 'sub-template'
12697 compileTpl : function(tpl)
12699 var fm = Roo.util.Format;
12700 var useF = this.disableFormats !== true;
12702 var sep = Roo.isGecko ? "+\n" : ",\n";
12704 var undef = function(str) {
12705 Roo.debug && Roo.log("Property not found :" + str);
12709 //Roo.log(tpl.body);
12713 var fn = function(m, lbrace, name, format, args)
12716 //Roo.log(arguments);
12717 args = args ? args.replace(/\\'/g,"'") : args;
12718 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12719 if (typeof(format) == 'undefined') {
12720 format = 'htmlEncode';
12722 if (format == 'raw' ) {
12726 if(name.substr(0, 6) == 'domtpl'){
12727 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12730 // build an array of options to determine if value is undefined..
12732 // basically get 'xxxx.yyyy' then do
12733 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12734 // (function () { Roo.log("Property not found"); return ''; })() :
12739 Roo.each(name.split('.'), function(st) {
12740 lookfor += (lookfor.length ? '.': '') + st;
12741 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12744 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12747 if(format && useF){
12749 args = args ? ',' + args : "";
12751 if(format.substr(0, 5) != "this."){
12752 format = "fm." + format + '(';
12754 format = 'this.call("'+ format.substr(5) + '", ';
12758 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12761 if (args && args.length) {
12762 // called with xxyx.yuu:(test,test)
12764 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12766 // raw.. - :raw modifier..
12767 return "'"+ sep + udef_st + name + ")"+sep+"'";
12771 // branched to use + in gecko and [].join() in others
12773 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12774 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12777 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12778 body.push(tpl.body.replace(/(\r\n|\n)/g,
12779 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12780 body.push("'].join('');};};");
12781 body = body.join('');
12784 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12786 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12793 * same as applyTemplate, except it's done to one of the subTemplates
12794 * when using named templates, you can do:
12796 * var str = pl.applySubTemplate('your-name', values);
12799 * @param {Number} id of the template
12800 * @param {Object} values to apply to template
12801 * @param {Object} parent (normaly the instance of this object)
12803 applySubTemplate : function(id, values, parent)
12807 var t = this.tpls[id];
12811 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12812 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12816 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12823 if(t.execCall && t.execCall.call(this, values, parent)){
12827 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12833 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12834 parent = t.target ? values : parent;
12835 if(t.forCall && vs instanceof Array){
12837 for(var i = 0, len = vs.length; i < len; i++){
12839 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12841 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12843 //Roo.log(t.compiled);
12847 return buf.join('');
12850 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12855 return t.compiled.call(this, vs, parent);
12857 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12859 //Roo.log(t.compiled);
12867 applyTemplate : function(values){
12868 return this.master.compiled.call(this, values, {});
12869 //var s = this.subs;
12872 apply : function(){
12873 return this.applyTemplate.apply(this, arguments);
12878 Roo.DomTemplate.from = function(el){
12879 el = Roo.getDom(el);
12880 return new Roo.Domtemplate(el.value || el.innerHTML);
12883 * Ext JS Library 1.1.1
12884 * Copyright(c) 2006-2007, Ext JS, LLC.
12886 * Originally Released Under LGPL - original licence link has changed is not relivant.
12889 * <script type="text/javascript">
12893 * @class Roo.util.DelayedTask
12894 * Provides a convenient method of performing setTimeout where a new
12895 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12896 * You can use this class to buffer
12897 * the keypress events for a certain number of milliseconds, and perform only if they stop
12898 * for that amount of time.
12899 * @constructor The parameters to this constructor serve as defaults and are not required.
12900 * @param {Function} fn (optional) The default function to timeout
12901 * @param {Object} scope (optional) The default scope of that timeout
12902 * @param {Array} args (optional) The default Array of arguments
12904 Roo.util.DelayedTask = function(fn, scope, args){
12905 var id = null, d, t;
12907 var call = function(){
12908 var now = new Date().getTime();
12912 fn.apply(scope, args || []);
12916 * Cancels any pending timeout and queues a new one
12917 * @param {Number} delay The milliseconds to delay
12918 * @param {Function} newFn (optional) Overrides function passed to constructor
12919 * @param {Object} newScope (optional) Overrides scope passed to constructor
12920 * @param {Array} newArgs (optional) Overrides args passed to constructor
12922 this.delay = function(delay, newFn, newScope, newArgs){
12923 if(id && delay != d){
12927 t = new Date().getTime();
12929 scope = newScope || scope;
12930 args = newArgs || args;
12932 id = setInterval(call, d);
12937 * Cancel the last queued timeout
12939 this.cancel = function(){
12947 * Ext JS Library 1.1.1
12948 * Copyright(c) 2006-2007, Ext JS, LLC.
12950 * Originally Released Under LGPL - original licence link has changed is not relivant.
12953 * <script type="text/javascript">
12957 Roo.util.TaskRunner = function(interval){
12958 interval = interval || 10;
12959 var tasks = [], removeQueue = [];
12961 var running = false;
12963 var stopThread = function(){
12969 var startThread = function(){
12972 id = setInterval(runTasks, interval);
12976 var removeTask = function(task){
12977 removeQueue.push(task);
12983 var runTasks = function(){
12984 if(removeQueue.length > 0){
12985 for(var i = 0, len = removeQueue.length; i < len; i++){
12986 tasks.remove(removeQueue[i]);
12989 if(tasks.length < 1){
12994 var now = new Date().getTime();
12995 for(var i = 0, len = tasks.length; i < len; ++i){
12997 var itime = now - t.taskRunTime;
12998 if(t.interval <= itime){
12999 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13000 t.taskRunTime = now;
13001 if(rt === false || t.taskRunCount === t.repeat){
13006 if(t.duration && t.duration <= (now - t.taskStartTime)){
13013 * Queues a new task.
13014 * @param {Object} task
13016 this.start = function(task){
13018 task.taskStartTime = new Date().getTime();
13019 task.taskRunTime = 0;
13020 task.taskRunCount = 0;
13025 this.stop = function(task){
13030 this.stopAll = function(){
13032 for(var i = 0, len = tasks.length; i < len; i++){
13033 if(tasks[i].onStop){
13042 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13044 * Ext JS Library 1.1.1
13045 * Copyright(c) 2006-2007, Ext JS, LLC.
13047 * Originally Released Under LGPL - original licence link has changed is not relivant.
13050 * <script type="text/javascript">
13055 * @class Roo.util.MixedCollection
13056 * @extends Roo.util.Observable
13057 * A Collection class that maintains both numeric indexes and keys and exposes events.
13059 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13060 * collection (defaults to false)
13061 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13062 * and return the key value for that item. This is used when available to look up the key on items that
13063 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13064 * equivalent to providing an implementation for the {@link #getKey} method.
13066 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13074 * Fires when the collection is cleared.
13079 * Fires when an item is added to the collection.
13080 * @param {Number} index The index at which the item was added.
13081 * @param {Object} o The item added.
13082 * @param {String} key The key associated with the added item.
13087 * Fires when an item is replaced in the collection.
13088 * @param {String} key he key associated with the new added.
13089 * @param {Object} old The item being replaced.
13090 * @param {Object} new The new item.
13095 * Fires when an item is removed from the collection.
13096 * @param {Object} o The item being removed.
13097 * @param {String} key (optional) The key associated with the removed item.
13102 this.allowFunctions = allowFunctions === true;
13104 this.getKey = keyFn;
13106 Roo.util.MixedCollection.superclass.constructor.call(this);
13109 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13110 allowFunctions : false,
13113 * Adds an item to the collection.
13114 * @param {String} key The key to associate with the item
13115 * @param {Object} o The item to add.
13116 * @return {Object} The item added.
13118 add : function(key, o){
13119 if(arguments.length == 1){
13121 key = this.getKey(o);
13123 if(typeof key == "undefined" || key === null){
13125 this.items.push(o);
13126 this.keys.push(null);
13128 var old = this.map[key];
13130 return this.replace(key, o);
13133 this.items.push(o);
13135 this.keys.push(key);
13137 this.fireEvent("add", this.length-1, o, key);
13142 * MixedCollection has a generic way to fetch keys if you implement getKey.
13145 var mc = new Roo.util.MixedCollection();
13146 mc.add(someEl.dom.id, someEl);
13147 mc.add(otherEl.dom.id, otherEl);
13151 var mc = new Roo.util.MixedCollection();
13152 mc.getKey = function(el){
13158 // or via the constructor
13159 var mc = new Roo.util.MixedCollection(false, function(el){
13165 * @param o {Object} The item for which to find the key.
13166 * @return {Object} The key for the passed item.
13168 getKey : function(o){
13173 * Replaces an item in the collection.
13174 * @param {String} key The key associated with the item to replace, or the item to replace.
13175 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13176 * @return {Object} The new item.
13178 replace : function(key, o){
13179 if(arguments.length == 1){
13181 key = this.getKey(o);
13183 var old = this.item(key);
13184 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13185 return this.add(key, o);
13187 var index = this.indexOfKey(key);
13188 this.items[index] = o;
13190 this.fireEvent("replace", key, old, o);
13195 * Adds all elements of an Array or an Object to the collection.
13196 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13197 * an Array of values, each of which are added to the collection.
13199 addAll : function(objs){
13200 if(arguments.length > 1 || objs instanceof Array){
13201 var args = arguments.length > 1 ? arguments : objs;
13202 for(var i = 0, len = args.length; i < len; i++){
13206 for(var key in objs){
13207 if(this.allowFunctions || typeof objs[key] != "function"){
13208 this.add(key, objs[key]);
13215 * Executes the specified function once for every item in the collection, passing each
13216 * item as the first and only parameter. returning false from the function will stop the iteration.
13217 * @param {Function} fn The function to execute for each item.
13218 * @param {Object} scope (optional) The scope in which to execute the function.
13220 each : function(fn, scope){
13221 var items = [].concat(this.items); // each safe for removal
13222 for(var i = 0, len = items.length; i < len; i++){
13223 if(fn.call(scope || items[i], items[i], i, len) === false){
13230 * Executes the specified function once for every key in the collection, passing each
13231 * key, and its associated item as the first two parameters.
13232 * @param {Function} fn The function to execute for each item.
13233 * @param {Object} scope (optional) The scope in which to execute the function.
13235 eachKey : function(fn, scope){
13236 for(var i = 0, len = this.keys.length; i < len; i++){
13237 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13242 * Returns the first item in the collection which elicits a true return value from the
13243 * passed selection function.
13244 * @param {Function} fn The selection function to execute for each item.
13245 * @param {Object} scope (optional) The scope in which to execute the function.
13246 * @return {Object} The first item in the collection which returned true from the selection function.
13248 find : function(fn, scope){
13249 for(var i = 0, len = this.items.length; i < len; i++){
13250 if(fn.call(scope || window, this.items[i], this.keys[i])){
13251 return this.items[i];
13258 * Inserts an item at the specified index in the collection.
13259 * @param {Number} index The index to insert the item at.
13260 * @param {String} key The key to associate with the new item, or the item itself.
13261 * @param {Object} o (optional) If the second parameter was a key, the new item.
13262 * @return {Object} The item inserted.
13264 insert : function(index, key, o){
13265 if(arguments.length == 2){
13267 key = this.getKey(o);
13269 if(index >= this.length){
13270 return this.add(key, o);
13273 this.items.splice(index, 0, o);
13274 if(typeof key != "undefined" && key != null){
13277 this.keys.splice(index, 0, key);
13278 this.fireEvent("add", index, o, key);
13283 * Removed an item from the collection.
13284 * @param {Object} o The item to remove.
13285 * @return {Object} The item removed.
13287 remove : function(o){
13288 return this.removeAt(this.indexOf(o));
13292 * Remove an item from a specified index in the collection.
13293 * @param {Number} index The index within the collection of the item to remove.
13295 removeAt : function(index){
13296 if(index < this.length && index >= 0){
13298 var o = this.items[index];
13299 this.items.splice(index, 1);
13300 var key = this.keys[index];
13301 if(typeof key != "undefined"){
13302 delete this.map[key];
13304 this.keys.splice(index, 1);
13305 this.fireEvent("remove", o, key);
13310 * Removed an item associated with the passed key fom the collection.
13311 * @param {String} key The key of the item to remove.
13313 removeKey : function(key){
13314 return this.removeAt(this.indexOfKey(key));
13318 * Returns the number of items in the collection.
13319 * @return {Number} the number of items in the collection.
13321 getCount : function(){
13322 return this.length;
13326 * Returns index within the collection of the passed Object.
13327 * @param {Object} o The item to find the index of.
13328 * @return {Number} index of the item.
13330 indexOf : function(o){
13331 if(!this.items.indexOf){
13332 for(var i = 0, len = this.items.length; i < len; i++){
13333 if(this.items[i] == o) {
13339 return this.items.indexOf(o);
13344 * Returns index within the collection of the passed key.
13345 * @param {String} key The key to find the index of.
13346 * @return {Number} index of the key.
13348 indexOfKey : function(key){
13349 if(!this.keys.indexOf){
13350 for(var i = 0, len = this.keys.length; i < len; i++){
13351 if(this.keys[i] == key) {
13357 return this.keys.indexOf(key);
13362 * Returns the item associated with the passed key OR index. Key has priority over index.
13363 * @param {String/Number} key The key or index of the item.
13364 * @return {Object} The item associated with the passed key.
13366 item : function(key){
13367 if (key === 'length') {
13370 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13371 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13375 * Returns the item at the specified index.
13376 * @param {Number} index The index of the item.
13379 itemAt : function(index){
13380 return this.items[index];
13384 * Returns the item associated with the passed key.
13385 * @param {String/Number} key The key of the item.
13386 * @return {Object} The item associated with the passed key.
13388 key : function(key){
13389 return this.map[key];
13393 * Returns true if the collection contains the passed Object as an item.
13394 * @param {Object} o The Object to look for in the collection.
13395 * @return {Boolean} True if the collection contains the Object as an item.
13397 contains : function(o){
13398 return this.indexOf(o) != -1;
13402 * Returns true if the collection contains the passed Object as a key.
13403 * @param {String} key The key to look for in the collection.
13404 * @return {Boolean} True if the collection contains the Object as a key.
13406 containsKey : function(key){
13407 return typeof this.map[key] != "undefined";
13411 * Removes all items from the collection.
13413 clear : function(){
13418 this.fireEvent("clear");
13422 * Returns the first item in the collection.
13423 * @return {Object} the first item in the collection..
13425 first : function(){
13426 return this.items[0];
13430 * Returns the last item in the collection.
13431 * @return {Object} the last item in the collection..
13434 return this.items[this.length-1];
13437 _sort : function(property, dir, fn){
13438 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13439 fn = fn || function(a, b){
13442 var c = [], k = this.keys, items = this.items;
13443 for(var i = 0, len = items.length; i < len; i++){
13444 c[c.length] = {key: k[i], value: items[i], index: i};
13446 c.sort(function(a, b){
13447 var v = fn(a[property], b[property]) * dsc;
13449 v = (a.index < b.index ? -1 : 1);
13453 for(var i = 0, len = c.length; i < len; i++){
13454 items[i] = c[i].value;
13457 this.fireEvent("sort", this);
13461 * Sorts this collection with the passed comparison function
13462 * @param {String} direction (optional) "ASC" or "DESC"
13463 * @param {Function} fn (optional) comparison function
13465 sort : function(dir, fn){
13466 this._sort("value", dir, fn);
13470 * Sorts this collection by keys
13471 * @param {String} direction (optional) "ASC" or "DESC"
13472 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13474 keySort : function(dir, fn){
13475 this._sort("key", dir, fn || function(a, b){
13476 return String(a).toUpperCase()-String(b).toUpperCase();
13481 * Returns a range of items in this collection
13482 * @param {Number} startIndex (optional) defaults to 0
13483 * @param {Number} endIndex (optional) default to the last item
13484 * @return {Array} An array of items
13486 getRange : function(start, end){
13487 var items = this.items;
13488 if(items.length < 1){
13491 start = start || 0;
13492 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13495 for(var i = start; i <= end; i++) {
13496 r[r.length] = items[i];
13499 for(var i = start; i >= end; i--) {
13500 r[r.length] = items[i];
13507 * Filter the <i>objects</i> in this collection by a specific property.
13508 * Returns a new collection that has been filtered.
13509 * @param {String} property A property on your objects
13510 * @param {String/RegExp} value Either string that the property values
13511 * should start with or a RegExp to test against the property
13512 * @return {MixedCollection} The new filtered collection
13514 filter : function(property, value){
13515 if(!value.exec){ // not a regex
13516 value = String(value);
13517 if(value.length == 0){
13518 return this.clone();
13520 value = new RegExp("^" + Roo.escapeRe(value), "i");
13522 return this.filterBy(function(o){
13523 return o && value.test(o[property]);
13528 * Filter by a function. * Returns a new collection that has been filtered.
13529 * The passed function will be called with each
13530 * object in the collection. If the function returns true, the value is included
13531 * otherwise it is filtered.
13532 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13533 * @param {Object} scope (optional) The scope of the function (defaults to this)
13534 * @return {MixedCollection} The new filtered collection
13536 filterBy : function(fn, scope){
13537 var r = new Roo.util.MixedCollection();
13538 r.getKey = this.getKey;
13539 var k = this.keys, it = this.items;
13540 for(var i = 0, len = it.length; i < len; i++){
13541 if(fn.call(scope||this, it[i], k[i])){
13542 r.add(k[i], it[i]);
13549 * Creates a duplicate of this collection
13550 * @return {MixedCollection}
13552 clone : function(){
13553 var r = new Roo.util.MixedCollection();
13554 var k = this.keys, it = this.items;
13555 for(var i = 0, len = it.length; i < len; i++){
13556 r.add(k[i], it[i]);
13558 r.getKey = this.getKey;
13563 * Returns the item associated with the passed key or index.
13565 * @param {String/Number} key The key or index of the item.
13566 * @return {Object} The item associated with the passed key.
13568 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13570 * Ext JS Library 1.1.1
13571 * Copyright(c) 2006-2007, Ext JS, LLC.
13573 * Originally Released Under LGPL - original licence link has changed is not relivant.
13576 * <script type="text/javascript">
13579 * @class Roo.util.JSON
13580 * Modified version of Douglas Crockford"s json.js that doesn"t
13581 * mess with the Object prototype
13582 * http://www.json.org/js.html
13585 Roo.util.JSON = new (function(){
13586 var useHasOwn = {}.hasOwnProperty ? true : false;
13588 // crashes Safari in some instances
13589 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13591 var pad = function(n) {
13592 return n < 10 ? "0" + n : n;
13605 var encodeString = function(s){
13606 if (/["\\\x00-\x1f]/.test(s)) {
13607 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13612 c = b.charCodeAt();
13614 Math.floor(c / 16).toString(16) +
13615 (c % 16).toString(16);
13618 return '"' + s + '"';
13621 var encodeArray = function(o){
13622 var a = ["["], b, i, l = o.length, v;
13623 for (i = 0; i < l; i += 1) {
13625 switch (typeof v) {
13634 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13642 var encodeDate = function(o){
13643 return '"' + o.getFullYear() + "-" +
13644 pad(o.getMonth() + 1) + "-" +
13645 pad(o.getDate()) + "T" +
13646 pad(o.getHours()) + ":" +
13647 pad(o.getMinutes()) + ":" +
13648 pad(o.getSeconds()) + '"';
13652 * Encodes an Object, Array or other value
13653 * @param {Mixed} o The variable to encode
13654 * @return {String} The JSON string
13656 this.encode = function(o)
13658 // should this be extended to fully wrap stringify..
13660 if(typeof o == "undefined" || o === null){
13662 }else if(o instanceof Array){
13663 return encodeArray(o);
13664 }else if(o instanceof Date){
13665 return encodeDate(o);
13666 }else if(typeof o == "string"){
13667 return encodeString(o);
13668 }else if(typeof o == "number"){
13669 return isFinite(o) ? String(o) : "null";
13670 }else if(typeof o == "boolean"){
13673 var a = ["{"], b, i, v;
13675 if(!useHasOwn || o.hasOwnProperty(i)) {
13677 switch (typeof v) {
13686 a.push(this.encode(i), ":",
13687 v === null ? "null" : this.encode(v));
13698 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13699 * @param {String} json The JSON string
13700 * @return {Object} The resulting object
13702 this.decode = function(json){
13704 return /** eval:var:json */ eval("(" + json + ')');
13708 * Shorthand for {@link Roo.util.JSON#encode}
13709 * @member Roo encode
13711 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13713 * Shorthand for {@link Roo.util.JSON#decode}
13714 * @member Roo decode
13716 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13719 * Ext JS Library 1.1.1
13720 * Copyright(c) 2006-2007, Ext JS, LLC.
13722 * Originally Released Under LGPL - original licence link has changed is not relivant.
13725 * <script type="text/javascript">
13729 * @class Roo.util.Format
13730 * Reusable data formatting functions
13733 Roo.util.Format = function(){
13734 var trimRe = /^\s+|\s+$/g;
13737 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13738 * @param {String} value The string to truncate
13739 * @param {Number} length The maximum length to allow before truncating
13740 * @return {String} The converted text
13742 ellipsis : function(value, len){
13743 if(value && value.length > len){
13744 return value.substr(0, len-3)+"...";
13750 * Checks a reference and converts it to empty string if it is undefined
13751 * @param {Mixed} value Reference to check
13752 * @return {Mixed} Empty string if converted, otherwise the original value
13754 undef : function(value){
13755 return typeof value != "undefined" ? value : "";
13759 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13760 * @param {String} value The string to encode
13761 * @return {String} The encoded text
13763 htmlEncode : function(value){
13764 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13768 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13769 * @param {String} value The string to decode
13770 * @return {String} The decoded text
13772 htmlDecode : function(value){
13773 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13777 * Trims any whitespace from either side of a string
13778 * @param {String} value The text to trim
13779 * @return {String} The trimmed text
13781 trim : function(value){
13782 return String(value).replace(trimRe, "");
13786 * Returns a substring from within an original string
13787 * @param {String} value The original text
13788 * @param {Number} start The start index of the substring
13789 * @param {Number} length The length of the substring
13790 * @return {String} The substring
13792 substr : function(value, start, length){
13793 return String(value).substr(start, length);
13797 * Converts a string to all lower case letters
13798 * @param {String} value The text to convert
13799 * @return {String} The converted text
13801 lowercase : function(value){
13802 return String(value).toLowerCase();
13806 * Converts a string to all upper case letters
13807 * @param {String} value The text to convert
13808 * @return {String} The converted text
13810 uppercase : function(value){
13811 return String(value).toUpperCase();
13815 * Converts the first character only of a string to upper case
13816 * @param {String} value The text to convert
13817 * @return {String} The converted text
13819 capitalize : function(value){
13820 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13824 call : function(value, fn){
13825 if(arguments.length > 2){
13826 var args = Array.prototype.slice.call(arguments, 2);
13827 args.unshift(value);
13829 return /** eval:var:value */ eval(fn).apply(window, args);
13831 /** eval:var:value */
13832 return /** eval:var:value */ eval(fn).call(window, value);
13838 * safer version of Math.toFixed..??/
13839 * @param {Number/String} value The numeric value to format
13840 * @param {Number/String} value Decimal places
13841 * @return {String} The formatted currency string
13843 toFixed : function(v, n)
13845 // why not use to fixed - precision is buggered???
13847 return Math.round(v-0);
13849 var fact = Math.pow(10,n+1);
13850 v = (Math.round((v-0)*fact))/fact;
13851 var z = (''+fact).substring(2);
13852 if (v == Math.floor(v)) {
13853 return Math.floor(v) + '.' + z;
13856 // now just padd decimals..
13857 var ps = String(v).split('.');
13858 var fd = (ps[1] + z);
13859 var r = fd.substring(0,n);
13860 var rm = fd.substring(n);
13862 return ps[0] + '.' + r;
13864 r*=1; // turn it into a number;
13866 if (String(r).length != n) {
13869 r = String(r).substring(1); // chop the end off.
13872 return ps[0] + '.' + r;
13877 * Format a number as US currency
13878 * @param {Number/String} value The numeric value to format
13879 * @return {String} The formatted currency string
13881 usMoney : function(v){
13882 return '$' + Roo.util.Format.number(v);
13887 * eventually this should probably emulate php's number_format
13888 * @param {Number/String} value The numeric value to format
13889 * @param {Number} decimals number of decimal places
13890 * @param {String} delimiter for thousands (default comma)
13891 * @return {String} The formatted currency string
13893 number : function(v, decimals, thousandsDelimiter)
13895 // multiply and round.
13896 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13897 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13899 var mul = Math.pow(10, decimals);
13900 var zero = String(mul).substring(1);
13901 v = (Math.round((v-0)*mul))/mul;
13903 // if it's '0' number.. then
13905 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13907 var ps = v.split('.');
13910 var r = /(\d+)(\d{3})/;
13913 if(thousandsDelimiter.length != 0) {
13914 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13919 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13920 // does not have decimals
13921 (decimals ? ('.' + zero) : '');
13924 return whole + sub ;
13928 * Parse a value into a formatted date using the specified format pattern.
13929 * @param {Mixed} value The value to format
13930 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13931 * @return {String} The formatted date string
13933 date : function(v, format){
13937 if(!(v instanceof Date)){
13938 v = new Date(Date.parse(v));
13940 return v.dateFormat(format || Roo.util.Format.defaults.date);
13944 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13945 * @param {String} format Any valid date format string
13946 * @return {Function} The date formatting function
13948 dateRenderer : function(format){
13949 return function(v){
13950 return Roo.util.Format.date(v, format);
13955 stripTagsRE : /<\/?[^>]+>/gi,
13958 * Strips all HTML tags
13959 * @param {Mixed} value The text from which to strip tags
13960 * @return {String} The stripped text
13962 stripTags : function(v){
13963 return !v ? v : String(v).replace(this.stripTagsRE, "");
13967 Roo.util.Format.defaults = {
13971 * Ext JS Library 1.1.1
13972 * Copyright(c) 2006-2007, Ext JS, LLC.
13974 * Originally Released Under LGPL - original licence link has changed is not relivant.
13977 * <script type="text/javascript">
13984 * @class Roo.MasterTemplate
13985 * @extends Roo.Template
13986 * Provides a template that can have child templates. The syntax is:
13988 var t = new Roo.MasterTemplate(
13989 '<select name="{name}">',
13990 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13993 t.add('options', {value: 'foo', text: 'bar'});
13994 // or you can add multiple child elements in one shot
13995 t.addAll('options', [
13996 {value: 'foo', text: 'bar'},
13997 {value: 'foo2', text: 'bar2'},
13998 {value: 'foo3', text: 'bar3'}
14000 // then append, applying the master template values
14001 t.append('my-form', {name: 'my-select'});
14003 * A name attribute for the child template is not required if you have only one child
14004 * template or you want to refer to them by index.
14006 Roo.MasterTemplate = function(){
14007 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14008 this.originalHtml = this.html;
14010 var m, re = this.subTemplateRe;
14013 while(m = re.exec(this.html)){
14014 var name = m[1], content = m[2];
14019 tpl : new Roo.Template(content)
14022 st[name] = st[subIndex];
14024 st[subIndex].tpl.compile();
14025 st[subIndex].tpl.call = this.call.createDelegate(this);
14028 this.subCount = subIndex;
14031 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14033 * The regular expression used to match sub templates
14037 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14040 * Applies the passed values to a child template.
14041 * @param {String/Number} name (optional) The name or index of the child template
14042 * @param {Array/Object} values The values to be applied to the template
14043 * @return {MasterTemplate} this
14045 add : function(name, values){
14046 if(arguments.length == 1){
14047 values = arguments[0];
14050 var s = this.subs[name];
14051 s.buffer[s.buffer.length] = s.tpl.apply(values);
14056 * Applies all the passed values to a child template.
14057 * @param {String/Number} name (optional) The name or index of the child template
14058 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14059 * @param {Boolean} reset (optional) True to reset the template first
14060 * @return {MasterTemplate} this
14062 fill : function(name, values, reset){
14064 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14072 for(var i = 0, len = values.length; i < len; i++){
14073 this.add(name, values[i]);
14079 * Resets the template for reuse
14080 * @return {MasterTemplate} this
14082 reset : function(){
14084 for(var i = 0; i < this.subCount; i++){
14090 applyTemplate : function(values){
14092 var replaceIndex = -1;
14093 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14094 return s[++replaceIndex].buffer.join("");
14096 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14099 apply : function(){
14100 return this.applyTemplate.apply(this, arguments);
14103 compile : function(){return this;}
14107 * Alias for fill().
14110 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14112 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14113 * var tpl = Roo.MasterTemplate.from('element-id');
14114 * @param {String/HTMLElement} el
14115 * @param {Object} config
14118 Roo.MasterTemplate.from = function(el, config){
14119 el = Roo.getDom(el);
14120 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14123 * Ext JS Library 1.1.1
14124 * Copyright(c) 2006-2007, Ext JS, LLC.
14126 * Originally Released Under LGPL - original licence link has changed is not relivant.
14129 * <script type="text/javascript">
14134 * @class Roo.util.CSS
14135 * Utility class for manipulating CSS rules
14138 Roo.util.CSS = function(){
14140 var doc = document;
14142 var camelRe = /(-[a-z])/gi;
14143 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14147 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14148 * tag and appended to the HEAD of the document.
14149 * @param {String|Object} cssText The text containing the css rules
14150 * @param {String} id An id to add to the stylesheet for later removal
14151 * @return {StyleSheet}
14153 createStyleSheet : function(cssText, id){
14155 var head = doc.getElementsByTagName("head")[0];
14156 var nrules = doc.createElement("style");
14157 nrules.setAttribute("type", "text/css");
14159 nrules.setAttribute("id", id);
14161 if (typeof(cssText) != 'string') {
14162 // support object maps..
14163 // not sure if this a good idea..
14164 // perhaps it should be merged with the general css handling
14165 // and handle js style props.
14166 var cssTextNew = [];
14167 for(var n in cssText) {
14169 for(var k in cssText[n]) {
14170 citems.push( k + ' : ' +cssText[n][k] + ';' );
14172 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14175 cssText = cssTextNew.join("\n");
14181 head.appendChild(nrules);
14182 ss = nrules.styleSheet;
14183 ss.cssText = cssText;
14186 nrules.appendChild(doc.createTextNode(cssText));
14188 nrules.cssText = cssText;
14190 head.appendChild(nrules);
14191 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14193 this.cacheStyleSheet(ss);
14198 * Removes a style or link tag by id
14199 * @param {String} id The id of the tag
14201 removeStyleSheet : function(id){
14202 var existing = doc.getElementById(id);
14204 existing.parentNode.removeChild(existing);
14209 * Dynamically swaps an existing stylesheet reference for a new one
14210 * @param {String} id The id of an existing link tag to remove
14211 * @param {String} url The href of the new stylesheet to include
14213 swapStyleSheet : function(id, url){
14214 this.removeStyleSheet(id);
14215 var ss = doc.createElement("link");
14216 ss.setAttribute("rel", "stylesheet");
14217 ss.setAttribute("type", "text/css");
14218 ss.setAttribute("id", id);
14219 ss.setAttribute("href", url);
14220 doc.getElementsByTagName("head")[0].appendChild(ss);
14224 * Refresh the rule cache if you have dynamically added stylesheets
14225 * @return {Object} An object (hash) of rules indexed by selector
14227 refreshCache : function(){
14228 return this.getRules(true);
14232 cacheStyleSheet : function(stylesheet){
14236 try{// try catch for cross domain access issue
14237 var ssRules = stylesheet.cssRules || stylesheet.rules;
14238 for(var j = ssRules.length-1; j >= 0; --j){
14239 rules[ssRules[j].selectorText] = ssRules[j];
14245 * Gets all css rules for the document
14246 * @param {Boolean} refreshCache true to refresh the internal cache
14247 * @return {Object} An object (hash) of rules indexed by selector
14249 getRules : function(refreshCache){
14250 if(rules == null || refreshCache){
14252 var ds = doc.styleSheets;
14253 for(var i =0, len = ds.length; i < len; i++){
14255 this.cacheStyleSheet(ds[i]);
14263 * Gets an an individual CSS rule by selector(s)
14264 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14265 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14266 * @return {CSSRule} The CSS rule or null if one is not found
14268 getRule : function(selector, refreshCache){
14269 var rs = this.getRules(refreshCache);
14270 if(!(selector instanceof Array)){
14271 return rs[selector];
14273 for(var i = 0; i < selector.length; i++){
14274 if(rs[selector[i]]){
14275 return rs[selector[i]];
14283 * Updates a rule property
14284 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14285 * @param {String} property The css property
14286 * @param {String} value The new value for the property
14287 * @return {Boolean} true If a rule was found and updated
14289 updateRule : function(selector, property, value){
14290 if(!(selector instanceof Array)){
14291 var rule = this.getRule(selector);
14293 rule.style[property.replace(camelRe, camelFn)] = value;
14297 for(var i = 0; i < selector.length; i++){
14298 if(this.updateRule(selector[i], property, value)){
14308 * Ext JS Library 1.1.1
14309 * Copyright(c) 2006-2007, Ext JS, LLC.
14311 * Originally Released Under LGPL - original licence link has changed is not relivant.
14314 * <script type="text/javascript">
14320 * @class Roo.util.ClickRepeater
14321 * @extends Roo.util.Observable
14323 * A wrapper class which can be applied to any element. Fires a "click" event while the
14324 * mouse is pressed. The interval between firings may be specified in the config but
14325 * defaults to 10 milliseconds.
14327 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14329 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14330 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14331 * Similar to an autorepeat key delay.
14332 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14333 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14334 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14335 * "interval" and "delay" are ignored. "immediate" is honored.
14336 * @cfg {Boolean} preventDefault True to prevent the default click event
14337 * @cfg {Boolean} stopDefault True to stop the default click event
14340 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14341 * 2007-02-02 jvs Renamed to ClickRepeater
14342 * 2007-02-03 jvs Modifications for FF Mac and Safari
14345 * @param {String/HTMLElement/Element} el The element to listen on
14346 * @param {Object} config
14348 Roo.util.ClickRepeater = function(el, config)
14350 this.el = Roo.get(el);
14351 this.el.unselectable();
14353 Roo.apply(this, config);
14358 * Fires when the mouse button is depressed.
14359 * @param {Roo.util.ClickRepeater} this
14361 "mousedown" : true,
14364 * Fires on a specified interval during the time the element is pressed.
14365 * @param {Roo.util.ClickRepeater} this
14370 * Fires when the mouse key is released.
14371 * @param {Roo.util.ClickRepeater} this
14376 this.el.on("mousedown", this.handleMouseDown, this);
14377 if(this.preventDefault || this.stopDefault){
14378 this.el.on("click", function(e){
14379 if(this.preventDefault){
14380 e.preventDefault();
14382 if(this.stopDefault){
14388 // allow inline handler
14390 this.on("click", this.handler, this.scope || this);
14393 Roo.util.ClickRepeater.superclass.constructor.call(this);
14396 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14399 preventDefault : true,
14400 stopDefault : false,
14404 handleMouseDown : function(){
14405 clearTimeout(this.timer);
14407 if(this.pressClass){
14408 this.el.addClass(this.pressClass);
14410 this.mousedownTime = new Date();
14412 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14413 this.el.on("mouseout", this.handleMouseOut, this);
14415 this.fireEvent("mousedown", this);
14416 this.fireEvent("click", this);
14418 this.timer = this.click.defer(this.delay || this.interval, this);
14422 click : function(){
14423 this.fireEvent("click", this);
14424 this.timer = this.click.defer(this.getInterval(), this);
14428 getInterval: function(){
14429 if(!this.accelerate){
14430 return this.interval;
14432 var pressTime = this.mousedownTime.getElapsed();
14433 if(pressTime < 500){
14435 }else if(pressTime < 1700){
14437 }else if(pressTime < 2600){
14439 }else if(pressTime < 3500){
14441 }else if(pressTime < 4400){
14443 }else if(pressTime < 5300){
14445 }else if(pressTime < 6200){
14453 handleMouseOut : function(){
14454 clearTimeout(this.timer);
14455 if(this.pressClass){
14456 this.el.removeClass(this.pressClass);
14458 this.el.on("mouseover", this.handleMouseReturn, this);
14462 handleMouseReturn : function(){
14463 this.el.un("mouseover", this.handleMouseReturn);
14464 if(this.pressClass){
14465 this.el.addClass(this.pressClass);
14471 handleMouseUp : function(){
14472 clearTimeout(this.timer);
14473 this.el.un("mouseover", this.handleMouseReturn);
14474 this.el.un("mouseout", this.handleMouseOut);
14475 Roo.get(document).un("mouseup", this.handleMouseUp);
14476 this.el.removeClass(this.pressClass);
14477 this.fireEvent("mouseup", this);
14481 * Ext JS Library 1.1.1
14482 * Copyright(c) 2006-2007, Ext JS, LLC.
14484 * Originally Released Under LGPL - original licence link has changed is not relivant.
14487 * <script type="text/javascript">
14492 * @class Roo.KeyNav
14493 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14494 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14495 * way to implement custom navigation schemes for any UI component.</p>
14496 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14497 * pageUp, pageDown, del, home, end. Usage:</p>
14499 var nav = new Roo.KeyNav("my-element", {
14500 "left" : function(e){
14501 this.moveLeft(e.ctrlKey);
14503 "right" : function(e){
14504 this.moveRight(e.ctrlKey);
14506 "enter" : function(e){
14513 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14514 * @param {Object} config The config
14516 Roo.KeyNav = function(el, config){
14517 this.el = Roo.get(el);
14518 Roo.apply(this, config);
14519 if(!this.disabled){
14520 this.disabled = true;
14525 Roo.KeyNav.prototype = {
14527 * @cfg {Boolean} disabled
14528 * True to disable this KeyNav instance (defaults to false)
14532 * @cfg {String} defaultEventAction
14533 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14534 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14535 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14537 defaultEventAction: "stopEvent",
14539 * @cfg {Boolean} forceKeyDown
14540 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14541 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14542 * handle keydown instead of keypress.
14544 forceKeyDown : false,
14547 prepareEvent : function(e){
14548 var k = e.getKey();
14549 var h = this.keyToHandler[k];
14550 //if(h && this[h]){
14551 // e.stopPropagation();
14553 if(Roo.isSafari && h && k >= 37 && k <= 40){
14559 relay : function(e){
14560 var k = e.getKey();
14561 var h = this.keyToHandler[k];
14563 if(this.doRelay(e, this[h], h) !== true){
14564 e[this.defaultEventAction]();
14570 doRelay : function(e, h, hname){
14571 return h.call(this.scope || this, e);
14574 // possible handlers
14588 // quick lookup hash
14605 * Enable this KeyNav
14607 enable: function(){
14609 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14610 // the EventObject will normalize Safari automatically
14611 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14612 this.el.on("keydown", this.relay, this);
14614 this.el.on("keydown", this.prepareEvent, this);
14615 this.el.on("keypress", this.relay, this);
14617 this.disabled = false;
14622 * Disable this KeyNav
14624 disable: function(){
14625 if(!this.disabled){
14626 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14627 this.el.un("keydown", this.relay);
14629 this.el.un("keydown", this.prepareEvent);
14630 this.el.un("keypress", this.relay);
14632 this.disabled = true;
14637 * Ext JS Library 1.1.1
14638 * Copyright(c) 2006-2007, Ext JS, LLC.
14640 * Originally Released Under LGPL - original licence link has changed is not relivant.
14643 * <script type="text/javascript">
14648 * @class Roo.KeyMap
14649 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14650 * The constructor accepts the same config object as defined by {@link #addBinding}.
14651 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14652 * combination it will call the function with this signature (if the match is a multi-key
14653 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14654 * A KeyMap can also handle a string representation of keys.<br />
14657 // map one key by key code
14658 var map = new Roo.KeyMap("my-element", {
14659 key: 13, // or Roo.EventObject.ENTER
14664 // map multiple keys to one action by string
14665 var map = new Roo.KeyMap("my-element", {
14671 // map multiple keys to multiple actions by strings and array of codes
14672 var map = new Roo.KeyMap("my-element", [
14675 fn: function(){ alert("Return was pressed"); }
14678 fn: function(){ alert('a, b or c was pressed'); }
14683 fn: function(){ alert('Control + shift + tab was pressed.'); }
14687 * <b>Note: A KeyMap starts enabled</b>
14689 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14690 * @param {Object} config The config (see {@link #addBinding})
14691 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14693 Roo.KeyMap = function(el, config, eventName){
14694 this.el = Roo.get(el);
14695 this.eventName = eventName || "keydown";
14696 this.bindings = [];
14698 this.addBinding(config);
14703 Roo.KeyMap.prototype = {
14705 * True to stop the event from bubbling and prevent the default browser action if the
14706 * key was handled by the KeyMap (defaults to false)
14712 * Add a new binding to this KeyMap. The following config object properties are supported:
14714 Property Type Description
14715 ---------- --------------- ----------------------------------------------------------------------
14716 key String/Array A single keycode or an array of keycodes to handle
14717 shift Boolean True to handle key only when shift is pressed (defaults to false)
14718 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14719 alt Boolean True to handle key only when alt is pressed (defaults to false)
14720 fn Function The function to call when KeyMap finds the expected key combination
14721 scope Object The scope of the callback function
14727 var map = new Roo.KeyMap(document, {
14728 key: Roo.EventObject.ENTER,
14733 //Add a new binding to the existing KeyMap later
14741 * @param {Object/Array} config A single KeyMap config or an array of configs
14743 addBinding : function(config){
14744 if(config instanceof Array){
14745 for(var i = 0, len = config.length; i < len; i++){
14746 this.addBinding(config[i]);
14750 var keyCode = config.key,
14751 shift = config.shift,
14752 ctrl = config.ctrl,
14755 scope = config.scope;
14756 if(typeof keyCode == "string"){
14758 var keyString = keyCode.toUpperCase();
14759 for(var j = 0, len = keyString.length; j < len; j++){
14760 ks.push(keyString.charCodeAt(j));
14764 var keyArray = keyCode instanceof Array;
14765 var handler = function(e){
14766 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14767 var k = e.getKey();
14769 for(var i = 0, len = keyCode.length; i < len; i++){
14770 if(keyCode[i] == k){
14771 if(this.stopEvent){
14774 fn.call(scope || window, k, e);
14780 if(this.stopEvent){
14783 fn.call(scope || window, k, e);
14788 this.bindings.push(handler);
14792 * Shorthand for adding a single key listener
14793 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14794 * following options:
14795 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14796 * @param {Function} fn The function to call
14797 * @param {Object} scope (optional) The scope of the function
14799 on : function(key, fn, scope){
14800 var keyCode, shift, ctrl, alt;
14801 if(typeof key == "object" && !(key instanceof Array)){
14820 handleKeyDown : function(e){
14821 if(this.enabled){ //just in case
14822 var b = this.bindings;
14823 for(var i = 0, len = b.length; i < len; i++){
14824 b[i].call(this, e);
14830 * Returns true if this KeyMap is enabled
14831 * @return {Boolean}
14833 isEnabled : function(){
14834 return this.enabled;
14838 * Enables this KeyMap
14840 enable: function(){
14842 this.el.on(this.eventName, this.handleKeyDown, this);
14843 this.enabled = true;
14848 * Disable this KeyMap
14850 disable: function(){
14852 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14853 this.enabled = false;
14858 * Ext JS Library 1.1.1
14859 * Copyright(c) 2006-2007, Ext JS, LLC.
14861 * Originally Released Under LGPL - original licence link has changed is not relivant.
14864 * <script type="text/javascript">
14869 * @class Roo.util.TextMetrics
14870 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14871 * wide, in pixels, a given block of text will be.
14874 Roo.util.TextMetrics = function(){
14878 * Measures the size of the specified text
14879 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14880 * that can affect the size of the rendered text
14881 * @param {String} text The text to measure
14882 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14883 * in order to accurately measure the text height
14884 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14886 measure : function(el, text, fixedWidth){
14888 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14891 shared.setFixedWidth(fixedWidth || 'auto');
14892 return shared.getSize(text);
14896 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14897 * the overhead of multiple calls to initialize the style properties on each measurement.
14898 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14899 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14900 * in order to accurately measure the text height
14901 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14903 createInstance : function(el, fixedWidth){
14904 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14911 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14912 var ml = new Roo.Element(document.createElement('div'));
14913 document.body.appendChild(ml.dom);
14914 ml.position('absolute');
14915 ml.setLeftTop(-1000, -1000);
14919 ml.setWidth(fixedWidth);
14924 * Returns the size of the specified text based on the internal element's style and width properties
14925 * @memberOf Roo.util.TextMetrics.Instance#
14926 * @param {String} text The text to measure
14927 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14929 getSize : function(text){
14931 var s = ml.getSize();
14937 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14938 * that can affect the size of the rendered text
14939 * @memberOf Roo.util.TextMetrics.Instance#
14940 * @param {String/HTMLElement} el The element, dom node or id
14942 bind : function(el){
14944 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14949 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14950 * to set a fixed width in order to accurately measure the text height.
14951 * @memberOf Roo.util.TextMetrics.Instance#
14952 * @param {Number} width The width to set on the element
14954 setFixedWidth : function(width){
14955 ml.setWidth(width);
14959 * Returns the measured width of the specified text
14960 * @memberOf Roo.util.TextMetrics.Instance#
14961 * @param {String} text The text to measure
14962 * @return {Number} width The width in pixels
14964 getWidth : function(text){
14965 ml.dom.style.width = 'auto';
14966 return this.getSize(text).width;
14970 * Returns the measured height of the specified text. For multiline text, be sure to call
14971 * {@link #setFixedWidth} if necessary.
14972 * @memberOf Roo.util.TextMetrics.Instance#
14973 * @param {String} text The text to measure
14974 * @return {Number} height The height in pixels
14976 getHeight : function(text){
14977 return this.getSize(text).height;
14981 instance.bind(bindTo);
14986 // backwards compat
14987 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14989 * Ext JS Library 1.1.1
14990 * Copyright(c) 2006-2007, Ext JS, LLC.
14992 * Originally Released Under LGPL - original licence link has changed is not relivant.
14995 * <script type="text/javascript">
14999 * @class Roo.state.Provider
15000 * Abstract base class for state provider implementations. This class provides methods
15001 * for encoding and decoding <b>typed</b> variables including dates and defines the
15002 * Provider interface.
15004 Roo.state.Provider = function(){
15006 * @event statechange
15007 * Fires when a state change occurs.
15008 * @param {Provider} this This state provider
15009 * @param {String} key The state key which was changed
15010 * @param {String} value The encoded value for the state
15013 "statechange": true
15016 Roo.state.Provider.superclass.constructor.call(this);
15018 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15020 * Returns the current value for a key
15021 * @param {String} name The key name
15022 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15023 * @return {Mixed} The state data
15025 get : function(name, defaultValue){
15026 return typeof this.state[name] == "undefined" ?
15027 defaultValue : this.state[name];
15031 * Clears a value from the state
15032 * @param {String} name The key name
15034 clear : function(name){
15035 delete this.state[name];
15036 this.fireEvent("statechange", this, name, null);
15040 * Sets the value for a key
15041 * @param {String} name The key name
15042 * @param {Mixed} value The value to set
15044 set : function(name, value){
15045 this.state[name] = value;
15046 this.fireEvent("statechange", this, name, value);
15050 * Decodes a string previously encoded with {@link #encodeValue}.
15051 * @param {String} value The value to decode
15052 * @return {Mixed} The decoded value
15054 decodeValue : function(cookie){
15055 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15056 var matches = re.exec(unescape(cookie));
15057 if(!matches || !matches[1]) {
15058 return; // non state cookie
15060 var type = matches[1];
15061 var v = matches[2];
15064 return parseFloat(v);
15066 return new Date(Date.parse(v));
15071 var values = v.split("^");
15072 for(var i = 0, len = values.length; i < len; i++){
15073 all.push(this.decodeValue(values[i]));
15078 var values = v.split("^");
15079 for(var i = 0, len = values.length; i < len; i++){
15080 var kv = values[i].split("=");
15081 all[kv[0]] = this.decodeValue(kv[1]);
15090 * Encodes a value including type information. Decode with {@link #decodeValue}.
15091 * @param {Mixed} value The value to encode
15092 * @return {String} The encoded value
15094 encodeValue : function(v){
15096 if(typeof v == "number"){
15098 }else if(typeof v == "boolean"){
15099 enc = "b:" + (v ? "1" : "0");
15100 }else if(v instanceof Date){
15101 enc = "d:" + v.toGMTString();
15102 }else if(v instanceof Array){
15104 for(var i = 0, len = v.length; i < len; i++){
15105 flat += this.encodeValue(v[i]);
15111 }else if(typeof v == "object"){
15114 if(typeof v[key] != "function"){
15115 flat += key + "=" + this.encodeValue(v[key]) + "^";
15118 enc = "o:" + flat.substring(0, flat.length-1);
15122 return escape(enc);
15128 * Ext JS Library 1.1.1
15129 * Copyright(c) 2006-2007, Ext JS, LLC.
15131 * Originally Released Under LGPL - original licence link has changed is not relivant.
15134 * <script type="text/javascript">
15137 * @class Roo.state.Manager
15138 * This is the global state manager. By default all components that are "state aware" check this class
15139 * for state information if you don't pass them a custom state provider. In order for this class
15140 * to be useful, it must be initialized with a provider when your application initializes.
15142 // in your initialization function
15144 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15146 // supposed you have a {@link Roo.BorderLayout}
15147 var layout = new Roo.BorderLayout(...);
15148 layout.restoreState();
15149 // or a {Roo.BasicDialog}
15150 var dialog = new Roo.BasicDialog(...);
15151 dialog.restoreState();
15155 Roo.state.Manager = function(){
15156 var provider = new Roo.state.Provider();
15160 * Configures the default state provider for your application
15161 * @param {Provider} stateProvider The state provider to set
15163 setProvider : function(stateProvider){
15164 provider = stateProvider;
15168 * Returns the current value for a key
15169 * @param {String} name The key name
15170 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15171 * @return {Mixed} The state data
15173 get : function(key, defaultValue){
15174 return provider.get(key, defaultValue);
15178 * Sets the value for a key
15179 * @param {String} name The key name
15180 * @param {Mixed} value The state data
15182 set : function(key, value){
15183 provider.set(key, value);
15187 * Clears a value from the state
15188 * @param {String} name The key name
15190 clear : function(key){
15191 provider.clear(key);
15195 * Gets the currently configured state provider
15196 * @return {Provider} The state provider
15198 getProvider : function(){
15205 * Ext JS Library 1.1.1
15206 * Copyright(c) 2006-2007, Ext JS, LLC.
15208 * Originally Released Under LGPL - original licence link has changed is not relivant.
15211 * <script type="text/javascript">
15214 * @class Roo.state.CookieProvider
15215 * @extends Roo.state.Provider
15216 * The default Provider implementation which saves state via cookies.
15219 var cp = new Roo.state.CookieProvider({
15221 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15222 domain: "roojs.com"
15224 Roo.state.Manager.setProvider(cp);
15226 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15227 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15228 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15229 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15230 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15231 * domain the page is running on including the 'www' like 'www.roojs.com')
15232 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15234 * Create a new CookieProvider
15235 * @param {Object} config The configuration object
15237 Roo.state.CookieProvider = function(config){
15238 Roo.state.CookieProvider.superclass.constructor.call(this);
15240 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15241 this.domain = null;
15242 this.secure = false;
15243 Roo.apply(this, config);
15244 this.state = this.readCookies();
15247 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15249 set : function(name, value){
15250 if(typeof value == "undefined" || value === null){
15254 this.setCookie(name, value);
15255 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15259 clear : function(name){
15260 this.clearCookie(name);
15261 Roo.state.CookieProvider.superclass.clear.call(this, name);
15265 readCookies : function(){
15267 var c = document.cookie + ";";
15268 var re = /\s?(.*?)=(.*?);/g;
15270 while((matches = re.exec(c)) != null){
15271 var name = matches[1];
15272 var value = matches[2];
15273 if(name && name.substring(0,3) == "ys-"){
15274 cookies[name.substr(3)] = this.decodeValue(value);
15281 setCookie : function(name, value){
15282 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15283 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15284 ((this.path == null) ? "" : ("; path=" + this.path)) +
15285 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15286 ((this.secure == true) ? "; secure" : "");
15290 clearCookie : function(name){
15291 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15292 ((this.path == null) ? "" : ("; path=" + this.path)) +
15293 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15294 ((this.secure == true) ? "; secure" : "");
15298 * Ext JS Library 1.1.1
15299 * Copyright(c) 2006-2007, Ext JS, LLC.
15301 * Originally Released Under LGPL - original licence link has changed is not relivant.
15304 * <script type="text/javascript">
15309 * @class Roo.ComponentMgr
15310 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15313 Roo.ComponentMgr = function(){
15314 var all = new Roo.util.MixedCollection();
15318 * Registers a component.
15319 * @param {Roo.Component} c The component
15321 register : function(c){
15326 * Unregisters a component.
15327 * @param {Roo.Component} c The component
15329 unregister : function(c){
15334 * Returns a component by id
15335 * @param {String} id The component id
15337 get : function(id){
15338 return all.get(id);
15342 * Registers a function that will be called when a specified component is added to ComponentMgr
15343 * @param {String} id The component id
15344 * @param {Funtction} fn The callback function
15345 * @param {Object} scope The scope of the callback
15347 onAvailable : function(id, fn, scope){
15348 all.on("add", function(index, o){
15350 fn.call(scope || o, o);
15351 all.un("add", fn, scope);
15358 * Ext JS Library 1.1.1
15359 * Copyright(c) 2006-2007, Ext JS, LLC.
15361 * Originally Released Under LGPL - original licence link has changed is not relivant.
15364 * <script type="text/javascript">
15368 * @class Roo.Component
15369 * @extends Roo.util.Observable
15370 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15371 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15372 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15373 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15374 * All visual components (widgets) that require rendering into a layout should subclass Component.
15376 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15377 * 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
15378 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15380 Roo.Component = function(config){
15381 config = config || {};
15382 if(config.tagName || config.dom || typeof config == "string"){ // element object
15383 config = {el: config, id: config.id || config};
15385 this.initialConfig = config;
15387 Roo.apply(this, config);
15391 * Fires after the component is disabled.
15392 * @param {Roo.Component} this
15397 * Fires after the component is enabled.
15398 * @param {Roo.Component} this
15402 * @event beforeshow
15403 * Fires before the component is shown. Return false to stop the show.
15404 * @param {Roo.Component} this
15409 * Fires after the component is shown.
15410 * @param {Roo.Component} this
15414 * @event beforehide
15415 * Fires before the component is hidden. Return false to stop the hide.
15416 * @param {Roo.Component} this
15421 * Fires after the component is hidden.
15422 * @param {Roo.Component} this
15426 * @event beforerender
15427 * Fires before the component is rendered. Return false to stop the render.
15428 * @param {Roo.Component} this
15430 beforerender : true,
15433 * Fires after the component is rendered.
15434 * @param {Roo.Component} this
15438 * @event beforedestroy
15439 * Fires before the component is destroyed. Return false to stop the destroy.
15440 * @param {Roo.Component} this
15442 beforedestroy : true,
15445 * Fires after the component is destroyed.
15446 * @param {Roo.Component} this
15451 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15453 Roo.ComponentMgr.register(this);
15454 Roo.Component.superclass.constructor.call(this);
15455 this.initComponent();
15456 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15457 this.render(this.renderTo);
15458 delete this.renderTo;
15463 Roo.Component.AUTO_ID = 1000;
15465 Roo.extend(Roo.Component, Roo.util.Observable, {
15467 * @scope Roo.Component.prototype
15469 * true if this component is hidden. Read-only.
15474 * true if this component is disabled. Read-only.
15479 * true if this component has been rendered. Read-only.
15483 /** @cfg {String} disableClass
15484 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15486 disabledClass : "x-item-disabled",
15487 /** @cfg {Boolean} allowDomMove
15488 * Whether the component can move the Dom node when rendering (defaults to true).
15490 allowDomMove : true,
15491 /** @cfg {String} hideMode (display|visibility)
15492 * How this component should hidden. Supported values are
15493 * "visibility" (css visibility), "offsets" (negative offset position) and
15494 * "display" (css display) - defaults to "display".
15496 hideMode: 'display',
15499 ctype : "Roo.Component",
15502 * @cfg {String} actionMode
15503 * which property holds the element that used for hide() / show() / disable() / enable()
15504 * default is 'el' for forms you probably want to set this to fieldEl
15509 getActionEl : function(){
15510 return this[this.actionMode];
15513 initComponent : Roo.emptyFn,
15515 * If this is a lazy rendering component, render it to its container element.
15516 * @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.
15518 render : function(container, position){
15524 if(this.fireEvent("beforerender", this) === false){
15528 if(!container && this.el){
15529 this.el = Roo.get(this.el);
15530 container = this.el.dom.parentNode;
15531 this.allowDomMove = false;
15533 this.container = Roo.get(container);
15534 this.rendered = true;
15535 if(position !== undefined){
15536 if(typeof position == 'number'){
15537 position = this.container.dom.childNodes[position];
15539 position = Roo.getDom(position);
15542 this.onRender(this.container, position || null);
15544 this.el.addClass(this.cls);
15548 this.el.applyStyles(this.style);
15551 this.fireEvent("render", this);
15552 this.afterRender(this.container);
15565 // default function is not really useful
15566 onRender : function(ct, position){
15568 this.el = Roo.get(this.el);
15569 if(this.allowDomMove !== false){
15570 ct.dom.insertBefore(this.el.dom, position);
15576 getAutoCreate : function(){
15577 var cfg = typeof this.autoCreate == "object" ?
15578 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15579 if(this.id && !cfg.id){
15586 afterRender : Roo.emptyFn,
15589 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15590 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15592 destroy : function(){
15593 if(this.fireEvent("beforedestroy", this) !== false){
15594 this.purgeListeners();
15595 this.beforeDestroy();
15597 this.el.removeAllListeners();
15599 if(this.actionMode == "container"){
15600 this.container.remove();
15604 Roo.ComponentMgr.unregister(this);
15605 this.fireEvent("destroy", this);
15610 beforeDestroy : function(){
15615 onDestroy : function(){
15620 * Returns the underlying {@link Roo.Element}.
15621 * @return {Roo.Element} The element
15623 getEl : function(){
15628 * Returns the id of this component.
15631 getId : function(){
15636 * Try to focus this component.
15637 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15638 * @return {Roo.Component} this
15640 focus : function(selectText){
15643 if(selectText === true){
15644 this.el.dom.select();
15659 * Disable this component.
15660 * @return {Roo.Component} this
15662 disable : function(){
15666 this.disabled = true;
15667 this.fireEvent("disable", this);
15672 onDisable : function(){
15673 this.getActionEl().addClass(this.disabledClass);
15674 this.el.dom.disabled = true;
15678 * Enable this component.
15679 * @return {Roo.Component} this
15681 enable : function(){
15685 this.disabled = false;
15686 this.fireEvent("enable", this);
15691 onEnable : function(){
15692 this.getActionEl().removeClass(this.disabledClass);
15693 this.el.dom.disabled = false;
15697 * Convenience function for setting disabled/enabled by boolean.
15698 * @param {Boolean} disabled
15700 setDisabled : function(disabled){
15701 this[disabled ? "disable" : "enable"]();
15705 * Show this component.
15706 * @return {Roo.Component} this
15709 if(this.fireEvent("beforeshow", this) !== false){
15710 this.hidden = false;
15714 this.fireEvent("show", this);
15720 onShow : function(){
15721 var ae = this.getActionEl();
15722 if(this.hideMode == 'visibility'){
15723 ae.dom.style.visibility = "visible";
15724 }else if(this.hideMode == 'offsets'){
15725 ae.removeClass('x-hidden');
15727 ae.dom.style.display = "";
15732 * Hide this component.
15733 * @return {Roo.Component} this
15736 if(this.fireEvent("beforehide", this) !== false){
15737 this.hidden = true;
15741 this.fireEvent("hide", this);
15747 onHide : function(){
15748 var ae = this.getActionEl();
15749 if(this.hideMode == 'visibility'){
15750 ae.dom.style.visibility = "hidden";
15751 }else if(this.hideMode == 'offsets'){
15752 ae.addClass('x-hidden');
15754 ae.dom.style.display = "none";
15759 * Convenience function to hide or show this component by boolean.
15760 * @param {Boolean} visible True to show, false to hide
15761 * @return {Roo.Component} this
15763 setVisible: function(visible){
15773 * Returns true if this component is visible.
15775 isVisible : function(){
15776 return this.getActionEl().isVisible();
15779 cloneConfig : function(overrides){
15780 overrides = overrides || {};
15781 var id = overrides.id || Roo.id();
15782 var cfg = Roo.applyIf(overrides, this.initialConfig);
15783 cfg.id = id; // prevent dup id
15784 return new this.constructor(cfg);
15788 * Ext JS Library 1.1.1
15789 * Copyright(c) 2006-2007, Ext JS, LLC.
15791 * Originally Released Under LGPL - original licence link has changed is not relivant.
15794 * <script type="text/javascript">
15798 * @class Roo.BoxComponent
15799 * @extends Roo.Component
15800 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15801 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15802 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15803 * layout containers.
15805 * @param {Roo.Element/String/Object} config The configuration options.
15807 Roo.BoxComponent = function(config){
15808 Roo.Component.call(this, config);
15812 * Fires after the component is resized.
15813 * @param {Roo.Component} this
15814 * @param {Number} adjWidth The box-adjusted width that was set
15815 * @param {Number} adjHeight The box-adjusted height that was set
15816 * @param {Number} rawWidth The width that was originally specified
15817 * @param {Number} rawHeight The height that was originally specified
15822 * Fires after the component is moved.
15823 * @param {Roo.Component} this
15824 * @param {Number} x The new x position
15825 * @param {Number} y The new y position
15831 Roo.extend(Roo.BoxComponent, Roo.Component, {
15832 // private, set in afterRender to signify that the component has been rendered
15834 // private, used to defer height settings to subclasses
15835 deferHeight: false,
15836 /** @cfg {Number} width
15837 * width (optional) size of component
15839 /** @cfg {Number} height
15840 * height (optional) size of component
15844 * Sets the width and height of the component. This method fires the resize event. This method can accept
15845 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15846 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15847 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15848 * @return {Roo.BoxComponent} this
15850 setSize : function(w, h){
15851 // support for standard size objects
15852 if(typeof w == 'object'){
15857 if(!this.boxReady){
15863 // prevent recalcs when not needed
15864 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15867 this.lastSize = {width: w, height: h};
15869 var adj = this.adjustSize(w, h);
15870 var aw = adj.width, ah = adj.height;
15871 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15872 var rz = this.getResizeEl();
15873 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15874 rz.setSize(aw, ah);
15875 }else if(!this.deferHeight && ah !== undefined){
15877 }else if(aw !== undefined){
15880 this.onResize(aw, ah, w, h);
15881 this.fireEvent('resize', this, aw, ah, w, h);
15887 * Gets the current size of the component's underlying element.
15888 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15890 getSize : function(){
15891 return this.el.getSize();
15895 * Gets the current XY position of the component's underlying element.
15896 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15897 * @return {Array} The XY position of the element (e.g., [100, 200])
15899 getPosition : function(local){
15900 if(local === true){
15901 return [this.el.getLeft(true), this.el.getTop(true)];
15903 return this.xy || this.el.getXY();
15907 * Gets the current box measurements of the component's underlying element.
15908 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15909 * @returns {Object} box An object in the format {x, y, width, height}
15911 getBox : function(local){
15912 var s = this.el.getSize();
15914 s.x = this.el.getLeft(true);
15915 s.y = this.el.getTop(true);
15917 var xy = this.xy || this.el.getXY();
15925 * Sets the current box measurements of the component's underlying element.
15926 * @param {Object} box An object in the format {x, y, width, height}
15927 * @returns {Roo.BoxComponent} this
15929 updateBox : function(box){
15930 this.setSize(box.width, box.height);
15931 this.setPagePosition(box.x, box.y);
15936 getResizeEl : function(){
15937 return this.resizeEl || this.el;
15941 getPositionEl : function(){
15942 return this.positionEl || this.el;
15946 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15947 * This method fires the move event.
15948 * @param {Number} left The new left
15949 * @param {Number} top The new top
15950 * @returns {Roo.BoxComponent} this
15952 setPosition : function(x, y){
15955 if(!this.boxReady){
15958 var adj = this.adjustPosition(x, y);
15959 var ax = adj.x, ay = adj.y;
15961 var el = this.getPositionEl();
15962 if(ax !== undefined || ay !== undefined){
15963 if(ax !== undefined && ay !== undefined){
15964 el.setLeftTop(ax, ay);
15965 }else if(ax !== undefined){
15967 }else if(ay !== undefined){
15970 this.onPosition(ax, ay);
15971 this.fireEvent('move', this, ax, ay);
15977 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15978 * This method fires the move event.
15979 * @param {Number} x The new x position
15980 * @param {Number} y The new y position
15981 * @returns {Roo.BoxComponent} this
15983 setPagePosition : function(x, y){
15986 if(!this.boxReady){
15989 if(x === undefined || y === undefined){ // cannot translate undefined points
15992 var p = this.el.translatePoints(x, y);
15993 this.setPosition(p.left, p.top);
15998 onRender : function(ct, position){
15999 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16001 this.resizeEl = Roo.get(this.resizeEl);
16003 if(this.positionEl){
16004 this.positionEl = Roo.get(this.positionEl);
16009 afterRender : function(){
16010 Roo.BoxComponent.superclass.afterRender.call(this);
16011 this.boxReady = true;
16012 this.setSize(this.width, this.height);
16013 if(this.x || this.y){
16014 this.setPosition(this.x, this.y);
16016 if(this.pageX || this.pageY){
16017 this.setPagePosition(this.pageX, this.pageY);
16022 * Force the component's size to recalculate based on the underlying element's current height and width.
16023 * @returns {Roo.BoxComponent} this
16025 syncSize : function(){
16026 delete this.lastSize;
16027 this.setSize(this.el.getWidth(), this.el.getHeight());
16032 * Called after the component is resized, this method is empty by default but can be implemented by any
16033 * subclass that needs to perform custom logic after a resize occurs.
16034 * @param {Number} adjWidth The box-adjusted width that was set
16035 * @param {Number} adjHeight The box-adjusted height that was set
16036 * @param {Number} rawWidth The width that was originally specified
16037 * @param {Number} rawHeight The height that was originally specified
16039 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16044 * Called after the component is moved, this method is empty by default but can be implemented by any
16045 * subclass that needs to perform custom logic after a move occurs.
16046 * @param {Number} x The new x position
16047 * @param {Number} y The new y position
16049 onPosition : function(x, y){
16054 adjustSize : function(w, h){
16055 if(this.autoWidth){
16058 if(this.autoHeight){
16061 return {width : w, height: h};
16065 adjustPosition : function(x, y){
16066 return {x : x, y: y};
16070 * Ext JS Library 1.1.1
16071 * Copyright(c) 2006-2007, Ext JS, LLC.
16073 * Originally Released Under LGPL - original licence link has changed is not relivant.
16076 * <script type="text/javascript">
16081 * @extends Roo.Element
16082 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16083 * automatic maintaining of shadow/shim positions.
16084 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16085 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16086 * you can pass a string with a CSS class name. False turns off the shadow.
16087 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16088 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16089 * @cfg {String} cls CSS class to add to the element
16090 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16091 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16093 * @param {Object} config An object with config options.
16094 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16097 Roo.Layer = function(config, existingEl){
16098 config = config || {};
16099 var dh = Roo.DomHelper;
16100 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16102 this.dom = Roo.getDom(existingEl);
16105 var o = config.dh || {tag: "div", cls: "x-layer"};
16106 this.dom = dh.append(pel, o);
16109 this.addClass(config.cls);
16111 this.constrain = config.constrain !== false;
16112 this.visibilityMode = Roo.Element.VISIBILITY;
16114 this.id = this.dom.id = config.id;
16116 this.id = Roo.id(this.dom);
16118 this.zindex = config.zindex || this.getZIndex();
16119 this.position("absolute", this.zindex);
16121 this.shadowOffset = config.shadowOffset || 4;
16122 this.shadow = new Roo.Shadow({
16123 offset : this.shadowOffset,
16124 mode : config.shadow
16127 this.shadowOffset = 0;
16129 this.useShim = config.shim !== false && Roo.useShims;
16130 this.useDisplay = config.useDisplay;
16134 var supr = Roo.Element.prototype;
16136 // shims are shared among layer to keep from having 100 iframes
16139 Roo.extend(Roo.Layer, Roo.Element, {
16141 getZIndex : function(){
16142 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16145 getShim : function(){
16152 var shim = shims.shift();
16154 shim = this.createShim();
16155 shim.enableDisplayMode('block');
16156 shim.dom.style.display = 'none';
16157 shim.dom.style.visibility = 'visible';
16159 var pn = this.dom.parentNode;
16160 if(shim.dom.parentNode != pn){
16161 pn.insertBefore(shim.dom, this.dom);
16163 shim.setStyle('z-index', this.getZIndex()-2);
16168 hideShim : function(){
16170 this.shim.setDisplayed(false);
16171 shims.push(this.shim);
16176 disableShadow : function(){
16178 this.shadowDisabled = true;
16179 this.shadow.hide();
16180 this.lastShadowOffset = this.shadowOffset;
16181 this.shadowOffset = 0;
16185 enableShadow : function(show){
16187 this.shadowDisabled = false;
16188 this.shadowOffset = this.lastShadowOffset;
16189 delete this.lastShadowOffset;
16197 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16198 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16199 sync : function(doShow){
16200 var sw = this.shadow;
16201 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16202 var sh = this.getShim();
16204 var w = this.getWidth(),
16205 h = this.getHeight();
16207 var l = this.getLeft(true),
16208 t = this.getTop(true);
16210 if(sw && !this.shadowDisabled){
16211 if(doShow && !sw.isVisible()){
16214 sw.realign(l, t, w, h);
16220 // fit the shim behind the shadow, so it is shimmed too
16221 var a = sw.adjusts, s = sh.dom.style;
16222 s.left = (Math.min(l, l+a.l))+"px";
16223 s.top = (Math.min(t, t+a.t))+"px";
16224 s.width = (w+a.w)+"px";
16225 s.height = (h+a.h)+"px";
16232 sh.setLeftTop(l, t);
16239 destroy : function(){
16242 this.shadow.hide();
16244 this.removeAllListeners();
16245 var pn = this.dom.parentNode;
16247 pn.removeChild(this.dom);
16249 Roo.Element.uncache(this.id);
16252 remove : function(){
16257 beginUpdate : function(){
16258 this.updating = true;
16262 endUpdate : function(){
16263 this.updating = false;
16268 hideUnders : function(negOffset){
16270 this.shadow.hide();
16276 constrainXY : function(){
16277 if(this.constrain){
16278 var vw = Roo.lib.Dom.getViewWidth(),
16279 vh = Roo.lib.Dom.getViewHeight();
16280 var s = Roo.get(document).getScroll();
16282 var xy = this.getXY();
16283 var x = xy[0], y = xy[1];
16284 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16285 // only move it if it needs it
16287 // first validate right/bottom
16288 if((x + w) > vw+s.left){
16289 x = vw - w - this.shadowOffset;
16292 if((y + h) > vh+s.top){
16293 y = vh - h - this.shadowOffset;
16296 // then make sure top/left isn't negative
16307 var ay = this.avoidY;
16308 if(y <= ay && (y+h) >= ay){
16314 supr.setXY.call(this, xy);
16320 isVisible : function(){
16321 return this.visible;
16325 showAction : function(){
16326 this.visible = true; // track visibility to prevent getStyle calls
16327 if(this.useDisplay === true){
16328 this.setDisplayed("");
16329 }else if(this.lastXY){
16330 supr.setXY.call(this, this.lastXY);
16331 }else if(this.lastLT){
16332 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16337 hideAction : function(){
16338 this.visible = false;
16339 if(this.useDisplay === true){
16340 this.setDisplayed(false);
16342 this.setLeftTop(-10000,-10000);
16346 // overridden Element method
16347 setVisible : function(v, a, d, c, e){
16352 var cb = function(){
16357 }.createDelegate(this);
16358 supr.setVisible.call(this, true, true, d, cb, e);
16361 this.hideUnders(true);
16370 }.createDelegate(this);
16372 supr.setVisible.call(this, v, a, d, cb, e);
16381 storeXY : function(xy){
16382 delete this.lastLT;
16386 storeLeftTop : function(left, top){
16387 delete this.lastXY;
16388 this.lastLT = [left, top];
16392 beforeFx : function(){
16393 this.beforeAction();
16394 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16398 afterFx : function(){
16399 Roo.Layer.superclass.afterFx.apply(this, arguments);
16400 this.sync(this.isVisible());
16404 beforeAction : function(){
16405 if(!this.updating && this.shadow){
16406 this.shadow.hide();
16410 // overridden Element method
16411 setLeft : function(left){
16412 this.storeLeftTop(left, this.getTop(true));
16413 supr.setLeft.apply(this, arguments);
16417 setTop : function(top){
16418 this.storeLeftTop(this.getLeft(true), top);
16419 supr.setTop.apply(this, arguments);
16423 setLeftTop : function(left, top){
16424 this.storeLeftTop(left, top);
16425 supr.setLeftTop.apply(this, arguments);
16429 setXY : function(xy, a, d, c, e){
16431 this.beforeAction();
16433 var cb = this.createCB(c);
16434 supr.setXY.call(this, xy, a, d, cb, e);
16441 createCB : function(c){
16452 // overridden Element method
16453 setX : function(x, a, d, c, e){
16454 this.setXY([x, this.getY()], a, d, c, e);
16457 // overridden Element method
16458 setY : function(y, a, d, c, e){
16459 this.setXY([this.getX(), y], a, d, c, e);
16462 // overridden Element method
16463 setSize : function(w, h, a, d, c, e){
16464 this.beforeAction();
16465 var cb = this.createCB(c);
16466 supr.setSize.call(this, w, h, a, d, cb, e);
16472 // overridden Element method
16473 setWidth : function(w, a, d, c, e){
16474 this.beforeAction();
16475 var cb = this.createCB(c);
16476 supr.setWidth.call(this, w, a, d, cb, e);
16482 // overridden Element method
16483 setHeight : function(h, a, d, c, e){
16484 this.beforeAction();
16485 var cb = this.createCB(c);
16486 supr.setHeight.call(this, h, a, d, cb, e);
16492 // overridden Element method
16493 setBounds : function(x, y, w, h, a, d, c, e){
16494 this.beforeAction();
16495 var cb = this.createCB(c);
16497 this.storeXY([x, y]);
16498 supr.setXY.call(this, [x, y]);
16499 supr.setSize.call(this, w, h, a, d, cb, e);
16502 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16508 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16509 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16510 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16511 * @param {Number} zindex The new z-index to set
16512 * @return {this} The Layer
16514 setZIndex : function(zindex){
16515 this.zindex = zindex;
16516 this.setStyle("z-index", zindex + 2);
16518 this.shadow.setZIndex(zindex + 1);
16521 this.shim.setStyle("z-index", zindex);
16526 * Original code for Roojs - LGPL
16527 * <script type="text/javascript">
16531 * @class Roo.XComponent
16532 * A delayed Element creator...
16533 * Or a way to group chunks of interface together.
16534 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16535 * used in conjunction with XComponent.build() it will create an instance of each element,
16536 * then call addxtype() to build the User interface.
16538 * Mypart.xyx = new Roo.XComponent({
16540 parent : 'Mypart.xyz', // empty == document.element.!!
16544 disabled : function() {}
16546 tree : function() { // return an tree of xtype declared components
16550 xtype : 'NestedLayoutPanel',
16557 * It can be used to build a big heiracy, with parent etc.
16558 * or you can just use this to render a single compoent to a dom element
16559 * MYPART.render(Roo.Element | String(id) | dom_element )
16566 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16567 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16569 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16571 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16572 * - if mulitple topModules exist, the last one is defined as the top module.
16576 * When the top level or multiple modules are to embedded into a existing HTML page,
16577 * the parent element can container '#id' of the element where the module will be drawn.
16581 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16582 * it relies more on a include mechanism, where sub modules are included into an outer page.
16583 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16585 * Bootstrap Roo Included elements
16587 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16588 * hence confusing the component builder as it thinks there are multiple top level elements.
16590 * String Over-ride & Translations
16592 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16593 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16594 * are needed. @see Roo.XComponent.overlayString
16598 * @extends Roo.util.Observable
16600 * @param cfg {Object} configuration of component
16603 Roo.XComponent = function(cfg) {
16604 Roo.apply(this, cfg);
16608 * Fires when this the componnt is built
16609 * @param {Roo.XComponent} c the component
16614 this.region = this.region || 'center'; // default..
16615 Roo.XComponent.register(this);
16616 this.modules = false;
16617 this.el = false; // where the layout goes..
16621 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16624 * The created element (with Roo.factory())
16625 * @type {Roo.Layout}
16631 * for BC - use el in new code
16632 * @type {Roo.Layout}
16638 * for BC - use el in new code
16639 * @type {Roo.Layout}
16644 * @cfg {Function|boolean} disabled
16645 * If this module is disabled by some rule, return true from the funtion
16650 * @cfg {String} parent
16651 * Name of parent element which it get xtype added to..
16656 * @cfg {String} order
16657 * Used to set the order in which elements are created (usefull for multiple tabs)
16662 * @cfg {String} name
16663 * String to display while loading.
16667 * @cfg {String} region
16668 * Region to render component to (defaults to center)
16673 * @cfg {Array} items
16674 * A single item array - the first element is the root of the tree..
16675 * It's done this way to stay compatible with the Xtype system...
16681 * The method that retuns the tree of parts that make up this compoennt
16688 * render element to dom or tree
16689 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16692 render : function(el)
16696 var hp = this.parent ? 1 : 0;
16697 Roo.debug && Roo.log(this);
16699 var tree = this._tree ? this._tree() : this.tree();
16702 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16703 // if parent is a '#.....' string, then let's use that..
16704 var ename = this.parent.substr(1);
16705 this.parent = false;
16706 Roo.debug && Roo.log(ename);
16708 case 'bootstrap-body':
16709 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16710 // this is the BorderLayout standard?
16711 this.parent = { el : true };
16714 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16715 // need to insert stuff...
16717 el : new Roo.bootstrap.layout.Border({
16718 el : document.body,
16724 tabPosition: 'top',
16725 //resizeTabs: true,
16726 alwaysShowTabs: true,
16736 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16737 this.parent = { el : new Roo.bootstrap.Body() };
16738 Roo.debug && Roo.log("setting el to doc body");
16741 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16745 this.parent = { el : true};
16748 el = Roo.get(ename);
16749 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16750 this.parent = { el : true};
16757 if (!el && !this.parent) {
16758 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16763 Roo.debug && Roo.log("EL:");
16764 Roo.debug && Roo.log(el);
16765 Roo.debug && Roo.log("this.parent.el:");
16766 Roo.debug && Roo.log(this.parent.el);
16769 // altertive root elements ??? - we need a better way to indicate these.
16770 var is_alt = Roo.XComponent.is_alt ||
16771 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16772 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16773 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16777 if (!this.parent && is_alt) {
16778 //el = Roo.get(document.body);
16779 this.parent = { el : true };
16784 if (!this.parent) {
16786 Roo.debug && Roo.log("no parent - creating one");
16788 el = el ? Roo.get(el) : false;
16790 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16793 el : new Roo.bootstrap.layout.Border({
16794 el: el || document.body,
16800 tabPosition: 'top',
16801 //resizeTabs: true,
16802 alwaysShowTabs: false,
16805 overflow: 'visible'
16811 // it's a top level one..
16813 el : new Roo.BorderLayout(el || document.body, {
16818 tabPosition: 'top',
16819 //resizeTabs: true,
16820 alwaysShowTabs: el && hp? false : true,
16821 hideTabs: el || !hp ? true : false,
16829 if (!this.parent.el) {
16830 // probably an old style ctor, which has been disabled.
16834 // The 'tree' method is '_tree now'
16836 tree.region = tree.region || this.region;
16837 var is_body = false;
16838 if (this.parent.el === true) {
16839 // bootstrap... - body..
16843 this.parent.el = Roo.factory(tree);
16847 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16848 this.fireEvent('built', this);
16850 this.panel = this.el;
16851 this.layout = this.panel.layout;
16852 this.parentLayout = this.parent.layout || false;
16858 Roo.apply(Roo.XComponent, {
16860 * @property hideProgress
16861 * true to disable the building progress bar.. usefull on single page renders.
16864 hideProgress : false,
16866 * @property buildCompleted
16867 * True when the builder has completed building the interface.
16870 buildCompleted : false,
16873 * @property topModule
16874 * the upper most module - uses document.element as it's constructor.
16881 * @property modules
16882 * array of modules to be created by registration system.
16883 * @type {Array} of Roo.XComponent
16888 * @property elmodules
16889 * array of modules to be created by which use #ID
16890 * @type {Array} of Roo.XComponent
16897 * Is an alternative Root - normally used by bootstrap or other systems,
16898 * where the top element in the tree can wrap 'body'
16899 * @type {boolean} (default false)
16904 * @property build_from_html
16905 * Build elements from html - used by bootstrap HTML stuff
16906 * - this is cleared after build is completed
16907 * @type {boolean} (default false)
16910 build_from_html : false,
16912 * Register components to be built later.
16914 * This solves the following issues
16915 * - Building is not done on page load, but after an authentication process has occured.
16916 * - Interface elements are registered on page load
16917 * - Parent Interface elements may not be loaded before child, so this handles that..
16924 module : 'Pman.Tab.projectMgr',
16926 parent : 'Pman.layout',
16927 disabled : false, // or use a function..
16930 * * @param {Object} details about module
16932 register : function(obj) {
16934 Roo.XComponent.event.fireEvent('register', obj);
16935 switch(typeof(obj.disabled) ) {
16941 if ( obj.disabled() ) {
16947 if (obj.disabled || obj.region == '#disabled') {
16953 this.modules.push(obj);
16957 * convert a string to an object..
16958 * eg. 'AAA.BBB' -> finds AAA.BBB
16962 toObject : function(str)
16964 if (!str || typeof(str) == 'object') {
16967 if (str.substring(0,1) == '#') {
16971 var ar = str.split('.');
16976 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16978 throw "Module not found : " + str;
16982 throw "Module not found : " + str;
16984 Roo.each(ar, function(e) {
16985 if (typeof(o[e]) == 'undefined') {
16986 throw "Module not found : " + str;
16997 * move modules into their correct place in the tree..
17000 preBuild : function ()
17003 Roo.each(this.modules , function (obj)
17005 Roo.XComponent.event.fireEvent('beforebuild', obj);
17007 var opar = obj.parent;
17009 obj.parent = this.toObject(opar);
17011 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17016 Roo.debug && Roo.log("GOT top level module");
17017 Roo.debug && Roo.log(obj);
17018 obj.modules = new Roo.util.MixedCollection(false,
17019 function(o) { return o.order + '' }
17021 this.topModule = obj;
17024 // parent is a string (usually a dom element name..)
17025 if (typeof(obj.parent) == 'string') {
17026 this.elmodules.push(obj);
17029 if (obj.parent.constructor != Roo.XComponent) {
17030 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17032 if (!obj.parent.modules) {
17033 obj.parent.modules = new Roo.util.MixedCollection(false,
17034 function(o) { return o.order + '' }
17037 if (obj.parent.disabled) {
17038 obj.disabled = true;
17040 obj.parent.modules.add(obj);
17045 * make a list of modules to build.
17046 * @return {Array} list of modules.
17049 buildOrder : function()
17052 var cmp = function(a,b) {
17053 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17055 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17056 throw "No top level modules to build";
17059 // make a flat list in order of modules to build.
17060 var mods = this.topModule ? [ this.topModule ] : [];
17063 // elmodules (is a list of DOM based modules )
17064 Roo.each(this.elmodules, function(e) {
17066 if (!this.topModule &&
17067 typeof(e.parent) == 'string' &&
17068 e.parent.substring(0,1) == '#' &&
17069 Roo.get(e.parent.substr(1))
17072 _this.topModule = e;
17078 // add modules to their parents..
17079 var addMod = function(m) {
17080 Roo.debug && Roo.log("build Order: add: " + m.name);
17083 if (m.modules && !m.disabled) {
17084 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17085 m.modules.keySort('ASC', cmp );
17086 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17088 m.modules.each(addMod);
17090 Roo.debug && Roo.log("build Order: no child modules");
17092 // not sure if this is used any more..
17094 m.finalize.name = m.name + " (clean up) ";
17095 mods.push(m.finalize);
17099 if (this.topModule && this.topModule.modules) {
17100 this.topModule.modules.keySort('ASC', cmp );
17101 this.topModule.modules.each(addMod);
17107 * Build the registered modules.
17108 * @param {Object} parent element.
17109 * @param {Function} optional method to call after module has been added.
17113 build : function(opts)
17116 if (typeof(opts) != 'undefined') {
17117 Roo.apply(this,opts);
17121 var mods = this.buildOrder();
17123 //this.allmods = mods;
17124 //Roo.debug && Roo.log(mods);
17126 if (!mods.length) { // should not happen
17127 throw "NO modules!!!";
17131 var msg = "Building Interface...";
17132 // flash it up as modal - so we store the mask!?
17133 if (!this.hideProgress && Roo.MessageBox) {
17134 Roo.MessageBox.show({ title: 'loading' });
17135 Roo.MessageBox.show({
17136 title: "Please wait...",
17146 var total = mods.length;
17149 var progressRun = function() {
17150 if (!mods.length) {
17151 Roo.debug && Roo.log('hide?');
17152 if (!this.hideProgress && Roo.MessageBox) {
17153 Roo.MessageBox.hide();
17155 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17157 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17163 var m = mods.shift();
17166 Roo.debug && Roo.log(m);
17167 // not sure if this is supported any more.. - modules that are are just function
17168 if (typeof(m) == 'function') {
17170 return progressRun.defer(10, _this);
17174 msg = "Building Interface " + (total - mods.length) +
17176 (m.name ? (' - ' + m.name) : '');
17177 Roo.debug && Roo.log(msg);
17178 if (!_this.hideProgress && Roo.MessageBox) {
17179 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17183 // is the module disabled?
17184 var disabled = (typeof(m.disabled) == 'function') ?
17185 m.disabled.call(m.module.disabled) : m.disabled;
17189 return progressRun(); // we do not update the display!
17197 // it's 10 on top level, and 1 on others??? why...
17198 return progressRun.defer(10, _this);
17201 progressRun.defer(1, _this);
17207 * Overlay a set of modified strings onto a component
17208 * This is dependant on our builder exporting the strings and 'named strings' elements.
17210 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17211 * @param {Object} associative array of 'named' string and it's new value.
17214 overlayStrings : function( component, strings )
17216 if (typeof(component['_named_strings']) == 'undefined') {
17217 throw "ERROR: component does not have _named_strings";
17219 for ( var k in strings ) {
17220 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17221 if (md !== false) {
17222 component['_strings'][md] = strings[k];
17224 Roo.log('could not find named string: ' + k + ' in');
17225 Roo.log(component);
17240 * wrapper for event.on - aliased later..
17241 * Typically use to register a event handler for register:
17243 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17252 Roo.XComponent.event = new Roo.util.Observable({
17256 * Fires when an Component is registered,
17257 * set the disable property on the Component to stop registration.
17258 * @param {Roo.XComponent} c the component being registerd.
17263 * @event beforebuild
17264 * Fires before each Component is built
17265 * can be used to apply permissions.
17266 * @param {Roo.XComponent} c the component being registerd.
17269 'beforebuild' : true,
17271 * @event buildcomplete
17272 * Fires on the top level element when all elements have been built
17273 * @param {Roo.XComponent} the top level component.
17275 'buildcomplete' : true
17280 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17283 * marked - a markdown parser
17284 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17285 * https://github.com/chjj/marked
17291 * Roo.Markdown - is a very crude wrapper around marked..
17295 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17297 * Note: move the sample code to the bottom of this
17298 * file before uncommenting it.
17303 Roo.Markdown.toHtml = function(text) {
17305 var c = new Roo.Markdown.marked.setOptions({
17306 renderer: new Roo.Markdown.marked.Renderer(),
17317 text = text.replace(/\\\n/g,' ');
17318 return Roo.Markdown.marked(text);
17323 // Wraps all "globals" so that the only thing
17324 // exposed is makeHtml().
17330 * eval:var:unescape
17338 var escape = function (html, encode) {
17340 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17341 .replace(/</g, '<')
17342 .replace(/>/g, '>')
17343 .replace(/"/g, '"')
17344 .replace(/'/g, ''');
17347 var unescape = function (html) {
17348 // explicitly match decimal, hex, and named HTML entities
17349 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17350 n = n.toLowerCase();
17351 if (n === 'colon') { return ':'; }
17352 if (n.charAt(0) === '#') {
17353 return n.charAt(1) === 'x'
17354 ? String.fromCharCode(parseInt(n.substring(2), 16))
17355 : String.fromCharCode(+n.substring(1));
17361 var replace = function (regex, opt) {
17362 regex = regex.source;
17364 return function self(name, val) {
17365 if (!name) { return new RegExp(regex, opt); }
17366 val = val.source || val;
17367 val = val.replace(/(^|[^\[])\^/g, '$1');
17368 regex = regex.replace(name, val);
17377 var noop = function () {}
17383 var merge = function (obj) {
17388 for (; i < arguments.length; i++) {
17389 target = arguments[i];
17390 for (key in target) {
17391 if (Object.prototype.hasOwnProperty.call(target, key)) {
17392 obj[key] = target[key];
17402 * Block-Level Grammar
17410 code: /^( {4}[^\n]+\n*)+/,
17412 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17413 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17415 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17416 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17417 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17418 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17419 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17421 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17425 block.bullet = /(?:[*+-]|\d+\.)/;
17426 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17427 block.item = replace(block.item, 'gm')
17428 (/bull/g, block.bullet)
17431 block.list = replace(block.list)
17432 (/bull/g, block.bullet)
17433 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17434 ('def', '\\n+(?=' + block.def.source + ')')
17437 block.blockquote = replace(block.blockquote)
17441 block._tag = '(?!(?:'
17442 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17443 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17444 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17446 block.html = replace(block.html)
17447 ('comment', /<!--[\s\S]*?-->/)
17448 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17449 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17450 (/tag/g, block._tag)
17453 block.paragraph = replace(block.paragraph)
17455 ('heading', block.heading)
17456 ('lheading', block.lheading)
17457 ('blockquote', block.blockquote)
17458 ('tag', '<' + block._tag)
17463 * Normal Block Grammar
17466 block.normal = merge({}, block);
17469 * GFM Block Grammar
17472 block.gfm = merge({}, block.normal, {
17473 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17475 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17478 block.gfm.paragraph = replace(block.paragraph)
17480 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17481 + block.list.source.replace('\\1', '\\3') + '|')
17485 * GFM + Tables Block Grammar
17488 block.tables = merge({}, block.gfm, {
17489 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17490 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17497 var Lexer = function (options) {
17499 this.tokens.links = {};
17500 this.options = options || marked.defaults;
17501 this.rules = block.normal;
17503 if (this.options.gfm) {
17504 if (this.options.tables) {
17505 this.rules = block.tables;
17507 this.rules = block.gfm;
17513 * Expose Block Rules
17516 Lexer.rules = block;
17519 * Static Lex Method
17522 Lexer.lex = function(src, options) {
17523 var lexer = new Lexer(options);
17524 return lexer.lex(src);
17531 Lexer.prototype.lex = function(src) {
17533 .replace(/\r\n|\r/g, '\n')
17534 .replace(/\t/g, ' ')
17535 .replace(/\u00a0/g, ' ')
17536 .replace(/\u2424/g, '\n');
17538 return this.token(src, true);
17545 Lexer.prototype.token = function(src, top, bq) {
17546 var src = src.replace(/^ +$/gm, '')
17559 if (cap = this.rules.newline.exec(src)) {
17560 src = src.substring(cap[0].length);
17561 if (cap[0].length > 1) {
17569 if (cap = this.rules.code.exec(src)) {
17570 src = src.substring(cap[0].length);
17571 cap = cap[0].replace(/^ {4}/gm, '');
17574 text: !this.options.pedantic
17575 ? cap.replace(/\n+$/, '')
17582 if (cap = this.rules.fences.exec(src)) {
17583 src = src.substring(cap[0].length);
17593 if (cap = this.rules.heading.exec(src)) {
17594 src = src.substring(cap[0].length);
17597 depth: cap[1].length,
17603 // table no leading pipe (gfm)
17604 if (top && (cap = this.rules.nptable.exec(src))) {
17605 src = src.substring(cap[0].length);
17609 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17610 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17611 cells: cap[3].replace(/\n$/, '').split('\n')
17614 for (i = 0; i < item.align.length; i++) {
17615 if (/^ *-+: *$/.test(item.align[i])) {
17616 item.align[i] = 'right';
17617 } else if (/^ *:-+: *$/.test(item.align[i])) {
17618 item.align[i] = 'center';
17619 } else if (/^ *:-+ *$/.test(item.align[i])) {
17620 item.align[i] = 'left';
17622 item.align[i] = null;
17626 for (i = 0; i < item.cells.length; i++) {
17627 item.cells[i] = item.cells[i].split(/ *\| */);
17630 this.tokens.push(item);
17636 if (cap = this.rules.lheading.exec(src)) {
17637 src = src.substring(cap[0].length);
17640 depth: cap[2] === '=' ? 1 : 2,
17647 if (cap = this.rules.hr.exec(src)) {
17648 src = src.substring(cap[0].length);
17656 if (cap = this.rules.blockquote.exec(src)) {
17657 src = src.substring(cap[0].length);
17660 type: 'blockquote_start'
17663 cap = cap[0].replace(/^ *> ?/gm, '');
17665 // Pass `top` to keep the current
17666 // "toplevel" state. This is exactly
17667 // how markdown.pl works.
17668 this.token(cap, top, true);
17671 type: 'blockquote_end'
17678 if (cap = this.rules.list.exec(src)) {
17679 src = src.substring(cap[0].length);
17683 type: 'list_start',
17684 ordered: bull.length > 1
17687 // Get each top-level item.
17688 cap = cap[0].match(this.rules.item);
17694 for (; i < l; i++) {
17697 // Remove the list item's bullet
17698 // so it is seen as the next token.
17699 space = item.length;
17700 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17702 // Outdent whatever the
17703 // list item contains. Hacky.
17704 if (~item.indexOf('\n ')) {
17705 space -= item.length;
17706 item = !this.options.pedantic
17707 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17708 : item.replace(/^ {1,4}/gm, '');
17711 // Determine whether the next list item belongs here.
17712 // Backpedal if it does not belong in this list.
17713 if (this.options.smartLists && i !== l - 1) {
17714 b = block.bullet.exec(cap[i + 1])[0];
17715 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17716 src = cap.slice(i + 1).join('\n') + src;
17721 // Determine whether item is loose or not.
17722 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17723 // for discount behavior.
17724 loose = next || /\n\n(?!\s*$)/.test(item);
17726 next = item.charAt(item.length - 1) === '\n';
17727 if (!loose) { loose = next; }
17732 ? 'loose_item_start'
17733 : 'list_item_start'
17737 this.token(item, false, bq);
17740 type: 'list_item_end'
17752 if (cap = this.rules.html.exec(src)) {
17753 src = src.substring(cap[0].length);
17755 type: this.options.sanitize
17758 pre: !this.options.sanitizer
17759 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17766 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17767 src = src.substring(cap[0].length);
17768 this.tokens.links[cap[1].toLowerCase()] = {
17776 if (top && (cap = this.rules.table.exec(src))) {
17777 src = src.substring(cap[0].length);
17781 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17782 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17783 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17786 for (i = 0; i < item.align.length; i++) {
17787 if (/^ *-+: *$/.test(item.align[i])) {
17788 item.align[i] = 'right';
17789 } else if (/^ *:-+: *$/.test(item.align[i])) {
17790 item.align[i] = 'center';
17791 } else if (/^ *:-+ *$/.test(item.align[i])) {
17792 item.align[i] = 'left';
17794 item.align[i] = null;
17798 for (i = 0; i < item.cells.length; i++) {
17799 item.cells[i] = item.cells[i]
17800 .replace(/^ *\| *| *\| *$/g, '')
17804 this.tokens.push(item);
17809 // top-level paragraph
17810 if (top && (cap = this.rules.paragraph.exec(src))) {
17811 src = src.substring(cap[0].length);
17814 text: cap[1].charAt(cap[1].length - 1) === '\n'
17815 ? cap[1].slice(0, -1)
17822 if (cap = this.rules.text.exec(src)) {
17823 // Top-level should never reach here.
17824 src = src.substring(cap[0].length);
17834 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17838 return this.tokens;
17842 * Inline-Level Grammar
17846 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17847 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17849 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17850 link: /^!?\[(inside)\]\(href\)/,
17851 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17852 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17853 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17854 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17855 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17856 br: /^ {2,}\n(?!\s*$)/,
17858 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17861 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17862 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17864 inline.link = replace(inline.link)
17865 ('inside', inline._inside)
17866 ('href', inline._href)
17869 inline.reflink = replace(inline.reflink)
17870 ('inside', inline._inside)
17874 * Normal Inline Grammar
17877 inline.normal = merge({}, inline);
17880 * Pedantic Inline Grammar
17883 inline.pedantic = merge({}, inline.normal, {
17884 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17885 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17889 * GFM Inline Grammar
17892 inline.gfm = merge({}, inline.normal, {
17893 escape: replace(inline.escape)('])', '~|])')(),
17894 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17895 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17896 text: replace(inline.text)
17898 ('|', '|https?://|')
17903 * GFM + Line Breaks Inline Grammar
17906 inline.breaks = merge({}, inline.gfm, {
17907 br: replace(inline.br)('{2,}', '*')(),
17908 text: replace(inline.gfm.text)('{2,}', '*')()
17912 * Inline Lexer & Compiler
17915 var InlineLexer = function (links, options) {
17916 this.options = options || marked.defaults;
17917 this.links = links;
17918 this.rules = inline.normal;
17919 this.renderer = this.options.renderer || new Renderer;
17920 this.renderer.options = this.options;
17924 Error('Tokens array requires a `links` property.');
17927 if (this.options.gfm) {
17928 if (this.options.breaks) {
17929 this.rules = inline.breaks;
17931 this.rules = inline.gfm;
17933 } else if (this.options.pedantic) {
17934 this.rules = inline.pedantic;
17939 * Expose Inline Rules
17942 InlineLexer.rules = inline;
17945 * Static Lexing/Compiling Method
17948 InlineLexer.output = function(src, links, options) {
17949 var inline = new InlineLexer(links, options);
17950 return inline.output(src);
17957 InlineLexer.prototype.output = function(src) {
17966 if (cap = this.rules.escape.exec(src)) {
17967 src = src.substring(cap[0].length);
17973 if (cap = this.rules.autolink.exec(src)) {
17974 src = src.substring(cap[0].length);
17975 if (cap[2] === '@') {
17976 text = cap[1].charAt(6) === ':'
17977 ? this.mangle(cap[1].substring(7))
17978 : this.mangle(cap[1]);
17979 href = this.mangle('mailto:') + text;
17981 text = escape(cap[1]);
17984 out += this.renderer.link(href, null, text);
17989 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17990 src = src.substring(cap[0].length);
17991 text = escape(cap[1]);
17993 out += this.renderer.link(href, null, text);
17998 if (cap = this.rules.tag.exec(src)) {
17999 if (!this.inLink && /^<a /i.test(cap[0])) {
18000 this.inLink = true;
18001 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18002 this.inLink = false;
18004 src = src.substring(cap[0].length);
18005 out += this.options.sanitize
18006 ? this.options.sanitizer
18007 ? this.options.sanitizer(cap[0])
18014 if (cap = this.rules.link.exec(src)) {
18015 src = src.substring(cap[0].length);
18016 this.inLink = true;
18017 out += this.outputLink(cap, {
18021 this.inLink = false;
18026 if ((cap = this.rules.reflink.exec(src))
18027 || (cap = this.rules.nolink.exec(src))) {
18028 src = src.substring(cap[0].length);
18029 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18030 link = this.links[link.toLowerCase()];
18031 if (!link || !link.href) {
18032 out += cap[0].charAt(0);
18033 src = cap[0].substring(1) + src;
18036 this.inLink = true;
18037 out += this.outputLink(cap, link);
18038 this.inLink = false;
18043 if (cap = this.rules.strong.exec(src)) {
18044 src = src.substring(cap[0].length);
18045 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18050 if (cap = this.rules.em.exec(src)) {
18051 src = src.substring(cap[0].length);
18052 out += this.renderer.em(this.output(cap[2] || cap[1]));
18057 if (cap = this.rules.code.exec(src)) {
18058 src = src.substring(cap[0].length);
18059 out += this.renderer.codespan(escape(cap[2], true));
18064 if (cap = this.rules.br.exec(src)) {
18065 src = src.substring(cap[0].length);
18066 out += this.renderer.br();
18071 if (cap = this.rules.del.exec(src)) {
18072 src = src.substring(cap[0].length);
18073 out += this.renderer.del(this.output(cap[1]));
18078 if (cap = this.rules.text.exec(src)) {
18079 src = src.substring(cap[0].length);
18080 out += this.renderer.text(escape(this.smartypants(cap[0])));
18086 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18097 InlineLexer.prototype.outputLink = function(cap, link) {
18098 var href = escape(link.href)
18099 , title = link.title ? escape(link.title) : null;
18101 return cap[0].charAt(0) !== '!'
18102 ? this.renderer.link(href, title, this.output(cap[1]))
18103 : this.renderer.image(href, title, escape(cap[1]));
18107 * Smartypants Transformations
18110 InlineLexer.prototype.smartypants = function(text) {
18111 if (!this.options.smartypants) { return text; }
18114 .replace(/---/g, '\u2014')
18116 .replace(/--/g, '\u2013')
18118 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18119 // closing singles & apostrophes
18120 .replace(/'/g, '\u2019')
18122 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18124 .replace(/"/g, '\u201d')
18126 .replace(/\.{3}/g, '\u2026');
18133 InlineLexer.prototype.mangle = function(text) {
18134 if (!this.options.mangle) { return text; }
18140 for (; i < l; i++) {
18141 ch = text.charCodeAt(i);
18142 if (Math.random() > 0.5) {
18143 ch = 'x' + ch.toString(16);
18145 out += '&#' + ch + ';';
18156 * eval:var:Renderer
18159 var Renderer = function (options) {
18160 this.options = options || {};
18163 Renderer.prototype.code = function(code, lang, escaped) {
18164 if (this.options.highlight) {
18165 var out = this.options.highlight(code, lang);
18166 if (out != null && out !== code) {
18171 // hack!!! - it's already escapeD?
18176 return '<pre><code>'
18177 + (escaped ? code : escape(code, true))
18178 + '\n</code></pre>';
18181 return '<pre><code class="'
18182 + this.options.langPrefix
18183 + escape(lang, true)
18185 + (escaped ? code : escape(code, true))
18186 + '\n</code></pre>\n';
18189 Renderer.prototype.blockquote = function(quote) {
18190 return '<blockquote>\n' + quote + '</blockquote>\n';
18193 Renderer.prototype.html = function(html) {
18197 Renderer.prototype.heading = function(text, level, raw) {
18201 + this.options.headerPrefix
18202 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18210 Renderer.prototype.hr = function() {
18211 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18214 Renderer.prototype.list = function(body, ordered) {
18215 var type = ordered ? 'ol' : 'ul';
18216 return '<' + type + '>\n' + body + '</' + type + '>\n';
18219 Renderer.prototype.listitem = function(text) {
18220 return '<li>' + text + '</li>\n';
18223 Renderer.prototype.paragraph = function(text) {
18224 return '<p>' + text + '</p>\n';
18227 Renderer.prototype.table = function(header, body) {
18228 return '<table class="table table-striped">\n'
18238 Renderer.prototype.tablerow = function(content) {
18239 return '<tr>\n' + content + '</tr>\n';
18242 Renderer.prototype.tablecell = function(content, flags) {
18243 var type = flags.header ? 'th' : 'td';
18244 var tag = flags.align
18245 ? '<' + type + ' style="text-align:' + flags.align + '">'
18246 : '<' + type + '>';
18247 return tag + content + '</' + type + '>\n';
18250 // span level renderer
18251 Renderer.prototype.strong = function(text) {
18252 return '<strong>' + text + '</strong>';
18255 Renderer.prototype.em = function(text) {
18256 return '<em>' + text + '</em>';
18259 Renderer.prototype.codespan = function(text) {
18260 return '<code>' + text + '</code>';
18263 Renderer.prototype.br = function() {
18264 return this.options.xhtml ? '<br/>' : '<br>';
18267 Renderer.prototype.del = function(text) {
18268 return '<del>' + text + '</del>';
18271 Renderer.prototype.link = function(href, title, text) {
18272 if (this.options.sanitize) {
18274 var prot = decodeURIComponent(unescape(href))
18275 .replace(/[^\w:]/g, '')
18280 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18284 var out = '<a href="' + href + '"';
18286 out += ' title="' + title + '"';
18288 out += '>' + text + '</a>';
18292 Renderer.prototype.image = function(href, title, text) {
18293 var out = '<img src="' + href + '" alt="' + text + '"';
18295 out += ' title="' + title + '"';
18297 out += this.options.xhtml ? '/>' : '>';
18301 Renderer.prototype.text = function(text) {
18306 * Parsing & Compiling
18312 var Parser= function (options) {
18315 this.options = options || marked.defaults;
18316 this.options.renderer = this.options.renderer || new Renderer;
18317 this.renderer = this.options.renderer;
18318 this.renderer.options = this.options;
18322 * Static Parse Method
18325 Parser.parse = function(src, options, renderer) {
18326 var parser = new Parser(options, renderer);
18327 return parser.parse(src);
18334 Parser.prototype.parse = function(src) {
18335 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18336 this.tokens = src.reverse();
18339 while (this.next()) {
18350 Parser.prototype.next = function() {
18351 return this.token = this.tokens.pop();
18355 * Preview Next Token
18358 Parser.prototype.peek = function() {
18359 return this.tokens[this.tokens.length - 1] || 0;
18363 * Parse Text Tokens
18366 Parser.prototype.parseText = function() {
18367 var body = this.token.text;
18369 while (this.peek().type === 'text') {
18370 body += '\n' + this.next().text;
18373 return this.inline.output(body);
18377 * Parse Current Token
18380 Parser.prototype.tok = function() {
18381 switch (this.token.type) {
18386 return this.renderer.hr();
18389 return this.renderer.heading(
18390 this.inline.output(this.token.text),
18395 return this.renderer.code(this.token.text,
18397 this.token.escaped);
18410 for (i = 0; i < this.token.header.length; i++) {
18411 flags = { header: true, align: this.token.align[i] };
18412 cell += this.renderer.tablecell(
18413 this.inline.output(this.token.header[i]),
18414 { header: true, align: this.token.align[i] }
18417 header += this.renderer.tablerow(cell);
18419 for (i = 0; i < this.token.cells.length; i++) {
18420 row = this.token.cells[i];
18423 for (j = 0; j < row.length; j++) {
18424 cell += this.renderer.tablecell(
18425 this.inline.output(row[j]),
18426 { header: false, align: this.token.align[j] }
18430 body += this.renderer.tablerow(cell);
18432 return this.renderer.table(header, body);
18434 case 'blockquote_start': {
18437 while (this.next().type !== 'blockquote_end') {
18438 body += this.tok();
18441 return this.renderer.blockquote(body);
18443 case 'list_start': {
18445 , ordered = this.token.ordered;
18447 while (this.next().type !== 'list_end') {
18448 body += this.tok();
18451 return this.renderer.list(body, ordered);
18453 case 'list_item_start': {
18456 while (this.next().type !== 'list_item_end') {
18457 body += this.token.type === 'text'
18462 return this.renderer.listitem(body);
18464 case 'loose_item_start': {
18467 while (this.next().type !== 'list_item_end') {
18468 body += this.tok();
18471 return this.renderer.listitem(body);
18474 var html = !this.token.pre && !this.options.pedantic
18475 ? this.inline.output(this.token.text)
18477 return this.renderer.html(html);
18479 case 'paragraph': {
18480 return this.renderer.paragraph(this.inline.output(this.token.text));
18483 return this.renderer.paragraph(this.parseText());
18495 var marked = function (src, opt, callback) {
18496 if (callback || typeof opt === 'function') {
18502 opt = merge({}, marked.defaults, opt || {});
18504 var highlight = opt.highlight
18510 tokens = Lexer.lex(src, opt)
18512 return callback(e);
18515 pending = tokens.length;
18519 var done = function(err) {
18521 opt.highlight = highlight;
18522 return callback(err);
18528 out = Parser.parse(tokens, opt);
18533 opt.highlight = highlight;
18537 : callback(null, out);
18540 if (!highlight || highlight.length < 3) {
18544 delete opt.highlight;
18546 if (!pending) { return done(); }
18548 for (; i < tokens.length; i++) {
18550 if (token.type !== 'code') {
18551 return --pending || done();
18553 return highlight(token.text, token.lang, function(err, code) {
18554 if (err) { return done(err); }
18555 if (code == null || code === token.text) {
18556 return --pending || done();
18559 token.escaped = true;
18560 --pending || done();
18568 if (opt) { opt = merge({}, marked.defaults, opt); }
18569 return Parser.parse(Lexer.lex(src, opt), opt);
18571 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18572 if ((opt || marked.defaults).silent) {
18573 return '<p>An error occured:</p><pre>'
18574 + escape(e.message + '', true)
18586 marked.setOptions = function(opt) {
18587 merge(marked.defaults, opt);
18591 marked.defaults = {
18602 langPrefix: 'lang-',
18603 smartypants: false,
18605 renderer: new Renderer,
18613 marked.Parser = Parser;
18614 marked.parser = Parser.parse;
18616 marked.Renderer = Renderer;
18618 marked.Lexer = Lexer;
18619 marked.lexer = Lexer.lex;
18621 marked.InlineLexer = InlineLexer;
18622 marked.inlineLexer = InlineLexer.output;
18624 marked.parse = marked;
18626 Roo.Markdown.marked = marked;
18630 * Ext JS Library 1.1.1
18631 * Copyright(c) 2006-2007, Ext JS, LLC.
18633 * Originally Released Under LGPL - original licence link has changed is not relivant.
18636 * <script type="text/javascript">
18642 * These classes are derivatives of the similarly named classes in the YUI Library.
18643 * The original license:
18644 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18645 * Code licensed under the BSD License:
18646 * http://developer.yahoo.net/yui/license.txt
18651 var Event=Roo.EventManager;
18652 var Dom=Roo.lib.Dom;
18655 * @class Roo.dd.DragDrop
18656 * @extends Roo.util.Observable
18657 * Defines the interface and base operation of items that that can be
18658 * dragged or can be drop targets. It was designed to be extended, overriding
18659 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18660 * Up to three html elements can be associated with a DragDrop instance:
18662 * <li>linked element: the element that is passed into the constructor.
18663 * This is the element which defines the boundaries for interaction with
18664 * other DragDrop objects.</li>
18665 * <li>handle element(s): The drag operation only occurs if the element that
18666 * was clicked matches a handle element. By default this is the linked
18667 * element, but there are times that you will want only a portion of the
18668 * linked element to initiate the drag operation, and the setHandleElId()
18669 * method provides a way to define this.</li>
18670 * <li>drag element: this represents the element that would be moved along
18671 * with the cursor during a drag operation. By default, this is the linked
18672 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18673 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18676 * This class should not be instantiated until the onload event to ensure that
18677 * the associated elements are available.
18678 * The following would define a DragDrop obj that would interact with any
18679 * other DragDrop obj in the "group1" group:
18681 * dd = new Roo.dd.DragDrop("div1", "group1");
18683 * Since none of the event handlers have been implemented, nothing would
18684 * actually happen if you were to run the code above. Normally you would
18685 * override this class or one of the default implementations, but you can
18686 * also override the methods you want on an instance of the class...
18688 * dd.onDragDrop = function(e, id) {
18689 * alert("dd was dropped on " + id);
18693 * @param {String} id of the element that is linked to this instance
18694 * @param {String} sGroup the group of related DragDrop objects
18695 * @param {object} config an object containing configurable attributes
18696 * Valid properties for DragDrop:
18697 * padding, isTarget, maintainOffset, primaryButtonOnly
18699 Roo.dd.DragDrop = function(id, sGroup, config) {
18701 this.init(id, sGroup, config);
18706 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18709 * The id of the element associated with this object. This is what we
18710 * refer to as the "linked element" because the size and position of
18711 * this element is used to determine when the drag and drop objects have
18719 * Configuration attributes passed into the constructor
18726 * The id of the element that will be dragged. By default this is same
18727 * as the linked element , but could be changed to another element. Ex:
18729 * @property dragElId
18736 * the id of the element that initiates the drag operation. By default
18737 * this is the linked element, but could be changed to be a child of this
18738 * element. This lets us do things like only starting the drag when the
18739 * header element within the linked html element is clicked.
18740 * @property handleElId
18747 * An associative array of HTML tags that will be ignored if clicked.
18748 * @property invalidHandleTypes
18749 * @type {string: string}
18751 invalidHandleTypes: null,
18754 * An associative array of ids for elements that will be ignored if clicked
18755 * @property invalidHandleIds
18756 * @type {string: string}
18758 invalidHandleIds: null,
18761 * An indexted array of css class names for elements that will be ignored
18763 * @property invalidHandleClasses
18766 invalidHandleClasses: null,
18769 * The linked element's absolute X position at the time the drag was
18771 * @property startPageX
18778 * The linked element's absolute X position at the time the drag was
18780 * @property startPageY
18787 * The group defines a logical collection of DragDrop objects that are
18788 * related. Instances only get events when interacting with other
18789 * DragDrop object in the same group. This lets us define multiple
18790 * groups using a single DragDrop subclass if we want.
18792 * @type {string: string}
18797 * Individual drag/drop instances can be locked. This will prevent
18798 * onmousedown start drag.
18806 * Lock this instance
18809 lock: function() { this.locked = true; },
18812 * Unlock this instace
18815 unlock: function() { this.locked = false; },
18818 * By default, all insances can be a drop target. This can be disabled by
18819 * setting isTarget to false.
18826 * The padding configured for this drag and drop object for calculating
18827 * the drop zone intersection with this object.
18834 * Cached reference to the linked element
18835 * @property _domRef
18841 * Internal typeof flag
18842 * @property __ygDragDrop
18845 __ygDragDrop: true,
18848 * Set to true when horizontal contraints are applied
18849 * @property constrainX
18856 * Set to true when vertical contraints are applied
18857 * @property constrainY
18864 * The left constraint
18872 * The right constraint
18880 * The up constraint
18889 * The down constraint
18897 * Maintain offsets when we resetconstraints. Set to true when you want
18898 * the position of the element relative to its parent to stay the same
18899 * when the page changes
18901 * @property maintainOffset
18904 maintainOffset: false,
18907 * Array of pixel locations the element will snap to if we specified a
18908 * horizontal graduation/interval. This array is generated automatically
18909 * when you define a tick interval.
18916 * Array of pixel locations the element will snap to if we specified a
18917 * vertical graduation/interval. This array is generated automatically
18918 * when you define a tick interval.
18925 * By default the drag and drop instance will only respond to the primary
18926 * button click (left button for a right-handed mouse). Set to true to
18927 * allow drag and drop to start with any mouse click that is propogated
18929 * @property primaryButtonOnly
18932 primaryButtonOnly: true,
18935 * The availabe property is false until the linked dom element is accessible.
18936 * @property available
18942 * By default, drags can only be initiated if the mousedown occurs in the
18943 * region the linked element is. This is done in part to work around a
18944 * bug in some browsers that mis-report the mousedown if the previous
18945 * mouseup happened outside of the window. This property is set to true
18946 * if outer handles are defined.
18948 * @property hasOuterHandles
18952 hasOuterHandles: false,
18955 * Code that executes immediately before the startDrag event
18956 * @method b4StartDrag
18959 b4StartDrag: function(x, y) { },
18962 * Abstract method called after a drag/drop object is clicked
18963 * and the drag or mousedown time thresholds have beeen met.
18964 * @method startDrag
18965 * @param {int} X click location
18966 * @param {int} Y click location
18968 startDrag: function(x, y) { /* override this */ },
18971 * Code that executes immediately before the onDrag event
18975 b4Drag: function(e) { },
18978 * Abstract method called during the onMouseMove event while dragging an
18981 * @param {Event} e the mousemove event
18983 onDrag: function(e) { /* override this */ },
18986 * Abstract method called when this element fist begins hovering over
18987 * another DragDrop obj
18988 * @method onDragEnter
18989 * @param {Event} e the mousemove event
18990 * @param {String|DragDrop[]} id In POINT mode, the element
18991 * id this is hovering over. In INTERSECT mode, an array of one or more
18992 * dragdrop items being hovered over.
18994 onDragEnter: function(e, id) { /* override this */ },
18997 * Code that executes immediately before the onDragOver event
18998 * @method b4DragOver
19001 b4DragOver: function(e) { },
19004 * Abstract method called when this element is hovering over another
19006 * @method onDragOver
19007 * @param {Event} e the mousemove event
19008 * @param {String|DragDrop[]} id In POINT mode, the element
19009 * id this is hovering over. In INTERSECT mode, an array of dd items
19010 * being hovered over.
19012 onDragOver: function(e, id) { /* override this */ },
19015 * Code that executes immediately before the onDragOut event
19016 * @method b4DragOut
19019 b4DragOut: function(e) { },
19022 * Abstract method called when we are no longer hovering over an element
19023 * @method onDragOut
19024 * @param {Event} e the mousemove event
19025 * @param {String|DragDrop[]} id In POINT mode, the element
19026 * id this was hovering over. In INTERSECT mode, an array of dd items
19027 * that the mouse is no longer over.
19029 onDragOut: function(e, id) { /* override this */ },
19032 * Code that executes immediately before the onDragDrop event
19033 * @method b4DragDrop
19036 b4DragDrop: function(e) { },
19039 * Abstract method called when this item is dropped on another DragDrop
19041 * @method onDragDrop
19042 * @param {Event} e the mouseup event
19043 * @param {String|DragDrop[]} id In POINT mode, the element
19044 * id this was dropped on. In INTERSECT mode, an array of dd items this
19047 onDragDrop: function(e, id) { /* override this */ },
19050 * Abstract method called when this item is dropped on an area with no
19052 * @method onInvalidDrop
19053 * @param {Event} e the mouseup event
19055 onInvalidDrop: function(e) { /* override this */ },
19058 * Code that executes immediately before the endDrag event
19059 * @method b4EndDrag
19062 b4EndDrag: function(e) { },
19065 * Fired when we are done dragging the object
19067 * @param {Event} e the mouseup event
19069 endDrag: function(e) { /* override this */ },
19072 * Code executed immediately before the onMouseDown event
19073 * @method b4MouseDown
19074 * @param {Event} e the mousedown event
19077 b4MouseDown: function(e) { },
19080 * Event handler that fires when a drag/drop obj gets a mousedown
19081 * @method onMouseDown
19082 * @param {Event} e the mousedown event
19084 onMouseDown: function(e) { /* override this */ },
19087 * Event handler that fires when a drag/drop obj gets a mouseup
19088 * @method onMouseUp
19089 * @param {Event} e the mouseup event
19091 onMouseUp: function(e) { /* override this */ },
19094 * Override the onAvailable method to do what is needed after the initial
19095 * position was determined.
19096 * @method onAvailable
19098 onAvailable: function () {
19102 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19105 defaultPadding : {left:0, right:0, top:0, bottom:0},
19108 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19112 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19113 { dragElId: "existingProxyDiv" });
19114 dd.startDrag = function(){
19115 this.constrainTo("parent-id");
19118 * Or you can initalize it using the {@link Roo.Element} object:
19120 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19121 startDrag : function(){
19122 this.constrainTo("parent-id");
19126 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19127 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19128 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19129 * an object containing the sides to pad. For example: {right:10, bottom:10}
19130 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19132 constrainTo : function(constrainTo, pad, inContent){
19133 if(typeof pad == "number"){
19134 pad = {left: pad, right:pad, top:pad, bottom:pad};
19136 pad = pad || this.defaultPadding;
19137 var b = Roo.get(this.getEl()).getBox();
19138 var ce = Roo.get(constrainTo);
19139 var s = ce.getScroll();
19140 var c, cd = ce.dom;
19141 if(cd == document.body){
19142 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19145 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19149 var topSpace = b.y - c.y;
19150 var leftSpace = b.x - c.x;
19152 this.resetConstraints();
19153 this.setXConstraint(leftSpace - (pad.left||0), // left
19154 c.width - leftSpace - b.width - (pad.right||0) //right
19156 this.setYConstraint(topSpace - (pad.top||0), //top
19157 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19162 * Returns a reference to the linked element
19164 * @return {HTMLElement} the html element
19166 getEl: function() {
19167 if (!this._domRef) {
19168 this._domRef = Roo.getDom(this.id);
19171 return this._domRef;
19175 * Returns a reference to the actual element to drag. By default this is
19176 * the same as the html element, but it can be assigned to another
19177 * element. An example of this can be found in Roo.dd.DDProxy
19178 * @method getDragEl
19179 * @return {HTMLElement} the html element
19181 getDragEl: function() {
19182 return Roo.getDom(this.dragElId);
19186 * Sets up the DragDrop object. Must be called in the constructor of any
19187 * Roo.dd.DragDrop subclass
19189 * @param id the id of the linked element
19190 * @param {String} sGroup the group of related items
19191 * @param {object} config configuration attributes
19193 init: function(id, sGroup, config) {
19194 this.initTarget(id, sGroup, config);
19195 if (!Roo.isTouch) {
19196 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19198 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19199 // Event.on(this.id, "selectstart", Event.preventDefault);
19203 * Initializes Targeting functionality only... the object does not
19204 * get a mousedown handler.
19205 * @method initTarget
19206 * @param id the id of the linked element
19207 * @param {String} sGroup the group of related items
19208 * @param {object} config configuration attributes
19210 initTarget: function(id, sGroup, config) {
19212 // configuration attributes
19213 this.config = config || {};
19215 // create a local reference to the drag and drop manager
19216 this.DDM = Roo.dd.DDM;
19217 // initialize the groups array
19220 // assume that we have an element reference instead of an id if the
19221 // parameter is not a string
19222 if (typeof id !== "string") {
19229 // add to an interaction group
19230 this.addToGroup((sGroup) ? sGroup : "default");
19232 // We don't want to register this as the handle with the manager
19233 // so we just set the id rather than calling the setter.
19234 this.handleElId = id;
19236 // the linked element is the element that gets dragged by default
19237 this.setDragElId(id);
19239 // by default, clicked anchors will not start drag operations.
19240 this.invalidHandleTypes = { A: "A" };
19241 this.invalidHandleIds = {};
19242 this.invalidHandleClasses = [];
19244 this.applyConfig();
19246 this.handleOnAvailable();
19250 * Applies the configuration parameters that were passed into the constructor.
19251 * This is supposed to happen at each level through the inheritance chain. So
19252 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19253 * DragDrop in order to get all of the parameters that are available in
19255 * @method applyConfig
19257 applyConfig: function() {
19259 // configurable properties:
19260 // padding, isTarget, maintainOffset, primaryButtonOnly
19261 this.padding = this.config.padding || [0, 0, 0, 0];
19262 this.isTarget = (this.config.isTarget !== false);
19263 this.maintainOffset = (this.config.maintainOffset);
19264 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19269 * Executed when the linked element is available
19270 * @method handleOnAvailable
19273 handleOnAvailable: function() {
19274 this.available = true;
19275 this.resetConstraints();
19276 this.onAvailable();
19280 * Configures the padding for the target zone in px. Effectively expands
19281 * (or reduces) the virtual object size for targeting calculations.
19282 * Supports css-style shorthand; if only one parameter is passed, all sides
19283 * will have that padding, and if only two are passed, the top and bottom
19284 * will have the first param, the left and right the second.
19285 * @method setPadding
19286 * @param {int} iTop Top pad
19287 * @param {int} iRight Right pad
19288 * @param {int} iBot Bot pad
19289 * @param {int} iLeft Left pad
19291 setPadding: function(iTop, iRight, iBot, iLeft) {
19292 // this.padding = [iLeft, iRight, iTop, iBot];
19293 if (!iRight && 0 !== iRight) {
19294 this.padding = [iTop, iTop, iTop, iTop];
19295 } else if (!iBot && 0 !== iBot) {
19296 this.padding = [iTop, iRight, iTop, iRight];
19298 this.padding = [iTop, iRight, iBot, iLeft];
19303 * Stores the initial placement of the linked element.
19304 * @method setInitialPosition
19305 * @param {int} diffX the X offset, default 0
19306 * @param {int} diffY the Y offset, default 0
19308 setInitPosition: function(diffX, diffY) {
19309 var el = this.getEl();
19311 if (!this.DDM.verifyEl(el)) {
19315 var dx = diffX || 0;
19316 var dy = diffY || 0;
19318 var p = Dom.getXY( el );
19320 this.initPageX = p[0] - dx;
19321 this.initPageY = p[1] - dy;
19323 this.lastPageX = p[0];
19324 this.lastPageY = p[1];
19327 this.setStartPosition(p);
19331 * Sets the start position of the element. This is set when the obj
19332 * is initialized, the reset when a drag is started.
19333 * @method setStartPosition
19334 * @param pos current position (from previous lookup)
19337 setStartPosition: function(pos) {
19338 var p = pos || Dom.getXY( this.getEl() );
19339 this.deltaSetXY = null;
19341 this.startPageX = p[0];
19342 this.startPageY = p[1];
19346 * Add this instance to a group of related drag/drop objects. All
19347 * instances belong to at least one group, and can belong to as many
19348 * groups as needed.
19349 * @method addToGroup
19350 * @param sGroup {string} the name of the group
19352 addToGroup: function(sGroup) {
19353 this.groups[sGroup] = true;
19354 this.DDM.regDragDrop(this, sGroup);
19358 * Remove's this instance from the supplied interaction group
19359 * @method removeFromGroup
19360 * @param {string} sGroup The group to drop
19362 removeFromGroup: function(sGroup) {
19363 if (this.groups[sGroup]) {
19364 delete this.groups[sGroup];
19367 this.DDM.removeDDFromGroup(this, sGroup);
19371 * Allows you to specify that an element other than the linked element
19372 * will be moved with the cursor during a drag
19373 * @method setDragElId
19374 * @param id {string} the id of the element that will be used to initiate the drag
19376 setDragElId: function(id) {
19377 this.dragElId = id;
19381 * Allows you to specify a child of the linked element that should be
19382 * used to initiate the drag operation. An example of this would be if
19383 * you have a content div with text and links. Clicking anywhere in the
19384 * content area would normally start the drag operation. Use this method
19385 * to specify that an element inside of the content div is the element
19386 * that starts the drag operation.
19387 * @method setHandleElId
19388 * @param id {string} the id of the element that will be used to
19389 * initiate the drag.
19391 setHandleElId: function(id) {
19392 if (typeof id !== "string") {
19395 this.handleElId = id;
19396 this.DDM.regHandle(this.id, id);
19400 * Allows you to set an element outside of the linked element as a drag
19402 * @method setOuterHandleElId
19403 * @param id the id of the element that will be used to initiate the drag
19405 setOuterHandleElId: function(id) {
19406 if (typeof id !== "string") {
19409 Event.on(id, "mousedown",
19410 this.handleMouseDown, this);
19411 this.setHandleElId(id);
19413 this.hasOuterHandles = true;
19417 * Remove all drag and drop hooks for this element
19420 unreg: function() {
19421 Event.un(this.id, "mousedown",
19422 this.handleMouseDown);
19423 Event.un(this.id, "touchstart",
19424 this.handleMouseDown);
19425 this._domRef = null;
19426 this.DDM._remove(this);
19429 destroy : function(){
19434 * Returns true if this instance is locked, or the drag drop mgr is locked
19435 * (meaning that all drag/drop is disabled on the page.)
19437 * @return {boolean} true if this obj or all drag/drop is locked, else
19440 isLocked: function() {
19441 return (this.DDM.isLocked() || this.locked);
19445 * Fired when this object is clicked
19446 * @method handleMouseDown
19448 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19451 handleMouseDown: function(e, oDD){
19453 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19454 //Roo.log('not touch/ button !=0');
19457 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19458 return; // double touch..
19462 if (this.isLocked()) {
19463 //Roo.log('locked');
19467 this.DDM.refreshCache(this.groups);
19468 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19469 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19470 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19471 //Roo.log('no outer handes or not over target');
19474 // Roo.log('check validator');
19475 if (this.clickValidator(e)) {
19476 // Roo.log('validate success');
19477 // set the initial element position
19478 this.setStartPosition();
19481 this.b4MouseDown(e);
19482 this.onMouseDown(e);
19484 this.DDM.handleMouseDown(e, this);
19486 this.DDM.stopEvent(e);
19494 clickValidator: function(e) {
19495 var target = e.getTarget();
19496 return ( this.isValidHandleChild(target) &&
19497 (this.id == this.handleElId ||
19498 this.DDM.handleWasClicked(target, this.id)) );
19502 * Allows you to specify a tag name that should not start a drag operation
19503 * when clicked. This is designed to facilitate embedding links within a
19504 * drag handle that do something other than start the drag.
19505 * @method addInvalidHandleType
19506 * @param {string} tagName the type of element to exclude
19508 addInvalidHandleType: function(tagName) {
19509 var type = tagName.toUpperCase();
19510 this.invalidHandleTypes[type] = type;
19514 * Lets you to specify an element id for a child of a drag handle
19515 * that should not initiate a drag
19516 * @method addInvalidHandleId
19517 * @param {string} id the element id of the element you wish to ignore
19519 addInvalidHandleId: function(id) {
19520 if (typeof id !== "string") {
19523 this.invalidHandleIds[id] = id;
19527 * Lets you specify a css class of elements that will not initiate a drag
19528 * @method addInvalidHandleClass
19529 * @param {string} cssClass the class of the elements you wish to ignore
19531 addInvalidHandleClass: function(cssClass) {
19532 this.invalidHandleClasses.push(cssClass);
19536 * Unsets an excluded tag name set by addInvalidHandleType
19537 * @method removeInvalidHandleType
19538 * @param {string} tagName the type of element to unexclude
19540 removeInvalidHandleType: function(tagName) {
19541 var type = tagName.toUpperCase();
19542 // this.invalidHandleTypes[type] = null;
19543 delete this.invalidHandleTypes[type];
19547 * Unsets an invalid handle id
19548 * @method removeInvalidHandleId
19549 * @param {string} id the id of the element to re-enable
19551 removeInvalidHandleId: function(id) {
19552 if (typeof id !== "string") {
19555 delete this.invalidHandleIds[id];
19559 * Unsets an invalid css class
19560 * @method removeInvalidHandleClass
19561 * @param {string} cssClass the class of the element(s) you wish to
19564 removeInvalidHandleClass: function(cssClass) {
19565 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19566 if (this.invalidHandleClasses[i] == cssClass) {
19567 delete this.invalidHandleClasses[i];
19573 * Checks the tag exclusion list to see if this click should be ignored
19574 * @method isValidHandleChild
19575 * @param {HTMLElement} node the HTMLElement to evaluate
19576 * @return {boolean} true if this is a valid tag type, false if not
19578 isValidHandleChild: function(node) {
19581 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19584 nodeName = node.nodeName.toUpperCase();
19586 nodeName = node.nodeName;
19588 valid = valid && !this.invalidHandleTypes[nodeName];
19589 valid = valid && !this.invalidHandleIds[node.id];
19591 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19592 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19601 * Create the array of horizontal tick marks if an interval was specified
19602 * in setXConstraint().
19603 * @method setXTicks
19606 setXTicks: function(iStartX, iTickSize) {
19608 this.xTickSize = iTickSize;
19612 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19614 this.xTicks[this.xTicks.length] = i;
19619 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19621 this.xTicks[this.xTicks.length] = i;
19626 this.xTicks.sort(this.DDM.numericSort) ;
19630 * Create the array of vertical tick marks if an interval was specified in
19631 * setYConstraint().
19632 * @method setYTicks
19635 setYTicks: function(iStartY, iTickSize) {
19637 this.yTickSize = iTickSize;
19641 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19643 this.yTicks[this.yTicks.length] = i;
19648 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19650 this.yTicks[this.yTicks.length] = i;
19655 this.yTicks.sort(this.DDM.numericSort) ;
19659 * By default, the element can be dragged any place on the screen. Use
19660 * this method to limit the horizontal travel of the element. Pass in
19661 * 0,0 for the parameters if you want to lock the drag to the y axis.
19662 * @method setXConstraint
19663 * @param {int} iLeft the number of pixels the element can move to the left
19664 * @param {int} iRight the number of pixels the element can move to the
19666 * @param {int} iTickSize optional parameter for specifying that the
19668 * should move iTickSize pixels at a time.
19670 setXConstraint: function(iLeft, iRight, iTickSize) {
19671 this.leftConstraint = iLeft;
19672 this.rightConstraint = iRight;
19674 this.minX = this.initPageX - iLeft;
19675 this.maxX = this.initPageX + iRight;
19676 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19678 this.constrainX = true;
19682 * Clears any constraints applied to this instance. Also clears ticks
19683 * since they can't exist independent of a constraint at this time.
19684 * @method clearConstraints
19686 clearConstraints: function() {
19687 this.constrainX = false;
19688 this.constrainY = false;
19693 * Clears any tick interval defined for this instance
19694 * @method clearTicks
19696 clearTicks: function() {
19697 this.xTicks = null;
19698 this.yTicks = null;
19699 this.xTickSize = 0;
19700 this.yTickSize = 0;
19704 * By default, the element can be dragged any place on the screen. Set
19705 * this to limit the vertical travel of the element. Pass in 0,0 for the
19706 * parameters if you want to lock the drag to the x axis.
19707 * @method setYConstraint
19708 * @param {int} iUp the number of pixels the element can move up
19709 * @param {int} iDown the number of pixels the element can move down
19710 * @param {int} iTickSize optional parameter for specifying that the
19711 * element should move iTickSize pixels at a time.
19713 setYConstraint: function(iUp, iDown, iTickSize) {
19714 this.topConstraint = iUp;
19715 this.bottomConstraint = iDown;
19717 this.minY = this.initPageY - iUp;
19718 this.maxY = this.initPageY + iDown;
19719 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19721 this.constrainY = true;
19726 * resetConstraints must be called if you manually reposition a dd element.
19727 * @method resetConstraints
19728 * @param {boolean} maintainOffset
19730 resetConstraints: function() {
19733 // Maintain offsets if necessary
19734 if (this.initPageX || this.initPageX === 0) {
19735 // figure out how much this thing has moved
19736 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19737 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19739 this.setInitPosition(dx, dy);
19741 // This is the first time we have detected the element's position
19743 this.setInitPosition();
19746 if (this.constrainX) {
19747 this.setXConstraint( this.leftConstraint,
19748 this.rightConstraint,
19752 if (this.constrainY) {
19753 this.setYConstraint( this.topConstraint,
19754 this.bottomConstraint,
19760 * Normally the drag element is moved pixel by pixel, but we can specify
19761 * that it move a number of pixels at a time. This method resolves the
19762 * location when we have it set up like this.
19764 * @param {int} val where we want to place the object
19765 * @param {int[]} tickArray sorted array of valid points
19766 * @return {int} the closest tick
19769 getTick: function(val, tickArray) {
19772 // If tick interval is not defined, it is effectively 1 pixel,
19773 // so we return the value passed to us.
19775 } else if (tickArray[0] >= val) {
19776 // The value is lower than the first tick, so we return the first
19778 return tickArray[0];
19780 for (var i=0, len=tickArray.length; i<len; ++i) {
19782 if (tickArray[next] && tickArray[next] >= val) {
19783 var diff1 = val - tickArray[i];
19784 var diff2 = tickArray[next] - val;
19785 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19789 // The value is larger than the last tick, so we return the last
19791 return tickArray[tickArray.length - 1];
19798 * @return {string} string representation of the dd obj
19800 toString: function() {
19801 return ("DragDrop " + this.id);
19809 * Ext JS Library 1.1.1
19810 * Copyright(c) 2006-2007, Ext JS, LLC.
19812 * Originally Released Under LGPL - original licence link has changed is not relivant.
19815 * <script type="text/javascript">
19820 * The drag and drop utility provides a framework for building drag and drop
19821 * applications. In addition to enabling drag and drop for specific elements,
19822 * the drag and drop elements are tracked by the manager class, and the
19823 * interactions between the various elements are tracked during the drag and
19824 * the implementing code is notified about these important moments.
19827 // Only load the library once. Rewriting the manager class would orphan
19828 // existing drag and drop instances.
19829 if (!Roo.dd.DragDropMgr) {
19832 * @class Roo.dd.DragDropMgr
19833 * DragDropMgr is a singleton that tracks the element interaction for
19834 * all DragDrop items in the window. Generally, you will not call
19835 * this class directly, but it does have helper methods that could
19836 * be useful in your DragDrop implementations.
19839 Roo.dd.DragDropMgr = function() {
19841 var Event = Roo.EventManager;
19846 * Two dimensional Array of registered DragDrop objects. The first
19847 * dimension is the DragDrop item group, the second the DragDrop
19850 * @type {string: string}
19857 * Array of element ids defined as drag handles. Used to determine
19858 * if the element that generated the mousedown event is actually the
19859 * handle and not the html element itself.
19860 * @property handleIds
19861 * @type {string: string}
19868 * the DragDrop object that is currently being dragged
19869 * @property dragCurrent
19877 * the DragDrop object(s) that are being hovered over
19878 * @property dragOvers
19886 * the X distance between the cursor and the object being dragged
19895 * the Y distance between the cursor and the object being dragged
19904 * Flag to determine if we should prevent the default behavior of the
19905 * events we define. By default this is true, but this can be set to
19906 * false if you need the default behavior (not recommended)
19907 * @property preventDefault
19911 preventDefault: true,
19914 * Flag to determine if we should stop the propagation of the events
19915 * we generate. This is true by default but you may want to set it to
19916 * false if the html element contains other features that require the
19918 * @property stopPropagation
19922 stopPropagation: true,
19925 * Internal flag that is set to true when drag and drop has been
19927 * @property initialized
19934 * All drag and drop can be disabled.
19942 * Called the first time an element is registered.
19948 this.initialized = true;
19952 * In point mode, drag and drop interaction is defined by the
19953 * location of the cursor during the drag/drop
19961 * In intersect mode, drag and drop interactio nis defined by the
19962 * overlap of two or more drag and drop objects.
19963 * @property INTERSECT
19970 * The current drag and drop mode. Default: POINT
19978 * Runs method on all drag and drop objects
19979 * @method _execOnAll
19983 _execOnAll: function(sMethod, args) {
19984 for (var i in this.ids) {
19985 for (var j in this.ids[i]) {
19986 var oDD = this.ids[i][j];
19987 if (! this.isTypeOfDD(oDD)) {
19990 oDD[sMethod].apply(oDD, args);
19996 * Drag and drop initialization. Sets up the global event handlers
20001 _onLoad: function() {
20005 if (!Roo.isTouch) {
20006 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20007 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20009 Event.on(document, "touchend", this.handleMouseUp, this, true);
20010 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20012 Event.on(window, "unload", this._onUnload, this, true);
20013 Event.on(window, "resize", this._onResize, this, true);
20014 // Event.on(window, "mouseout", this._test);
20019 * Reset constraints on all drag and drop objs
20020 * @method _onResize
20024 _onResize: function(e) {
20025 this._execOnAll("resetConstraints", []);
20029 * Lock all drag and drop functionality
20033 lock: function() { this.locked = true; },
20036 * Unlock all drag and drop functionality
20040 unlock: function() { this.locked = false; },
20043 * Is drag and drop locked?
20045 * @return {boolean} True if drag and drop is locked, false otherwise.
20048 isLocked: function() { return this.locked; },
20051 * Location cache that is set for all drag drop objects when a drag is
20052 * initiated, cleared when the drag is finished.
20053 * @property locationCache
20060 * Set useCache to false if you want to force object the lookup of each
20061 * drag and drop linked element constantly during a drag.
20062 * @property useCache
20069 * The number of pixels that the mouse needs to move after the
20070 * mousedown before the drag is initiated. Default=3;
20071 * @property clickPixelThresh
20075 clickPixelThresh: 3,
20078 * The number of milliseconds after the mousedown event to initiate the
20079 * drag if we don't get a mouseup event. Default=1000
20080 * @property clickTimeThresh
20084 clickTimeThresh: 350,
20087 * Flag that indicates that either the drag pixel threshold or the
20088 * mousdown time threshold has been met
20089 * @property dragThreshMet
20094 dragThreshMet: false,
20097 * Timeout used for the click time threshold
20098 * @property clickTimeout
20103 clickTimeout: null,
20106 * The X position of the mousedown event stored for later use when a
20107 * drag threshold is met.
20116 * The Y position of the mousedown event stored for later use when a
20117 * drag threshold is met.
20126 * Each DragDrop instance must be registered with the DragDropMgr.
20127 * This is executed in DragDrop.init()
20128 * @method regDragDrop
20129 * @param {DragDrop} oDD the DragDrop object to register
20130 * @param {String} sGroup the name of the group this element belongs to
20133 regDragDrop: function(oDD, sGroup) {
20134 if (!this.initialized) { this.init(); }
20136 if (!this.ids[sGroup]) {
20137 this.ids[sGroup] = {};
20139 this.ids[sGroup][oDD.id] = oDD;
20143 * Removes the supplied dd instance from the supplied group. Executed
20144 * by DragDrop.removeFromGroup, so don't call this function directly.
20145 * @method removeDDFromGroup
20149 removeDDFromGroup: function(oDD, sGroup) {
20150 if (!this.ids[sGroup]) {
20151 this.ids[sGroup] = {};
20154 var obj = this.ids[sGroup];
20155 if (obj && obj[oDD.id]) {
20156 delete obj[oDD.id];
20161 * Unregisters a drag and drop item. This is executed in
20162 * DragDrop.unreg, use that method instead of calling this directly.
20167 _remove: function(oDD) {
20168 for (var g in oDD.groups) {
20169 if (g && this.ids[g][oDD.id]) {
20170 delete this.ids[g][oDD.id];
20173 delete this.handleIds[oDD.id];
20177 * Each DragDrop handle element must be registered. This is done
20178 * automatically when executing DragDrop.setHandleElId()
20179 * @method regHandle
20180 * @param {String} sDDId the DragDrop id this element is a handle for
20181 * @param {String} sHandleId the id of the element that is the drag
20185 regHandle: function(sDDId, sHandleId) {
20186 if (!this.handleIds[sDDId]) {
20187 this.handleIds[sDDId] = {};
20189 this.handleIds[sDDId][sHandleId] = sHandleId;
20193 * Utility function to determine if a given element has been
20194 * registered as a drag drop item.
20195 * @method isDragDrop
20196 * @param {String} id the element id to check
20197 * @return {boolean} true if this element is a DragDrop item,
20201 isDragDrop: function(id) {
20202 return ( this.getDDById(id) ) ? true : false;
20206 * Returns the drag and drop instances that are in all groups the
20207 * passed in instance belongs to.
20208 * @method getRelated
20209 * @param {DragDrop} p_oDD the obj to get related data for
20210 * @param {boolean} bTargetsOnly if true, only return targetable objs
20211 * @return {DragDrop[]} the related instances
20214 getRelated: function(p_oDD, bTargetsOnly) {
20216 for (var i in p_oDD.groups) {
20217 for (j in this.ids[i]) {
20218 var dd = this.ids[i][j];
20219 if (! this.isTypeOfDD(dd)) {
20222 if (!bTargetsOnly || dd.isTarget) {
20223 oDDs[oDDs.length] = dd;
20232 * Returns true if the specified dd target is a legal target for
20233 * the specifice drag obj
20234 * @method isLegalTarget
20235 * @param {DragDrop} the drag obj
20236 * @param {DragDrop} the target
20237 * @return {boolean} true if the target is a legal target for the
20241 isLegalTarget: function (oDD, oTargetDD) {
20242 var targets = this.getRelated(oDD, true);
20243 for (var i=0, len=targets.length;i<len;++i) {
20244 if (targets[i].id == oTargetDD.id) {
20253 * My goal is to be able to transparently determine if an object is
20254 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20255 * returns "object", oDD.constructor.toString() always returns
20256 * "DragDrop" and not the name of the subclass. So for now it just
20257 * evaluates a well-known variable in DragDrop.
20258 * @method isTypeOfDD
20259 * @param {Object} the object to evaluate
20260 * @return {boolean} true if typeof oDD = DragDrop
20263 isTypeOfDD: function (oDD) {
20264 return (oDD && oDD.__ygDragDrop);
20268 * Utility function to determine if a given element has been
20269 * registered as a drag drop handle for the given Drag Drop object.
20271 * @param {String} id the element id to check
20272 * @return {boolean} true if this element is a DragDrop handle, false
20276 isHandle: function(sDDId, sHandleId) {
20277 return ( this.handleIds[sDDId] &&
20278 this.handleIds[sDDId][sHandleId] );
20282 * Returns the DragDrop instance for a given id
20283 * @method getDDById
20284 * @param {String} id the id of the DragDrop object
20285 * @return {DragDrop} the drag drop object, null if it is not found
20288 getDDById: function(id) {
20289 for (var i in this.ids) {
20290 if (this.ids[i][id]) {
20291 return this.ids[i][id];
20298 * Fired after a registered DragDrop object gets the mousedown event.
20299 * Sets up the events required to track the object being dragged
20300 * @method handleMouseDown
20301 * @param {Event} e the event
20302 * @param oDD the DragDrop object being dragged
20306 handleMouseDown: function(e, oDD) {
20308 Roo.QuickTips.disable();
20310 this.currentTarget = e.getTarget();
20312 this.dragCurrent = oDD;
20314 var el = oDD.getEl();
20316 // track start position
20317 this.startX = e.getPageX();
20318 this.startY = e.getPageY();
20320 this.deltaX = this.startX - el.offsetLeft;
20321 this.deltaY = this.startY - el.offsetTop;
20323 this.dragThreshMet = false;
20325 this.clickTimeout = setTimeout(
20327 var DDM = Roo.dd.DDM;
20328 DDM.startDrag(DDM.startX, DDM.startY);
20330 this.clickTimeThresh );
20334 * Fired when either the drag pixel threshol or the mousedown hold
20335 * time threshold has been met.
20336 * @method startDrag
20337 * @param x {int} the X position of the original mousedown
20338 * @param y {int} the Y position of the original mousedown
20341 startDrag: function(x, y) {
20342 clearTimeout(this.clickTimeout);
20343 if (this.dragCurrent) {
20344 this.dragCurrent.b4StartDrag(x, y);
20345 this.dragCurrent.startDrag(x, y);
20347 this.dragThreshMet = true;
20351 * Internal function to handle the mouseup event. Will be invoked
20352 * from the context of the document.
20353 * @method handleMouseUp
20354 * @param {Event} e the event
20358 handleMouseUp: function(e) {
20361 Roo.QuickTips.enable();
20363 if (! this.dragCurrent) {
20367 clearTimeout(this.clickTimeout);
20369 if (this.dragThreshMet) {
20370 this.fireEvents(e, true);
20380 * Utility to stop event propagation and event default, if these
20381 * features are turned on.
20382 * @method stopEvent
20383 * @param {Event} e the event as returned by this.getEvent()
20386 stopEvent: function(e){
20387 if(this.stopPropagation) {
20388 e.stopPropagation();
20391 if (this.preventDefault) {
20392 e.preventDefault();
20397 * Internal function to clean up event handlers after the drag
20398 * operation is complete
20400 * @param {Event} e the event
20404 stopDrag: function(e) {
20405 // Fire the drag end event for the item that was dragged
20406 if (this.dragCurrent) {
20407 if (this.dragThreshMet) {
20408 this.dragCurrent.b4EndDrag(e);
20409 this.dragCurrent.endDrag(e);
20412 this.dragCurrent.onMouseUp(e);
20415 this.dragCurrent = null;
20416 this.dragOvers = {};
20420 * Internal function to handle the mousemove event. Will be invoked
20421 * from the context of the html element.
20423 * @TODO figure out what we can do about mouse events lost when the
20424 * user drags objects beyond the window boundary. Currently we can
20425 * detect this in internet explorer by verifying that the mouse is
20426 * down during the mousemove event. Firefox doesn't give us the
20427 * button state on the mousemove event.
20428 * @method handleMouseMove
20429 * @param {Event} e the event
20433 handleMouseMove: function(e) {
20434 if (! this.dragCurrent) {
20438 // var button = e.which || e.button;
20440 // check for IE mouseup outside of page boundary
20441 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20443 return this.handleMouseUp(e);
20446 if (!this.dragThreshMet) {
20447 var diffX = Math.abs(this.startX - e.getPageX());
20448 var diffY = Math.abs(this.startY - e.getPageY());
20449 if (diffX > this.clickPixelThresh ||
20450 diffY > this.clickPixelThresh) {
20451 this.startDrag(this.startX, this.startY);
20455 if (this.dragThreshMet) {
20456 this.dragCurrent.b4Drag(e);
20457 this.dragCurrent.onDrag(e);
20458 if(!this.dragCurrent.moveOnly){
20459 this.fireEvents(e, false);
20469 * Iterates over all of the DragDrop elements to find ones we are
20470 * hovering over or dropping on
20471 * @method fireEvents
20472 * @param {Event} e the event
20473 * @param {boolean} isDrop is this a drop op or a mouseover op?
20477 fireEvents: function(e, isDrop) {
20478 var dc = this.dragCurrent;
20480 // If the user did the mouse up outside of the window, we could
20481 // get here even though we have ended the drag.
20482 if (!dc || dc.isLocked()) {
20486 var pt = e.getPoint();
20488 // cache the previous dragOver array
20494 var enterEvts = [];
20496 // Check to see if the object(s) we were hovering over is no longer
20497 // being hovered over so we can fire the onDragOut event
20498 for (var i in this.dragOvers) {
20500 var ddo = this.dragOvers[i];
20502 if (! this.isTypeOfDD(ddo)) {
20506 if (! this.isOverTarget(pt, ddo, this.mode)) {
20507 outEvts.push( ddo );
20510 oldOvers[i] = true;
20511 delete this.dragOvers[i];
20514 for (var sGroup in dc.groups) {
20516 if ("string" != typeof sGroup) {
20520 for (i in this.ids[sGroup]) {
20521 var oDD = this.ids[sGroup][i];
20522 if (! this.isTypeOfDD(oDD)) {
20526 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20527 if (this.isOverTarget(pt, oDD, this.mode)) {
20528 // look for drop interactions
20530 dropEvts.push( oDD );
20531 // look for drag enter and drag over interactions
20534 // initial drag over: dragEnter fires
20535 if (!oldOvers[oDD.id]) {
20536 enterEvts.push( oDD );
20537 // subsequent drag overs: dragOver fires
20539 overEvts.push( oDD );
20542 this.dragOvers[oDD.id] = oDD;
20550 if (outEvts.length) {
20551 dc.b4DragOut(e, outEvts);
20552 dc.onDragOut(e, outEvts);
20555 if (enterEvts.length) {
20556 dc.onDragEnter(e, enterEvts);
20559 if (overEvts.length) {
20560 dc.b4DragOver(e, overEvts);
20561 dc.onDragOver(e, overEvts);
20564 if (dropEvts.length) {
20565 dc.b4DragDrop(e, dropEvts);
20566 dc.onDragDrop(e, dropEvts);
20570 // fire dragout events
20572 for (i=0, len=outEvts.length; i<len; ++i) {
20573 dc.b4DragOut(e, outEvts[i].id);
20574 dc.onDragOut(e, outEvts[i].id);
20577 // fire enter events
20578 for (i=0,len=enterEvts.length; i<len; ++i) {
20579 // dc.b4DragEnter(e, oDD.id);
20580 dc.onDragEnter(e, enterEvts[i].id);
20583 // fire over events
20584 for (i=0,len=overEvts.length; i<len; ++i) {
20585 dc.b4DragOver(e, overEvts[i].id);
20586 dc.onDragOver(e, overEvts[i].id);
20589 // fire drop events
20590 for (i=0, len=dropEvts.length; i<len; ++i) {
20591 dc.b4DragDrop(e, dropEvts[i].id);
20592 dc.onDragDrop(e, dropEvts[i].id);
20597 // notify about a drop that did not find a target
20598 if (isDrop && !dropEvts.length) {
20599 dc.onInvalidDrop(e);
20605 * Helper function for getting the best match from the list of drag
20606 * and drop objects returned by the drag and drop events when we are
20607 * in INTERSECT mode. It returns either the first object that the
20608 * cursor is over, or the object that has the greatest overlap with
20609 * the dragged element.
20610 * @method getBestMatch
20611 * @param {DragDrop[]} dds The array of drag and drop objects
20613 * @return {DragDrop} The best single match
20616 getBestMatch: function(dds) {
20618 // Return null if the input is not what we expect
20619 //if (!dds || !dds.length || dds.length == 0) {
20621 // If there is only one item, it wins
20622 //} else if (dds.length == 1) {
20624 var len = dds.length;
20629 // Loop through the targeted items
20630 for (var i=0; i<len; ++i) {
20632 // If the cursor is over the object, it wins. If the
20633 // cursor is over multiple matches, the first one we come
20635 if (dd.cursorIsOver) {
20638 // Otherwise the object with the most overlap wins
20641 winner.overlap.getArea() < dd.overlap.getArea()) {
20652 * Refreshes the cache of the top-left and bottom-right points of the
20653 * drag and drop objects in the specified group(s). This is in the
20654 * format that is stored in the drag and drop instance, so typical
20657 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20661 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20663 * @TODO this really should be an indexed array. Alternatively this
20664 * method could accept both.
20665 * @method refreshCache
20666 * @param {Object} groups an associative array of groups to refresh
20669 refreshCache: function(groups) {
20670 for (var sGroup in groups) {
20671 if ("string" != typeof sGroup) {
20674 for (var i in this.ids[sGroup]) {
20675 var oDD = this.ids[sGroup][i];
20677 if (this.isTypeOfDD(oDD)) {
20678 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20679 var loc = this.getLocation(oDD);
20681 this.locationCache[oDD.id] = loc;
20683 delete this.locationCache[oDD.id];
20684 // this will unregister the drag and drop object if
20685 // the element is not in a usable state
20694 * This checks to make sure an element exists and is in the DOM. The
20695 * main purpose is to handle cases where innerHTML is used to remove
20696 * drag and drop objects from the DOM. IE provides an 'unspecified
20697 * error' when trying to access the offsetParent of such an element
20699 * @param {HTMLElement} el the element to check
20700 * @return {boolean} true if the element looks usable
20703 verifyEl: function(el) {
20708 parent = el.offsetParent;
20711 parent = el.offsetParent;
20722 * Returns a Region object containing the drag and drop element's position
20723 * and size, including the padding configured for it
20724 * @method getLocation
20725 * @param {DragDrop} oDD the drag and drop object to get the
20727 * @return {Roo.lib.Region} a Region object representing the total area
20728 * the element occupies, including any padding
20729 * the instance is configured for.
20732 getLocation: function(oDD) {
20733 if (! this.isTypeOfDD(oDD)) {
20737 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20740 pos= Roo.lib.Dom.getXY(el);
20748 x2 = x1 + el.offsetWidth;
20750 y2 = y1 + el.offsetHeight;
20752 t = y1 - oDD.padding[0];
20753 r = x2 + oDD.padding[1];
20754 b = y2 + oDD.padding[2];
20755 l = x1 - oDD.padding[3];
20757 return new Roo.lib.Region( t, r, b, l );
20761 * Checks the cursor location to see if it over the target
20762 * @method isOverTarget
20763 * @param {Roo.lib.Point} pt The point to evaluate
20764 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20765 * @return {boolean} true if the mouse is over the target
20769 isOverTarget: function(pt, oTarget, intersect) {
20770 // use cache if available
20771 var loc = this.locationCache[oTarget.id];
20772 if (!loc || !this.useCache) {
20773 loc = this.getLocation(oTarget);
20774 this.locationCache[oTarget.id] = loc;
20782 oTarget.cursorIsOver = loc.contains( pt );
20784 // DragDrop is using this as a sanity check for the initial mousedown
20785 // in this case we are done. In POINT mode, if the drag obj has no
20786 // contraints, we are also done. Otherwise we need to evaluate the
20787 // location of the target as related to the actual location of the
20788 // dragged element.
20789 var dc = this.dragCurrent;
20790 if (!dc || !dc.getTargetCoord ||
20791 (!intersect && !dc.constrainX && !dc.constrainY)) {
20792 return oTarget.cursorIsOver;
20795 oTarget.overlap = null;
20797 // Get the current location of the drag element, this is the
20798 // location of the mouse event less the delta that represents
20799 // where the original mousedown happened on the element. We
20800 // need to consider constraints and ticks as well.
20801 var pos = dc.getTargetCoord(pt.x, pt.y);
20803 var el = dc.getDragEl();
20804 var curRegion = new Roo.lib.Region( pos.y,
20805 pos.x + el.offsetWidth,
20806 pos.y + el.offsetHeight,
20809 var overlap = curRegion.intersect(loc);
20812 oTarget.overlap = overlap;
20813 return (intersect) ? true : oTarget.cursorIsOver;
20820 * unload event handler
20821 * @method _onUnload
20825 _onUnload: function(e, me) {
20826 Roo.dd.DragDropMgr.unregAll();
20830 * Cleans up the drag and drop events and objects.
20835 unregAll: function() {
20837 if (this.dragCurrent) {
20839 this.dragCurrent = null;
20842 this._execOnAll("unreg", []);
20844 for (i in this.elementCache) {
20845 delete this.elementCache[i];
20848 this.elementCache = {};
20853 * A cache of DOM elements
20854 * @property elementCache
20861 * Get the wrapper for the DOM element specified
20862 * @method getElWrapper
20863 * @param {String} id the id of the element to get
20864 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20866 * @deprecated This wrapper isn't that useful
20869 getElWrapper: function(id) {
20870 var oWrapper = this.elementCache[id];
20871 if (!oWrapper || !oWrapper.el) {
20872 oWrapper = this.elementCache[id] =
20873 new this.ElementWrapper(Roo.getDom(id));
20879 * Returns the actual DOM element
20880 * @method getElement
20881 * @param {String} id the id of the elment to get
20882 * @return {Object} The element
20883 * @deprecated use Roo.getDom instead
20886 getElement: function(id) {
20887 return Roo.getDom(id);
20891 * Returns the style property for the DOM element (i.e.,
20892 * document.getElById(id).style)
20894 * @param {String} id the id of the elment to get
20895 * @return {Object} The style property of the element
20896 * @deprecated use Roo.getDom instead
20899 getCss: function(id) {
20900 var el = Roo.getDom(id);
20901 return (el) ? el.style : null;
20905 * Inner class for cached elements
20906 * @class DragDropMgr.ElementWrapper
20911 ElementWrapper: function(el) {
20916 this.el = el || null;
20921 this.id = this.el && el.id;
20923 * A reference to the style property
20926 this.css = this.el && el.style;
20930 * Returns the X position of an html element
20932 * @param el the element for which to get the position
20933 * @return {int} the X coordinate
20935 * @deprecated use Roo.lib.Dom.getX instead
20938 getPosX: function(el) {
20939 return Roo.lib.Dom.getX(el);
20943 * Returns the Y position of an html element
20945 * @param el the element for which to get the position
20946 * @return {int} the Y coordinate
20947 * @deprecated use Roo.lib.Dom.getY instead
20950 getPosY: function(el) {
20951 return Roo.lib.Dom.getY(el);
20955 * Swap two nodes. In IE, we use the native method, for others we
20956 * emulate the IE behavior
20958 * @param n1 the first node to swap
20959 * @param n2 the other node to swap
20962 swapNode: function(n1, n2) {
20966 var p = n2.parentNode;
20967 var s = n2.nextSibling;
20970 p.insertBefore(n1, n2);
20971 } else if (n2 == n1.nextSibling) {
20972 p.insertBefore(n2, n1);
20974 n1.parentNode.replaceChild(n2, n1);
20975 p.insertBefore(n1, s);
20981 * Returns the current scroll position
20982 * @method getScroll
20986 getScroll: function () {
20987 var t, l, dde=document.documentElement, db=document.body;
20988 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20990 l = dde.scrollLeft;
20997 return { top: t, left: l };
21001 * Returns the specified element style property
21003 * @param {HTMLElement} el the element
21004 * @param {string} styleProp the style property
21005 * @return {string} The value of the style property
21006 * @deprecated use Roo.lib.Dom.getStyle
21009 getStyle: function(el, styleProp) {
21010 return Roo.fly(el).getStyle(styleProp);
21014 * Gets the scrollTop
21015 * @method getScrollTop
21016 * @return {int} the document's scrollTop
21019 getScrollTop: function () { return this.getScroll().top; },
21022 * Gets the scrollLeft
21023 * @method getScrollLeft
21024 * @return {int} the document's scrollTop
21027 getScrollLeft: function () { return this.getScroll().left; },
21030 * Sets the x/y position of an element to the location of the
21033 * @param {HTMLElement} moveEl The element to move
21034 * @param {HTMLElement} targetEl The position reference element
21037 moveToEl: function (moveEl, targetEl) {
21038 var aCoord = Roo.lib.Dom.getXY(targetEl);
21039 Roo.lib.Dom.setXY(moveEl, aCoord);
21043 * Numeric array sort function
21044 * @method numericSort
21047 numericSort: function(a, b) { return (a - b); },
21051 * @property _timeoutCount
21058 * Trying to make the load order less important. Without this we get
21059 * an error if this file is loaded before the Event Utility.
21060 * @method _addListeners
21064 _addListeners: function() {
21065 var DDM = Roo.dd.DDM;
21066 if ( Roo.lib.Event && document ) {
21069 if (DDM._timeoutCount > 2000) {
21071 setTimeout(DDM._addListeners, 10);
21072 if (document && document.body) {
21073 DDM._timeoutCount += 1;
21080 * Recursively searches the immediate parent and all child nodes for
21081 * the handle element in order to determine wheter or not it was
21083 * @method handleWasClicked
21084 * @param node the html element to inspect
21087 handleWasClicked: function(node, id) {
21088 if (this.isHandle(id, node.id)) {
21091 // check to see if this is a text node child of the one we want
21092 var p = node.parentNode;
21095 if (this.isHandle(id, p.id)) {
21110 // shorter alias, save a few bytes
21111 Roo.dd.DDM = Roo.dd.DragDropMgr;
21112 Roo.dd.DDM._addListeners();
21116 * Ext JS Library 1.1.1
21117 * Copyright(c) 2006-2007, Ext JS, LLC.
21119 * Originally Released Under LGPL - original licence link has changed is not relivant.
21122 * <script type="text/javascript">
21127 * A DragDrop implementation where the linked element follows the
21128 * mouse cursor during a drag.
21129 * @extends Roo.dd.DragDrop
21131 * @param {String} id the id of the linked element
21132 * @param {String} sGroup the group of related DragDrop items
21133 * @param {object} config an object containing configurable attributes
21134 * Valid properties for DD:
21137 Roo.dd.DD = function(id, sGroup, config) {
21139 this.init(id, sGroup, config);
21143 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21146 * When set to true, the utility automatically tries to scroll the browser
21147 * window wehn a drag and drop element is dragged near the viewport boundary.
21148 * Defaults to true.
21155 * Sets the pointer offset to the distance between the linked element's top
21156 * left corner and the location the element was clicked
21157 * @method autoOffset
21158 * @param {int} iPageX the X coordinate of the click
21159 * @param {int} iPageY the Y coordinate of the click
21161 autoOffset: function(iPageX, iPageY) {
21162 var x = iPageX - this.startPageX;
21163 var y = iPageY - this.startPageY;
21164 this.setDelta(x, y);
21168 * Sets the pointer offset. You can call this directly to force the
21169 * offset to be in a particular location (e.g., pass in 0,0 to set it
21170 * to the center of the object)
21172 * @param {int} iDeltaX the distance from the left
21173 * @param {int} iDeltaY the distance from the top
21175 setDelta: function(iDeltaX, iDeltaY) {
21176 this.deltaX = iDeltaX;
21177 this.deltaY = iDeltaY;
21181 * Sets the drag element to the location of the mousedown or click event,
21182 * maintaining the cursor location relative to the location on the element
21183 * that was clicked. Override this if you want to place the element in a
21184 * location other than where the cursor is.
21185 * @method setDragElPos
21186 * @param {int} iPageX the X coordinate of the mousedown or drag event
21187 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21189 setDragElPos: function(iPageX, iPageY) {
21190 // the first time we do this, we are going to check to make sure
21191 // the element has css positioning
21193 var el = this.getDragEl();
21194 this.alignElWithMouse(el, iPageX, iPageY);
21198 * Sets the element to the location of the mousedown or click event,
21199 * maintaining the cursor location relative to the location on the element
21200 * that was clicked. Override this if you want to place the element in a
21201 * location other than where the cursor is.
21202 * @method alignElWithMouse
21203 * @param {HTMLElement} el the element to move
21204 * @param {int} iPageX the X coordinate of the mousedown or drag event
21205 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21207 alignElWithMouse: function(el, iPageX, iPageY) {
21208 var oCoord = this.getTargetCoord(iPageX, iPageY);
21209 var fly = el.dom ? el : Roo.fly(el);
21210 if (!this.deltaSetXY) {
21211 var aCoord = [oCoord.x, oCoord.y];
21213 var newLeft = fly.getLeft(true);
21214 var newTop = fly.getTop(true);
21215 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21217 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21220 this.cachePosition(oCoord.x, oCoord.y);
21221 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21226 * Saves the most recent position so that we can reset the constraints and
21227 * tick marks on-demand. We need to know this so that we can calculate the
21228 * number of pixels the element is offset from its original position.
21229 * @method cachePosition
21230 * @param iPageX the current x position (optional, this just makes it so we
21231 * don't have to look it up again)
21232 * @param iPageY the current y position (optional, this just makes it so we
21233 * don't have to look it up again)
21235 cachePosition: function(iPageX, iPageY) {
21237 this.lastPageX = iPageX;
21238 this.lastPageY = iPageY;
21240 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21241 this.lastPageX = aCoord[0];
21242 this.lastPageY = aCoord[1];
21247 * Auto-scroll the window if the dragged object has been moved beyond the
21248 * visible window boundary.
21249 * @method autoScroll
21250 * @param {int} x the drag element's x position
21251 * @param {int} y the drag element's y position
21252 * @param {int} h the height of the drag element
21253 * @param {int} w the width of the drag element
21256 autoScroll: function(x, y, h, w) {
21259 // The client height
21260 var clientH = Roo.lib.Dom.getViewWidth();
21262 // The client width
21263 var clientW = Roo.lib.Dom.getViewHeight();
21265 // The amt scrolled down
21266 var st = this.DDM.getScrollTop();
21268 // The amt scrolled right
21269 var sl = this.DDM.getScrollLeft();
21271 // Location of the bottom of the element
21274 // Location of the right of the element
21277 // The distance from the cursor to the bottom of the visible area,
21278 // adjusted so that we don't scroll if the cursor is beyond the
21279 // element drag constraints
21280 var toBot = (clientH + st - y - this.deltaY);
21282 // The distance from the cursor to the right of the visible area
21283 var toRight = (clientW + sl - x - this.deltaX);
21286 // How close to the edge the cursor must be before we scroll
21287 // var thresh = (document.all) ? 100 : 40;
21290 // How many pixels to scroll per autoscroll op. This helps to reduce
21291 // clunky scrolling. IE is more sensitive about this ... it needs this
21292 // value to be higher.
21293 var scrAmt = (document.all) ? 80 : 30;
21295 // Scroll down if we are near the bottom of the visible page and the
21296 // obj extends below the crease
21297 if ( bot > clientH && toBot < thresh ) {
21298 window.scrollTo(sl, st + scrAmt);
21301 // Scroll up if the window is scrolled down and the top of the object
21302 // goes above the top border
21303 if ( y < st && st > 0 && y - st < thresh ) {
21304 window.scrollTo(sl, st - scrAmt);
21307 // Scroll right if the obj is beyond the right border and the cursor is
21308 // near the border.
21309 if ( right > clientW && toRight < thresh ) {
21310 window.scrollTo(sl + scrAmt, st);
21313 // Scroll left if the window has been scrolled to the right and the obj
21314 // extends past the left border
21315 if ( x < sl && sl > 0 && x - sl < thresh ) {
21316 window.scrollTo(sl - scrAmt, st);
21322 * Finds the location the element should be placed if we want to move
21323 * it to where the mouse location less the click offset would place us.
21324 * @method getTargetCoord
21325 * @param {int} iPageX the X coordinate of the click
21326 * @param {int} iPageY the Y coordinate of the click
21327 * @return an object that contains the coordinates (Object.x and Object.y)
21330 getTargetCoord: function(iPageX, iPageY) {
21333 var x = iPageX - this.deltaX;
21334 var y = iPageY - this.deltaY;
21336 if (this.constrainX) {
21337 if (x < this.minX) { x = this.minX; }
21338 if (x > this.maxX) { x = this.maxX; }
21341 if (this.constrainY) {
21342 if (y < this.minY) { y = this.minY; }
21343 if (y > this.maxY) { y = this.maxY; }
21346 x = this.getTick(x, this.xTicks);
21347 y = this.getTick(y, this.yTicks);
21354 * Sets up config options specific to this class. Overrides
21355 * Roo.dd.DragDrop, but all versions of this method through the
21356 * inheritance chain are called
21358 applyConfig: function() {
21359 Roo.dd.DD.superclass.applyConfig.call(this);
21360 this.scroll = (this.config.scroll !== false);
21364 * Event that fires prior to the onMouseDown event. Overrides
21367 b4MouseDown: function(e) {
21368 // this.resetConstraints();
21369 this.autoOffset(e.getPageX(),
21374 * Event that fires prior to the onDrag event. Overrides
21377 b4Drag: function(e) {
21378 this.setDragElPos(e.getPageX(),
21382 toString: function() {
21383 return ("DD " + this.id);
21386 //////////////////////////////////////////////////////////////////////////
21387 // Debugging ygDragDrop events that can be overridden
21388 //////////////////////////////////////////////////////////////////////////
21390 startDrag: function(x, y) {
21393 onDrag: function(e) {
21396 onDragEnter: function(e, id) {
21399 onDragOver: function(e, id) {
21402 onDragOut: function(e, id) {
21405 onDragDrop: function(e, id) {
21408 endDrag: function(e) {
21415 * Ext JS Library 1.1.1
21416 * Copyright(c) 2006-2007, Ext JS, LLC.
21418 * Originally Released Under LGPL - original licence link has changed is not relivant.
21421 * <script type="text/javascript">
21425 * @class Roo.dd.DDProxy
21426 * A DragDrop implementation that inserts an empty, bordered div into
21427 * the document that follows the cursor during drag operations. At the time of
21428 * the click, the frame div is resized to the dimensions of the linked html
21429 * element, and moved to the exact location of the linked element.
21431 * References to the "frame" element refer to the single proxy element that
21432 * was created to be dragged in place of all DDProxy elements on the
21435 * @extends Roo.dd.DD
21437 * @param {String} id the id of the linked html element
21438 * @param {String} sGroup the group of related DragDrop objects
21439 * @param {object} config an object containing configurable attributes
21440 * Valid properties for DDProxy in addition to those in DragDrop:
21441 * resizeFrame, centerFrame, dragElId
21443 Roo.dd.DDProxy = function(id, sGroup, config) {
21445 this.init(id, sGroup, config);
21451 * The default drag frame div id
21452 * @property Roo.dd.DDProxy.dragElId
21456 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21458 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21461 * By default we resize the drag frame to be the same size as the element
21462 * we want to drag (this is to get the frame effect). We can turn it off
21463 * if we want a different behavior.
21464 * @property resizeFrame
21470 * By default the frame is positioned exactly where the drag element is, so
21471 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21472 * you do not have constraints on the obj is to have the drag frame centered
21473 * around the cursor. Set centerFrame to true for this effect.
21474 * @property centerFrame
21477 centerFrame: false,
21480 * Creates the proxy element if it does not yet exist
21481 * @method createFrame
21483 createFrame: function() {
21485 var body = document.body;
21487 if (!body || !body.firstChild) {
21488 setTimeout( function() { self.createFrame(); }, 50 );
21492 var div = this.getDragEl();
21495 div = document.createElement("div");
21496 div.id = this.dragElId;
21499 s.position = "absolute";
21500 s.visibility = "hidden";
21502 s.border = "2px solid #aaa";
21505 // appendChild can blow up IE if invoked prior to the window load event
21506 // while rendering a table. It is possible there are other scenarios
21507 // that would cause this to happen as well.
21508 body.insertBefore(div, body.firstChild);
21513 * Initialization for the drag frame element. Must be called in the
21514 * constructor of all subclasses
21515 * @method initFrame
21517 initFrame: function() {
21518 this.createFrame();
21521 applyConfig: function() {
21522 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21524 this.resizeFrame = (this.config.resizeFrame !== false);
21525 this.centerFrame = (this.config.centerFrame);
21526 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21530 * Resizes the drag frame to the dimensions of the clicked object, positions
21531 * it over the object, and finally displays it
21532 * @method showFrame
21533 * @param {int} iPageX X click position
21534 * @param {int} iPageY Y click position
21537 showFrame: function(iPageX, iPageY) {
21538 var el = this.getEl();
21539 var dragEl = this.getDragEl();
21540 var s = dragEl.style;
21542 this._resizeProxy();
21544 if (this.centerFrame) {
21545 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21546 Math.round(parseInt(s.height, 10)/2) );
21549 this.setDragElPos(iPageX, iPageY);
21551 Roo.fly(dragEl).show();
21555 * The proxy is automatically resized to the dimensions of the linked
21556 * element when a drag is initiated, unless resizeFrame is set to false
21557 * @method _resizeProxy
21560 _resizeProxy: function() {
21561 if (this.resizeFrame) {
21562 var el = this.getEl();
21563 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21567 // overrides Roo.dd.DragDrop
21568 b4MouseDown: function(e) {
21569 var x = e.getPageX();
21570 var y = e.getPageY();
21571 this.autoOffset(x, y);
21572 this.setDragElPos(x, y);
21575 // overrides Roo.dd.DragDrop
21576 b4StartDrag: function(x, y) {
21577 // show the drag frame
21578 this.showFrame(x, y);
21581 // overrides Roo.dd.DragDrop
21582 b4EndDrag: function(e) {
21583 Roo.fly(this.getDragEl()).hide();
21586 // overrides Roo.dd.DragDrop
21587 // By default we try to move the element to the last location of the frame.
21588 // This is so that the default behavior mirrors that of Roo.dd.DD.
21589 endDrag: function(e) {
21591 var lel = this.getEl();
21592 var del = this.getDragEl();
21594 // Show the drag frame briefly so we can get its position
21595 del.style.visibility = "";
21598 // Hide the linked element before the move to get around a Safari
21600 lel.style.visibility = "hidden";
21601 Roo.dd.DDM.moveToEl(lel, del);
21602 del.style.visibility = "hidden";
21603 lel.style.visibility = "";
21608 beforeMove : function(){
21612 afterDrag : function(){
21616 toString: function() {
21617 return ("DDProxy " + this.id);
21623 * Ext JS Library 1.1.1
21624 * Copyright(c) 2006-2007, Ext JS, LLC.
21626 * Originally Released Under LGPL - original licence link has changed is not relivant.
21629 * <script type="text/javascript">
21633 * @class Roo.dd.DDTarget
21634 * A DragDrop implementation that does not move, but can be a drop
21635 * target. You would get the same result by simply omitting implementation
21636 * for the event callbacks, but this way we reduce the processing cost of the
21637 * event listener and the callbacks.
21638 * @extends Roo.dd.DragDrop
21640 * @param {String} id the id of the element that is a drop target
21641 * @param {String} sGroup the group of related DragDrop objects
21642 * @param {object} config an object containing configurable attributes
21643 * Valid properties for DDTarget in addition to those in
21647 Roo.dd.DDTarget = function(id, sGroup, config) {
21649 this.initTarget(id, sGroup, config);
21651 if (config && (config.listeners || config.events)) {
21652 Roo.dd.DragDrop.superclass.constructor.call(this, {
21653 listeners : config.listeners || {},
21654 events : config.events || {}
21659 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21660 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21661 toString: function() {
21662 return ("DDTarget " + this.id);
21667 * Ext JS Library 1.1.1
21668 * Copyright(c) 2006-2007, Ext JS, LLC.
21670 * Originally Released Under LGPL - original licence link has changed is not relivant.
21673 * <script type="text/javascript">
21678 * @class Roo.dd.ScrollManager
21679 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21680 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21683 Roo.dd.ScrollManager = function(){
21684 var ddm = Roo.dd.DragDropMgr;
21691 var onStop = function(e){
21696 var triggerRefresh = function(){
21697 if(ddm.dragCurrent){
21698 ddm.refreshCache(ddm.dragCurrent.groups);
21702 var doScroll = function(){
21703 if(ddm.dragCurrent){
21704 var dds = Roo.dd.ScrollManager;
21706 if(proc.el.scroll(proc.dir, dds.increment)){
21710 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21715 var clearProc = function(){
21717 clearInterval(proc.id);
21724 var startProc = function(el, dir){
21725 Roo.log('scroll startproc');
21729 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21732 var onFire = function(e, isDrop){
21734 if(isDrop || !ddm.dragCurrent){ return; }
21735 var dds = Roo.dd.ScrollManager;
21736 if(!dragEl || dragEl != ddm.dragCurrent){
21737 dragEl = ddm.dragCurrent;
21738 // refresh regions on drag start
21739 dds.refreshCache();
21742 var xy = Roo.lib.Event.getXY(e);
21743 var pt = new Roo.lib.Point(xy[0], xy[1]);
21744 for(var id in els){
21745 var el = els[id], r = el._region;
21746 if(r && r.contains(pt) && el.isScrollable()){
21747 if(r.bottom - pt.y <= dds.thresh){
21749 startProc(el, "down");
21752 }else if(r.right - pt.x <= dds.thresh){
21754 startProc(el, "left");
21757 }else if(pt.y - r.top <= dds.thresh){
21759 startProc(el, "up");
21762 }else if(pt.x - r.left <= dds.thresh){
21764 startProc(el, "right");
21773 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21774 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21778 * Registers new overflow element(s) to auto scroll
21779 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21781 register : function(el){
21782 if(el instanceof Array){
21783 for(var i = 0, len = el.length; i < len; i++) {
21784 this.register(el[i]);
21790 Roo.dd.ScrollManager.els = els;
21794 * Unregisters overflow element(s) so they are no longer scrolled
21795 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21797 unregister : function(el){
21798 if(el instanceof Array){
21799 for(var i = 0, len = el.length; i < len; i++) {
21800 this.unregister(el[i]);
21809 * The number of pixels from the edge of a container the pointer needs to be to
21810 * trigger scrolling (defaults to 25)
21816 * The number of pixels to scroll in each scroll increment (defaults to 50)
21822 * The frequency of scrolls in milliseconds (defaults to 500)
21828 * True to animate the scroll (defaults to true)
21834 * The animation duration in seconds -
21835 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21841 * Manually trigger a cache refresh.
21843 refreshCache : function(){
21844 for(var id in els){
21845 if(typeof els[id] == 'object'){ // for people extending the object prototype
21846 els[id]._region = els[id].getRegion();
21853 * Ext JS Library 1.1.1
21854 * Copyright(c) 2006-2007, Ext JS, LLC.
21856 * Originally Released Under LGPL - original licence link has changed is not relivant.
21859 * <script type="text/javascript">
21864 * @class Roo.dd.Registry
21865 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21866 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21869 Roo.dd.Registry = function(){
21872 var autoIdSeed = 0;
21874 var getId = function(el, autogen){
21875 if(typeof el == "string"){
21879 if(!id && autogen !== false){
21880 id = "roodd-" + (++autoIdSeed);
21888 * Register a drag drop element
21889 * @param {String|HTMLElement} element The id or DOM node to register
21890 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21891 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21892 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21893 * populated in the data object (if applicable):
21895 Value Description<br />
21896 --------- ------------------------------------------<br />
21897 handles Array of DOM nodes that trigger dragging<br />
21898 for the element being registered<br />
21899 isHandle True if the element passed in triggers<br />
21900 dragging itself, else false
21903 register : function(el, data){
21905 if(typeof el == "string"){
21906 el = document.getElementById(el);
21909 elements[getId(el)] = data;
21910 if(data.isHandle !== false){
21911 handles[data.ddel.id] = data;
21914 var hs = data.handles;
21915 for(var i = 0, len = hs.length; i < len; i++){
21916 handles[getId(hs[i])] = data;
21922 * Unregister a drag drop element
21923 * @param {String|HTMLElement} element The id or DOM node to unregister
21925 unregister : function(el){
21926 var id = getId(el, false);
21927 var data = elements[id];
21929 delete elements[id];
21931 var hs = data.handles;
21932 for(var i = 0, len = hs.length; i < len; i++){
21933 delete handles[getId(hs[i], false)];
21940 * Returns the handle registered for a DOM Node by id
21941 * @param {String|HTMLElement} id The DOM node or id to look up
21942 * @return {Object} handle The custom handle data
21944 getHandle : function(id){
21945 if(typeof id != "string"){ // must be element?
21948 return handles[id];
21952 * Returns the handle that is registered for the DOM node that is the target of the event
21953 * @param {Event} e The event
21954 * @return {Object} handle The custom handle data
21956 getHandleFromEvent : function(e){
21957 var t = Roo.lib.Event.getTarget(e);
21958 return t ? handles[t.id] : null;
21962 * Returns a custom data object that is registered for a DOM node by id
21963 * @param {String|HTMLElement} id The DOM node or id to look up
21964 * @return {Object} data The custom data
21966 getTarget : function(id){
21967 if(typeof id != "string"){ // must be element?
21970 return elements[id];
21974 * Returns a custom data object that is registered for the DOM node that is the target of the event
21975 * @param {Event} e The event
21976 * @return {Object} data The custom data
21978 getTargetFromEvent : function(e){
21979 var t = Roo.lib.Event.getTarget(e);
21980 return t ? elements[t.id] || handles[t.id] : null;
21985 * Ext JS Library 1.1.1
21986 * Copyright(c) 2006-2007, Ext JS, LLC.
21988 * Originally Released Under LGPL - original licence link has changed is not relivant.
21991 * <script type="text/javascript">
21996 * @class Roo.dd.StatusProxy
21997 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21998 * default drag proxy used by all Roo.dd components.
22000 * @param {Object} config
22002 Roo.dd.StatusProxy = function(config){
22003 Roo.apply(this, config);
22004 this.id = this.id || Roo.id();
22005 this.el = new Roo.Layer({
22007 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22008 {tag: "div", cls: "x-dd-drop-icon"},
22009 {tag: "div", cls: "x-dd-drag-ghost"}
22012 shadow: !config || config.shadow !== false
22014 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22015 this.dropStatus = this.dropNotAllowed;
22018 Roo.dd.StatusProxy.prototype = {
22020 * @cfg {String} dropAllowed
22021 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22023 dropAllowed : "x-dd-drop-ok",
22025 * @cfg {String} dropNotAllowed
22026 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22028 dropNotAllowed : "x-dd-drop-nodrop",
22031 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22032 * over the current target element.
22033 * @param {String} cssClass The css class for the new drop status indicator image
22035 setStatus : function(cssClass){
22036 cssClass = cssClass || this.dropNotAllowed;
22037 if(this.dropStatus != cssClass){
22038 this.el.replaceClass(this.dropStatus, cssClass);
22039 this.dropStatus = cssClass;
22044 * Resets the status indicator to the default dropNotAllowed value
22045 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22047 reset : function(clearGhost){
22048 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22049 this.dropStatus = this.dropNotAllowed;
22051 this.ghost.update("");
22056 * Updates the contents of the ghost element
22057 * @param {String} html The html that will replace the current innerHTML of the ghost element
22059 update : function(html){
22060 if(typeof html == "string"){
22061 this.ghost.update(html);
22063 this.ghost.update("");
22064 html.style.margin = "0";
22065 this.ghost.dom.appendChild(html);
22067 // ensure float = none set?? cant remember why though.
22068 var el = this.ghost.dom.firstChild;
22070 Roo.fly(el).setStyle('float', 'none');
22075 * Returns the underlying proxy {@link Roo.Layer}
22076 * @return {Roo.Layer} el
22078 getEl : function(){
22083 * Returns the ghost element
22084 * @return {Roo.Element} el
22086 getGhost : function(){
22092 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22094 hide : function(clear){
22102 * Stops the repair animation if it's currently running
22105 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22111 * Displays this proxy
22118 * Force the Layer to sync its shadow and shim positions to the element
22125 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22126 * invalid drop operation by the item being dragged.
22127 * @param {Array} xy The XY position of the element ([x, y])
22128 * @param {Function} callback The function to call after the repair is complete
22129 * @param {Object} scope The scope in which to execute the callback
22131 repair : function(xy, callback, scope){
22132 this.callback = callback;
22133 this.scope = scope;
22134 if(xy && this.animRepair !== false){
22135 this.el.addClass("x-dd-drag-repair");
22136 this.el.hideUnders(true);
22137 this.anim = this.el.shift({
22138 duration: this.repairDuration || .5,
22142 callback: this.afterRepair,
22146 this.afterRepair();
22151 afterRepair : function(){
22153 if(typeof this.callback == "function"){
22154 this.callback.call(this.scope || this);
22156 this.callback = null;
22161 * Ext JS Library 1.1.1
22162 * Copyright(c) 2006-2007, Ext JS, LLC.
22164 * Originally Released Under LGPL - original licence link has changed is not relivant.
22167 * <script type="text/javascript">
22171 * @class Roo.dd.DragSource
22172 * @extends Roo.dd.DDProxy
22173 * A simple class that provides the basic implementation needed to make any element draggable.
22175 * @param {String/HTMLElement/Element} el The container element
22176 * @param {Object} config
22178 Roo.dd.DragSource = function(el, config){
22179 this.el = Roo.get(el);
22180 this.dragData = {};
22182 Roo.apply(this, config);
22185 this.proxy = new Roo.dd.StatusProxy();
22188 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22189 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22191 this.dragging = false;
22194 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22196 * @cfg {String} dropAllowed
22197 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22199 dropAllowed : "x-dd-drop-ok",
22201 * @cfg {String} dropNotAllowed
22202 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22204 dropNotAllowed : "x-dd-drop-nodrop",
22207 * Returns the data object associated with this drag source
22208 * @return {Object} data An object containing arbitrary data
22210 getDragData : function(e){
22211 return this.dragData;
22215 onDragEnter : function(e, id){
22216 var target = Roo.dd.DragDropMgr.getDDById(id);
22217 this.cachedTarget = target;
22218 if(this.beforeDragEnter(target, e, id) !== false){
22219 if(target.isNotifyTarget){
22220 var status = target.notifyEnter(this, e, this.dragData);
22221 this.proxy.setStatus(status);
22223 this.proxy.setStatus(this.dropAllowed);
22226 if(this.afterDragEnter){
22228 * An empty function by default, but provided so that you can perform a custom action
22229 * when the dragged item enters the drop target by providing an implementation.
22230 * @param {Roo.dd.DragDrop} target The drop target
22231 * @param {Event} e The event object
22232 * @param {String} id The id of the dragged element
22233 * @method afterDragEnter
22235 this.afterDragEnter(target, e, id);
22241 * An empty function by default, but provided so that you can perform a custom action
22242 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22243 * @param {Roo.dd.DragDrop} target The drop target
22244 * @param {Event} e The event object
22245 * @param {String} id The id of the dragged element
22246 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22248 beforeDragEnter : function(target, e, id){
22253 alignElWithMouse: function() {
22254 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22259 onDragOver : function(e, id){
22260 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22261 if(this.beforeDragOver(target, e, id) !== false){
22262 if(target.isNotifyTarget){
22263 var status = target.notifyOver(this, e, this.dragData);
22264 this.proxy.setStatus(status);
22267 if(this.afterDragOver){
22269 * An empty function by default, but provided so that you can perform a custom action
22270 * while the dragged item is over the drop target by providing an implementation.
22271 * @param {Roo.dd.DragDrop} target The drop target
22272 * @param {Event} e The event object
22273 * @param {String} id The id of the dragged element
22274 * @method afterDragOver
22276 this.afterDragOver(target, e, id);
22282 * An empty function by default, but provided so that you can perform a custom action
22283 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22284 * @param {Roo.dd.DragDrop} target The drop target
22285 * @param {Event} e The event object
22286 * @param {String} id The id of the dragged element
22287 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22289 beforeDragOver : function(target, e, id){
22294 onDragOut : function(e, id){
22295 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22296 if(this.beforeDragOut(target, e, id) !== false){
22297 if(target.isNotifyTarget){
22298 target.notifyOut(this, e, this.dragData);
22300 this.proxy.reset();
22301 if(this.afterDragOut){
22303 * An empty function by default, but provided so that you can perform a custom action
22304 * after the dragged item is dragged out of the target without dropping.
22305 * @param {Roo.dd.DragDrop} target The drop target
22306 * @param {Event} e The event object
22307 * @param {String} id The id of the dragged element
22308 * @method afterDragOut
22310 this.afterDragOut(target, e, id);
22313 this.cachedTarget = null;
22317 * An empty function by default, but provided so that you can perform a custom action before the dragged
22318 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22319 * @param {Roo.dd.DragDrop} target The drop target
22320 * @param {Event} e The event object
22321 * @param {String} id The id of the dragged element
22322 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22324 beforeDragOut : function(target, e, id){
22329 onDragDrop : function(e, id){
22330 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22331 if(this.beforeDragDrop(target, e, id) !== false){
22332 if(target.isNotifyTarget){
22333 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22334 this.onValidDrop(target, e, id);
22336 this.onInvalidDrop(target, e, id);
22339 this.onValidDrop(target, e, id);
22342 if(this.afterDragDrop){
22344 * An empty function by default, but provided so that you can perform a custom action
22345 * after a valid drag drop has occurred by providing an implementation.
22346 * @param {Roo.dd.DragDrop} target The drop target
22347 * @param {Event} e The event object
22348 * @param {String} id The id of the dropped element
22349 * @method afterDragDrop
22351 this.afterDragDrop(target, e, id);
22354 delete this.cachedTarget;
22358 * An empty function by default, but provided so that you can perform a custom action before the dragged
22359 * item is dropped onto the target and optionally cancel the onDragDrop.
22360 * @param {Roo.dd.DragDrop} target The drop target
22361 * @param {Event} e The event object
22362 * @param {String} id The id of the dragged element
22363 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22365 beforeDragDrop : function(target, e, id){
22370 onValidDrop : function(target, e, id){
22372 if(this.afterValidDrop){
22374 * An empty function by default, but provided so that you can perform a custom action
22375 * after a valid drop has occurred by providing an implementation.
22376 * @param {Object} target The target DD
22377 * @param {Event} e The event object
22378 * @param {String} id The id of the dropped element
22379 * @method afterInvalidDrop
22381 this.afterValidDrop(target, e, id);
22386 getRepairXY : function(e, data){
22387 return this.el.getXY();
22391 onInvalidDrop : function(target, e, id){
22392 this.beforeInvalidDrop(target, e, id);
22393 if(this.cachedTarget){
22394 if(this.cachedTarget.isNotifyTarget){
22395 this.cachedTarget.notifyOut(this, e, this.dragData);
22397 this.cacheTarget = null;
22399 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22401 if(this.afterInvalidDrop){
22403 * An empty function by default, but provided so that you can perform a custom action
22404 * after an invalid drop has occurred by providing an implementation.
22405 * @param {Event} e The event object
22406 * @param {String} id The id of the dropped element
22407 * @method afterInvalidDrop
22409 this.afterInvalidDrop(e, id);
22414 afterRepair : function(){
22416 this.el.highlight(this.hlColor || "c3daf9");
22418 this.dragging = false;
22422 * An empty function by default, but provided so that you can perform a custom action after an invalid
22423 * drop has occurred.
22424 * @param {Roo.dd.DragDrop} target The drop target
22425 * @param {Event} e The event object
22426 * @param {String} id The id of the dragged element
22427 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22429 beforeInvalidDrop : function(target, e, id){
22434 handleMouseDown : function(e){
22435 if(this.dragging) {
22438 var data = this.getDragData(e);
22439 if(data && this.onBeforeDrag(data, e) !== false){
22440 this.dragData = data;
22442 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22447 * An empty function by default, but provided so that you can perform a custom action before the initial
22448 * drag event begins and optionally cancel it.
22449 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22450 * @param {Event} e The event object
22451 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22453 onBeforeDrag : function(data, e){
22458 * An empty function by default, but provided so that you can perform a custom action once the initial
22459 * drag event has begun. The drag cannot be canceled from this function.
22460 * @param {Number} x The x position of the click on the dragged object
22461 * @param {Number} y The y position of the click on the dragged object
22463 onStartDrag : Roo.emptyFn,
22465 // private - YUI override
22466 startDrag : function(x, y){
22467 this.proxy.reset();
22468 this.dragging = true;
22469 this.proxy.update("");
22470 this.onInitDrag(x, y);
22475 onInitDrag : function(x, y){
22476 var clone = this.el.dom.cloneNode(true);
22477 clone.id = Roo.id(); // prevent duplicate ids
22478 this.proxy.update(clone);
22479 this.onStartDrag(x, y);
22484 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22485 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22487 getProxy : function(){
22492 * Hides the drag source's {@link Roo.dd.StatusProxy}
22494 hideProxy : function(){
22496 this.proxy.reset(true);
22497 this.dragging = false;
22501 triggerCacheRefresh : function(){
22502 Roo.dd.DDM.refreshCache(this.groups);
22505 // private - override to prevent hiding
22506 b4EndDrag: function(e) {
22509 // private - override to prevent moving
22510 endDrag : function(e){
22511 this.onEndDrag(this.dragData, e);
22515 onEndDrag : function(data, e){
22518 // private - pin to cursor
22519 autoOffset : function(x, y) {
22520 this.setDelta(-12, -20);
22524 * Ext JS Library 1.1.1
22525 * Copyright(c) 2006-2007, Ext JS, LLC.
22527 * Originally Released Under LGPL - original licence link has changed is not relivant.
22530 * <script type="text/javascript">
22535 * @class Roo.dd.DropTarget
22536 * @extends Roo.dd.DDTarget
22537 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22538 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22540 * @param {String/HTMLElement/Element} el The container element
22541 * @param {Object} config
22543 Roo.dd.DropTarget = function(el, config){
22544 this.el = Roo.get(el);
22546 var listeners = false; ;
22547 if (config && config.listeners) {
22548 listeners= config.listeners;
22549 delete config.listeners;
22551 Roo.apply(this, config);
22553 if(this.containerScroll){
22554 Roo.dd.ScrollManager.register(this.el);
22558 * @scope Roo.dd.DropTarget
22563 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22564 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22565 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22567 * IMPORTANT : it should set this.overClass and this.dropAllowed
22569 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22570 * @param {Event} e The event
22571 * @param {Object} data An object containing arbitrary data supplied by the drag source
22577 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22578 * This method will be called on every mouse movement while the drag source is over the drop target.
22579 * This default implementation simply returns the dropAllowed config value.
22581 * IMPORTANT : it should set this.dropAllowed
22583 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22584 * @param {Event} e The event
22585 * @param {Object} data An object containing arbitrary data supplied by the drag source
22591 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22592 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22593 * overClass (if any) from the drop element.
22595 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22596 * @param {Event} e The event
22597 * @param {Object} data An object containing arbitrary data supplied by the drag source
22603 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22604 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22605 * implementation that does something to process the drop event and returns true so that the drag source's
22606 * repair action does not run.
22608 * IMPORTANT : it should set this.success
22610 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22611 * @param {Event} e The event
22612 * @param {Object} data An object containing arbitrary data supplied by the drag source
22618 Roo.dd.DropTarget.superclass.constructor.call( this,
22620 this.ddGroup || this.group,
22623 listeners : listeners || {}
22631 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22633 * @cfg {String} overClass
22634 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22637 * @cfg {String} ddGroup
22638 * The drag drop group to handle drop events for
22642 * @cfg {String} dropAllowed
22643 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22645 dropAllowed : "x-dd-drop-ok",
22647 * @cfg {String} dropNotAllowed
22648 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22650 dropNotAllowed : "x-dd-drop-nodrop",
22652 * @cfg {boolean} success
22653 * set this after drop listener..
22657 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22658 * if the drop point is valid for over/enter..
22665 isNotifyTarget : true,
22670 notifyEnter : function(dd, e, data)
22673 this.fireEvent('enter', dd, e, data);
22674 if(this.overClass){
22675 this.el.addClass(this.overClass);
22677 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22678 this.valid ? this.dropAllowed : this.dropNotAllowed
22685 notifyOver : function(dd, e, data)
22688 this.fireEvent('over', dd, e, data);
22689 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22690 this.valid ? this.dropAllowed : this.dropNotAllowed
22697 notifyOut : function(dd, e, data)
22699 this.fireEvent('out', dd, e, data);
22700 if(this.overClass){
22701 this.el.removeClass(this.overClass);
22708 notifyDrop : function(dd, e, data)
22710 this.success = false;
22711 this.fireEvent('drop', dd, e, data);
22712 return this.success;
22716 * Ext JS Library 1.1.1
22717 * Copyright(c) 2006-2007, Ext JS, LLC.
22719 * Originally Released Under LGPL - original licence link has changed is not relivant.
22722 * <script type="text/javascript">
22727 * @class Roo.dd.DragZone
22728 * @extends Roo.dd.DragSource
22729 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22730 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22732 * @param {String/HTMLElement/Element} el The container element
22733 * @param {Object} config
22735 Roo.dd.DragZone = function(el, config){
22736 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22737 if(this.containerScroll){
22738 Roo.dd.ScrollManager.register(this.el);
22742 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22744 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22745 * for auto scrolling during drag operations.
22748 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22749 * method after a failed drop (defaults to "c3daf9" - light blue)
22753 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22754 * for a valid target to drag based on the mouse down. Override this method
22755 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22756 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22757 * @param {EventObject} e The mouse down event
22758 * @return {Object} The dragData
22760 getDragData : function(e){
22761 return Roo.dd.Registry.getHandleFromEvent(e);
22765 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22766 * this.dragData.ddel
22767 * @param {Number} x The x position of the click on the dragged object
22768 * @param {Number} y The y position of the click on the dragged object
22769 * @return {Boolean} true to continue the drag, false to cancel
22771 onInitDrag : function(x, y){
22772 this.proxy.update(this.dragData.ddel.cloneNode(true));
22773 this.onStartDrag(x, y);
22778 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22780 afterRepair : function(){
22782 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22784 this.dragging = false;
22788 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22789 * the XY of this.dragData.ddel
22790 * @param {EventObject} e The mouse up event
22791 * @return {Array} The xy location (e.g. [100, 200])
22793 getRepairXY : function(e){
22794 return Roo.Element.fly(this.dragData.ddel).getXY();
22798 * Ext JS Library 1.1.1
22799 * Copyright(c) 2006-2007, Ext JS, LLC.
22801 * Originally Released Under LGPL - original licence link has changed is not relivant.
22804 * <script type="text/javascript">
22807 * @class Roo.dd.DropZone
22808 * @extends Roo.dd.DropTarget
22809 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22810 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22812 * @param {String/HTMLElement/Element} el The container element
22813 * @param {Object} config
22815 Roo.dd.DropZone = function(el, config){
22816 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22819 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22821 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22822 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22823 * provide your own custom lookup.
22824 * @param {Event} e The event
22825 * @return {Object} data The custom data
22827 getTargetFromEvent : function(e){
22828 return Roo.dd.Registry.getTargetFromEvent(e);
22832 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22833 * that it has registered. This method has no default implementation and should be overridden to provide
22834 * node-specific processing if necessary.
22835 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22836 * {@link #getTargetFromEvent} for this node)
22837 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22838 * @param {Event} e The event
22839 * @param {Object} data An object containing arbitrary data supplied by the drag source
22841 onNodeEnter : function(n, dd, e, data){
22846 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22847 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22848 * overridden to provide the proper feedback.
22849 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22850 * {@link #getTargetFromEvent} for this node)
22851 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22852 * @param {Event} e The event
22853 * @param {Object} data An object containing arbitrary data supplied by the drag source
22854 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22855 * underlying {@link Roo.dd.StatusProxy} can be updated
22857 onNodeOver : function(n, dd, e, data){
22858 return this.dropAllowed;
22862 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22863 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22864 * node-specific processing if necessary.
22865 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22866 * {@link #getTargetFromEvent} for this node)
22867 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22868 * @param {Event} e The event
22869 * @param {Object} data An object containing arbitrary data supplied by the drag source
22871 onNodeOut : function(n, dd, e, data){
22876 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22877 * the drop node. The default implementation returns false, so it should be overridden to provide the
22878 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22879 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22880 * {@link #getTargetFromEvent} for this node)
22881 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22882 * @param {Event} e The event
22883 * @param {Object} data An object containing arbitrary data supplied by the drag source
22884 * @return {Boolean} True if the drop was valid, else false
22886 onNodeDrop : function(n, dd, e, data){
22891 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22892 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22893 * it should be overridden to provide the proper feedback if necessary.
22894 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22895 * @param {Event} e The event
22896 * @param {Object} data An object containing arbitrary data supplied by the drag source
22897 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22898 * underlying {@link Roo.dd.StatusProxy} can be updated
22900 onContainerOver : function(dd, e, data){
22901 return this.dropNotAllowed;
22905 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22906 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22907 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22908 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22909 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22910 * @param {Event} e The event
22911 * @param {Object} data An object containing arbitrary data supplied by the drag source
22912 * @return {Boolean} True if the drop was valid, else false
22914 onContainerDrop : function(dd, e, data){
22919 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22920 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22921 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22922 * you should override this method and provide a custom implementation.
22923 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22924 * @param {Event} e The event
22925 * @param {Object} data An object containing arbitrary data supplied by the drag source
22926 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22927 * underlying {@link Roo.dd.StatusProxy} can be updated
22929 notifyEnter : function(dd, e, data){
22930 return this.dropNotAllowed;
22934 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22935 * This method will be called on every mouse movement while the drag source is over the drop zone.
22936 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22937 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22938 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22939 * registered node, it will call {@link #onContainerOver}.
22940 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22941 * @param {Event} e The event
22942 * @param {Object} data An object containing arbitrary data supplied by the drag source
22943 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22944 * underlying {@link Roo.dd.StatusProxy} can be updated
22946 notifyOver : function(dd, e, data){
22947 var n = this.getTargetFromEvent(e);
22948 if(!n){ // not over valid drop target
22949 if(this.lastOverNode){
22950 this.onNodeOut(this.lastOverNode, dd, e, data);
22951 this.lastOverNode = null;
22953 return this.onContainerOver(dd, e, data);
22955 if(this.lastOverNode != n){
22956 if(this.lastOverNode){
22957 this.onNodeOut(this.lastOverNode, dd, e, data);
22959 this.onNodeEnter(n, dd, e, data);
22960 this.lastOverNode = n;
22962 return this.onNodeOver(n, dd, e, data);
22966 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22967 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22968 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22969 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22970 * @param {Event} e The event
22971 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22973 notifyOut : function(dd, e, data){
22974 if(this.lastOverNode){
22975 this.onNodeOut(this.lastOverNode, dd, e, data);
22976 this.lastOverNode = null;
22981 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22982 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22983 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22984 * otherwise it will call {@link #onContainerDrop}.
22985 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22986 * @param {Event} e The event
22987 * @param {Object} data An object containing arbitrary data supplied by the drag source
22988 * @return {Boolean} True if the drop was valid, else false
22990 notifyDrop : function(dd, e, data){
22991 if(this.lastOverNode){
22992 this.onNodeOut(this.lastOverNode, dd, e, data);
22993 this.lastOverNode = null;
22995 var n = this.getTargetFromEvent(e);
22997 this.onNodeDrop(n, dd, e, data) :
22998 this.onContainerDrop(dd, e, data);
23002 triggerCacheRefresh : function(){
23003 Roo.dd.DDM.refreshCache(this.groups);
23007 * Ext JS Library 1.1.1
23008 * Copyright(c) 2006-2007, Ext JS, LLC.
23010 * Originally Released Under LGPL - original licence link has changed is not relivant.
23013 * <script type="text/javascript">
23018 * @class Roo.data.SortTypes
23020 * Defines the default sorting (casting?) comparison functions used when sorting data.
23022 Roo.data.SortTypes = {
23024 * Default sort that does nothing
23025 * @param {Mixed} s The value being converted
23026 * @return {Mixed} The comparison value
23028 none : function(s){
23033 * The regular expression used to strip tags
23037 stripTagsRE : /<\/?[^>]+>/gi,
23040 * Strips all HTML tags to sort on text only
23041 * @param {Mixed} s The value being converted
23042 * @return {String} The comparison value
23044 asText : function(s){
23045 return String(s).replace(this.stripTagsRE, "");
23049 * Strips all HTML tags to sort on text only - Case insensitive
23050 * @param {Mixed} s The value being converted
23051 * @return {String} The comparison value
23053 asUCText : function(s){
23054 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23058 * Case insensitive string
23059 * @param {Mixed} s The value being converted
23060 * @return {String} The comparison value
23062 asUCString : function(s) {
23063 return String(s).toUpperCase();
23068 * @param {Mixed} s The value being converted
23069 * @return {Number} The comparison value
23071 asDate : function(s) {
23075 if(s instanceof Date){
23076 return s.getTime();
23078 return Date.parse(String(s));
23083 * @param {Mixed} s The value being converted
23084 * @return {Float} The comparison value
23086 asFloat : function(s) {
23087 var val = parseFloat(String(s).replace(/,/g, ""));
23096 * @param {Mixed} s The value being converted
23097 * @return {Number} The comparison value
23099 asInt : function(s) {
23100 var val = parseInt(String(s).replace(/,/g, ""));
23108 * Ext JS Library 1.1.1
23109 * Copyright(c) 2006-2007, Ext JS, LLC.
23111 * Originally Released Under LGPL - original licence link has changed is not relivant.
23114 * <script type="text/javascript">
23118 * @class Roo.data.Record
23119 * Instances of this class encapsulate both record <em>definition</em> information, and record
23120 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
23121 * to access Records cached in an {@link Roo.data.Store} object.<br>
23123 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
23124 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
23127 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
23129 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
23130 * {@link #create}. The parameters are the same.
23131 * @param {Array} data An associative Array of data values keyed by the field name.
23132 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
23133 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
23134 * not specified an integer id is generated.
23136 Roo.data.Record = function(data, id){
23137 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
23142 * Generate a constructor for a specific record layout.
23143 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
23144 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
23145 * Each field definition object may contain the following properties: <ul>
23146 * <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,
23147 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
23148 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
23149 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
23150 * is being used, then this is a string containing the javascript expression to reference the data relative to
23151 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
23152 * to the data item relative to the record element. If the mapping expression is the same as the field name,
23153 * this may be omitted.</p></li>
23154 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
23155 * <ul><li>auto (Default, implies no conversion)</li>
23160 * <li>date</li></ul></p></li>
23161 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
23162 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
23163 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
23164 * by the Reader into an object that will be stored in the Record. It is passed the
23165 * following parameters:<ul>
23166 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
23168 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
23170 * <br>usage:<br><pre><code>
23171 var TopicRecord = Roo.data.Record.create(
23172 {name: 'title', mapping: 'topic_title'},
23173 {name: 'author', mapping: 'username'},
23174 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
23175 {name: 'lastPost', mapping: 'post_time', type: 'date'},
23176 {name: 'lastPoster', mapping: 'user2'},
23177 {name: 'excerpt', mapping: 'post_text'}
23180 var myNewRecord = new TopicRecord({
23181 title: 'Do my job please',
23184 lastPost: new Date(),
23185 lastPoster: 'Animal',
23186 excerpt: 'No way dude!'
23188 myStore.add(myNewRecord);
23193 Roo.data.Record.create = function(o){
23194 var f = function(){
23195 f.superclass.constructor.apply(this, arguments);
23197 Roo.extend(f, Roo.data.Record);
23198 var p = f.prototype;
23199 p.fields = new Roo.util.MixedCollection(false, function(field){
23202 for(var i = 0, len = o.length; i < len; i++){
23203 p.fields.add(new Roo.data.Field(o[i]));
23205 f.getField = function(name){
23206 return p.fields.get(name);
23211 Roo.data.Record.AUTO_ID = 1000;
23212 Roo.data.Record.EDIT = 'edit';
23213 Roo.data.Record.REJECT = 'reject';
23214 Roo.data.Record.COMMIT = 'commit';
23216 Roo.data.Record.prototype = {
23218 * Readonly flag - true if this record has been modified.
23227 join : function(store){
23228 this.store = store;
23232 * Set the named field to the specified value.
23233 * @param {String} name The name of the field to set.
23234 * @param {Object} value The value to set the field to.
23236 set : function(name, value){
23237 if(this.data[name] == value){
23241 if(!this.modified){
23242 this.modified = {};
23244 if(typeof this.modified[name] == 'undefined'){
23245 this.modified[name] = this.data[name];
23247 this.data[name] = value;
23248 if(!this.editing && this.store){
23249 this.store.afterEdit(this);
23254 * Get the value of the named field.
23255 * @param {String} name The name of the field to get the value of.
23256 * @return {Object} The value of the field.
23258 get : function(name){
23259 return this.data[name];
23263 beginEdit : function(){
23264 this.editing = true;
23265 this.modified = {};
23269 cancelEdit : function(){
23270 this.editing = false;
23271 delete this.modified;
23275 endEdit : function(){
23276 this.editing = false;
23277 if(this.dirty && this.store){
23278 this.store.afterEdit(this);
23283 * Usually called by the {@link Roo.data.Store} which owns the Record.
23284 * Rejects all changes made to the Record since either creation, or the last commit operation.
23285 * Modified fields are reverted to their original values.
23287 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23288 * of reject operations.
23290 reject : function(){
23291 var m = this.modified;
23293 if(typeof m[n] != "function"){
23294 this.data[n] = m[n];
23297 this.dirty = false;
23298 delete this.modified;
23299 this.editing = false;
23301 this.store.afterReject(this);
23306 * Usually called by the {@link Roo.data.Store} which owns the Record.
23307 * Commits all changes made to the Record since either creation, or the last commit operation.
23309 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23310 * of commit operations.
23312 commit : function(){
23313 this.dirty = false;
23314 delete this.modified;
23315 this.editing = false;
23317 this.store.afterCommit(this);
23322 hasError : function(){
23323 return this.error != null;
23327 clearError : function(){
23332 * Creates a copy of this record.
23333 * @param {String} id (optional) A new record id if you don't want to use this record's id
23336 copy : function(newId) {
23337 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
23341 * Ext JS Library 1.1.1
23342 * Copyright(c) 2006-2007, Ext JS, LLC.
23344 * Originally Released Under LGPL - original licence link has changed is not relivant.
23347 * <script type="text/javascript">
23353 * @class Roo.data.Store
23354 * @extends Roo.util.Observable
23355 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
23356 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
23358 * 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
23359 * has no knowledge of the format of the data returned by the Proxy.<br>
23361 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
23362 * instances from the data object. These records are cached and made available through accessor functions.
23364 * Creates a new Store.
23365 * @param {Object} config A config object containing the objects needed for the Store to access data,
23366 * and read the data into Records.
23368 Roo.data.Store = function(config){
23369 this.data = new Roo.util.MixedCollection(false);
23370 this.data.getKey = function(o){
23373 this.baseParams = {};
23375 this.paramNames = {
23380 "multisort" : "_multisort"
23383 if(config && config.data){
23384 this.inlineData = config.data;
23385 delete config.data;
23388 Roo.apply(this, config);
23390 if(this.reader){ // reader passed
23391 this.reader = Roo.factory(this.reader, Roo.data);
23392 this.reader.xmodule = this.xmodule || false;
23393 if(!this.recordType){
23394 this.recordType = this.reader.recordType;
23396 if(this.reader.onMetaChange){
23397 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
23401 if(this.recordType){
23402 this.fields = this.recordType.prototype.fields;
23404 this.modified = [];
23408 * @event datachanged
23409 * Fires when the data cache has changed, and a widget which is using this Store
23410 * as a Record cache should refresh its view.
23411 * @param {Store} this
23413 datachanged : true,
23415 * @event metachange
23416 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
23417 * @param {Store} this
23418 * @param {Object} meta The JSON metadata
23423 * Fires when Records have been added to the Store
23424 * @param {Store} this
23425 * @param {Roo.data.Record[]} records The array of Records added
23426 * @param {Number} index The index at which the record(s) were added
23431 * Fires when a Record has been removed from the Store
23432 * @param {Store} this
23433 * @param {Roo.data.Record} record The Record that was removed
23434 * @param {Number} index The index at which the record was removed
23439 * Fires when a Record has been updated
23440 * @param {Store} this
23441 * @param {Roo.data.Record} record The Record that was updated
23442 * @param {String} operation The update operation being performed. Value may be one of:
23444 Roo.data.Record.EDIT
23445 Roo.data.Record.REJECT
23446 Roo.data.Record.COMMIT
23452 * Fires when the data cache has been cleared.
23453 * @param {Store} this
23457 * @event beforeload
23458 * Fires before a request is made for a new data object. If the beforeload handler returns false
23459 * the load action will be canceled.
23460 * @param {Store} this
23461 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23465 * @event beforeloadadd
23466 * Fires after a new set of Records has been loaded.
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)
23471 beforeloadadd : true,
23474 * Fires after a new set of Records has been loaded, before they are added to the store.
23475 * @param {Store} this
23476 * @param {Roo.data.Record[]} records The Records that were loaded
23477 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23478 * @params {Object} return from reader
23482 * @event loadexception
23483 * Fires if an exception occurs in the Proxy during loading.
23484 * Called with the signature of the Proxy's "loadexception" event.
23485 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
23488 * @param {Object} return from JsonData.reader() - success, totalRecords, records
23489 * @param {Object} load options
23490 * @param {Object} jsonData from your request (normally this contains the Exception)
23492 loadexception : true
23496 this.proxy = Roo.factory(this.proxy, Roo.data);
23497 this.proxy.xmodule = this.xmodule || false;
23498 this.relayEvents(this.proxy, ["loadexception"]);
23500 this.sortToggle = {};
23501 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
23503 Roo.data.Store.superclass.constructor.call(this);
23505 if(this.inlineData){
23506 this.loadData(this.inlineData);
23507 delete this.inlineData;
23511 Roo.extend(Roo.data.Store, Roo.util.Observable, {
23513 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
23514 * without a remote query - used by combo/forms at present.
23518 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
23521 * @cfg {Array} data Inline data to be loaded when the store is initialized.
23524 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
23525 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
23528 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
23529 * on any HTTP request
23532 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
23535 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
23539 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
23540 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
23542 remoteSort : false,
23545 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
23546 * loaded or when a record is removed. (defaults to false).
23548 pruneModifiedRecords : false,
23551 lastOptions : null,
23554 * Add Records to the Store and fires the add event.
23555 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23557 add : function(records){
23558 records = [].concat(records);
23559 for(var i = 0, len = records.length; i < len; i++){
23560 records[i].join(this);
23562 var index = this.data.length;
23563 this.data.addAll(records);
23564 this.fireEvent("add", this, records, index);
23568 * Remove a Record from the Store and fires the remove event.
23569 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23571 remove : function(record){
23572 var index = this.data.indexOf(record);
23573 this.data.removeAt(index);
23575 if(this.pruneModifiedRecords){
23576 this.modified.remove(record);
23578 this.fireEvent("remove", this, record, index);
23582 * Remove all Records from the Store and fires the clear event.
23584 removeAll : function(){
23586 if(this.pruneModifiedRecords){
23587 this.modified = [];
23589 this.fireEvent("clear", this);
23593 * Inserts Records to the Store at the given index and fires the add event.
23594 * @param {Number} index The start index at which to insert the passed Records.
23595 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23597 insert : function(index, records){
23598 records = [].concat(records);
23599 for(var i = 0, len = records.length; i < len; i++){
23600 this.data.insert(index, records[i]);
23601 records[i].join(this);
23603 this.fireEvent("add", this, records, index);
23607 * Get the index within the cache of the passed Record.
23608 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23609 * @return {Number} The index of the passed Record. Returns -1 if not found.
23611 indexOf : function(record){
23612 return this.data.indexOf(record);
23616 * Get the index within the cache of the Record with the passed id.
23617 * @param {String} id The id of the Record to find.
23618 * @return {Number} The index of the Record. Returns -1 if not found.
23620 indexOfId : function(id){
23621 return this.data.indexOfKey(id);
23625 * Get the Record with the specified id.
23626 * @param {String} id The id of the Record to find.
23627 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23629 getById : function(id){
23630 return this.data.key(id);
23634 * Get the Record at the specified index.
23635 * @param {Number} index The index of the Record to find.
23636 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23638 getAt : function(index){
23639 return this.data.itemAt(index);
23643 * Returns a range of Records between specified indices.
23644 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23645 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23646 * @return {Roo.data.Record[]} An array of Records
23648 getRange : function(start, end){
23649 return this.data.getRange(start, end);
23653 storeOptions : function(o){
23654 o = Roo.apply({}, o);
23657 this.lastOptions = o;
23661 * Loads the Record cache from the configured Proxy using the configured Reader.
23663 * If using remote paging, then the first load call must specify the <em>start</em>
23664 * and <em>limit</em> properties in the options.params property to establish the initial
23665 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23667 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23668 * and this call will return before the new data has been loaded. Perform any post-processing
23669 * in a callback function, or in a "load" event handler.</strong>
23671 * @param {Object} options An object containing properties which control loading options:<ul>
23672 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23673 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23674 * passed the following arguments:<ul>
23675 * <li>r : Roo.data.Record[]</li>
23676 * <li>options: Options object from the load call</li>
23677 * <li>success: Boolean success indicator</li></ul></li>
23678 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23679 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23682 load : function(options){
23683 options = options || {};
23684 if(this.fireEvent("beforeload", this, options) !== false){
23685 this.storeOptions(options);
23686 var p = Roo.apply(options.params || {}, this.baseParams);
23687 // if meta was not loaded from remote source.. try requesting it.
23688 if (!this.reader.metaFromRemote) {
23689 p._requestMeta = 1;
23691 if(this.sortInfo && this.remoteSort){
23692 var pn = this.paramNames;
23693 p[pn["sort"]] = this.sortInfo.field;
23694 p[pn["dir"]] = this.sortInfo.direction;
23696 if (this.multiSort) {
23697 var pn = this.paramNames;
23698 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23701 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23706 * Reloads the Record cache from the configured Proxy using the configured Reader and
23707 * the options from the last load operation performed.
23708 * @param {Object} options (optional) An object containing properties which may override the options
23709 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23710 * the most recently used options are reused).
23712 reload : function(options){
23713 this.load(Roo.applyIf(options||{}, this.lastOptions));
23717 // Called as a callback by the Reader during a load operation.
23718 loadRecords : function(o, options, success){
23719 if(!o || success === false){
23720 if(success !== false){
23721 this.fireEvent("load", this, [], options, o);
23723 if(options.callback){
23724 options.callback.call(options.scope || this, [], options, false);
23728 // if data returned failure - throw an exception.
23729 if (o.success === false) {
23730 // show a message if no listener is registered.
23731 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23732 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23734 // loadmask wil be hooked into this..
23735 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23738 var r = o.records, t = o.totalRecords || r.length;
23740 this.fireEvent("beforeloadadd", this, r, options, o);
23742 if(!options || options.add !== true){
23743 if(this.pruneModifiedRecords){
23744 this.modified = [];
23746 for(var i = 0, len = r.length; i < len; i++){
23750 this.data = this.snapshot;
23751 delete this.snapshot;
23754 this.data.addAll(r);
23755 this.totalLength = t;
23757 this.fireEvent("datachanged", this);
23759 this.totalLength = Math.max(t, this.data.length+r.length);
23763 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23765 var e = new Roo.data.Record({});
23767 e.set(this.parent.displayField, this.parent.emptyTitle);
23768 e.set(this.parent.valueField, '');
23773 this.fireEvent("load", this, r, options, o);
23774 if(options.callback){
23775 options.callback.call(options.scope || this, r, options, true);
23781 * Loads data from a passed data block. A Reader which understands the format of the data
23782 * must have been configured in the constructor.
23783 * @param {Object} data The data block from which to read the Records. The format of the data expected
23784 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23785 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23787 loadData : function(o, append){
23788 var r = this.reader.readRecords(o);
23789 this.loadRecords(r, {add: append}, true);
23793 * using 'cn' the nested child reader read the child array into it's child stores.
23794 * @param {Object} rec The record with a 'children array
23796 loadDataFromChildren : function(rec)
23798 this.loadData(this.reader.toLoadData(rec));
23803 * Gets the number of cached records.
23805 * <em>If using paging, this may not be the total size of the dataset. If the data object
23806 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23807 * the data set size</em>
23809 getCount : function(){
23810 return this.data.length || 0;
23814 * Gets the total number of records in the dataset as returned by the server.
23816 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23817 * the dataset size</em>
23819 getTotalCount : function(){
23820 return this.totalLength || 0;
23824 * Returns the sort state of the Store as an object with two properties:
23826 field {String} The name of the field by which the Records are sorted
23827 direction {String} The sort order, "ASC" or "DESC"
23830 getSortState : function(){
23831 return this.sortInfo;
23835 applySort : function(){
23836 if(this.sortInfo && !this.remoteSort){
23837 var s = this.sortInfo, f = s.field;
23838 var st = this.fields.get(f).sortType;
23839 var fn = function(r1, r2){
23840 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23841 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23843 this.data.sort(s.direction, fn);
23844 if(this.snapshot && this.snapshot != this.data){
23845 this.snapshot.sort(s.direction, fn);
23851 * Sets the default sort column and order to be used by the next load operation.
23852 * @param {String} fieldName The name of the field to sort by.
23853 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23855 setDefaultSort : function(field, dir){
23856 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23860 * Sort the Records.
23861 * If remote sorting is used, the sort is performed on the server, and the cache is
23862 * reloaded. If local sorting is used, the cache is sorted internally.
23863 * @param {String} fieldName The name of the field to sort by.
23864 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23866 sort : function(fieldName, dir){
23867 var f = this.fields.get(fieldName);
23869 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23871 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23872 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23877 this.sortToggle[f.name] = dir;
23878 this.sortInfo = {field: f.name, direction: dir};
23879 if(!this.remoteSort){
23881 this.fireEvent("datachanged", this);
23883 this.load(this.lastOptions);
23888 * Calls the specified function for each of the Records in the cache.
23889 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23890 * Returning <em>false</em> aborts and exits the iteration.
23891 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23893 each : function(fn, scope){
23894 this.data.each(fn, scope);
23898 * Gets all records modified since the last commit. Modified records are persisted across load operations
23899 * (e.g., during paging).
23900 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23902 getModifiedRecords : function(){
23903 return this.modified;
23907 createFilterFn : function(property, value, anyMatch){
23908 if(!value.exec){ // not a regex
23909 value = String(value);
23910 if(value.length == 0){
23913 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23915 return function(r){
23916 return value.test(r.data[property]);
23921 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23922 * @param {String} property A field on your records
23923 * @param {Number} start The record index to start at (defaults to 0)
23924 * @param {Number} end The last record index to include (defaults to length - 1)
23925 * @return {Number} The sum
23927 sum : function(property, start, end){
23928 var rs = this.data.items, v = 0;
23929 start = start || 0;
23930 end = (end || end === 0) ? end : rs.length-1;
23932 for(var i = start; i <= end; i++){
23933 v += (rs[i].data[property] || 0);
23939 * Filter the records by a specified property.
23940 * @param {String} field A field on your records
23941 * @param {String/RegExp} value Either a string that the field
23942 * should start with or a RegExp to test against the field
23943 * @param {Boolean} anyMatch True to match any part not just the beginning
23945 filter : function(property, value, anyMatch){
23946 var fn = this.createFilterFn(property, value, anyMatch);
23947 return fn ? this.filterBy(fn) : this.clearFilter();
23951 * Filter by a function. The specified function will be called with each
23952 * record in this data source. If the function returns true the record is included,
23953 * otherwise it is filtered.
23954 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23955 * @param {Object} scope (optional) The scope of the function (defaults to this)
23957 filterBy : function(fn, scope){
23958 this.snapshot = this.snapshot || this.data;
23959 this.data = this.queryBy(fn, scope||this);
23960 this.fireEvent("datachanged", this);
23964 * Query the records by a specified property.
23965 * @param {String} field A field on your records
23966 * @param {String/RegExp} value Either a string that the field
23967 * should start with or a RegExp to test against the field
23968 * @param {Boolean} anyMatch True to match any part not just the beginning
23969 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23971 query : function(property, value, anyMatch){
23972 var fn = this.createFilterFn(property, value, anyMatch);
23973 return fn ? this.queryBy(fn) : this.data.clone();
23977 * Query by a function. The specified function will be called with each
23978 * record in this data source. If the function returns true the record is included
23980 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23981 * @param {Object} scope (optional) The scope of the function (defaults to this)
23982 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23984 queryBy : function(fn, scope){
23985 var data = this.snapshot || this.data;
23986 return data.filterBy(fn, scope||this);
23990 * Collects unique values for a particular dataIndex from this store.
23991 * @param {String} dataIndex The property to collect
23992 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23993 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23994 * @return {Array} An array of the unique values
23996 collect : function(dataIndex, allowNull, bypassFilter){
23997 var d = (bypassFilter === true && this.snapshot) ?
23998 this.snapshot.items : this.data.items;
23999 var v, sv, r = [], l = {};
24000 for(var i = 0, len = d.length; i < len; i++){
24001 v = d[i].data[dataIndex];
24003 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24012 * Revert to a view of the Record cache with no filtering applied.
24013 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24015 clearFilter : function(suppressEvent){
24016 if(this.snapshot && this.snapshot != this.data){
24017 this.data = this.snapshot;
24018 delete this.snapshot;
24019 if(suppressEvent !== true){
24020 this.fireEvent("datachanged", this);
24026 afterEdit : function(record){
24027 if(this.modified.indexOf(record) == -1){
24028 this.modified.push(record);
24030 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24034 afterReject : function(record){
24035 this.modified.remove(record);
24036 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24040 afterCommit : function(record){
24041 this.modified.remove(record);
24042 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24046 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24047 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24049 commitChanges : function(){
24050 var m = this.modified.slice(0);
24051 this.modified = [];
24052 for(var i = 0, len = m.length; i < len; i++){
24058 * Cancel outstanding changes on all changed records.
24060 rejectChanges : function(){
24061 var m = this.modified.slice(0);
24062 this.modified = [];
24063 for(var i = 0, len = m.length; i < len; i++){
24068 onMetaChange : function(meta, rtype, o){
24069 this.recordType = rtype;
24070 this.fields = rtype.prototype.fields;
24071 delete this.snapshot;
24072 this.sortInfo = meta.sortInfo || this.sortInfo;
24073 this.modified = [];
24074 this.fireEvent('metachange', this, this.reader.meta);
24077 moveIndex : function(data, type)
24079 var index = this.indexOf(data);
24081 var newIndex = index + type;
24085 this.insert(newIndex, data);
24090 * Ext JS Library 1.1.1
24091 * Copyright(c) 2006-2007, Ext JS, LLC.
24093 * Originally Released Under LGPL - original licence link has changed is not relivant.
24096 * <script type="text/javascript">
24100 * @class Roo.data.SimpleStore
24101 * @extends Roo.data.Store
24102 * Small helper class to make creating Stores from Array data easier.
24103 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24104 * @cfg {Array} fields An array of field definition objects, or field name strings.
24105 * @cfg {Object} an existing reader (eg. copied from another store)
24106 * @cfg {Array} data The multi-dimensional array of data
24108 * @param {Object} config
24110 Roo.data.SimpleStore = function(config)
24112 Roo.data.SimpleStore.superclass.constructor.call(this, {
24114 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24117 Roo.data.Record.create(config.fields)
24119 proxy : new Roo.data.MemoryProxy(config.data)
24123 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24125 * Ext JS Library 1.1.1
24126 * Copyright(c) 2006-2007, Ext JS, LLC.
24128 * Originally Released Under LGPL - original licence link has changed is not relivant.
24131 * <script type="text/javascript">
24136 * @extends Roo.data.Store
24137 * @class Roo.data.JsonStore
24138 * Small helper class to make creating Stores for JSON data easier. <br/>
24140 var store = new Roo.data.JsonStore({
24141 url: 'get-images.php',
24143 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24146 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24147 * JsonReader and HttpProxy (unless inline data is provided).</b>
24148 * @cfg {Array} fields An array of field definition objects, or field name strings.
24150 * @param {Object} config
24152 Roo.data.JsonStore = function(c){
24153 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24154 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24155 reader: new Roo.data.JsonReader(c, c.fields)
24158 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
24160 * Ext JS Library 1.1.1
24161 * Copyright(c) 2006-2007, Ext JS, LLC.
24163 * Originally Released Under LGPL - original licence link has changed is not relivant.
24166 * <script type="text/javascript">
24170 Roo.data.Field = function(config){
24171 if(typeof config == "string"){
24172 config = {name: config};
24174 Roo.apply(this, config);
24177 this.type = "auto";
24180 var st = Roo.data.SortTypes;
24181 // named sortTypes are supported, here we look them up
24182 if(typeof this.sortType == "string"){
24183 this.sortType = st[this.sortType];
24186 // set default sortType for strings and dates
24187 if(!this.sortType){
24190 this.sortType = st.asUCString;
24193 this.sortType = st.asDate;
24196 this.sortType = st.none;
24201 var stripRe = /[\$,%]/g;
24203 // prebuilt conversion function for this field, instead of
24204 // switching every time we're reading a value
24206 var cv, dateFormat = this.dateFormat;
24211 cv = function(v){ return v; };
24214 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24218 return v !== undefined && v !== null && v !== '' ?
24219 parseInt(String(v).replace(stripRe, ""), 10) : '';
24224 return v !== undefined && v !== null && v !== '' ?
24225 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24230 cv = function(v){ return v === true || v === "true" || v == 1; };
24237 if(v instanceof Date){
24241 if(dateFormat == "timestamp"){
24242 return new Date(v*1000);
24244 return Date.parseDate(v, dateFormat);
24246 var parsed = Date.parse(v);
24247 return parsed ? new Date(parsed) : null;
24256 Roo.data.Field.prototype = {
24264 * Ext JS Library 1.1.1
24265 * Copyright(c) 2006-2007, Ext JS, LLC.
24267 * Originally Released Under LGPL - original licence link has changed is not relivant.
24270 * <script type="text/javascript">
24273 // Base class for reading structured data from a data source. This class is intended to be
24274 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24277 * @class Roo.data.DataReader
24278 * Base class for reading structured data from a data source. This class is intended to be
24279 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24282 Roo.data.DataReader = function(meta, recordType){
24286 this.recordType = recordType instanceof Array ?
24287 Roo.data.Record.create(recordType) : recordType;
24290 Roo.data.DataReader.prototype = {
24293 readerType : 'Data',
24295 * Create an empty record
24296 * @param {Object} data (optional) - overlay some values
24297 * @return {Roo.data.Record} record created.
24299 newRow : function(d) {
24301 this.recordType.prototype.fields.each(function(c) {
24303 case 'int' : da[c.name] = 0; break;
24304 case 'date' : da[c.name] = new Date(); break;
24305 case 'float' : da[c.name] = 0.0; break;
24306 case 'boolean' : da[c.name] = false; break;
24307 default : da[c.name] = ""; break;
24311 return new this.recordType(Roo.apply(da, d));
24317 * Ext JS Library 1.1.1
24318 * Copyright(c) 2006-2007, Ext JS, LLC.
24320 * Originally Released Under LGPL - original licence link has changed is not relivant.
24323 * <script type="text/javascript">
24327 * @class Roo.data.DataProxy
24328 * @extends Roo.data.Observable
24329 * This class is an abstract base class for implementations which provide retrieval of
24330 * unformatted data objects.<br>
24332 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24333 * (of the appropriate type which knows how to parse the data object) to provide a block of
24334 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24336 * Custom implementations must implement the load method as described in
24337 * {@link Roo.data.HttpProxy#load}.
24339 Roo.data.DataProxy = function(){
24342 * @event beforeload
24343 * Fires before a network request is made to retrieve a data object.
24344 * @param {Object} This DataProxy object.
24345 * @param {Object} params The params parameter to the load function.
24350 * Fires before the load method's callback is called.
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.
24357 * @event loadexception
24358 * Fires if an Exception occurs during data retrieval.
24359 * @param {Object} This DataProxy object.
24360 * @param {Object} o The data object.
24361 * @param {Object} arg The callback argument object passed to the load function.
24362 * @param {Object} e The Exception.
24364 loadexception : true
24366 Roo.data.DataProxy.superclass.constructor.call(this);
24369 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24372 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24376 * Ext JS Library 1.1.1
24377 * Copyright(c) 2006-2007, Ext JS, LLC.
24379 * Originally Released Under LGPL - original licence link has changed is not relivant.
24382 * <script type="text/javascript">
24385 * @class Roo.data.MemoryProxy
24386 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24387 * to the Reader when its load method is called.
24389 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24391 Roo.data.MemoryProxy = function(data){
24395 Roo.data.MemoryProxy.superclass.constructor.call(this);
24399 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24402 * Load data from the requested source (in this case an in-memory
24403 * data object passed to the constructor), read the data object into
24404 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24405 * process that block using the passed callback.
24406 * @param {Object} params This parameter is not used by the MemoryProxy class.
24407 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24408 * object into a block of Roo.data.Records.
24409 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24410 * The function must be passed <ul>
24411 * <li>The Record block object</li>
24412 * <li>The "arg" argument from the load function</li>
24413 * <li>A boolean success indicator</li>
24415 * @param {Object} scope The scope in which to call the callback
24416 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24418 load : function(params, reader, callback, scope, arg){
24419 params = params || {};
24422 result = reader.readRecords(params.data ? params.data :this.data);
24424 this.fireEvent("loadexception", this, arg, null, e);
24425 callback.call(scope, null, arg, false);
24428 callback.call(scope, result, arg, true);
24432 update : function(params, records){
24437 * Ext JS Library 1.1.1
24438 * Copyright(c) 2006-2007, Ext JS, LLC.
24440 * Originally Released Under LGPL - original licence link has changed is not relivant.
24443 * <script type="text/javascript">
24446 * @class Roo.data.HttpProxy
24447 * @extends Roo.data.DataProxy
24448 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24449 * configured to reference a certain URL.<br><br>
24451 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24452 * from which the running page was served.<br><br>
24454 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24456 * Be aware that to enable the browser to parse an XML document, the server must set
24457 * the Content-Type header in the HTTP response to "text/xml".
24459 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24460 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24461 * will be used to make the request.
24463 Roo.data.HttpProxy = function(conn){
24464 Roo.data.HttpProxy.superclass.constructor.call(this);
24465 // is conn a conn config or a real conn?
24467 this.useAjax = !conn || !conn.events;
24471 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24472 // thse are take from connection...
24475 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24478 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24479 * extra parameters to each request made by this object. (defaults to undefined)
24482 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24483 * to each request made by this object. (defaults to undefined)
24486 * @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)
24489 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24492 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24498 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24502 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24503 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24504 * a finer-grained basis than the DataProxy events.
24506 getConnection : function(){
24507 return this.useAjax ? Roo.Ajax : this.conn;
24511 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24512 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24513 * process that block using the passed callback.
24514 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24515 * for the request to the remote server.
24516 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24517 * object into a block of Roo.data.Records.
24518 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24519 * The function must be passed <ul>
24520 * <li>The Record block object</li>
24521 * <li>The "arg" argument from the load function</li>
24522 * <li>A boolean success indicator</li>
24524 * @param {Object} scope The scope in which to call the callback
24525 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24527 load : function(params, reader, callback, scope, arg){
24528 if(this.fireEvent("beforeload", this, params) !== false){
24530 params : params || {},
24532 callback : callback,
24537 callback : this.loadResponse,
24541 Roo.applyIf(o, this.conn);
24542 if(this.activeRequest){
24543 Roo.Ajax.abort(this.activeRequest);
24545 this.activeRequest = Roo.Ajax.request(o);
24547 this.conn.request(o);
24550 callback.call(scope||this, null, arg, false);
24555 loadResponse : function(o, success, response){
24556 delete this.activeRequest;
24558 this.fireEvent("loadexception", this, o, response);
24559 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24564 result = o.reader.read(response);
24566 this.fireEvent("loadexception", this, o, response, e);
24567 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24571 this.fireEvent("load", this, o, o.request.arg);
24572 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24576 update : function(dataSet){
24581 updateResponse : function(dataSet){
24586 * Ext JS Library 1.1.1
24587 * Copyright(c) 2006-2007, Ext JS, LLC.
24589 * Originally Released Under LGPL - original licence link has changed is not relivant.
24592 * <script type="text/javascript">
24596 * @class Roo.data.ScriptTagProxy
24597 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24598 * other than the originating domain of the running page.<br><br>
24600 * <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
24601 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24603 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24604 * source code that is used as the source inside a <script> tag.<br><br>
24606 * In order for the browser to process the returned data, the server must wrap the data object
24607 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24608 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24609 * depending on whether the callback name was passed:
24612 boolean scriptTag = false;
24613 String cb = request.getParameter("callback");
24616 response.setContentType("text/javascript");
24618 response.setContentType("application/x-json");
24620 Writer out = response.getWriter();
24622 out.write(cb + "(");
24624 out.print(dataBlock.toJsonString());
24631 * @param {Object} config A configuration object.
24633 Roo.data.ScriptTagProxy = function(config){
24634 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24635 Roo.apply(this, config);
24636 this.head = document.getElementsByTagName("head")[0];
24639 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24641 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24643 * @cfg {String} url The URL from which to request the data object.
24646 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24650 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24651 * the server the name of the callback function set up by the load call to process the returned data object.
24652 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24653 * javascript output which calls this named function passing the data object as its only parameter.
24655 callbackParam : "callback",
24657 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24658 * name to the request.
24663 * Load data from the configured URL, read the data object into
24664 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24665 * process that block using the passed callback.
24666 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24667 * for the request to the remote server.
24668 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24669 * object into a block of Roo.data.Records.
24670 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24671 * The function must be passed <ul>
24672 * <li>The Record block object</li>
24673 * <li>The "arg" argument from the load function</li>
24674 * <li>A boolean success indicator</li>
24676 * @param {Object} scope The scope in which to call the callback
24677 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24679 load : function(params, reader, callback, scope, arg){
24680 if(this.fireEvent("beforeload", this, params) !== false){
24682 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24684 var url = this.url;
24685 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24687 url += "&_dc=" + (new Date().getTime());
24689 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24692 cb : "stcCallback"+transId,
24693 scriptId : "stcScript"+transId,
24697 callback : callback,
24703 window[trans.cb] = function(o){
24704 conn.handleResponse(o, trans);
24707 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24709 if(this.autoAbort !== false){
24713 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24715 var script = document.createElement("script");
24716 script.setAttribute("src", url);
24717 script.setAttribute("type", "text/javascript");
24718 script.setAttribute("id", trans.scriptId);
24719 this.head.appendChild(script);
24721 this.trans = trans;
24723 callback.call(scope||this, null, arg, false);
24728 isLoading : function(){
24729 return this.trans ? true : false;
24733 * Abort the current server request.
24735 abort : function(){
24736 if(this.isLoading()){
24737 this.destroyTrans(this.trans);
24742 destroyTrans : function(trans, isLoaded){
24743 this.head.removeChild(document.getElementById(trans.scriptId));
24744 clearTimeout(trans.timeoutId);
24746 window[trans.cb] = undefined;
24748 delete window[trans.cb];
24751 // if hasn't been loaded, wait for load to remove it to prevent script error
24752 window[trans.cb] = function(){
24753 window[trans.cb] = undefined;
24755 delete window[trans.cb];
24762 handleResponse : function(o, trans){
24763 this.trans = false;
24764 this.destroyTrans(trans, true);
24767 result = trans.reader.readRecords(o);
24769 this.fireEvent("loadexception", this, o, trans.arg, e);
24770 trans.callback.call(trans.scope||window, null, trans.arg, false);
24773 this.fireEvent("load", this, o, trans.arg);
24774 trans.callback.call(trans.scope||window, result, trans.arg, true);
24778 handleFailure : function(trans){
24779 this.trans = false;
24780 this.destroyTrans(trans, false);
24781 this.fireEvent("loadexception", this, null, trans.arg);
24782 trans.callback.call(trans.scope||window, null, trans.arg, false);
24786 * Ext JS Library 1.1.1
24787 * Copyright(c) 2006-2007, Ext JS, LLC.
24789 * Originally Released Under LGPL - original licence link has changed is not relivant.
24792 * <script type="text/javascript">
24796 * @class Roo.data.JsonReader
24797 * @extends Roo.data.DataReader
24798 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24799 * based on mappings in a provided Roo.data.Record constructor.
24801 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24802 * in the reply previously.
24807 var RecordDef = Roo.data.Record.create([
24808 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24809 {name: 'occupation'} // This field will use "occupation" as the mapping.
24811 var myReader = new Roo.data.JsonReader({
24812 totalProperty: "results", // The property which contains the total dataset size (optional)
24813 root: "rows", // The property which contains an Array of row objects
24814 id: "id" // The property within each row object that provides an ID for the record (optional)
24818 * This would consume a JSON file like this:
24820 { 'results': 2, 'rows': [
24821 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24822 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24825 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24826 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24827 * paged from the remote server.
24828 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24829 * @cfg {String} root name of the property which contains the Array of row objects.
24830 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24831 * @cfg {Array} fields Array of field definition objects
24833 * Create a new JsonReader
24834 * @param {Object} meta Metadata configuration options
24835 * @param {Object} recordType Either an Array of field definition objects,
24836 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24838 Roo.data.JsonReader = function(meta, recordType){
24841 // set some defaults:
24842 Roo.applyIf(meta, {
24843 totalProperty: 'total',
24844 successProperty : 'success',
24849 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24851 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24853 readerType : 'Json',
24856 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24857 * Used by Store query builder to append _requestMeta to params.
24860 metaFromRemote : false,
24862 * This method is only used by a DataProxy which has retrieved data from a remote server.
24863 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24864 * @return {Object} data A data block which is used by an Roo.data.Store object as
24865 * a cache of Roo.data.Records.
24867 read : function(response){
24868 var json = response.responseText;
24870 var o = /* eval:var:o */ eval("("+json+")");
24872 throw {message: "JsonReader.read: Json object not found"};
24878 this.metaFromRemote = true;
24879 this.meta = o.metaData;
24880 this.recordType = Roo.data.Record.create(o.metaData.fields);
24881 this.onMetaChange(this.meta, this.recordType, o);
24883 return this.readRecords(o);
24886 // private function a store will implement
24887 onMetaChange : function(meta, recordType, o){
24894 simpleAccess: function(obj, subsc) {
24901 getJsonAccessor: function(){
24903 return function(expr) {
24905 return(re.test(expr))
24906 ? new Function("obj", "return obj." + expr)
24911 return Roo.emptyFn;
24916 * Create a data block containing Roo.data.Records from an XML document.
24917 * @param {Object} o An object which contains an Array of row objects in the property specified
24918 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24919 * which contains the total size of the dataset.
24920 * @return {Object} data A data block which is used by an Roo.data.Store object as
24921 * a cache of Roo.data.Records.
24923 readRecords : function(o){
24925 * After any data loads, the raw JSON data is available for further custom processing.
24929 var s = this.meta, Record = this.recordType,
24930 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24932 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24934 if(s.totalProperty) {
24935 this.getTotal = this.getJsonAccessor(s.totalProperty);
24937 if(s.successProperty) {
24938 this.getSuccess = this.getJsonAccessor(s.successProperty);
24940 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24942 var g = this.getJsonAccessor(s.id);
24943 this.getId = function(rec) {
24945 return (r === undefined || r === "") ? null : r;
24948 this.getId = function(){return null;};
24951 for(var jj = 0; jj < fl; jj++){
24953 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24954 this.ef[jj] = this.getJsonAccessor(map);
24958 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24959 if(s.totalProperty){
24960 var vt = parseInt(this.getTotal(o), 10);
24965 if(s.successProperty){
24966 var vs = this.getSuccess(o);
24967 if(vs === false || vs === 'false'){
24972 for(var i = 0; i < c; i++){
24975 var id = this.getId(n);
24976 for(var j = 0; j < fl; j++){
24978 var v = this.ef[j](n);
24980 Roo.log('missing convert for ' + f.name);
24984 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24986 var record = new Record(values, id);
24988 records[i] = record;
24994 totalRecords : totalRecords
24997 // used when loading children.. @see loadDataFromChildren
24998 toLoadData: function(rec)
25000 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25001 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25002 return { data : data, total : data.length };
25007 * Ext JS Library 1.1.1
25008 * Copyright(c) 2006-2007, Ext JS, LLC.
25010 * Originally Released Under LGPL - original licence link has changed is not relivant.
25013 * <script type="text/javascript">
25017 * @class Roo.data.XmlReader
25018 * @extends Roo.data.DataReader
25019 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25020 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25022 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25023 * header in the HTTP response must be set to "text/xml".</em>
25027 var RecordDef = Roo.data.Record.create([
25028 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25029 {name: 'occupation'} // This field will use "occupation" as the mapping.
25031 var myReader = new Roo.data.XmlReader({
25032 totalRecords: "results", // The element which contains the total dataset size (optional)
25033 record: "row", // The repeated element which contains row information
25034 id: "id" // The element within the row that provides an ID for the record (optional)
25038 * This would consume an XML file like this:
25042 <results>2</results>
25045 <name>Bill</name>
25046 <occupation>Gardener</occupation>
25050 <name>Ben</name>
25051 <occupation>Horticulturalist</occupation>
25055 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25056 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25057 * paged from the remote server.
25058 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25059 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25060 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25061 * a record identifier value.
25063 * Create a new XmlReader
25064 * @param {Object} meta Metadata configuration options
25065 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25066 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25067 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25069 Roo.data.XmlReader = function(meta, recordType){
25071 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25073 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25075 readerType : 'Xml',
25078 * This method is only used by a DataProxy which has retrieved data from a remote server.
25079 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25080 * to contain a method called 'responseXML' that returns an XML document object.
25081 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25082 * a cache of Roo.data.Records.
25084 read : function(response){
25085 var doc = response.responseXML;
25087 throw {message: "XmlReader.read: XML Document not available"};
25089 return this.readRecords(doc);
25093 * Create a data block containing Roo.data.Records from an XML document.
25094 * @param {Object} doc A parsed XML document.
25095 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25096 * a cache of Roo.data.Records.
25098 readRecords : function(doc){
25100 * After any data loads/reads, the raw XML Document is available for further custom processing.
25101 * @type XMLDocument
25103 this.xmlData = doc;
25104 var root = doc.documentElement || doc;
25105 var q = Roo.DomQuery;
25106 var recordType = this.recordType, fields = recordType.prototype.fields;
25107 var sid = this.meta.id;
25108 var totalRecords = 0, success = true;
25109 if(this.meta.totalRecords){
25110 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25113 if(this.meta.success){
25114 var sv = q.selectValue(this.meta.success, root, true);
25115 success = sv !== false && sv !== 'false';
25118 var ns = q.select(this.meta.record, root);
25119 for(var i = 0, len = ns.length; i < len; i++) {
25122 var id = sid ? q.selectValue(sid, n) : undefined;
25123 for(var j = 0, jlen = fields.length; j < jlen; j++){
25124 var f = fields.items[j];
25125 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25127 values[f.name] = v;
25129 var record = new recordType(values, id);
25131 records[records.length] = record;
25137 totalRecords : totalRecords || records.length
25142 * Ext JS Library 1.1.1
25143 * Copyright(c) 2006-2007, Ext JS, LLC.
25145 * Originally Released Under LGPL - original licence link has changed is not relivant.
25148 * <script type="text/javascript">
25152 * @class Roo.data.ArrayReader
25153 * @extends Roo.data.DataReader
25154 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25155 * Each element of that Array represents a row of data fields. The
25156 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25157 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25161 var RecordDef = Roo.data.Record.create([
25162 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25163 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25165 var myReader = new Roo.data.ArrayReader({
25166 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25170 * This would consume an Array like this:
25172 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25176 * Create a new JsonReader
25177 * @param {Object} meta Metadata configuration options.
25178 * @param {Object|Array} recordType Either an Array of field definition objects
25180 * @cfg {Array} fields Array of field definition objects
25181 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25182 * as specified to {@link Roo.data.Record#create},
25183 * or an {@link Roo.data.Record} object
25186 * created using {@link Roo.data.Record#create}.
25188 Roo.data.ArrayReader = function(meta, recordType)
25190 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25193 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25196 * Create a data block containing Roo.data.Records from an XML document.
25197 * @param {Object} o An Array of row objects which represents the dataset.
25198 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25199 * a cache of Roo.data.Records.
25201 readRecords : function(o)
25203 var sid = this.meta ? this.meta.id : null;
25204 var recordType = this.recordType, fields = recordType.prototype.fields;
25207 for(var i = 0; i < root.length; i++){
25210 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25211 for(var j = 0, jlen = fields.length; j < jlen; j++){
25212 var f = fields.items[j];
25213 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25214 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25216 values[f.name] = v;
25218 var record = new recordType(values, id);
25220 records[records.length] = record;
25224 totalRecords : records.length
25227 // used when loading children.. @see loadDataFromChildren
25228 toLoadData: function(rec)
25230 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25231 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25238 * Ext JS Library 1.1.1
25239 * Copyright(c) 2006-2007, Ext JS, LLC.
25241 * Originally Released Under LGPL - original licence link has changed is not relivant.
25244 * <script type="text/javascript">
25249 * @class Roo.data.Tree
25250 * @extends Roo.util.Observable
25251 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25252 * in the tree have most standard DOM functionality.
25254 * @param {Node} root (optional) The root node
25256 Roo.data.Tree = function(root){
25257 this.nodeHash = {};
25259 * The root node for this tree
25264 this.setRootNode(root);
25269 * Fires when a new child node is appended to a node in this tree.
25270 * @param {Tree} tree The owner tree
25271 * @param {Node} parent The parent node
25272 * @param {Node} node The newly appended node
25273 * @param {Number} index The index of the newly appended node
25278 * Fires when a child node is removed from a node in this tree.
25279 * @param {Tree} tree The owner tree
25280 * @param {Node} parent The parent node
25281 * @param {Node} node The child node removed
25286 * Fires when a node is moved to a new location in the tree
25287 * @param {Tree} tree The owner tree
25288 * @param {Node} node The node moved
25289 * @param {Node} oldParent The old parent of this node
25290 * @param {Node} newParent The new parent of this node
25291 * @param {Number} index The index it was moved to
25296 * Fires when a new child node is inserted in a node in this tree.
25297 * @param {Tree} tree The owner tree
25298 * @param {Node} parent The parent node
25299 * @param {Node} node The child node inserted
25300 * @param {Node} refNode The child node the node was inserted before
25304 * @event beforeappend
25305 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25306 * @param {Tree} tree The owner tree
25307 * @param {Node} parent The parent node
25308 * @param {Node} node The child node to be appended
25310 "beforeappend" : true,
25312 * @event beforeremove
25313 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25314 * @param {Tree} tree The owner tree
25315 * @param {Node} parent The parent node
25316 * @param {Node} node The child node to be removed
25318 "beforeremove" : true,
25320 * @event beforemove
25321 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25322 * @param {Tree} tree The owner tree
25323 * @param {Node} node The node being moved
25324 * @param {Node} oldParent The parent of the node
25325 * @param {Node} newParent The new parent the node is moving to
25326 * @param {Number} index The index it is being moved to
25328 "beforemove" : true,
25330 * @event beforeinsert
25331 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25332 * @param {Tree} tree The owner tree
25333 * @param {Node} parent The parent node
25334 * @param {Node} node The child node to be inserted
25335 * @param {Node} refNode The child node the node is being inserted before
25337 "beforeinsert" : true
25340 Roo.data.Tree.superclass.constructor.call(this);
25343 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25344 pathSeparator: "/",
25346 proxyNodeEvent : function(){
25347 return this.fireEvent.apply(this, arguments);
25351 * Returns the root node for this tree.
25354 getRootNode : function(){
25359 * Sets the root node for this tree.
25360 * @param {Node} node
25363 setRootNode : function(node){
25365 node.ownerTree = this;
25366 node.isRoot = true;
25367 this.registerNode(node);
25372 * Gets a node in this tree by its id.
25373 * @param {String} id
25376 getNodeById : function(id){
25377 return this.nodeHash[id];
25380 registerNode : function(node){
25381 this.nodeHash[node.id] = node;
25384 unregisterNode : function(node){
25385 delete this.nodeHash[node.id];
25388 toString : function(){
25389 return "[Tree"+(this.id?" "+this.id:"")+"]";
25394 * @class Roo.data.Node
25395 * @extends Roo.util.Observable
25396 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25397 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25399 * @param {Object} attributes The attributes/config for the node
25401 Roo.data.Node = function(attributes){
25403 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25406 this.attributes = attributes || {};
25407 this.leaf = this.attributes.leaf;
25409 * The node id. @type String
25411 this.id = this.attributes.id;
25413 this.id = Roo.id(null, "ynode-");
25414 this.attributes.id = this.id;
25419 * All child nodes of this node. @type Array
25421 this.childNodes = [];
25422 if(!this.childNodes.indexOf){ // indexOf is a must
25423 this.childNodes.indexOf = function(o){
25424 for(var i = 0, len = this.length; i < len; i++){
25433 * The parent node for this node. @type Node
25435 this.parentNode = null;
25437 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25439 this.firstChild = null;
25441 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25443 this.lastChild = null;
25445 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25447 this.previousSibling = null;
25449 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25451 this.nextSibling = null;
25456 * Fires when a new child node is appended
25457 * @param {Tree} tree The owner tree
25458 * @param {Node} this This node
25459 * @param {Node} node The newly appended node
25460 * @param {Number} index The index of the newly appended node
25465 * Fires when a child node is removed
25466 * @param {Tree} tree The owner tree
25467 * @param {Node} this This node
25468 * @param {Node} node The removed node
25473 * Fires when this node is moved to a new location in the tree
25474 * @param {Tree} tree The owner tree
25475 * @param {Node} this This node
25476 * @param {Node} oldParent The old parent of this node
25477 * @param {Node} newParent The new parent of this node
25478 * @param {Number} index The index it was moved to
25483 * Fires when a new child node is inserted.
25484 * @param {Tree} tree The owner tree
25485 * @param {Node} this This node
25486 * @param {Node} node The child node inserted
25487 * @param {Node} refNode The child node the node was inserted before
25491 * @event beforeappend
25492 * Fires before a new child is appended, return false to cancel the append.
25493 * @param {Tree} tree The owner tree
25494 * @param {Node} this This node
25495 * @param {Node} node The child node to be appended
25497 "beforeappend" : true,
25499 * @event beforeremove
25500 * Fires before a child is removed, return false to cancel the remove.
25501 * @param {Tree} tree The owner tree
25502 * @param {Node} this This node
25503 * @param {Node} node The child node to be removed
25505 "beforeremove" : true,
25507 * @event beforemove
25508 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25509 * @param {Tree} tree The owner tree
25510 * @param {Node} this This node
25511 * @param {Node} oldParent The parent of this node
25512 * @param {Node} newParent The new parent this node is moving to
25513 * @param {Number} index The index it is being moved to
25515 "beforemove" : true,
25517 * @event beforeinsert
25518 * Fires before a new child is inserted, return false to cancel the insert.
25519 * @param {Tree} tree The owner tree
25520 * @param {Node} this This node
25521 * @param {Node} node The child node to be inserted
25522 * @param {Node} refNode The child node the node is being inserted before
25524 "beforeinsert" : true
25526 this.listeners = this.attributes.listeners;
25527 Roo.data.Node.superclass.constructor.call(this);
25530 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25531 fireEvent : function(evtName){
25532 // first do standard event for this node
25533 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25536 // then bubble it up to the tree if the event wasn't cancelled
25537 var ot = this.getOwnerTree();
25539 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25547 * Returns true if this node is a leaf
25548 * @return {Boolean}
25550 isLeaf : function(){
25551 return this.leaf === true;
25555 setFirstChild : function(node){
25556 this.firstChild = node;
25560 setLastChild : function(node){
25561 this.lastChild = node;
25566 * Returns true if this node is the last child of its parent
25567 * @return {Boolean}
25569 isLast : function(){
25570 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25574 * Returns true if this node is the first child of its parent
25575 * @return {Boolean}
25577 isFirst : function(){
25578 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25581 hasChildNodes : function(){
25582 return !this.isLeaf() && this.childNodes.length > 0;
25586 * Insert node(s) as the last child node of this node.
25587 * @param {Node/Array} node The node or Array of nodes to append
25588 * @return {Node} The appended node if single append, or null if an array was passed
25590 appendChild : function(node){
25592 if(node instanceof Array){
25594 }else if(arguments.length > 1){
25598 // if passed an array or multiple args do them one by one
25600 for(var i = 0, len = multi.length; i < len; i++) {
25601 this.appendChild(multi[i]);
25604 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25607 var index = this.childNodes.length;
25608 var oldParent = node.parentNode;
25609 // it's a move, make sure we move it cleanly
25611 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25614 oldParent.removeChild(node);
25617 index = this.childNodes.length;
25619 this.setFirstChild(node);
25621 this.childNodes.push(node);
25622 node.parentNode = this;
25623 var ps = this.childNodes[index-1];
25625 node.previousSibling = ps;
25626 ps.nextSibling = node;
25628 node.previousSibling = null;
25630 node.nextSibling = null;
25631 this.setLastChild(node);
25632 node.setOwnerTree(this.getOwnerTree());
25633 this.fireEvent("append", this.ownerTree, this, node, index);
25634 if(this.ownerTree) {
25635 this.ownerTree.fireEvent("appendnode", this, node, index);
25638 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25645 * Removes a child node from this node.
25646 * @param {Node} node The node to remove
25647 * @return {Node} The removed node
25649 removeChild : function(node){
25650 var index = this.childNodes.indexOf(node);
25654 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25658 // remove it from childNodes collection
25659 this.childNodes.splice(index, 1);
25662 if(node.previousSibling){
25663 node.previousSibling.nextSibling = node.nextSibling;
25665 if(node.nextSibling){
25666 node.nextSibling.previousSibling = node.previousSibling;
25669 // update child refs
25670 if(this.firstChild == node){
25671 this.setFirstChild(node.nextSibling);
25673 if(this.lastChild == node){
25674 this.setLastChild(node.previousSibling);
25677 node.setOwnerTree(null);
25678 // clear any references from the node
25679 node.parentNode = null;
25680 node.previousSibling = null;
25681 node.nextSibling = null;
25682 this.fireEvent("remove", this.ownerTree, this, node);
25687 * Inserts the first node before the second node in this nodes childNodes collection.
25688 * @param {Node} node The node to insert
25689 * @param {Node} refNode The node to insert before (if null the node is appended)
25690 * @return {Node} The inserted node
25692 insertBefore : function(node, refNode){
25693 if(!refNode){ // like standard Dom, refNode can be null for append
25694 return this.appendChild(node);
25697 if(node == refNode){
25701 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25704 var index = this.childNodes.indexOf(refNode);
25705 var oldParent = node.parentNode;
25706 var refIndex = index;
25708 // when moving internally, indexes will change after remove
25709 if(oldParent == this && this.childNodes.indexOf(node) < index){
25713 // it's a move, make sure we move it cleanly
25715 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25718 oldParent.removeChild(node);
25721 this.setFirstChild(node);
25723 this.childNodes.splice(refIndex, 0, node);
25724 node.parentNode = this;
25725 var ps = this.childNodes[refIndex-1];
25727 node.previousSibling = ps;
25728 ps.nextSibling = node;
25730 node.previousSibling = null;
25732 node.nextSibling = refNode;
25733 refNode.previousSibling = node;
25734 node.setOwnerTree(this.getOwnerTree());
25735 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25737 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25743 * Returns the child node at the specified index.
25744 * @param {Number} index
25747 item : function(index){
25748 return this.childNodes[index];
25752 * Replaces one child node in this node with another.
25753 * @param {Node} newChild The replacement node
25754 * @param {Node} oldChild The node to replace
25755 * @return {Node} The replaced node
25757 replaceChild : function(newChild, oldChild){
25758 this.insertBefore(newChild, oldChild);
25759 this.removeChild(oldChild);
25764 * Returns the index of a child node
25765 * @param {Node} node
25766 * @return {Number} The index of the node or -1 if it was not found
25768 indexOf : function(child){
25769 return this.childNodes.indexOf(child);
25773 * Returns the tree this node is in.
25776 getOwnerTree : function(){
25777 // if it doesn't have one, look for one
25778 if(!this.ownerTree){
25782 this.ownerTree = p.ownerTree;
25788 return this.ownerTree;
25792 * Returns depth of this node (the root node has a depth of 0)
25795 getDepth : function(){
25798 while(p.parentNode){
25806 setOwnerTree : function(tree){
25807 // if it's move, we need to update everyone
25808 if(tree != this.ownerTree){
25809 if(this.ownerTree){
25810 this.ownerTree.unregisterNode(this);
25812 this.ownerTree = tree;
25813 var cs = this.childNodes;
25814 for(var i = 0, len = cs.length; i < len; i++) {
25815 cs[i].setOwnerTree(tree);
25818 tree.registerNode(this);
25824 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25825 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25826 * @return {String} The path
25828 getPath : function(attr){
25829 attr = attr || "id";
25830 var p = this.parentNode;
25831 var b = [this.attributes[attr]];
25833 b.unshift(p.attributes[attr]);
25836 var sep = this.getOwnerTree().pathSeparator;
25837 return sep + b.join(sep);
25841 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25842 * function call will be the scope provided or the current node. The arguments to the function
25843 * will be the args provided or the current node. If the function returns false at any point,
25844 * the bubble is stopped.
25845 * @param {Function} fn The function to call
25846 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25847 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25849 bubble : function(fn, scope, args){
25852 if(fn.call(scope || p, args || p) === false){
25860 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25861 * function call will be the scope provided or the current node. The arguments to the function
25862 * will be the args provided or the current node. If the function returns false at any point,
25863 * the cascade is stopped on that branch.
25864 * @param {Function} fn The function to call
25865 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25866 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25868 cascade : function(fn, scope, args){
25869 if(fn.call(scope || this, args || this) !== false){
25870 var cs = this.childNodes;
25871 for(var i = 0, len = cs.length; i < len; i++) {
25872 cs[i].cascade(fn, scope, args);
25878 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25879 * function call will be the scope provided or the current node. The arguments to the function
25880 * will be the args provided or the current node. If the function returns false at any point,
25881 * the iteration stops.
25882 * @param {Function} fn The function to call
25883 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25884 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25886 eachChild : function(fn, scope, args){
25887 var cs = this.childNodes;
25888 for(var i = 0, len = cs.length; i < len; i++) {
25889 if(fn.call(scope || this, args || cs[i]) === false){
25896 * Finds the first child that has the attribute with the specified value.
25897 * @param {String} attribute The attribute name
25898 * @param {Mixed} value The value to search for
25899 * @return {Node} The found child or null if none was found
25901 findChild : function(attribute, value){
25902 var cs = this.childNodes;
25903 for(var i = 0, len = cs.length; i < len; i++) {
25904 if(cs[i].attributes[attribute] == value){
25912 * Finds the first child by a custom function. The child matches if the function passed
25914 * @param {Function} fn
25915 * @param {Object} scope (optional)
25916 * @return {Node} The found child or null if none was found
25918 findChildBy : function(fn, scope){
25919 var cs = this.childNodes;
25920 for(var i = 0, len = cs.length; i < len; i++) {
25921 if(fn.call(scope||cs[i], cs[i]) === true){
25929 * Sorts this nodes children using the supplied sort function
25930 * @param {Function} fn
25931 * @param {Object} scope (optional)
25933 sort : function(fn, scope){
25934 var cs = this.childNodes;
25935 var len = cs.length;
25937 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25939 for(var i = 0; i < len; i++){
25941 n.previousSibling = cs[i-1];
25942 n.nextSibling = cs[i+1];
25944 this.setFirstChild(n);
25947 this.setLastChild(n);
25954 * Returns true if this node is an ancestor (at any point) of the passed node.
25955 * @param {Node} node
25956 * @return {Boolean}
25958 contains : function(node){
25959 return node.isAncestor(this);
25963 * Returns true if the passed node is an ancestor (at any point) of this node.
25964 * @param {Node} node
25965 * @return {Boolean}
25967 isAncestor : function(node){
25968 var p = this.parentNode;
25978 toString : function(){
25979 return "[Node"+(this.id?" "+this.id:"")+"]";
25983 * Ext JS Library 1.1.1
25984 * Copyright(c) 2006-2007, Ext JS, LLC.
25986 * Originally Released Under LGPL - original licence link has changed is not relivant.
25989 * <script type="text/javascript">
25994 * @class Roo.Shadow
25995 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25996 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25997 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25999 * Create a new Shadow
26000 * @param {Object} config The config object
26002 Roo.Shadow = function(config){
26003 Roo.apply(this, config);
26004 if(typeof this.mode != "string"){
26005 this.mode = this.defaultMode;
26007 var o = this.offset, a = {h: 0};
26008 var rad = Math.floor(this.offset/2);
26009 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26015 a.l -= this.offset + rad;
26016 a.t -= this.offset + rad;
26027 a.l -= (this.offset - rad);
26028 a.t -= this.offset + rad;
26030 a.w -= (this.offset - rad)*2;
26041 a.l -= (this.offset - rad);
26042 a.t -= (this.offset - rad);
26044 a.w -= (this.offset + rad + 1);
26045 a.h -= (this.offset + rad);
26054 Roo.Shadow.prototype = {
26056 * @cfg {String} mode
26057 * The shadow display mode. Supports the following options:<br />
26058 * sides: Shadow displays on both sides and bottom only<br />
26059 * frame: Shadow displays equally on all four sides<br />
26060 * drop: Traditional bottom-right drop shadow (default)
26063 * @cfg {String} offset
26064 * The number of pixels to offset the shadow from the element (defaults to 4)
26069 defaultMode: "drop",
26072 * Displays the shadow under the target element
26073 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26075 show : function(target){
26076 target = Roo.get(target);
26078 this.el = Roo.Shadow.Pool.pull();
26079 if(this.el.dom.nextSibling != target.dom){
26080 this.el.insertBefore(target);
26083 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26085 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26088 target.getLeft(true),
26089 target.getTop(true),
26093 this.el.dom.style.display = "block";
26097 * Returns true if the shadow is visible, else false
26099 isVisible : function(){
26100 return this.el ? true : false;
26104 * Direct alignment when values are already available. Show must be called at least once before
26105 * calling this method to ensure it is initialized.
26106 * @param {Number} left The target element left position
26107 * @param {Number} top The target element top position
26108 * @param {Number} width The target element width
26109 * @param {Number} height The target element height
26111 realign : function(l, t, w, h){
26115 var a = this.adjusts, d = this.el.dom, s = d.style;
26117 s.left = (l+a.l)+"px";
26118 s.top = (t+a.t)+"px";
26119 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26121 if(s.width != sws || s.height != shs){
26125 var cn = d.childNodes;
26126 var sww = Math.max(0, (sw-12))+"px";
26127 cn[0].childNodes[1].style.width = sww;
26128 cn[1].childNodes[1].style.width = sww;
26129 cn[2].childNodes[1].style.width = sww;
26130 cn[1].style.height = Math.max(0, (sh-12))+"px";
26136 * Hides this shadow
26140 this.el.dom.style.display = "none";
26141 Roo.Shadow.Pool.push(this.el);
26147 * Adjust the z-index of this shadow
26148 * @param {Number} zindex The new z-index
26150 setZIndex : function(z){
26153 this.el.setStyle("z-index", z);
26158 // Private utility class that manages the internal Shadow cache
26159 Roo.Shadow.Pool = function(){
26161 var markup = Roo.isIE ?
26162 '<div class="x-ie-shadow"></div>' :
26163 '<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>';
26166 var sh = p.shift();
26168 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26169 sh.autoBoxAdjust = false;
26174 push : function(sh){
26180 * Ext JS Library 1.1.1
26181 * Copyright(c) 2006-2007, Ext JS, LLC.
26183 * Originally Released Under LGPL - original licence link has changed is not relivant.
26186 * <script type="text/javascript">
26191 * @class Roo.SplitBar
26192 * @extends Roo.util.Observable
26193 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26197 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26198 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26199 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26200 split.minSize = 100;
26201 split.maxSize = 600;
26202 split.animate = true;
26203 split.on('moved', splitterMoved);
26206 * Create a new SplitBar
26207 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26208 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26209 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26210 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26211 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26212 position of the SplitBar).
26214 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26217 this.el = Roo.get(dragElement, true);
26218 this.el.dom.unselectable = "on";
26220 this.resizingEl = Roo.get(resizingElement, true);
26224 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26225 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26228 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26231 * The minimum size of the resizing element. (Defaults to 0)
26237 * The maximum size of the resizing element. (Defaults to 2000)
26240 this.maxSize = 2000;
26243 * Whether to animate the transition to the new size
26246 this.animate = false;
26249 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26252 this.useShim = false;
26257 if(!existingProxy){
26259 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26261 this.proxy = Roo.get(existingProxy).dom;
26264 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26267 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26270 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26273 this.dragSpecs = {};
26276 * @private The adapter to use to positon and resize elements
26278 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26279 this.adapter.init(this);
26281 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26283 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26284 this.el.addClass("x-splitbar-h");
26287 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26288 this.el.addClass("x-splitbar-v");
26294 * Fires when the splitter is moved (alias for {@link #event-moved})
26295 * @param {Roo.SplitBar} this
26296 * @param {Number} newSize the new width or height
26301 * Fires when the splitter is moved
26302 * @param {Roo.SplitBar} this
26303 * @param {Number} newSize the new width or height
26307 * @event beforeresize
26308 * Fires before the splitter is dragged
26309 * @param {Roo.SplitBar} this
26311 "beforeresize" : true,
26313 "beforeapply" : true
26316 Roo.util.Observable.call(this);
26319 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26320 onStartProxyDrag : function(x, y){
26321 this.fireEvent("beforeresize", this);
26323 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26325 o.enableDisplayMode("block");
26326 // all splitbars share the same overlay
26327 Roo.SplitBar.prototype.overlay = o;
26329 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26330 this.overlay.show();
26331 Roo.get(this.proxy).setDisplayed("block");
26332 var size = this.adapter.getElementSize(this);
26333 this.activeMinSize = this.getMinimumSize();;
26334 this.activeMaxSize = this.getMaximumSize();;
26335 var c1 = size - this.activeMinSize;
26336 var c2 = Math.max(this.activeMaxSize - size, 0);
26337 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26338 this.dd.resetConstraints();
26339 this.dd.setXConstraint(
26340 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26341 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26343 this.dd.setYConstraint(0, 0);
26345 this.dd.resetConstraints();
26346 this.dd.setXConstraint(0, 0);
26347 this.dd.setYConstraint(
26348 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26349 this.placement == Roo.SplitBar.TOP ? c2 : c1
26352 this.dragSpecs.startSize = size;
26353 this.dragSpecs.startPoint = [x, y];
26354 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26358 * @private Called after the drag operation by the DDProxy
26360 onEndProxyDrag : function(e){
26361 Roo.get(this.proxy).setDisplayed(false);
26362 var endPoint = Roo.lib.Event.getXY(e);
26364 this.overlay.hide();
26367 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26368 newSize = this.dragSpecs.startSize +
26369 (this.placement == Roo.SplitBar.LEFT ?
26370 endPoint[0] - this.dragSpecs.startPoint[0] :
26371 this.dragSpecs.startPoint[0] - endPoint[0]
26374 newSize = this.dragSpecs.startSize +
26375 (this.placement == Roo.SplitBar.TOP ?
26376 endPoint[1] - this.dragSpecs.startPoint[1] :
26377 this.dragSpecs.startPoint[1] - endPoint[1]
26380 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26381 if(newSize != this.dragSpecs.startSize){
26382 if(this.fireEvent('beforeapply', this, newSize) !== false){
26383 this.adapter.setElementSize(this, newSize);
26384 this.fireEvent("moved", this, newSize);
26385 this.fireEvent("resize", this, newSize);
26391 * Get the adapter this SplitBar uses
26392 * @return The adapter object
26394 getAdapter : function(){
26395 return this.adapter;
26399 * Set the adapter this SplitBar uses
26400 * @param {Object} adapter A SplitBar adapter object
26402 setAdapter : function(adapter){
26403 this.adapter = adapter;
26404 this.adapter.init(this);
26408 * Gets the minimum size for the resizing element
26409 * @return {Number} The minimum size
26411 getMinimumSize : function(){
26412 return this.minSize;
26416 * Sets the minimum size for the resizing element
26417 * @param {Number} minSize The minimum size
26419 setMinimumSize : function(minSize){
26420 this.minSize = minSize;
26424 * Gets the maximum size for the resizing element
26425 * @return {Number} The maximum size
26427 getMaximumSize : function(){
26428 return this.maxSize;
26432 * Sets the maximum size for the resizing element
26433 * @param {Number} maxSize The maximum size
26435 setMaximumSize : function(maxSize){
26436 this.maxSize = maxSize;
26440 * Sets the initialize size for the resizing element
26441 * @param {Number} size The initial size
26443 setCurrentSize : function(size){
26444 var oldAnimate = this.animate;
26445 this.animate = false;
26446 this.adapter.setElementSize(this, size);
26447 this.animate = oldAnimate;
26451 * Destroy this splitbar.
26452 * @param {Boolean} removeEl True to remove the element
26454 destroy : function(removeEl){
26456 this.shim.remove();
26459 this.proxy.parentNode.removeChild(this.proxy);
26467 * @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.
26469 Roo.SplitBar.createProxy = function(dir){
26470 var proxy = new Roo.Element(document.createElement("div"));
26471 proxy.unselectable();
26472 var cls = 'x-splitbar-proxy';
26473 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26474 document.body.appendChild(proxy.dom);
26479 * @class Roo.SplitBar.BasicLayoutAdapter
26480 * Default Adapter. It assumes the splitter and resizing element are not positioned
26481 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26483 Roo.SplitBar.BasicLayoutAdapter = function(){
26486 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26487 // do nothing for now
26488 init : function(s){
26492 * Called before drag operations to get the current size of the resizing element.
26493 * @param {Roo.SplitBar} s The SplitBar using this adapter
26495 getElementSize : function(s){
26496 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26497 return s.resizingEl.getWidth();
26499 return s.resizingEl.getHeight();
26504 * Called after drag operations to set the size of the resizing element.
26505 * @param {Roo.SplitBar} s The SplitBar using this adapter
26506 * @param {Number} newSize The new size to set
26507 * @param {Function} onComplete A function to be invoked when resizing is complete
26509 setElementSize : function(s, newSize, onComplete){
26510 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26512 s.resizingEl.setWidth(newSize);
26514 onComplete(s, newSize);
26517 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26522 s.resizingEl.setHeight(newSize);
26524 onComplete(s, newSize);
26527 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26534 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26535 * @extends Roo.SplitBar.BasicLayoutAdapter
26536 * Adapter that moves the splitter element to align with the resized sizing element.
26537 * Used with an absolute positioned SplitBar.
26538 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26539 * document.body, make sure you assign an id to the body element.
26541 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26542 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26543 this.container = Roo.get(container);
26546 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26547 init : function(s){
26548 this.basic.init(s);
26551 getElementSize : function(s){
26552 return this.basic.getElementSize(s);
26555 setElementSize : function(s, newSize, onComplete){
26556 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26559 moveSplitter : function(s){
26560 var yes = Roo.SplitBar;
26561 switch(s.placement){
26563 s.el.setX(s.resizingEl.getRight());
26566 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26569 s.el.setY(s.resizingEl.getBottom());
26572 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26579 * Orientation constant - Create a vertical SplitBar
26583 Roo.SplitBar.VERTICAL = 1;
26586 * Orientation constant - Create a horizontal SplitBar
26590 Roo.SplitBar.HORIZONTAL = 2;
26593 * Placement constant - The resizing element is to the left of the splitter element
26597 Roo.SplitBar.LEFT = 1;
26600 * Placement constant - The resizing element is to the right of the splitter element
26604 Roo.SplitBar.RIGHT = 2;
26607 * Placement constant - The resizing element is positioned above the splitter element
26611 Roo.SplitBar.TOP = 3;
26614 * Placement constant - The resizing element is positioned under splitter element
26618 Roo.SplitBar.BOTTOM = 4;
26621 * Ext JS Library 1.1.1
26622 * Copyright(c) 2006-2007, Ext JS, LLC.
26624 * Originally Released Under LGPL - original licence link has changed is not relivant.
26627 * <script type="text/javascript">
26632 * @extends Roo.util.Observable
26633 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26634 * This class also supports single and multi selection modes. <br>
26635 * Create a data model bound view:
26637 var store = new Roo.data.Store(...);
26639 var view = new Roo.View({
26641 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26643 singleSelect: true,
26644 selectedClass: "ydataview-selected",
26648 // listen for node click?
26649 view.on("click", function(vw, index, node, e){
26650 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26654 dataModel.load("foobar.xml");
26656 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26658 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26659 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26661 * Note: old style constructor is still suported (container, template, config)
26664 * Create a new View
26665 * @param {Object} config The config object
26668 Roo.View = function(config, depreciated_tpl, depreciated_config){
26670 this.parent = false;
26672 if (typeof(depreciated_tpl) == 'undefined') {
26673 // new way.. - universal constructor.
26674 Roo.apply(this, config);
26675 this.el = Roo.get(this.el);
26678 this.el = Roo.get(config);
26679 this.tpl = depreciated_tpl;
26680 Roo.apply(this, depreciated_config);
26682 this.wrapEl = this.el.wrap().wrap();
26683 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26686 if(typeof(this.tpl) == "string"){
26687 this.tpl = new Roo.Template(this.tpl);
26689 // support xtype ctors..
26690 this.tpl = new Roo.factory(this.tpl, Roo);
26694 this.tpl.compile();
26699 * @event beforeclick
26700 * Fires before a click is processed. Returns false to cancel the default action.
26701 * @param {Roo.View} this
26702 * @param {Number} index The index of the target node
26703 * @param {HTMLElement} node The target node
26704 * @param {Roo.EventObject} e The raw event object
26706 "beforeclick" : true,
26709 * Fires when a template node is clicked.
26710 * @param {Roo.View} this
26711 * @param {Number} index The index of the target node
26712 * @param {HTMLElement} node The target node
26713 * @param {Roo.EventObject} e The raw event object
26718 * Fires when a template node is double clicked.
26719 * @param {Roo.View} this
26720 * @param {Number} index The index of the target node
26721 * @param {HTMLElement} node The target node
26722 * @param {Roo.EventObject} e The raw event object
26726 * @event contextmenu
26727 * Fires when a template node is right clicked.
26728 * @param {Roo.View} this
26729 * @param {Number} index The index of the target node
26730 * @param {HTMLElement} node The target node
26731 * @param {Roo.EventObject} e The raw event object
26733 "contextmenu" : true,
26735 * @event selectionchange
26736 * Fires when the selected nodes change.
26737 * @param {Roo.View} this
26738 * @param {Array} selections Array of the selected nodes
26740 "selectionchange" : true,
26743 * @event beforeselect
26744 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26745 * @param {Roo.View} this
26746 * @param {HTMLElement} node The node to be selected
26747 * @param {Array} selections Array of currently selected nodes
26749 "beforeselect" : true,
26751 * @event preparedata
26752 * Fires on every row to render, to allow you to change the data.
26753 * @param {Roo.View} this
26754 * @param {Object} data to be rendered (change this)
26756 "preparedata" : true
26764 "click": this.onClick,
26765 "dblclick": this.onDblClick,
26766 "contextmenu": this.onContextMenu,
26770 this.selections = [];
26772 this.cmp = new Roo.CompositeElementLite([]);
26774 this.store = Roo.factory(this.store, Roo.data);
26775 this.setStore(this.store, true);
26778 if ( this.footer && this.footer.xtype) {
26780 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26782 this.footer.dataSource = this.store;
26783 this.footer.container = fctr;
26784 this.footer = Roo.factory(this.footer, Roo);
26785 fctr.insertFirst(this.el);
26787 // this is a bit insane - as the paging toolbar seems to detach the el..
26788 // dom.parentNode.parentNode.parentNode
26789 // they get detached?
26793 Roo.View.superclass.constructor.call(this);
26798 Roo.extend(Roo.View, Roo.util.Observable, {
26801 * @cfg {Roo.data.Store} store Data store to load data from.
26806 * @cfg {String|Roo.Element} el The container element.
26811 * @cfg {String|Roo.Template} tpl The template used by this View
26815 * @cfg {String} dataName the named area of the template to use as the data area
26816 * Works with domtemplates roo-name="name"
26820 * @cfg {String} selectedClass The css class to add to selected nodes
26822 selectedClass : "x-view-selected",
26824 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26829 * @cfg {String} text to display on mask (default Loading)
26833 * @cfg {Boolean} multiSelect Allow multiple selection
26835 multiSelect : false,
26837 * @cfg {Boolean} singleSelect Allow single selection
26839 singleSelect: false,
26842 * @cfg {Boolean} toggleSelect - selecting
26844 toggleSelect : false,
26847 * @cfg {Boolean} tickable - selecting
26852 * Returns the element this view is bound to.
26853 * @return {Roo.Element}
26855 getEl : function(){
26856 return this.wrapEl;
26862 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26864 refresh : function(){
26865 //Roo.log('refresh');
26868 // if we are using something like 'domtemplate', then
26869 // the what gets used is:
26870 // t.applySubtemplate(NAME, data, wrapping data..)
26871 // the outer template then get' applied with
26872 // the store 'extra data'
26873 // and the body get's added to the
26874 // roo-name="data" node?
26875 // <span class='roo-tpl-{name}'></span> ?????
26879 this.clearSelections();
26880 this.el.update("");
26882 var records = this.store.getRange();
26883 if(records.length < 1) {
26885 // is this valid?? = should it render a template??
26887 this.el.update(this.emptyText);
26891 if (this.dataName) {
26892 this.el.update(t.apply(this.store.meta)); //????
26893 el = this.el.child('.roo-tpl-' + this.dataName);
26896 for(var i = 0, len = records.length; i < len; i++){
26897 var data = this.prepareData(records[i].data, i, records[i]);
26898 this.fireEvent("preparedata", this, data, i, records[i]);
26900 var d = Roo.apply({}, data);
26903 Roo.apply(d, {'roo-id' : Roo.id()});
26907 Roo.each(this.parent.item, function(item){
26908 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26911 Roo.apply(d, {'roo-data-checked' : 'checked'});
26915 html[html.length] = Roo.util.Format.trim(
26917 t.applySubtemplate(this.dataName, d, this.store.meta) :
26924 el.update(html.join(""));
26925 this.nodes = el.dom.childNodes;
26926 this.updateIndexes(0);
26931 * Function to override to reformat the data that is sent to
26932 * the template for each node.
26933 * DEPRICATED - use the preparedata event handler.
26934 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26935 * a JSON object for an UpdateManager bound view).
26937 prepareData : function(data, index, record)
26939 this.fireEvent("preparedata", this, data, index, record);
26943 onUpdate : function(ds, record){
26944 // Roo.log('on update');
26945 this.clearSelections();
26946 var index = this.store.indexOf(record);
26947 var n = this.nodes[index];
26948 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26949 n.parentNode.removeChild(n);
26950 this.updateIndexes(index, index);
26956 onAdd : function(ds, records, index)
26958 //Roo.log(['on Add', ds, records, index] );
26959 this.clearSelections();
26960 if(this.nodes.length == 0){
26964 var n = this.nodes[index];
26965 for(var i = 0, len = records.length; i < len; i++){
26966 var d = this.prepareData(records[i].data, i, records[i]);
26968 this.tpl.insertBefore(n, d);
26971 this.tpl.append(this.el, d);
26974 this.updateIndexes(index);
26977 onRemove : function(ds, record, index){
26978 // Roo.log('onRemove');
26979 this.clearSelections();
26980 var el = this.dataName ?
26981 this.el.child('.roo-tpl-' + this.dataName) :
26984 el.dom.removeChild(this.nodes[index]);
26985 this.updateIndexes(index);
26989 * Refresh an individual node.
26990 * @param {Number} index
26992 refreshNode : function(index){
26993 this.onUpdate(this.store, this.store.getAt(index));
26996 updateIndexes : function(startIndex, endIndex){
26997 var ns = this.nodes;
26998 startIndex = startIndex || 0;
26999 endIndex = endIndex || ns.length - 1;
27000 for(var i = startIndex; i <= endIndex; i++){
27001 ns[i].nodeIndex = i;
27006 * Changes the data store this view uses and refresh the view.
27007 * @param {Store} store
27009 setStore : function(store, initial){
27010 if(!initial && this.store){
27011 this.store.un("datachanged", this.refresh);
27012 this.store.un("add", this.onAdd);
27013 this.store.un("remove", this.onRemove);
27014 this.store.un("update", this.onUpdate);
27015 this.store.un("clear", this.refresh);
27016 this.store.un("beforeload", this.onBeforeLoad);
27017 this.store.un("load", this.onLoad);
27018 this.store.un("loadexception", this.onLoad);
27022 store.on("datachanged", this.refresh, this);
27023 store.on("add", this.onAdd, this);
27024 store.on("remove", this.onRemove, this);
27025 store.on("update", this.onUpdate, this);
27026 store.on("clear", this.refresh, this);
27027 store.on("beforeload", this.onBeforeLoad, this);
27028 store.on("load", this.onLoad, this);
27029 store.on("loadexception", this.onLoad, this);
27037 * onbeforeLoad - masks the loading area.
27040 onBeforeLoad : function(store,opts)
27042 //Roo.log('onBeforeLoad');
27044 this.el.update("");
27046 this.el.mask(this.mask ? this.mask : "Loading" );
27048 onLoad : function ()
27055 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27056 * @param {HTMLElement} node
27057 * @return {HTMLElement} The template node
27059 findItemFromChild : function(node){
27060 var el = this.dataName ?
27061 this.el.child('.roo-tpl-' + this.dataName,true) :
27064 if(!node || node.parentNode == el){
27067 var p = node.parentNode;
27068 while(p && p != el){
27069 if(p.parentNode == el){
27078 onClick : function(e){
27079 var item = this.findItemFromChild(e.getTarget());
27081 var index = this.indexOf(item);
27082 if(this.onItemClick(item, index, e) !== false){
27083 this.fireEvent("click", this, index, item, e);
27086 this.clearSelections();
27091 onContextMenu : function(e){
27092 var item = this.findItemFromChild(e.getTarget());
27094 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27099 onDblClick : function(e){
27100 var item = this.findItemFromChild(e.getTarget());
27102 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27106 onItemClick : function(item, index, e)
27108 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27111 if (this.toggleSelect) {
27112 var m = this.isSelected(item) ? 'unselect' : 'select';
27115 _t[m](item, true, false);
27118 if(this.multiSelect || this.singleSelect){
27119 if(this.multiSelect && e.shiftKey && this.lastSelection){
27120 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27122 this.select(item, this.multiSelect && e.ctrlKey);
27123 this.lastSelection = item;
27126 if(!this.tickable){
27127 e.preventDefault();
27135 * Get the number of selected nodes.
27138 getSelectionCount : function(){
27139 return this.selections.length;
27143 * Get the currently selected nodes.
27144 * @return {Array} An array of HTMLElements
27146 getSelectedNodes : function(){
27147 return this.selections;
27151 * Get the indexes of the selected nodes.
27154 getSelectedIndexes : function(){
27155 var indexes = [], s = this.selections;
27156 for(var i = 0, len = s.length; i < len; i++){
27157 indexes.push(s[i].nodeIndex);
27163 * Clear all selections
27164 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27166 clearSelections : function(suppressEvent){
27167 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27168 this.cmp.elements = this.selections;
27169 this.cmp.removeClass(this.selectedClass);
27170 this.selections = [];
27171 if(!suppressEvent){
27172 this.fireEvent("selectionchange", this, this.selections);
27178 * Returns true if the passed node is selected
27179 * @param {HTMLElement/Number} node The node or node index
27180 * @return {Boolean}
27182 isSelected : function(node){
27183 var s = this.selections;
27187 node = this.getNode(node);
27188 return s.indexOf(node) !== -1;
27193 * @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
27194 * @param {Boolean} keepExisting (optional) true to keep existing selections
27195 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27197 select : function(nodeInfo, keepExisting, suppressEvent){
27198 if(nodeInfo instanceof Array){
27200 this.clearSelections(true);
27202 for(var i = 0, len = nodeInfo.length; i < len; i++){
27203 this.select(nodeInfo[i], true, true);
27207 var node = this.getNode(nodeInfo);
27208 if(!node || this.isSelected(node)){
27209 return; // already selected.
27212 this.clearSelections(true);
27215 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27216 Roo.fly(node).addClass(this.selectedClass);
27217 this.selections.push(node);
27218 if(!suppressEvent){
27219 this.fireEvent("selectionchange", this, this.selections);
27227 * @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
27228 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27229 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27231 unselect : function(nodeInfo, keepExisting, suppressEvent)
27233 if(nodeInfo instanceof Array){
27234 Roo.each(this.selections, function(s) {
27235 this.unselect(s, nodeInfo);
27239 var node = this.getNode(nodeInfo);
27240 if(!node || !this.isSelected(node)){
27241 //Roo.log("not selected");
27242 return; // not selected.
27246 Roo.each(this.selections, function(s) {
27248 Roo.fly(node).removeClass(this.selectedClass);
27255 this.selections= ns;
27256 this.fireEvent("selectionchange", this, this.selections);
27260 * Gets a template node.
27261 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27262 * @return {HTMLElement} The node or null if it wasn't found
27264 getNode : function(nodeInfo){
27265 if(typeof nodeInfo == "string"){
27266 return document.getElementById(nodeInfo);
27267 }else if(typeof nodeInfo == "number"){
27268 return this.nodes[nodeInfo];
27274 * Gets a range template nodes.
27275 * @param {Number} startIndex
27276 * @param {Number} endIndex
27277 * @return {Array} An array of nodes
27279 getNodes : function(start, end){
27280 var ns = this.nodes;
27281 start = start || 0;
27282 end = typeof end == "undefined" ? ns.length - 1 : end;
27285 for(var i = start; i <= end; i++){
27289 for(var i = start; i >= end; i--){
27297 * Finds the index of the passed node
27298 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27299 * @return {Number} The index of the node or -1
27301 indexOf : function(node){
27302 node = this.getNode(node);
27303 if(typeof node.nodeIndex == "number"){
27304 return node.nodeIndex;
27306 var ns = this.nodes;
27307 for(var i = 0, len = ns.length; i < len; i++){
27317 * Ext JS Library 1.1.1
27318 * Copyright(c) 2006-2007, Ext JS, LLC.
27320 * Originally Released Under LGPL - original licence link has changed is not relivant.
27323 * <script type="text/javascript">
27327 * @class Roo.JsonView
27328 * @extends Roo.View
27329 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27331 var view = new Roo.JsonView({
27332 container: "my-element",
27333 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27338 // listen for node click?
27339 view.on("click", function(vw, index, node, e){
27340 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27343 // direct load of JSON data
27344 view.load("foobar.php");
27346 // Example from my blog list
27347 var tpl = new Roo.Template(
27348 '<div class="entry">' +
27349 '<a class="entry-title" href="{link}">{title}</a>' +
27350 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27351 "</div><hr />"
27354 var moreView = new Roo.JsonView({
27355 container : "entry-list",
27359 moreView.on("beforerender", this.sortEntries, this);
27361 url: "/blog/get-posts.php",
27362 params: "allposts=true",
27363 text: "Loading Blog Entries..."
27367 * Note: old code is supported with arguments : (container, template, config)
27371 * Create a new JsonView
27373 * @param {Object} config The config object
27376 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27379 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27381 var um = this.el.getUpdateManager();
27382 um.setRenderer(this);
27383 um.on("update", this.onLoad, this);
27384 um.on("failure", this.onLoadException, this);
27387 * @event beforerender
27388 * Fires before rendering of the downloaded JSON data.
27389 * @param {Roo.JsonView} this
27390 * @param {Object} data The JSON data loaded
27394 * Fires when data is loaded.
27395 * @param {Roo.JsonView} this
27396 * @param {Object} data The JSON data loaded
27397 * @param {Object} response The raw Connect response object
27400 * @event loadexception
27401 * Fires when loading fails.
27402 * @param {Roo.JsonView} this
27403 * @param {Object} response The raw Connect response object
27406 'beforerender' : true,
27408 'loadexception' : true
27411 Roo.extend(Roo.JsonView, Roo.View, {
27413 * @type {String} The root property in the loaded JSON object that contains the data
27418 * Refreshes the view.
27420 refresh : function(){
27421 this.clearSelections();
27422 this.el.update("");
27424 var o = this.jsonData;
27425 if(o && o.length > 0){
27426 for(var i = 0, len = o.length; i < len; i++){
27427 var data = this.prepareData(o[i], i, o);
27428 html[html.length] = this.tpl.apply(data);
27431 html.push(this.emptyText);
27433 this.el.update(html.join(""));
27434 this.nodes = this.el.dom.childNodes;
27435 this.updateIndexes(0);
27439 * 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.
27440 * @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:
27443 url: "your-url.php",
27444 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27445 callback: yourFunction,
27446 scope: yourObject, //(optional scope)
27449 text: "Loading...",
27454 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27455 * 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.
27456 * @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}
27457 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27458 * @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.
27461 var um = this.el.getUpdateManager();
27462 um.update.apply(um, arguments);
27465 // note - render is a standard framework call...
27466 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27467 render : function(el, response){
27469 this.clearSelections();
27470 this.el.update("");
27473 if (response != '') {
27474 o = Roo.util.JSON.decode(response.responseText);
27477 o = o[this.jsonRoot];
27483 * The current JSON data or null
27486 this.beforeRender();
27491 * Get the number of records in the current JSON dataset
27494 getCount : function(){
27495 return this.jsonData ? this.jsonData.length : 0;
27499 * Returns the JSON object for the specified node(s)
27500 * @param {HTMLElement/Array} node The node or an array of nodes
27501 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27502 * you get the JSON object for the node
27504 getNodeData : function(node){
27505 if(node instanceof Array){
27507 for(var i = 0, len = node.length; i < len; i++){
27508 data.push(this.getNodeData(node[i]));
27512 return this.jsonData[this.indexOf(node)] || null;
27515 beforeRender : function(){
27516 this.snapshot = this.jsonData;
27518 this.sort.apply(this, this.sortInfo);
27520 this.fireEvent("beforerender", this, this.jsonData);
27523 onLoad : function(el, o){
27524 this.fireEvent("load", this, this.jsonData, o);
27527 onLoadException : function(el, o){
27528 this.fireEvent("loadexception", this, o);
27532 * Filter the data by a specific property.
27533 * @param {String} property A property on your JSON objects
27534 * @param {String/RegExp} value Either string that the property values
27535 * should start with, or a RegExp to test against the property
27537 filter : function(property, value){
27540 var ss = this.snapshot;
27541 if(typeof value == "string"){
27542 var vlen = value.length;
27544 this.clearFilter();
27547 value = value.toLowerCase();
27548 for(var i = 0, len = ss.length; i < len; i++){
27550 if(o[property].substr(0, vlen).toLowerCase() == value){
27554 } else if(value.exec){ // regex?
27555 for(var i = 0, len = ss.length; i < len; i++){
27557 if(value.test(o[property])){
27564 this.jsonData = data;
27570 * Filter by a function. The passed function will be called with each
27571 * object in the current dataset. If the function returns true the value is kept,
27572 * otherwise it is filtered.
27573 * @param {Function} fn
27574 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27576 filterBy : function(fn, scope){
27579 var ss = this.snapshot;
27580 for(var i = 0, len = ss.length; i < len; i++){
27582 if(fn.call(scope || this, o)){
27586 this.jsonData = data;
27592 * Clears the current filter.
27594 clearFilter : function(){
27595 if(this.snapshot && this.jsonData != this.snapshot){
27596 this.jsonData = this.snapshot;
27603 * Sorts the data for this view and refreshes it.
27604 * @param {String} property A property on your JSON objects to sort on
27605 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27606 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27608 sort : function(property, dir, sortType){
27609 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27612 var dsc = dir && dir.toLowerCase() == "desc";
27613 var f = function(o1, o2){
27614 var v1 = sortType ? sortType(o1[p]) : o1[p];
27615 var v2 = sortType ? sortType(o2[p]) : o2[p];
27618 return dsc ? +1 : -1;
27619 } else if(v1 > v2){
27620 return dsc ? -1 : +1;
27625 this.jsonData.sort(f);
27627 if(this.jsonData != this.snapshot){
27628 this.snapshot.sort(f);
27634 * Ext JS Library 1.1.1
27635 * Copyright(c) 2006-2007, Ext JS, LLC.
27637 * Originally Released Under LGPL - original licence link has changed is not relivant.
27640 * <script type="text/javascript">
27645 * @class Roo.ColorPalette
27646 * @extends Roo.Component
27647 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27648 * Here's an example of typical usage:
27650 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27651 cp.render('my-div');
27653 cp.on('select', function(palette, selColor){
27654 // do something with selColor
27658 * Create a new ColorPalette
27659 * @param {Object} config The config object
27661 Roo.ColorPalette = function(config){
27662 Roo.ColorPalette.superclass.constructor.call(this, config);
27666 * Fires when a color is selected
27667 * @param {ColorPalette} this
27668 * @param {String} color The 6-digit color hex code (without the # symbol)
27674 this.on("select", this.handler, this.scope, true);
27677 Roo.extend(Roo.ColorPalette, Roo.Component, {
27679 * @cfg {String} itemCls
27680 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27682 itemCls : "x-color-palette",
27684 * @cfg {String} value
27685 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27686 * the hex codes are case-sensitive.
27689 clickEvent:'click',
27691 ctype: "Roo.ColorPalette",
27694 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27696 allowReselect : false,
27699 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27700 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27701 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27702 * of colors with the width setting until the box is symmetrical.</p>
27703 * <p>You can override individual colors if needed:</p>
27705 var cp = new Roo.ColorPalette();
27706 cp.colors[0] = "FF0000"; // change the first box to red
27709 Or you can provide a custom array of your own for complete control:
27711 var cp = new Roo.ColorPalette();
27712 cp.colors = ["000000", "993300", "333300"];
27717 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27718 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27719 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27720 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27721 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27725 onRender : function(container, position){
27726 var t = new Roo.MasterTemplate(
27727 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27729 var c = this.colors;
27730 for(var i = 0, len = c.length; i < len; i++){
27733 var el = document.createElement("div");
27734 el.className = this.itemCls;
27736 container.dom.insertBefore(el, position);
27737 this.el = Roo.get(el);
27738 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27739 if(this.clickEvent != 'click'){
27740 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27745 afterRender : function(){
27746 Roo.ColorPalette.superclass.afterRender.call(this);
27748 var s = this.value;
27755 handleClick : function(e, t){
27756 e.preventDefault();
27757 if(!this.disabled){
27758 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27759 this.select(c.toUpperCase());
27764 * Selects the specified color in the palette (fires the select event)
27765 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27767 select : function(color){
27768 color = color.replace("#", "");
27769 if(color != this.value || this.allowReselect){
27772 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27774 el.child("a.color-"+color).addClass("x-color-palette-sel");
27775 this.value = color;
27776 this.fireEvent("select", this, color);
27781 * Ext JS Library 1.1.1
27782 * Copyright(c) 2006-2007, Ext JS, LLC.
27784 * Originally Released Under LGPL - original licence link has changed is not relivant.
27787 * <script type="text/javascript">
27791 * @class Roo.DatePicker
27792 * @extends Roo.Component
27793 * Simple date picker class.
27795 * Create a new DatePicker
27796 * @param {Object} config The config object
27798 Roo.DatePicker = function(config){
27799 Roo.DatePicker.superclass.constructor.call(this, config);
27801 this.value = config && config.value ?
27802 config.value.clearTime() : new Date().clearTime();
27807 * Fires when a date is selected
27808 * @param {DatePicker} this
27809 * @param {Date} date The selected date
27813 * @event monthchange
27814 * Fires when the displayed month changes
27815 * @param {DatePicker} this
27816 * @param {Date} date The selected month
27818 'monthchange': true
27822 this.on("select", this.handler, this.scope || this);
27824 // build the disabledDatesRE
27825 if(!this.disabledDatesRE && this.disabledDates){
27826 var dd = this.disabledDates;
27828 for(var i = 0; i < dd.length; i++){
27830 if(i != dd.length-1) {
27834 this.disabledDatesRE = new RegExp(re + ")");
27838 Roo.extend(Roo.DatePicker, Roo.Component, {
27840 * @cfg {String} todayText
27841 * The text to display on the button that selects the current date (defaults to "Today")
27843 todayText : "Today",
27845 * @cfg {String} okText
27846 * The text to display on the ok button
27848 okText : " OK ", //   to give the user extra clicking room
27850 * @cfg {String} cancelText
27851 * The text to display on the cancel button
27853 cancelText : "Cancel",
27855 * @cfg {String} todayTip
27856 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27858 todayTip : "{0} (Spacebar)",
27860 * @cfg {Date} minDate
27861 * Minimum allowable date (JavaScript date object, defaults to null)
27865 * @cfg {Date} maxDate
27866 * Maximum allowable date (JavaScript date object, defaults to null)
27870 * @cfg {String} minText
27871 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27873 minText : "This date is before the minimum date",
27875 * @cfg {String} maxText
27876 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27878 maxText : "This date is after the maximum date",
27880 * @cfg {String} format
27881 * The default date format string which can be overriden for localization support. The format must be
27882 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27886 * @cfg {Array} disabledDays
27887 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27889 disabledDays : null,
27891 * @cfg {String} disabledDaysText
27892 * The tooltip to display when the date falls on a disabled day (defaults to "")
27894 disabledDaysText : "",
27896 * @cfg {RegExp} disabledDatesRE
27897 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27899 disabledDatesRE : null,
27901 * @cfg {String} disabledDatesText
27902 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27904 disabledDatesText : "",
27906 * @cfg {Boolean} constrainToViewport
27907 * True to constrain the date picker to the viewport (defaults to true)
27909 constrainToViewport : true,
27911 * @cfg {Array} monthNames
27912 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27914 monthNames : Date.monthNames,
27916 * @cfg {Array} dayNames
27917 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27919 dayNames : Date.dayNames,
27921 * @cfg {String} nextText
27922 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27924 nextText: 'Next Month (Control+Right)',
27926 * @cfg {String} prevText
27927 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27929 prevText: 'Previous Month (Control+Left)',
27931 * @cfg {String} monthYearText
27932 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27934 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27936 * @cfg {Number} startDay
27937 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27941 * @cfg {Bool} showClear
27942 * Show a clear button (usefull for date form elements that can be blank.)
27948 * Sets the value of the date field
27949 * @param {Date} value The date to set
27951 setValue : function(value){
27952 var old = this.value;
27954 if (typeof(value) == 'string') {
27956 value = Date.parseDate(value, this.format);
27959 value = new Date();
27962 this.value = value.clearTime(true);
27964 this.update(this.value);
27969 * Gets the current selected value of the date field
27970 * @return {Date} The selected date
27972 getValue : function(){
27977 focus : function(){
27979 this.update(this.activeDate);
27984 onRender : function(container, position){
27987 '<table cellspacing="0">',
27988 '<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>',
27989 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27990 var dn = this.dayNames;
27991 for(var i = 0; i < 7; i++){
27992 var d = this.startDay+i;
27996 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27998 m[m.length] = "</tr></thead><tbody><tr>";
27999 for(var i = 0; i < 42; i++) {
28000 if(i % 7 == 0 && i != 0){
28001 m[m.length] = "</tr><tr>";
28003 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28005 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28006 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28008 var el = document.createElement("div");
28009 el.className = "x-date-picker";
28010 el.innerHTML = m.join("");
28012 container.dom.insertBefore(el, position);
28014 this.el = Roo.get(el);
28015 this.eventEl = Roo.get(el.firstChild);
28017 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28018 handler: this.showPrevMonth,
28020 preventDefault:true,
28024 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28025 handler: this.showNextMonth,
28027 preventDefault:true,
28031 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28033 this.monthPicker = this.el.down('div.x-date-mp');
28034 this.monthPicker.enableDisplayMode('block');
28036 var kn = new Roo.KeyNav(this.eventEl, {
28037 "left" : function(e){
28039 this.showPrevMonth() :
28040 this.update(this.activeDate.add("d", -1));
28043 "right" : function(e){
28045 this.showNextMonth() :
28046 this.update(this.activeDate.add("d", 1));
28049 "up" : function(e){
28051 this.showNextYear() :
28052 this.update(this.activeDate.add("d", -7));
28055 "down" : function(e){
28057 this.showPrevYear() :
28058 this.update(this.activeDate.add("d", 7));
28061 "pageUp" : function(e){
28062 this.showNextMonth();
28065 "pageDown" : function(e){
28066 this.showPrevMonth();
28069 "enter" : function(e){
28070 e.stopPropagation();
28077 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28079 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28081 this.el.unselectable();
28083 this.cells = this.el.select("table.x-date-inner tbody td");
28084 this.textNodes = this.el.query("table.x-date-inner tbody span");
28086 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28088 tooltip: this.monthYearText
28091 this.mbtn.on('click', this.showMonthPicker, this);
28092 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28095 var today = (new Date()).dateFormat(this.format);
28097 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28098 if (this.showClear) {
28099 baseTb.add( new Roo.Toolbar.Fill());
28102 text: String.format(this.todayText, today),
28103 tooltip: String.format(this.todayTip, today),
28104 handler: this.selectToday,
28108 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28111 if (this.showClear) {
28113 baseTb.add( new Roo.Toolbar.Fill());
28116 cls: 'x-btn-icon x-btn-clear',
28117 handler: function() {
28119 this.fireEvent("select", this, '');
28129 this.update(this.value);
28132 createMonthPicker : function(){
28133 if(!this.monthPicker.dom.firstChild){
28134 var buf = ['<table border="0" cellspacing="0">'];
28135 for(var i = 0; i < 6; i++){
28137 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28138 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28140 '<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>' :
28141 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28145 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28147 '</button><button type="button" class="x-date-mp-cancel">',
28149 '</button></td></tr>',
28152 this.monthPicker.update(buf.join(''));
28153 this.monthPicker.on('click', this.onMonthClick, this);
28154 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28156 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28157 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28159 this.mpMonths.each(function(m, a, i){
28162 m.dom.xmonth = 5 + Math.round(i * .5);
28164 m.dom.xmonth = Math.round((i-1) * .5);
28170 showMonthPicker : function(){
28171 this.createMonthPicker();
28172 var size = this.el.getSize();
28173 this.monthPicker.setSize(size);
28174 this.monthPicker.child('table').setSize(size);
28176 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28177 this.updateMPMonth(this.mpSelMonth);
28178 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28179 this.updateMPYear(this.mpSelYear);
28181 this.monthPicker.slideIn('t', {duration:.2});
28184 updateMPYear : function(y){
28186 var ys = this.mpYears.elements;
28187 for(var i = 1; i <= 10; i++){
28188 var td = ys[i-1], y2;
28190 y2 = y + Math.round(i * .5);
28191 td.firstChild.innerHTML = y2;
28194 y2 = y - (5-Math.round(i * .5));
28195 td.firstChild.innerHTML = y2;
28198 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28202 updateMPMonth : function(sm){
28203 this.mpMonths.each(function(m, a, i){
28204 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28208 selectMPMonth: function(m){
28212 onMonthClick : function(e, t){
28214 var el = new Roo.Element(t), pn;
28215 if(el.is('button.x-date-mp-cancel')){
28216 this.hideMonthPicker();
28218 else if(el.is('button.x-date-mp-ok')){
28219 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28220 this.hideMonthPicker();
28222 else if(pn = el.up('td.x-date-mp-month', 2)){
28223 this.mpMonths.removeClass('x-date-mp-sel');
28224 pn.addClass('x-date-mp-sel');
28225 this.mpSelMonth = pn.dom.xmonth;
28227 else if(pn = el.up('td.x-date-mp-year', 2)){
28228 this.mpYears.removeClass('x-date-mp-sel');
28229 pn.addClass('x-date-mp-sel');
28230 this.mpSelYear = pn.dom.xyear;
28232 else if(el.is('a.x-date-mp-prev')){
28233 this.updateMPYear(this.mpyear-10);
28235 else if(el.is('a.x-date-mp-next')){
28236 this.updateMPYear(this.mpyear+10);
28240 onMonthDblClick : function(e, t){
28242 var el = new Roo.Element(t), pn;
28243 if(pn = el.up('td.x-date-mp-month', 2)){
28244 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28245 this.hideMonthPicker();
28247 else if(pn = el.up('td.x-date-mp-year', 2)){
28248 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28249 this.hideMonthPicker();
28253 hideMonthPicker : function(disableAnim){
28254 if(this.monthPicker){
28255 if(disableAnim === true){
28256 this.monthPicker.hide();
28258 this.monthPicker.slideOut('t', {duration:.2});
28264 showPrevMonth : function(e){
28265 this.update(this.activeDate.add("mo", -1));
28269 showNextMonth : function(e){
28270 this.update(this.activeDate.add("mo", 1));
28274 showPrevYear : function(){
28275 this.update(this.activeDate.add("y", -1));
28279 showNextYear : function(){
28280 this.update(this.activeDate.add("y", 1));
28284 handleMouseWheel : function(e){
28285 var delta = e.getWheelDelta();
28287 this.showPrevMonth();
28289 } else if(delta < 0){
28290 this.showNextMonth();
28296 handleDateClick : function(e, t){
28298 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28299 this.setValue(new Date(t.dateValue));
28300 this.fireEvent("select", this, this.value);
28305 selectToday : function(){
28306 this.setValue(new Date().clearTime());
28307 this.fireEvent("select", this, this.value);
28311 update : function(date)
28313 var vd = this.activeDate;
28314 this.activeDate = date;
28316 var t = date.getTime();
28317 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28318 this.cells.removeClass("x-date-selected");
28319 this.cells.each(function(c){
28320 if(c.dom.firstChild.dateValue == t){
28321 c.addClass("x-date-selected");
28322 setTimeout(function(){
28323 try{c.dom.firstChild.focus();}catch(e){}
28332 var days = date.getDaysInMonth();
28333 var firstOfMonth = date.getFirstDateOfMonth();
28334 var startingPos = firstOfMonth.getDay()-this.startDay;
28336 if(startingPos <= this.startDay){
28340 var pm = date.add("mo", -1);
28341 var prevStart = pm.getDaysInMonth()-startingPos;
28343 var cells = this.cells.elements;
28344 var textEls = this.textNodes;
28345 days += startingPos;
28347 // convert everything to numbers so it's fast
28348 var day = 86400000;
28349 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28350 var today = new Date().clearTime().getTime();
28351 var sel = date.clearTime().getTime();
28352 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28353 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28354 var ddMatch = this.disabledDatesRE;
28355 var ddText = this.disabledDatesText;
28356 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28357 var ddaysText = this.disabledDaysText;
28358 var format = this.format;
28360 var setCellClass = function(cal, cell){
28362 var t = d.getTime();
28363 cell.firstChild.dateValue = t;
28365 cell.className += " x-date-today";
28366 cell.title = cal.todayText;
28369 cell.className += " x-date-selected";
28370 setTimeout(function(){
28371 try{cell.firstChild.focus();}catch(e){}
28376 cell.className = " x-date-disabled";
28377 cell.title = cal.minText;
28381 cell.className = " x-date-disabled";
28382 cell.title = cal.maxText;
28386 if(ddays.indexOf(d.getDay()) != -1){
28387 cell.title = ddaysText;
28388 cell.className = " x-date-disabled";
28391 if(ddMatch && format){
28392 var fvalue = d.dateFormat(format);
28393 if(ddMatch.test(fvalue)){
28394 cell.title = ddText.replace("%0", fvalue);
28395 cell.className = " x-date-disabled";
28401 for(; i < startingPos; i++) {
28402 textEls[i].innerHTML = (++prevStart);
28403 d.setDate(d.getDate()+1);
28404 cells[i].className = "x-date-prevday";
28405 setCellClass(this, cells[i]);
28407 for(; i < days; i++){
28408 intDay = i - startingPos + 1;
28409 textEls[i].innerHTML = (intDay);
28410 d.setDate(d.getDate()+1);
28411 cells[i].className = "x-date-active";
28412 setCellClass(this, cells[i]);
28415 for(; i < 42; i++) {
28416 textEls[i].innerHTML = (++extraDays);
28417 d.setDate(d.getDate()+1);
28418 cells[i].className = "x-date-nextday";
28419 setCellClass(this, cells[i]);
28422 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28423 this.fireEvent('monthchange', this, date);
28425 if(!this.internalRender){
28426 var main = this.el.dom.firstChild;
28427 var w = main.offsetWidth;
28428 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28429 Roo.fly(main).setWidth(w);
28430 this.internalRender = true;
28431 // opera does not respect the auto grow header center column
28432 // then, after it gets a width opera refuses to recalculate
28433 // without a second pass
28434 if(Roo.isOpera && !this.secondPass){
28435 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28436 this.secondPass = true;
28437 this.update.defer(10, this, [date]);
28445 * Ext JS Library 1.1.1
28446 * Copyright(c) 2006-2007, Ext JS, LLC.
28448 * Originally Released Under LGPL - original licence link has changed is not relivant.
28451 * <script type="text/javascript">
28454 * @class Roo.TabPanel
28455 * @extends Roo.util.Observable
28456 * A lightweight tab container.
28460 // basic tabs 1, built from existing content
28461 var tabs = new Roo.TabPanel("tabs1");
28462 tabs.addTab("script", "View Script");
28463 tabs.addTab("markup", "View Markup");
28464 tabs.activate("script");
28466 // more advanced tabs, built from javascript
28467 var jtabs = new Roo.TabPanel("jtabs");
28468 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28470 // set up the UpdateManager
28471 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28472 var updater = tab2.getUpdateManager();
28473 updater.setDefaultUrl("ajax1.htm");
28474 tab2.on('activate', updater.refresh, updater, true);
28476 // Use setUrl for Ajax loading
28477 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28478 tab3.setUrl("ajax2.htm", null, true);
28481 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28484 jtabs.activate("jtabs-1");
28487 * Create a new TabPanel.
28488 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28489 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28491 Roo.TabPanel = function(container, config){
28493 * The container element for this TabPanel.
28494 * @type Roo.Element
28496 this.el = Roo.get(container, true);
28498 if(typeof config == "boolean"){
28499 this.tabPosition = config ? "bottom" : "top";
28501 Roo.apply(this, config);
28504 if(this.tabPosition == "bottom"){
28505 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28506 this.el.addClass("x-tabs-bottom");
28508 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28509 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28510 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28512 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28514 if(this.tabPosition != "bottom"){
28515 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28516 * @type Roo.Element
28518 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28519 this.el.addClass("x-tabs-top");
28523 this.bodyEl.setStyle("position", "relative");
28525 this.active = null;
28526 this.activateDelegate = this.activate.createDelegate(this);
28531 * Fires when the active tab changes
28532 * @param {Roo.TabPanel} this
28533 * @param {Roo.TabPanelItem} activePanel The new active tab
28537 * @event beforetabchange
28538 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28539 * @param {Roo.TabPanel} this
28540 * @param {Object} e Set cancel to true on this object to cancel the tab change
28541 * @param {Roo.TabPanelItem} tab The tab being changed to
28543 "beforetabchange" : true
28546 Roo.EventManager.onWindowResize(this.onResize, this);
28547 this.cpad = this.el.getPadding("lr");
28548 this.hiddenCount = 0;
28551 // toolbar on the tabbar support...
28552 if (this.toolbar) {
28553 var tcfg = this.toolbar;
28554 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28555 this.toolbar = new Roo.Toolbar(tcfg);
28556 if (Roo.isSafari) {
28557 var tbl = tcfg.container.child('table', true);
28558 tbl.setAttribute('width', '100%');
28565 Roo.TabPanel.superclass.constructor.call(this);
28568 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28570 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28572 tabPosition : "top",
28574 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28576 currentTabWidth : 0,
28578 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28582 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28586 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28588 preferredTabWidth : 175,
28590 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28592 resizeTabs : false,
28594 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28596 monitorResize : true,
28598 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28603 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28604 * @param {String} id The id of the div to use <b>or create</b>
28605 * @param {String} text The text for the tab
28606 * @param {String} content (optional) Content to put in the TabPanelItem body
28607 * @param {Boolean} closable (optional) True to create a close icon on the tab
28608 * @return {Roo.TabPanelItem} The created TabPanelItem
28610 addTab : function(id, text, content, closable){
28611 var item = new Roo.TabPanelItem(this, id, text, closable);
28612 this.addTabItem(item);
28614 item.setContent(content);
28620 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28621 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28622 * @return {Roo.TabPanelItem}
28624 getTab : function(id){
28625 return this.items[id];
28629 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28630 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28632 hideTab : function(id){
28633 var t = this.items[id];
28636 this.hiddenCount++;
28637 this.autoSizeTabs();
28642 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28643 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28645 unhideTab : function(id){
28646 var t = this.items[id];
28648 t.setHidden(false);
28649 this.hiddenCount--;
28650 this.autoSizeTabs();
28655 * Adds an existing {@link Roo.TabPanelItem}.
28656 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28658 addTabItem : function(item){
28659 this.items[item.id] = item;
28660 this.items.push(item);
28661 if(this.resizeTabs){
28662 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28663 this.autoSizeTabs();
28670 * Removes a {@link Roo.TabPanelItem}.
28671 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28673 removeTab : function(id){
28674 var items = this.items;
28675 var tab = items[id];
28676 if(!tab) { return; }
28677 var index = items.indexOf(tab);
28678 if(this.active == tab && items.length > 1){
28679 var newTab = this.getNextAvailable(index);
28684 this.stripEl.dom.removeChild(tab.pnode.dom);
28685 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28686 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28688 items.splice(index, 1);
28689 delete this.items[tab.id];
28690 tab.fireEvent("close", tab);
28691 tab.purgeListeners();
28692 this.autoSizeTabs();
28695 getNextAvailable : function(start){
28696 var items = this.items;
28698 // look for a next tab that will slide over to
28699 // replace the one being removed
28700 while(index < items.length){
28701 var item = items[++index];
28702 if(item && !item.isHidden()){
28706 // if one isn't found select the previous tab (on the left)
28709 var item = items[--index];
28710 if(item && !item.isHidden()){
28718 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28719 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28721 disableTab : function(id){
28722 var tab = this.items[id];
28723 if(tab && this.active != tab){
28729 * Enables a {@link Roo.TabPanelItem} that is disabled.
28730 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28732 enableTab : function(id){
28733 var tab = this.items[id];
28738 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28739 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28740 * @return {Roo.TabPanelItem} The TabPanelItem.
28742 activate : function(id){
28743 var tab = this.items[id];
28747 if(tab == this.active || tab.disabled){
28751 this.fireEvent("beforetabchange", this, e, tab);
28752 if(e.cancel !== true && !tab.disabled){
28754 this.active.hide();
28756 this.active = this.items[id];
28757 this.active.show();
28758 this.fireEvent("tabchange", this, this.active);
28764 * Gets the active {@link Roo.TabPanelItem}.
28765 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28767 getActiveTab : function(){
28768 return this.active;
28772 * Updates the tab body element to fit the height of the container element
28773 * for overflow scrolling
28774 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28776 syncHeight : function(targetHeight){
28777 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28778 var bm = this.bodyEl.getMargins();
28779 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28780 this.bodyEl.setHeight(newHeight);
28784 onResize : function(){
28785 if(this.monitorResize){
28786 this.autoSizeTabs();
28791 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28793 beginUpdate : function(){
28794 this.updating = true;
28798 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28800 endUpdate : function(){
28801 this.updating = false;
28802 this.autoSizeTabs();
28806 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28808 autoSizeTabs : function(){
28809 var count = this.items.length;
28810 var vcount = count - this.hiddenCount;
28811 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28814 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28815 var availWidth = Math.floor(w / vcount);
28816 var b = this.stripBody;
28817 if(b.getWidth() > w){
28818 var tabs = this.items;
28819 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28820 if(availWidth < this.minTabWidth){
28821 /*if(!this.sleft){ // incomplete scrolling code
28822 this.createScrollButtons();
28825 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28828 if(this.currentTabWidth < this.preferredTabWidth){
28829 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28835 * Returns the number of tabs in this TabPanel.
28838 getCount : function(){
28839 return this.items.length;
28843 * Resizes all the tabs to the passed width
28844 * @param {Number} The new width
28846 setTabWidth : function(width){
28847 this.currentTabWidth = width;
28848 for(var i = 0, len = this.items.length; i < len; i++) {
28849 if(!this.items[i].isHidden()) {
28850 this.items[i].setWidth(width);
28856 * Destroys this TabPanel
28857 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28859 destroy : function(removeEl){
28860 Roo.EventManager.removeResizeListener(this.onResize, this);
28861 for(var i = 0, len = this.items.length; i < len; i++){
28862 this.items[i].purgeListeners();
28864 if(removeEl === true){
28865 this.el.update("");
28872 * @class Roo.TabPanelItem
28873 * @extends Roo.util.Observable
28874 * Represents an individual item (tab plus body) in a TabPanel.
28875 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28876 * @param {String} id The id of this TabPanelItem
28877 * @param {String} text The text for the tab of this TabPanelItem
28878 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28880 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28882 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28883 * @type Roo.TabPanel
28885 this.tabPanel = tabPanel;
28887 * The id for this TabPanelItem
28892 this.disabled = false;
28896 this.loaded = false;
28897 this.closable = closable;
28900 * The body element for this TabPanelItem.
28901 * @type Roo.Element
28903 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28904 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28905 this.bodyEl.setStyle("display", "block");
28906 this.bodyEl.setStyle("zoom", "1");
28909 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28911 this.el = Roo.get(els.el, true);
28912 this.inner = Roo.get(els.inner, true);
28913 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28914 this.pnode = Roo.get(els.el.parentNode, true);
28915 this.el.on("mousedown", this.onTabMouseDown, this);
28916 this.el.on("click", this.onTabClick, this);
28919 var c = Roo.get(els.close, true);
28920 c.dom.title = this.closeText;
28921 c.addClassOnOver("close-over");
28922 c.on("click", this.closeClick, this);
28928 * Fires when this tab becomes the active tab.
28929 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28930 * @param {Roo.TabPanelItem} this
28934 * @event beforeclose
28935 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28936 * @param {Roo.TabPanelItem} this
28937 * @param {Object} e Set cancel to true on this object to cancel the close.
28939 "beforeclose": true,
28942 * Fires when this tab is closed.
28943 * @param {Roo.TabPanelItem} this
28947 * @event deactivate
28948 * Fires when this tab is no longer the active tab.
28949 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28950 * @param {Roo.TabPanelItem} this
28952 "deactivate" : true
28954 this.hidden = false;
28956 Roo.TabPanelItem.superclass.constructor.call(this);
28959 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28960 purgeListeners : function(){
28961 Roo.util.Observable.prototype.purgeListeners.call(this);
28962 this.el.removeAllListeners();
28965 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28968 this.pnode.addClass("on");
28971 this.tabPanel.stripWrap.repaint();
28973 this.fireEvent("activate", this.tabPanel, this);
28977 * Returns true if this tab is the active tab.
28978 * @return {Boolean}
28980 isActive : function(){
28981 return this.tabPanel.getActiveTab() == this;
28985 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28988 this.pnode.removeClass("on");
28990 this.fireEvent("deactivate", this.tabPanel, this);
28993 hideAction : function(){
28994 this.bodyEl.hide();
28995 this.bodyEl.setStyle("position", "absolute");
28996 this.bodyEl.setLeft("-20000px");
28997 this.bodyEl.setTop("-20000px");
29000 showAction : function(){
29001 this.bodyEl.setStyle("position", "relative");
29002 this.bodyEl.setTop("");
29003 this.bodyEl.setLeft("");
29004 this.bodyEl.show();
29008 * Set the tooltip for the tab.
29009 * @param {String} tooltip The tab's tooltip
29011 setTooltip : function(text){
29012 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29013 this.textEl.dom.qtip = text;
29014 this.textEl.dom.removeAttribute('title');
29016 this.textEl.dom.title = text;
29020 onTabClick : function(e){
29021 e.preventDefault();
29022 this.tabPanel.activate(this.id);
29025 onTabMouseDown : function(e){
29026 e.preventDefault();
29027 this.tabPanel.activate(this.id);
29030 getWidth : function(){
29031 return this.inner.getWidth();
29034 setWidth : function(width){
29035 var iwidth = width - this.pnode.getPadding("lr");
29036 this.inner.setWidth(iwidth);
29037 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29038 this.pnode.setWidth(width);
29042 * Show or hide the tab
29043 * @param {Boolean} hidden True to hide or false to show.
29045 setHidden : function(hidden){
29046 this.hidden = hidden;
29047 this.pnode.setStyle("display", hidden ? "none" : "");
29051 * Returns true if this tab is "hidden"
29052 * @return {Boolean}
29054 isHidden : function(){
29055 return this.hidden;
29059 * Returns the text for this tab
29062 getText : function(){
29066 autoSize : function(){
29067 //this.el.beginMeasure();
29068 this.textEl.setWidth(1);
29070 * #2804 [new] Tabs in Roojs
29071 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29073 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29074 //this.el.endMeasure();
29078 * Sets the text for the tab (Note: this also sets the tooltip text)
29079 * @param {String} text The tab's text and tooltip
29081 setText : function(text){
29083 this.textEl.update(text);
29084 this.setTooltip(text);
29085 if(!this.tabPanel.resizeTabs){
29090 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29092 activate : function(){
29093 this.tabPanel.activate(this.id);
29097 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29099 disable : function(){
29100 if(this.tabPanel.active != this){
29101 this.disabled = true;
29102 this.pnode.addClass("disabled");
29107 * Enables this TabPanelItem if it was previously disabled.
29109 enable : function(){
29110 this.disabled = false;
29111 this.pnode.removeClass("disabled");
29115 * Sets the content for this TabPanelItem.
29116 * @param {String} content The content
29117 * @param {Boolean} loadScripts true to look for and load scripts
29119 setContent : function(content, loadScripts){
29120 this.bodyEl.update(content, loadScripts);
29124 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29125 * @return {Roo.UpdateManager} The UpdateManager
29127 getUpdateManager : function(){
29128 return this.bodyEl.getUpdateManager();
29132 * Set a URL to be used to load the content for this TabPanelItem.
29133 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29134 * @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)
29135 * @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)
29136 * @return {Roo.UpdateManager} The UpdateManager
29138 setUrl : function(url, params, loadOnce){
29139 if(this.refreshDelegate){
29140 this.un('activate', this.refreshDelegate);
29142 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29143 this.on("activate", this.refreshDelegate);
29144 return this.bodyEl.getUpdateManager();
29148 _handleRefresh : function(url, params, loadOnce){
29149 if(!loadOnce || !this.loaded){
29150 var updater = this.bodyEl.getUpdateManager();
29151 updater.update(url, params, this._setLoaded.createDelegate(this));
29156 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29157 * Will fail silently if the setUrl method has not been called.
29158 * This does not activate the panel, just updates its content.
29160 refresh : function(){
29161 if(this.refreshDelegate){
29162 this.loaded = false;
29163 this.refreshDelegate();
29168 _setLoaded : function(){
29169 this.loaded = true;
29173 closeClick : function(e){
29176 this.fireEvent("beforeclose", this, o);
29177 if(o.cancel !== true){
29178 this.tabPanel.removeTab(this.id);
29182 * The text displayed in the tooltip for the close icon.
29185 closeText : "Close this tab"
29189 Roo.TabPanel.prototype.createStrip = function(container){
29190 var strip = document.createElement("div");
29191 strip.className = "x-tabs-wrap";
29192 container.appendChild(strip);
29196 Roo.TabPanel.prototype.createStripList = function(strip){
29197 // div wrapper for retard IE
29198 // returns the "tr" element.
29199 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29200 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29201 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29202 return strip.firstChild.firstChild.firstChild.firstChild;
29205 Roo.TabPanel.prototype.createBody = function(container){
29206 var body = document.createElement("div");
29207 Roo.id(body, "tab-body");
29208 Roo.fly(body).addClass("x-tabs-body");
29209 container.appendChild(body);
29213 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29214 var body = Roo.getDom(id);
29216 body = document.createElement("div");
29219 Roo.fly(body).addClass("x-tabs-item-body");
29220 bodyEl.insertBefore(body, bodyEl.firstChild);
29224 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29225 var td = document.createElement("td");
29226 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29227 //stripEl.appendChild(td);
29229 td.className = "x-tabs-closable";
29230 if(!this.closeTpl){
29231 this.closeTpl = new Roo.Template(
29232 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29233 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29234 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29237 var el = this.closeTpl.overwrite(td, {"text": text});
29238 var close = el.getElementsByTagName("div")[0];
29239 var inner = el.getElementsByTagName("em")[0];
29240 return {"el": el, "close": close, "inner": inner};
29243 this.tabTpl = new Roo.Template(
29244 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29245 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29248 var el = this.tabTpl.overwrite(td, {"text": text});
29249 var inner = el.getElementsByTagName("em")[0];
29250 return {"el": el, "inner": inner};
29254 * Ext JS Library 1.1.1
29255 * Copyright(c) 2006-2007, Ext JS, LLC.
29257 * Originally Released Under LGPL - original licence link has changed is not relivant.
29260 * <script type="text/javascript">
29264 * @class Roo.Button
29265 * @extends Roo.util.Observable
29266 * Simple Button class
29267 * @cfg {String} text The button text
29268 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29269 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29270 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29271 * @cfg {Object} scope The scope of the handler
29272 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29273 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29274 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29275 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29276 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29277 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29278 applies if enableToggle = true)
29279 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29280 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29281 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29283 * Create a new button
29284 * @param {Object} config The config object
29286 Roo.Button = function(renderTo, config)
29290 renderTo = config.renderTo || false;
29293 Roo.apply(this, config);
29297 * Fires when this button is clicked
29298 * @param {Button} this
29299 * @param {EventObject} e The click event
29304 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29305 * @param {Button} this
29306 * @param {Boolean} pressed
29311 * Fires when the mouse hovers over the button
29312 * @param {Button} this
29313 * @param {Event} e The event object
29315 'mouseover' : true,
29318 * Fires when the mouse exits the button
29319 * @param {Button} this
29320 * @param {Event} e The event object
29325 * Fires when the button is rendered
29326 * @param {Button} this
29331 this.menu = Roo.menu.MenuMgr.get(this.menu);
29333 // register listeners first!! - so render can be captured..
29334 Roo.util.Observable.call(this);
29336 this.render(renderTo);
29342 Roo.extend(Roo.Button, Roo.util.Observable, {
29348 * Read-only. True if this button is hidden
29353 * Read-only. True if this button is disabled
29358 * Read-only. True if this button is pressed (only if enableToggle = true)
29364 * @cfg {Number} tabIndex
29365 * The DOM tabIndex for this button (defaults to undefined)
29367 tabIndex : undefined,
29370 * @cfg {Boolean} enableToggle
29371 * True to enable pressed/not pressed toggling (defaults to false)
29373 enableToggle: false,
29375 * @cfg {Mixed} menu
29376 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29380 * @cfg {String} menuAlign
29381 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29383 menuAlign : "tl-bl?",
29386 * @cfg {String} iconCls
29387 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29389 iconCls : undefined,
29391 * @cfg {String} type
29392 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29397 menuClassTarget: 'tr',
29400 * @cfg {String} clickEvent
29401 * The type of event to map to the button's event handler (defaults to 'click')
29403 clickEvent : 'click',
29406 * @cfg {Boolean} handleMouseEvents
29407 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29409 handleMouseEvents : true,
29412 * @cfg {String} tooltipType
29413 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29415 tooltipType : 'qtip',
29418 * @cfg {String} cls
29419 * A CSS class to apply to the button's main element.
29423 * @cfg {Roo.Template} template (Optional)
29424 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29425 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29426 * require code modifications if required elements (e.g. a button) aren't present.
29430 render : function(renderTo){
29432 if(this.hideParent){
29433 this.parentEl = Roo.get(renderTo);
29435 if(!this.dhconfig){
29436 if(!this.template){
29437 if(!Roo.Button.buttonTemplate){
29438 // hideous table template
29439 Roo.Button.buttonTemplate = new Roo.Template(
29440 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29441 '<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>',
29442 "</tr></tbody></table>");
29444 this.template = Roo.Button.buttonTemplate;
29446 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29447 var btnEl = btn.child("button:first");
29448 btnEl.on('focus', this.onFocus, this);
29449 btnEl.on('blur', this.onBlur, this);
29451 btn.addClass(this.cls);
29454 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29457 btnEl.addClass(this.iconCls);
29459 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29462 if(this.tabIndex !== undefined){
29463 btnEl.dom.tabIndex = this.tabIndex;
29466 if(typeof this.tooltip == 'object'){
29467 Roo.QuickTips.tips(Roo.apply({
29471 btnEl.dom[this.tooltipType] = this.tooltip;
29475 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29479 this.el.dom.id = this.el.id = this.id;
29482 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29483 this.menu.on("show", this.onMenuShow, this);
29484 this.menu.on("hide", this.onMenuHide, this);
29486 btn.addClass("x-btn");
29487 if(Roo.isIE && !Roo.isIE7){
29488 this.autoWidth.defer(1, this);
29492 if(this.handleMouseEvents){
29493 btn.on("mouseover", this.onMouseOver, this);
29494 btn.on("mouseout", this.onMouseOut, this);
29495 btn.on("mousedown", this.onMouseDown, this);
29497 btn.on(this.clickEvent, this.onClick, this);
29498 //btn.on("mouseup", this.onMouseUp, this);
29505 Roo.ButtonToggleMgr.register(this);
29507 this.el.addClass("x-btn-pressed");
29510 var repeater = new Roo.util.ClickRepeater(btn,
29511 typeof this.repeat == "object" ? this.repeat : {}
29513 repeater.on("click", this.onClick, this);
29516 this.fireEvent('render', this);
29520 * Returns the button's underlying element
29521 * @return {Roo.Element} The element
29523 getEl : function(){
29528 * Destroys this Button and removes any listeners.
29530 destroy : function(){
29531 Roo.ButtonToggleMgr.unregister(this);
29532 this.el.removeAllListeners();
29533 this.purgeListeners();
29538 autoWidth : function(){
29540 this.el.setWidth("auto");
29541 if(Roo.isIE7 && Roo.isStrict){
29542 var ib = this.el.child('button');
29543 if(ib && ib.getWidth() > 20){
29545 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29550 this.el.beginMeasure();
29552 if(this.el.getWidth() < this.minWidth){
29553 this.el.setWidth(this.minWidth);
29556 this.el.endMeasure();
29563 * Assigns this button's click handler
29564 * @param {Function} handler The function to call when the button is clicked
29565 * @param {Object} scope (optional) Scope for the function passed in
29567 setHandler : function(handler, scope){
29568 this.handler = handler;
29569 this.scope = scope;
29573 * Sets this button's text
29574 * @param {String} text The button text
29576 setText : function(text){
29579 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29585 * Gets the text for this button
29586 * @return {String} The button text
29588 getText : function(){
29596 this.hidden = false;
29598 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29606 this.hidden = true;
29608 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29613 * Convenience function for boolean show/hide
29614 * @param {Boolean} visible True to show, false to hide
29616 setVisible: function(visible){
29625 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29626 * @param {Boolean} state (optional) Force a particular state
29628 toggle : function(state){
29629 state = state === undefined ? !this.pressed : state;
29630 if(state != this.pressed){
29632 this.el.addClass("x-btn-pressed");
29633 this.pressed = true;
29634 this.fireEvent("toggle", this, true);
29636 this.el.removeClass("x-btn-pressed");
29637 this.pressed = false;
29638 this.fireEvent("toggle", this, false);
29640 if(this.toggleHandler){
29641 this.toggleHandler.call(this.scope || this, this, state);
29649 focus : function(){
29650 this.el.child('button:first').focus();
29654 * Disable this button
29656 disable : function(){
29658 this.el.addClass("x-btn-disabled");
29660 this.disabled = true;
29664 * Enable this button
29666 enable : function(){
29668 this.el.removeClass("x-btn-disabled");
29670 this.disabled = false;
29674 * Convenience function for boolean enable/disable
29675 * @param {Boolean} enabled True to enable, false to disable
29677 setDisabled : function(v){
29678 this[v !== true ? "enable" : "disable"]();
29682 onClick : function(e)
29685 e.preventDefault();
29690 if(!this.disabled){
29691 if(this.enableToggle){
29694 if(this.menu && !this.menu.isVisible()){
29695 this.menu.show(this.el, this.menuAlign);
29697 this.fireEvent("click", this, e);
29699 this.el.removeClass("x-btn-over");
29700 this.handler.call(this.scope || this, this, e);
29705 onMouseOver : function(e){
29706 if(!this.disabled){
29707 this.el.addClass("x-btn-over");
29708 this.fireEvent('mouseover', this, e);
29712 onMouseOut : function(e){
29713 if(!e.within(this.el, true)){
29714 this.el.removeClass("x-btn-over");
29715 this.fireEvent('mouseout', this, e);
29719 onFocus : function(e){
29720 if(!this.disabled){
29721 this.el.addClass("x-btn-focus");
29725 onBlur : function(e){
29726 this.el.removeClass("x-btn-focus");
29729 onMouseDown : function(e){
29730 if(!this.disabled && e.button == 0){
29731 this.el.addClass("x-btn-click");
29732 Roo.get(document).on('mouseup', this.onMouseUp, this);
29736 onMouseUp : function(e){
29738 this.el.removeClass("x-btn-click");
29739 Roo.get(document).un('mouseup', this.onMouseUp, this);
29743 onMenuShow : function(e){
29744 this.el.addClass("x-btn-menu-active");
29747 onMenuHide : function(e){
29748 this.el.removeClass("x-btn-menu-active");
29752 // Private utility class used by Button
29753 Roo.ButtonToggleMgr = function(){
29756 function toggleGroup(btn, state){
29758 var g = groups[btn.toggleGroup];
29759 for(var i = 0, l = g.length; i < l; i++){
29761 g[i].toggle(false);
29768 register : function(btn){
29769 if(!btn.toggleGroup){
29772 var g = groups[btn.toggleGroup];
29774 g = groups[btn.toggleGroup] = [];
29777 btn.on("toggle", toggleGroup);
29780 unregister : function(btn){
29781 if(!btn.toggleGroup){
29784 var g = groups[btn.toggleGroup];
29787 btn.un("toggle", toggleGroup);
29793 * Ext JS Library 1.1.1
29794 * Copyright(c) 2006-2007, Ext JS, LLC.
29796 * Originally Released Under LGPL - original licence link has changed is not relivant.
29799 * <script type="text/javascript">
29803 * @class Roo.SplitButton
29804 * @extends Roo.Button
29805 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29806 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29807 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29808 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29809 * @cfg {String} arrowTooltip The title attribute of the arrow
29811 * Create a new menu button
29812 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29813 * @param {Object} config The config object
29815 Roo.SplitButton = function(renderTo, config){
29816 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29818 * @event arrowclick
29819 * Fires when this button's arrow is clicked
29820 * @param {SplitButton} this
29821 * @param {EventObject} e The click event
29823 this.addEvents({"arrowclick":true});
29826 Roo.extend(Roo.SplitButton, Roo.Button, {
29827 render : function(renderTo){
29828 // this is one sweet looking template!
29829 var tpl = new Roo.Template(
29830 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29831 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29832 '<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>',
29833 "</tbody></table></td><td>",
29834 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29835 '<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>',
29836 "</tbody></table></td></tr></table>"
29838 var btn = tpl.append(renderTo, [this.text, this.type], true);
29839 var btnEl = btn.child("button");
29841 btn.addClass(this.cls);
29844 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29847 btnEl.addClass(this.iconCls);
29849 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29853 if(this.handleMouseEvents){
29854 btn.on("mouseover", this.onMouseOver, this);
29855 btn.on("mouseout", this.onMouseOut, this);
29856 btn.on("mousedown", this.onMouseDown, this);
29857 btn.on("mouseup", this.onMouseUp, this);
29859 btn.on(this.clickEvent, this.onClick, this);
29861 if(typeof this.tooltip == 'object'){
29862 Roo.QuickTips.tips(Roo.apply({
29866 btnEl.dom[this.tooltipType] = this.tooltip;
29869 if(this.arrowTooltip){
29870 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29879 this.el.addClass("x-btn-pressed");
29881 if(Roo.isIE && !Roo.isIE7){
29882 this.autoWidth.defer(1, this);
29887 this.menu.on("show", this.onMenuShow, this);
29888 this.menu.on("hide", this.onMenuHide, this);
29890 this.fireEvent('render', this);
29894 autoWidth : function(){
29896 var tbl = this.el.child("table:first");
29897 var tbl2 = this.el.child("table:last");
29898 this.el.setWidth("auto");
29899 tbl.setWidth("auto");
29900 if(Roo.isIE7 && Roo.isStrict){
29901 var ib = this.el.child('button:first');
29902 if(ib && ib.getWidth() > 20){
29904 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29909 this.el.beginMeasure();
29911 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29912 tbl.setWidth(this.minWidth-tbl2.getWidth());
29915 this.el.endMeasure();
29918 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29922 * Sets this button's click handler
29923 * @param {Function} handler The function to call when the button is clicked
29924 * @param {Object} scope (optional) Scope for the function passed above
29926 setHandler : function(handler, scope){
29927 this.handler = handler;
29928 this.scope = scope;
29932 * Sets this button's arrow click handler
29933 * @param {Function} handler The function to call when the arrow is clicked
29934 * @param {Object} scope (optional) Scope for the function passed above
29936 setArrowHandler : function(handler, scope){
29937 this.arrowHandler = handler;
29938 this.scope = scope;
29944 focus : function(){
29946 this.el.child("button:first").focus();
29951 onClick : function(e){
29952 e.preventDefault();
29953 if(!this.disabled){
29954 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29955 if(this.menu && !this.menu.isVisible()){
29956 this.menu.show(this.el, this.menuAlign);
29958 this.fireEvent("arrowclick", this, e);
29959 if(this.arrowHandler){
29960 this.arrowHandler.call(this.scope || this, this, e);
29963 this.fireEvent("click", this, e);
29965 this.handler.call(this.scope || this, this, e);
29971 onMouseDown : function(e){
29972 if(!this.disabled){
29973 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29977 onMouseUp : function(e){
29978 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29983 // backwards compat
29984 Roo.MenuButton = Roo.SplitButton;/*
29986 * Ext JS Library 1.1.1
29987 * Copyright(c) 2006-2007, Ext JS, LLC.
29989 * Originally Released Under LGPL - original licence link has changed is not relivant.
29992 * <script type="text/javascript">
29996 * @class Roo.Toolbar
29997 * Basic Toolbar class.
29999 * Creates a new Toolbar
30000 * @param {Object} container The config object
30002 Roo.Toolbar = function(container, buttons, config)
30004 /// old consturctor format still supported..
30005 if(container instanceof Array){ // omit the container for later rendering
30006 buttons = container;
30010 if (typeof(container) == 'object' && container.xtype) {
30011 config = container;
30012 container = config.container;
30013 buttons = config.buttons || []; // not really - use items!!
30016 if (config && config.items) {
30017 xitems = config.items;
30018 delete config.items;
30020 Roo.apply(this, config);
30021 this.buttons = buttons;
30024 this.render(container);
30026 this.xitems = xitems;
30027 Roo.each(xitems, function(b) {
30033 Roo.Toolbar.prototype = {
30035 * @cfg {Array} items
30036 * array of button configs or elements to add (will be converted to a MixedCollection)
30040 * @cfg {String/HTMLElement/Element} container
30041 * The id or element that will contain the toolbar
30044 render : function(ct){
30045 this.el = Roo.get(ct);
30047 this.el.addClass(this.cls);
30049 // using a table allows for vertical alignment
30050 // 100% width is needed by Safari...
30051 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30052 this.tr = this.el.child("tr", true);
30054 this.items = new Roo.util.MixedCollection(false, function(o){
30055 return o.id || ("item" + (++autoId));
30058 this.add.apply(this, this.buttons);
30059 delete this.buttons;
30064 * Adds element(s) to the toolbar -- this function takes a variable number of
30065 * arguments of mixed type and adds them to the toolbar.
30066 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30068 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30069 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30070 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30071 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30072 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30073 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30074 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30075 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30076 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30078 * @param {Mixed} arg2
30079 * @param {Mixed} etc.
30082 var a = arguments, l = a.length;
30083 for(var i = 0; i < l; i++){
30088 _add : function(el) {
30091 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30094 if (el.applyTo){ // some kind of form field
30095 return this.addField(el);
30097 if (el.render){ // some kind of Toolbar.Item
30098 return this.addItem(el);
30100 if (typeof el == "string"){ // string
30101 if(el == "separator" || el == "-"){
30102 return this.addSeparator();
30105 return this.addSpacer();
30108 return this.addFill();
30110 return this.addText(el);
30113 if(el.tagName){ // element
30114 return this.addElement(el);
30116 if(typeof el == "object"){ // must be button config?
30117 return this.addButton(el);
30119 // and now what?!?!
30125 * Add an Xtype element
30126 * @param {Object} xtype Xtype Object
30127 * @return {Object} created Object
30129 addxtype : function(e){
30130 return this.add(e);
30134 * Returns the Element for this toolbar.
30135 * @return {Roo.Element}
30137 getEl : function(){
30143 * @return {Roo.Toolbar.Item} The separator item
30145 addSeparator : function(){
30146 return this.addItem(new Roo.Toolbar.Separator());
30150 * Adds a spacer element
30151 * @return {Roo.Toolbar.Spacer} The spacer item
30153 addSpacer : function(){
30154 return this.addItem(new Roo.Toolbar.Spacer());
30158 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30159 * @return {Roo.Toolbar.Fill} The fill item
30161 addFill : function(){
30162 return this.addItem(new Roo.Toolbar.Fill());
30166 * Adds any standard HTML element to the toolbar
30167 * @param {String/HTMLElement/Element} el The element or id of the element to add
30168 * @return {Roo.Toolbar.Item} The element's item
30170 addElement : function(el){
30171 return this.addItem(new Roo.Toolbar.Item(el));
30174 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30175 * @type Roo.util.MixedCollection
30180 * Adds any Toolbar.Item or subclass
30181 * @param {Roo.Toolbar.Item} item
30182 * @return {Roo.Toolbar.Item} The item
30184 addItem : function(item){
30185 var td = this.nextBlock();
30187 this.items.add(item);
30192 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30193 * @param {Object/Array} config A button config or array of configs
30194 * @return {Roo.Toolbar.Button/Array}
30196 addButton : function(config){
30197 if(config instanceof Array){
30199 for(var i = 0, len = config.length; i < len; i++) {
30200 buttons.push(this.addButton(config[i]));
30205 if(!(config instanceof Roo.Toolbar.Button)){
30207 new Roo.Toolbar.SplitButton(config) :
30208 new Roo.Toolbar.Button(config);
30210 var td = this.nextBlock();
30217 * Adds text to the toolbar
30218 * @param {String} text The text to add
30219 * @return {Roo.Toolbar.Item} The element's item
30221 addText : function(text){
30222 return this.addItem(new Roo.Toolbar.TextItem(text));
30226 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30227 * @param {Number} index The index where the item is to be inserted
30228 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30229 * @return {Roo.Toolbar.Button/Item}
30231 insertButton : function(index, item){
30232 if(item instanceof Array){
30234 for(var i = 0, len = item.length; i < len; i++) {
30235 buttons.push(this.insertButton(index + i, item[i]));
30239 if (!(item instanceof Roo.Toolbar.Button)){
30240 item = new Roo.Toolbar.Button(item);
30242 var td = document.createElement("td");
30243 this.tr.insertBefore(td, this.tr.childNodes[index]);
30245 this.items.insert(index, item);
30250 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30251 * @param {Object} config
30252 * @return {Roo.Toolbar.Item} The element's item
30254 addDom : function(config, returnEl){
30255 var td = this.nextBlock();
30256 Roo.DomHelper.overwrite(td, config);
30257 var ti = new Roo.Toolbar.Item(td.firstChild);
30259 this.items.add(ti);
30264 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30265 * @type Roo.util.MixedCollection
30270 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30271 * Note: the field should not have been rendered yet. For a field that has already been
30272 * rendered, use {@link #addElement}.
30273 * @param {Roo.form.Field} field
30274 * @return {Roo.ToolbarItem}
30278 addField : function(field) {
30279 if (!this.fields) {
30281 this.fields = new Roo.util.MixedCollection(false, function(o){
30282 return o.id || ("item" + (++autoId));
30287 var td = this.nextBlock();
30289 var ti = new Roo.Toolbar.Item(td.firstChild);
30291 this.items.add(ti);
30292 this.fields.add(field);
30303 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30304 this.el.child('div').hide();
30312 this.el.child('div').show();
30316 nextBlock : function(){
30317 var td = document.createElement("td");
30318 this.tr.appendChild(td);
30323 destroy : function(){
30324 if(this.items){ // rendered?
30325 Roo.destroy.apply(Roo, this.items.items);
30327 if(this.fields){ // rendered?
30328 Roo.destroy.apply(Roo, this.fields.items);
30330 Roo.Element.uncache(this.el, this.tr);
30335 * @class Roo.Toolbar.Item
30336 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30338 * Creates a new Item
30339 * @param {HTMLElement} el
30341 Roo.Toolbar.Item = function(el){
30343 if (typeof (el.xtype) != 'undefined') {
30348 this.el = Roo.getDom(el);
30349 this.id = Roo.id(this.el);
30350 this.hidden = false;
30355 * Fires when the button is rendered
30356 * @param {Button} this
30360 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30362 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30363 //Roo.Toolbar.Item.prototype = {
30366 * Get this item's HTML Element
30367 * @return {HTMLElement}
30369 getEl : function(){
30374 render : function(td){
30377 td.appendChild(this.el);
30379 this.fireEvent('render', this);
30383 * Removes and destroys this item.
30385 destroy : function(){
30386 this.td.parentNode.removeChild(this.td);
30393 this.hidden = false;
30394 this.td.style.display = "";
30401 this.hidden = true;
30402 this.td.style.display = "none";
30406 * Convenience function for boolean show/hide.
30407 * @param {Boolean} visible true to show/false to hide
30409 setVisible: function(visible){
30418 * Try to focus this item.
30420 focus : function(){
30421 Roo.fly(this.el).focus();
30425 * Disables this item.
30427 disable : function(){
30428 Roo.fly(this.td).addClass("x-item-disabled");
30429 this.disabled = true;
30430 this.el.disabled = true;
30434 * Enables this item.
30436 enable : function(){
30437 Roo.fly(this.td).removeClass("x-item-disabled");
30438 this.disabled = false;
30439 this.el.disabled = false;
30445 * @class Roo.Toolbar.Separator
30446 * @extends Roo.Toolbar.Item
30447 * A simple toolbar separator class
30449 * Creates a new Separator
30451 Roo.Toolbar.Separator = function(cfg){
30453 var s = document.createElement("span");
30454 s.className = "ytb-sep";
30459 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30461 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30462 enable:Roo.emptyFn,
30463 disable:Roo.emptyFn,
30468 * @class Roo.Toolbar.Spacer
30469 * @extends Roo.Toolbar.Item
30470 * A simple element that adds extra horizontal space to a toolbar.
30472 * Creates a new Spacer
30474 Roo.Toolbar.Spacer = function(cfg){
30475 var s = document.createElement("div");
30476 s.className = "ytb-spacer";
30480 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30482 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30483 enable:Roo.emptyFn,
30484 disable:Roo.emptyFn,
30489 * @class Roo.Toolbar.Fill
30490 * @extends Roo.Toolbar.Spacer
30491 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30493 * Creates a new Spacer
30495 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30497 render : function(td){
30498 td.style.width = '100%';
30499 Roo.Toolbar.Fill.superclass.render.call(this, td);
30504 * @class Roo.Toolbar.TextItem
30505 * @extends Roo.Toolbar.Item
30506 * A simple class that renders text directly into a toolbar.
30508 * Creates a new TextItem
30509 * @cfg {string} text
30511 Roo.Toolbar.TextItem = function(cfg){
30512 var text = cfg || "";
30513 if (typeof(cfg) == 'object') {
30514 text = cfg.text || "";
30518 var s = document.createElement("span");
30519 s.className = "ytb-text";
30520 s.innerHTML = text;
30525 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30527 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30530 enable:Roo.emptyFn,
30531 disable:Roo.emptyFn,
30536 * @class Roo.Toolbar.Button
30537 * @extends Roo.Button
30538 * A button that renders into a toolbar.
30540 * Creates a new Button
30541 * @param {Object} config A standard {@link Roo.Button} config object
30543 Roo.Toolbar.Button = function(config){
30544 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30546 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30547 render : function(td){
30549 Roo.Toolbar.Button.superclass.render.call(this, td);
30553 * Removes and destroys this button
30555 destroy : function(){
30556 Roo.Toolbar.Button.superclass.destroy.call(this);
30557 this.td.parentNode.removeChild(this.td);
30561 * Shows this button
30564 this.hidden = false;
30565 this.td.style.display = "";
30569 * Hides this button
30572 this.hidden = true;
30573 this.td.style.display = "none";
30577 * Disables this item
30579 disable : function(){
30580 Roo.fly(this.td).addClass("x-item-disabled");
30581 this.disabled = true;
30585 * Enables this item
30587 enable : function(){
30588 Roo.fly(this.td).removeClass("x-item-disabled");
30589 this.disabled = false;
30592 // backwards compat
30593 Roo.ToolbarButton = Roo.Toolbar.Button;
30596 * @class Roo.Toolbar.SplitButton
30597 * @extends Roo.SplitButton
30598 * A menu button that renders into a toolbar.
30600 * Creates a new SplitButton
30601 * @param {Object} config A standard {@link Roo.SplitButton} config object
30603 Roo.Toolbar.SplitButton = function(config){
30604 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30606 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30607 render : function(td){
30609 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30613 * Removes and destroys this button
30615 destroy : function(){
30616 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30617 this.td.parentNode.removeChild(this.td);
30621 * Shows this button
30624 this.hidden = false;
30625 this.td.style.display = "";
30629 * Hides this button
30632 this.hidden = true;
30633 this.td.style.display = "none";
30637 // backwards compat
30638 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30640 * Ext JS Library 1.1.1
30641 * Copyright(c) 2006-2007, Ext JS, LLC.
30643 * Originally Released Under LGPL - original licence link has changed is not relivant.
30646 * <script type="text/javascript">
30650 * @class Roo.PagingToolbar
30651 * @extends Roo.Toolbar
30652 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30654 * Create a new PagingToolbar
30655 * @param {Object} config The config object
30657 Roo.PagingToolbar = function(el, ds, config)
30659 // old args format still supported... - xtype is prefered..
30660 if (typeof(el) == 'object' && el.xtype) {
30661 // created from xtype...
30663 ds = el.dataSource;
30664 el = config.container;
30667 if (config.items) {
30668 items = config.items;
30672 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30675 this.renderButtons(this.el);
30678 // supprot items array.
30680 Roo.each(items, function(e) {
30681 this.add(Roo.factory(e));
30686 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30688 * @cfg {Roo.data.Store} dataSource
30689 * The underlying data store providing the paged data
30692 * @cfg {String/HTMLElement/Element} container
30693 * container The id or element that will contain the toolbar
30696 * @cfg {Boolean} displayInfo
30697 * True to display the displayMsg (defaults to false)
30700 * @cfg {Number} pageSize
30701 * The number of records to display per page (defaults to 20)
30705 * @cfg {String} displayMsg
30706 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30708 displayMsg : 'Displaying {0} - {1} of {2}',
30710 * @cfg {String} emptyMsg
30711 * The message to display when no records are found (defaults to "No data to display")
30713 emptyMsg : 'No data to display',
30715 * Customizable piece of the default paging text (defaults to "Page")
30718 beforePageText : "Page",
30720 * Customizable piece of the default paging text (defaults to "of %0")
30723 afterPageText : "of {0}",
30725 * Customizable piece of the default paging text (defaults to "First Page")
30728 firstText : "First Page",
30730 * Customizable piece of the default paging text (defaults to "Previous Page")
30733 prevText : "Previous Page",
30735 * Customizable piece of the default paging text (defaults to "Next Page")
30738 nextText : "Next Page",
30740 * Customizable piece of the default paging text (defaults to "Last Page")
30743 lastText : "Last Page",
30745 * Customizable piece of the default paging text (defaults to "Refresh")
30748 refreshText : "Refresh",
30751 renderButtons : function(el){
30752 Roo.PagingToolbar.superclass.render.call(this, el);
30753 this.first = this.addButton({
30754 tooltip: this.firstText,
30755 cls: "x-btn-icon x-grid-page-first",
30757 handler: this.onClick.createDelegate(this, ["first"])
30759 this.prev = this.addButton({
30760 tooltip: this.prevText,
30761 cls: "x-btn-icon x-grid-page-prev",
30763 handler: this.onClick.createDelegate(this, ["prev"])
30765 //this.addSeparator();
30766 this.add(this.beforePageText);
30767 this.field = Roo.get(this.addDom({
30772 cls: "x-grid-page-number"
30774 this.field.on("keydown", this.onPagingKeydown, this);
30775 this.field.on("focus", function(){this.dom.select();});
30776 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30777 this.field.setHeight(18);
30778 //this.addSeparator();
30779 this.next = this.addButton({
30780 tooltip: this.nextText,
30781 cls: "x-btn-icon x-grid-page-next",
30783 handler: this.onClick.createDelegate(this, ["next"])
30785 this.last = this.addButton({
30786 tooltip: this.lastText,
30787 cls: "x-btn-icon x-grid-page-last",
30789 handler: this.onClick.createDelegate(this, ["last"])
30791 //this.addSeparator();
30792 this.loading = this.addButton({
30793 tooltip: this.refreshText,
30794 cls: "x-btn-icon x-grid-loading",
30795 handler: this.onClick.createDelegate(this, ["refresh"])
30798 if(this.displayInfo){
30799 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30804 updateInfo : function(){
30805 if(this.displayEl){
30806 var count = this.ds.getCount();
30807 var msg = count == 0 ?
30811 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30813 this.displayEl.update(msg);
30818 onLoad : function(ds, r, o){
30819 this.cursor = o.params ? o.params.start : 0;
30820 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30822 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30823 this.field.dom.value = ap;
30824 this.first.setDisabled(ap == 1);
30825 this.prev.setDisabled(ap == 1);
30826 this.next.setDisabled(ap == ps);
30827 this.last.setDisabled(ap == ps);
30828 this.loading.enable();
30833 getPageData : function(){
30834 var total = this.ds.getTotalCount();
30837 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30838 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30843 onLoadError : function(){
30844 this.loading.enable();
30848 onPagingKeydown : function(e){
30849 var k = e.getKey();
30850 var d = this.getPageData();
30852 var v = this.field.dom.value, pageNum;
30853 if(!v || isNaN(pageNum = parseInt(v, 10))){
30854 this.field.dom.value = d.activePage;
30857 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30858 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30861 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))
30863 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30864 this.field.dom.value = pageNum;
30865 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30868 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30870 var v = this.field.dom.value, pageNum;
30871 var increment = (e.shiftKey) ? 10 : 1;
30872 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30875 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30876 this.field.dom.value = d.activePage;
30879 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30881 this.field.dom.value = parseInt(v, 10) + increment;
30882 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30883 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30890 beforeLoad : function(){
30892 this.loading.disable();
30897 onClick : function(which){
30901 ds.load({params:{start: 0, limit: this.pageSize}});
30904 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30907 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30910 var total = ds.getTotalCount();
30911 var extra = total % this.pageSize;
30912 var lastStart = extra ? (total - extra) : total-this.pageSize;
30913 ds.load({params:{start: lastStart, limit: this.pageSize}});
30916 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30922 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30923 * @param {Roo.data.Store} store The data store to unbind
30925 unbind : function(ds){
30926 ds.un("beforeload", this.beforeLoad, this);
30927 ds.un("load", this.onLoad, this);
30928 ds.un("loadexception", this.onLoadError, this);
30929 ds.un("remove", this.updateInfo, this);
30930 ds.un("add", this.updateInfo, this);
30931 this.ds = undefined;
30935 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30936 * @param {Roo.data.Store} store The data store to bind
30938 bind : function(ds){
30939 ds.on("beforeload", this.beforeLoad, this);
30940 ds.on("load", this.onLoad, this);
30941 ds.on("loadexception", this.onLoadError, this);
30942 ds.on("remove", this.updateInfo, this);
30943 ds.on("add", this.updateInfo, this);
30948 * Ext JS Library 1.1.1
30949 * Copyright(c) 2006-2007, Ext JS, LLC.
30951 * Originally Released Under LGPL - original licence link has changed is not relivant.
30954 * <script type="text/javascript">
30958 * @class Roo.Resizable
30959 * @extends Roo.util.Observable
30960 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30961 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30962 * 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
30963 * the element will be wrapped for you automatically.</p>
30964 * <p>Here is the list of valid resize handles:</p>
30967 ------ -------------------
30976 'hd' horizontal drag
30979 * <p>Here's an example showing the creation of a typical Resizable:</p>
30981 var resizer = new Roo.Resizable("element-id", {
30989 resizer.on("resize", myHandler);
30991 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30992 * resizer.east.setDisplayed(false);</p>
30993 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30994 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30995 * resize operation's new size (defaults to [0, 0])
30996 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30997 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30998 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30999 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31000 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31001 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31002 * @cfg {Number} width The width of the element in pixels (defaults to null)
31003 * @cfg {Number} height The height of the element in pixels (defaults to null)
31004 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31005 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31006 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31007 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31008 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31009 * in favor of the handles config option (defaults to false)
31010 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31011 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31012 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31013 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31014 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31015 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31016 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31017 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31018 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31019 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31020 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31022 * Create a new resizable component
31023 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31024 * @param {Object} config configuration options
31026 Roo.Resizable = function(el, config)
31028 this.el = Roo.get(el);
31030 if(config && config.wrap){
31031 config.resizeChild = this.el;
31032 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31033 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31034 this.el.setStyle("overflow", "hidden");
31035 this.el.setPositioning(config.resizeChild.getPositioning());
31036 config.resizeChild.clearPositioning();
31037 if(!config.width || !config.height){
31038 var csize = config.resizeChild.getSize();
31039 this.el.setSize(csize.width, csize.height);
31041 if(config.pinned && !config.adjustments){
31042 config.adjustments = "auto";
31046 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31047 this.proxy.unselectable();
31048 this.proxy.enableDisplayMode('block');
31050 Roo.apply(this, config);
31053 this.disableTrackOver = true;
31054 this.el.addClass("x-resizable-pinned");
31056 // if the element isn't positioned, make it relative
31057 var position = this.el.getStyle("position");
31058 if(position != "absolute" && position != "fixed"){
31059 this.el.setStyle("position", "relative");
31061 if(!this.handles){ // no handles passed, must be legacy style
31062 this.handles = 's,e,se';
31063 if(this.multiDirectional){
31064 this.handles += ',n,w';
31067 if(this.handles == "all"){
31068 this.handles = "n s e w ne nw se sw";
31070 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31071 var ps = Roo.Resizable.positions;
31072 for(var i = 0, len = hs.length; i < len; i++){
31073 if(hs[i] && ps[hs[i]]){
31074 var pos = ps[hs[i]];
31075 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31079 this.corner = this.southeast;
31081 // updateBox = the box can move..
31082 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31083 this.updateBox = true;
31086 this.activeHandle = null;
31088 if(this.resizeChild){
31089 if(typeof this.resizeChild == "boolean"){
31090 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31092 this.resizeChild = Roo.get(this.resizeChild, true);
31096 if(this.adjustments == "auto"){
31097 var rc = this.resizeChild;
31098 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31099 if(rc && (hw || hn)){
31100 rc.position("relative");
31101 rc.setLeft(hw ? hw.el.getWidth() : 0);
31102 rc.setTop(hn ? hn.el.getHeight() : 0);
31104 this.adjustments = [
31105 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31106 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31110 if(this.draggable){
31111 this.dd = this.dynamic ?
31112 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31113 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31119 * @event beforeresize
31120 * Fired before resize is allowed. Set enabled to false to cancel resize.
31121 * @param {Roo.Resizable} this
31122 * @param {Roo.EventObject} e The mousedown event
31124 "beforeresize" : true,
31127 * Fired a resizing.
31128 * @param {Roo.Resizable} this
31129 * @param {Number} x The new x position
31130 * @param {Number} y The new y position
31131 * @param {Number} w The new w width
31132 * @param {Number} h The new h hight
31133 * @param {Roo.EventObject} e The mouseup event
31138 * Fired after a resize.
31139 * @param {Roo.Resizable} this
31140 * @param {Number} width The new width
31141 * @param {Number} height The new height
31142 * @param {Roo.EventObject} e The mouseup event
31147 if(this.width !== null && this.height !== null){
31148 this.resizeTo(this.width, this.height);
31150 this.updateChildSize();
31153 this.el.dom.style.zoom = 1;
31155 Roo.Resizable.superclass.constructor.call(this);
31158 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31159 resizeChild : false,
31160 adjustments : [0, 0],
31170 multiDirectional : false,
31171 disableTrackOver : false,
31172 easing : 'easeOutStrong',
31173 widthIncrement : 0,
31174 heightIncrement : 0,
31178 preserveRatio : false,
31179 transparent: false,
31185 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31187 constrainTo: undefined,
31189 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31191 resizeRegion: undefined,
31195 * Perform a manual resize
31196 * @param {Number} width
31197 * @param {Number} height
31199 resizeTo : function(width, height){
31200 this.el.setSize(width, height);
31201 this.updateChildSize();
31202 this.fireEvent("resize", this, width, height, null);
31206 startSizing : function(e, handle){
31207 this.fireEvent("beforeresize", this, e);
31208 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31211 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31212 this.overlay.unselectable();
31213 this.overlay.enableDisplayMode("block");
31214 this.overlay.on("mousemove", this.onMouseMove, this);
31215 this.overlay.on("mouseup", this.onMouseUp, this);
31217 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31219 this.resizing = true;
31220 this.startBox = this.el.getBox();
31221 this.startPoint = e.getXY();
31222 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31223 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31225 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31226 this.overlay.show();
31228 if(this.constrainTo) {
31229 var ct = Roo.get(this.constrainTo);
31230 this.resizeRegion = ct.getRegion().adjust(
31231 ct.getFrameWidth('t'),
31232 ct.getFrameWidth('l'),
31233 -ct.getFrameWidth('b'),
31234 -ct.getFrameWidth('r')
31238 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31240 this.proxy.setBox(this.startBox);
31242 this.proxy.setStyle('visibility', 'visible');
31248 onMouseDown : function(handle, e){
31251 this.activeHandle = handle;
31252 this.startSizing(e, handle);
31257 onMouseUp : function(e){
31258 var size = this.resizeElement();
31259 this.resizing = false;
31261 this.overlay.hide();
31263 this.fireEvent("resize", this, size.width, size.height, e);
31267 updateChildSize : function(){
31269 if(this.resizeChild){
31271 var child = this.resizeChild;
31272 var adj = this.adjustments;
31273 if(el.dom.offsetWidth){
31274 var b = el.getSize(true);
31275 child.setSize(b.width+adj[0], b.height+adj[1]);
31277 // Second call here for IE
31278 // The first call enables instant resizing and
31279 // the second call corrects scroll bars if they
31282 setTimeout(function(){
31283 if(el.dom.offsetWidth){
31284 var b = el.getSize(true);
31285 child.setSize(b.width+adj[0], b.height+adj[1]);
31293 snap : function(value, inc, min){
31294 if(!inc || !value) {
31297 var newValue = value;
31298 var m = value % inc;
31301 newValue = value + (inc-m);
31303 newValue = value - m;
31306 return Math.max(min, newValue);
31310 resizeElement : function(){
31311 var box = this.proxy.getBox();
31312 if(this.updateBox){
31313 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31315 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31317 this.updateChildSize();
31325 constrain : function(v, diff, m, mx){
31328 }else if(v - diff > mx){
31335 onMouseMove : function(e){
31338 try{// try catch so if something goes wrong the user doesn't get hung
31340 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31344 //var curXY = this.startPoint;
31345 var curSize = this.curSize || this.startBox;
31346 var x = this.startBox.x, y = this.startBox.y;
31347 var ox = x, oy = y;
31348 var w = curSize.width, h = curSize.height;
31349 var ow = w, oh = h;
31350 var mw = this.minWidth, mh = this.minHeight;
31351 var mxw = this.maxWidth, mxh = this.maxHeight;
31352 var wi = this.widthIncrement;
31353 var hi = this.heightIncrement;
31355 var eventXY = e.getXY();
31356 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31357 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31359 var pos = this.activeHandle.position;
31364 w = Math.min(Math.max(mw, w), mxw);
31369 h = Math.min(Math.max(mh, h), mxh);
31374 w = Math.min(Math.max(mw, w), mxw);
31375 h = Math.min(Math.max(mh, h), mxh);
31378 diffY = this.constrain(h, diffY, mh, mxh);
31385 var adiffX = Math.abs(diffX);
31386 var sub = (adiffX % wi); // how much
31387 if (sub > (wi/2)) { // far enough to snap
31388 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31390 // remove difference..
31391 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31395 x = Math.max(this.minX, x);
31398 diffX = this.constrain(w, diffX, mw, mxw);
31404 w = Math.min(Math.max(mw, w), mxw);
31405 diffY = this.constrain(h, diffY, mh, mxh);
31410 diffX = this.constrain(w, diffX, mw, mxw);
31411 diffY = this.constrain(h, diffY, mh, mxh);
31418 diffX = this.constrain(w, diffX, mw, mxw);
31420 h = Math.min(Math.max(mh, h), mxh);
31426 var sw = this.snap(w, wi, mw);
31427 var sh = this.snap(h, hi, mh);
31428 if(sw != w || sh != h){
31451 if(this.preserveRatio){
31456 h = Math.min(Math.max(mh, h), mxh);
31461 w = Math.min(Math.max(mw, w), mxw);
31466 w = Math.min(Math.max(mw, w), mxw);
31472 w = Math.min(Math.max(mw, w), mxw);
31478 h = Math.min(Math.max(mh, h), mxh);
31486 h = Math.min(Math.max(mh, h), mxh);
31496 h = Math.min(Math.max(mh, h), mxh);
31504 if (pos == 'hdrag') {
31507 this.proxy.setBounds(x, y, w, h);
31509 this.resizeElement();
31513 this.fireEvent("resizing", this, x, y, w, h, e);
31517 handleOver : function(){
31519 this.el.addClass("x-resizable-over");
31524 handleOut : function(){
31525 if(!this.resizing){
31526 this.el.removeClass("x-resizable-over");
31531 * Returns the element this component is bound to.
31532 * @return {Roo.Element}
31534 getEl : function(){
31539 * Returns the resizeChild element (or null).
31540 * @return {Roo.Element}
31542 getResizeChild : function(){
31543 return this.resizeChild;
31545 groupHandler : function()
31550 * Destroys this resizable. If the element was wrapped and
31551 * removeEl is not true then the element remains.
31552 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31554 destroy : function(removeEl){
31555 this.proxy.remove();
31557 this.overlay.removeAllListeners();
31558 this.overlay.remove();
31560 var ps = Roo.Resizable.positions;
31562 if(typeof ps[k] != "function" && this[ps[k]]){
31563 var h = this[ps[k]];
31564 h.el.removeAllListeners();
31569 this.el.update("");
31576 // hash to map config positions to true positions
31577 Roo.Resizable.positions = {
31578 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31583 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31585 // only initialize the template if resizable is used
31586 var tpl = Roo.DomHelper.createTemplate(
31587 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31590 Roo.Resizable.Handle.prototype.tpl = tpl;
31592 this.position = pos;
31594 // show north drag fro topdra
31595 var handlepos = pos == 'hdrag' ? 'north' : pos;
31597 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31598 if (pos == 'hdrag') {
31599 this.el.setStyle('cursor', 'pointer');
31601 this.el.unselectable();
31603 this.el.setOpacity(0);
31605 this.el.on("mousedown", this.onMouseDown, this);
31606 if(!disableTrackOver){
31607 this.el.on("mouseover", this.onMouseOver, this);
31608 this.el.on("mouseout", this.onMouseOut, this);
31613 Roo.Resizable.Handle.prototype = {
31614 afterResize : function(rz){
31619 onMouseDown : function(e){
31620 this.rz.onMouseDown(this, e);
31623 onMouseOver : function(e){
31624 this.rz.handleOver(this, e);
31627 onMouseOut : function(e){
31628 this.rz.handleOut(this, e);
31632 * Ext JS Library 1.1.1
31633 * Copyright(c) 2006-2007, Ext JS, LLC.
31635 * Originally Released Under LGPL - original licence link has changed is not relivant.
31638 * <script type="text/javascript">
31642 * @class Roo.Editor
31643 * @extends Roo.Component
31644 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31646 * Create a new Editor
31647 * @param {Roo.form.Field} field The Field object (or descendant)
31648 * @param {Object} config The config object
31650 Roo.Editor = function(field, config){
31651 Roo.Editor.superclass.constructor.call(this, config);
31652 this.field = field;
31655 * @event beforestartedit
31656 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31657 * false from the handler of this event.
31658 * @param {Editor} this
31659 * @param {Roo.Element} boundEl The underlying element bound to this editor
31660 * @param {Mixed} value The field value being set
31662 "beforestartedit" : true,
31665 * Fires when this editor is displayed
31666 * @param {Roo.Element} boundEl The underlying element bound to this editor
31667 * @param {Mixed} value The starting field value
31669 "startedit" : true,
31671 * @event beforecomplete
31672 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31673 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31674 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31675 * event will not fire since no edit actually occurred.
31676 * @param {Editor} this
31677 * @param {Mixed} value The current field value
31678 * @param {Mixed} startValue The original field value
31680 "beforecomplete" : true,
31683 * Fires after editing is complete and any changed value has been written to the underlying field.
31684 * @param {Editor} this
31685 * @param {Mixed} value The current field value
31686 * @param {Mixed} startValue The original field value
31690 * @event specialkey
31691 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31692 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31693 * @param {Roo.form.Field} this
31694 * @param {Roo.EventObject} e The event object
31696 "specialkey" : true
31700 Roo.extend(Roo.Editor, Roo.Component, {
31702 * @cfg {Boolean/String} autosize
31703 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31704 * or "height" to adopt the height only (defaults to false)
31707 * @cfg {Boolean} revertInvalid
31708 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31709 * validation fails (defaults to true)
31712 * @cfg {Boolean} ignoreNoChange
31713 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31714 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31715 * will never be ignored.
31718 * @cfg {Boolean} hideEl
31719 * False to keep the bound element visible while the editor is displayed (defaults to true)
31722 * @cfg {Mixed} value
31723 * The data value of the underlying field (defaults to "")
31727 * @cfg {String} alignment
31728 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31732 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31733 * for bottom-right shadow (defaults to "frame")
31737 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31741 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31743 completeOnEnter : false,
31745 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31747 cancelOnEsc : false,
31749 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31754 onRender : function(ct, position){
31755 this.el = new Roo.Layer({
31756 shadow: this.shadow,
31762 constrain: this.constrain
31764 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31765 if(this.field.msgTarget != 'title'){
31766 this.field.msgTarget = 'qtip';
31768 this.field.render(this.el);
31770 this.field.el.dom.setAttribute('autocomplete', 'off');
31772 this.field.on("specialkey", this.onSpecialKey, this);
31773 if(this.swallowKeys){
31774 this.field.el.swallowEvent(['keydown','keypress']);
31777 this.field.on("blur", this.onBlur, this);
31778 if(this.field.grow){
31779 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31783 onSpecialKey : function(field, e)
31785 //Roo.log('editor onSpecialKey');
31786 if(this.completeOnEnter && e.getKey() == e.ENTER){
31788 this.completeEdit();
31791 // do not fire special key otherwise it might hide close the editor...
31792 if(e.getKey() == e.ENTER){
31795 if(this.cancelOnEsc && e.getKey() == e.ESC){
31799 this.fireEvent('specialkey', field, e);
31804 * Starts the editing process and shows the editor.
31805 * @param {String/HTMLElement/Element} el The element to edit
31806 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31807 * to the innerHTML of el.
31809 startEdit : function(el, value){
31811 this.completeEdit();
31813 this.boundEl = Roo.get(el);
31814 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31815 if(!this.rendered){
31816 this.render(this.parentEl || document.body);
31818 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31821 this.startValue = v;
31822 this.field.setValue(v);
31824 var sz = this.boundEl.getSize();
31825 switch(this.autoSize){
31827 this.setSize(sz.width, "");
31830 this.setSize("", sz.height);
31833 this.setSize(sz.width, sz.height);
31836 this.el.alignTo(this.boundEl, this.alignment);
31837 this.editing = true;
31839 Roo.QuickTips.disable();
31845 * Sets the height and width of this editor.
31846 * @param {Number} width The new width
31847 * @param {Number} height The new height
31849 setSize : function(w, h){
31850 this.field.setSize(w, h);
31857 * Realigns the editor to the bound field based on the current alignment config value.
31859 realign : function(){
31860 this.el.alignTo(this.boundEl, this.alignment);
31864 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31865 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31867 completeEdit : function(remainVisible){
31871 var v = this.getValue();
31872 if(this.revertInvalid !== false && !this.field.isValid()){
31873 v = this.startValue;
31874 this.cancelEdit(true);
31876 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31877 this.editing = false;
31881 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31882 this.editing = false;
31883 if(this.updateEl && this.boundEl){
31884 this.boundEl.update(v);
31886 if(remainVisible !== true){
31889 this.fireEvent("complete", this, v, this.startValue);
31894 onShow : function(){
31896 if(this.hideEl !== false){
31897 this.boundEl.hide();
31900 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31901 this.fixIEFocus = true;
31902 this.deferredFocus.defer(50, this);
31904 this.field.focus();
31906 this.fireEvent("startedit", this.boundEl, this.startValue);
31909 deferredFocus : function(){
31911 this.field.focus();
31916 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31917 * reverted to the original starting value.
31918 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31919 * cancel (defaults to false)
31921 cancelEdit : function(remainVisible){
31923 this.setValue(this.startValue);
31924 if(remainVisible !== true){
31931 onBlur : function(){
31932 if(this.allowBlur !== true && this.editing){
31933 this.completeEdit();
31938 onHide : function(){
31940 this.completeEdit();
31944 if(this.field.collapse){
31945 this.field.collapse();
31948 if(this.hideEl !== false){
31949 this.boundEl.show();
31952 Roo.QuickTips.enable();
31957 * Sets the data value of the editor
31958 * @param {Mixed} value Any valid value supported by the underlying field
31960 setValue : function(v){
31961 this.field.setValue(v);
31965 * Gets the data value of the editor
31966 * @return {Mixed} The data value
31968 getValue : function(){
31969 return this.field.getValue();
31973 * Ext JS Library 1.1.1
31974 * Copyright(c) 2006-2007, Ext JS, LLC.
31976 * Originally Released Under LGPL - original licence link has changed is not relivant.
31979 * <script type="text/javascript">
31983 * @class Roo.BasicDialog
31984 * @extends Roo.util.Observable
31985 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31987 var dlg = new Roo.BasicDialog("my-dlg", {
31996 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31997 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31998 dlg.addButton('Cancel', dlg.hide, dlg);
32001 <b>A Dialog should always be a direct child of the body element.</b>
32002 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32003 * @cfg {String} title Default text to display in the title bar (defaults to null)
32004 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32005 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32006 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32007 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32008 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32009 * (defaults to null with no animation)
32010 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32011 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32012 * property for valid values (defaults to 'all')
32013 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32014 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32015 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32016 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32017 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32018 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32019 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32020 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32021 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32022 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32023 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32024 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32025 * draggable = true (defaults to false)
32026 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32027 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32028 * shadow (defaults to false)
32029 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32030 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32031 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32032 * @cfg {Array} buttons Array of buttons
32033 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32035 * Create a new BasicDialog.
32036 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32037 * @param {Object} config Configuration options
32039 Roo.BasicDialog = function(el, config){
32040 this.el = Roo.get(el);
32041 var dh = Roo.DomHelper;
32042 if(!this.el && config && config.autoCreate){
32043 if(typeof config.autoCreate == "object"){
32044 if(!config.autoCreate.id){
32045 config.autoCreate.id = el;
32047 this.el = dh.append(document.body,
32048 config.autoCreate, true);
32050 this.el = dh.append(document.body,
32051 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32055 el.setDisplayed(true);
32056 el.hide = this.hideAction;
32058 el.addClass("x-dlg");
32060 Roo.apply(this, config);
32062 this.proxy = el.createProxy("x-dlg-proxy");
32063 this.proxy.hide = this.hideAction;
32064 this.proxy.setOpacity(.5);
32068 el.setWidth(config.width);
32071 el.setHeight(config.height);
32073 this.size = el.getSize();
32074 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32075 this.xy = [config.x,config.y];
32077 this.xy = el.getCenterXY(true);
32079 /** The header element @type Roo.Element */
32080 this.header = el.child("> .x-dlg-hd");
32081 /** The body element @type Roo.Element */
32082 this.body = el.child("> .x-dlg-bd");
32083 /** The footer element @type Roo.Element */
32084 this.footer = el.child("> .x-dlg-ft");
32087 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32090 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32093 this.header.unselectable();
32095 this.header.update(this.title);
32097 // this element allows the dialog to be focused for keyboard event
32098 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32099 this.focusEl.swallowEvent("click", true);
32101 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32103 // wrap the body and footer for special rendering
32104 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32106 this.bwrap.dom.appendChild(this.footer.dom);
32109 this.bg = this.el.createChild({
32110 tag: "div", cls:"x-dlg-bg",
32111 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32113 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32116 if(this.autoScroll !== false && !this.autoTabs){
32117 this.body.setStyle("overflow", "auto");
32120 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32122 if(this.closable !== false){
32123 this.el.addClass("x-dlg-closable");
32124 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32125 this.close.on("click", this.closeClick, this);
32126 this.close.addClassOnOver("x-dlg-close-over");
32128 if(this.collapsible !== false){
32129 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32130 this.collapseBtn.on("click", this.collapseClick, this);
32131 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32132 this.header.on("dblclick", this.collapseClick, this);
32134 if(this.resizable !== false){
32135 this.el.addClass("x-dlg-resizable");
32136 this.resizer = new Roo.Resizable(el, {
32137 minWidth: this.minWidth || 80,
32138 minHeight:this.minHeight || 80,
32139 handles: this.resizeHandles || "all",
32142 this.resizer.on("beforeresize", this.beforeResize, this);
32143 this.resizer.on("resize", this.onResize, this);
32145 if(this.draggable !== false){
32146 el.addClass("x-dlg-draggable");
32147 if (!this.proxyDrag) {
32148 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32151 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32153 dd.setHandleElId(this.header.id);
32154 dd.endDrag = this.endMove.createDelegate(this);
32155 dd.startDrag = this.startMove.createDelegate(this);
32156 dd.onDrag = this.onDrag.createDelegate(this);
32161 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32162 this.mask.enableDisplayMode("block");
32164 this.el.addClass("x-dlg-modal");
32167 this.shadow = new Roo.Shadow({
32168 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32169 offset : this.shadowOffset
32172 this.shadowOffset = 0;
32174 if(Roo.useShims && this.shim !== false){
32175 this.shim = this.el.createShim();
32176 this.shim.hide = this.hideAction;
32184 if (this.buttons) {
32185 var bts= this.buttons;
32187 Roo.each(bts, function(b) {
32196 * Fires when a key is pressed
32197 * @param {Roo.BasicDialog} this
32198 * @param {Roo.EventObject} e
32203 * Fires when this dialog is moved by the user.
32204 * @param {Roo.BasicDialog} this
32205 * @param {Number} x The new page X
32206 * @param {Number} y The new page Y
32211 * Fires when this dialog is resized by the user.
32212 * @param {Roo.BasicDialog} this
32213 * @param {Number} width The new width
32214 * @param {Number} height The new height
32218 * @event beforehide
32219 * Fires before this dialog is hidden.
32220 * @param {Roo.BasicDialog} this
32222 "beforehide" : true,
32225 * Fires when this dialog is hidden.
32226 * @param {Roo.BasicDialog} this
32230 * @event beforeshow
32231 * Fires before this dialog is shown.
32232 * @param {Roo.BasicDialog} this
32234 "beforeshow" : true,
32237 * Fires when this dialog is shown.
32238 * @param {Roo.BasicDialog} this
32242 el.on("keydown", this.onKeyDown, this);
32243 el.on("mousedown", this.toFront, this);
32244 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32246 Roo.DialogManager.register(this);
32247 Roo.BasicDialog.superclass.constructor.call(this);
32250 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32251 shadowOffset: Roo.isIE ? 6 : 5,
32254 minButtonWidth: 75,
32255 defaultButton: null,
32256 buttonAlign: "right",
32261 * Sets the dialog title text
32262 * @param {String} text The title text to display
32263 * @return {Roo.BasicDialog} this
32265 setTitle : function(text){
32266 this.header.update(text);
32271 closeClick : function(){
32276 collapseClick : function(){
32277 this[this.collapsed ? "expand" : "collapse"]();
32281 * Collapses the dialog to its minimized state (only the title bar is visible).
32282 * Equivalent to the user clicking the collapse dialog button.
32284 collapse : function(){
32285 if(!this.collapsed){
32286 this.collapsed = true;
32287 this.el.addClass("x-dlg-collapsed");
32288 this.restoreHeight = this.el.getHeight();
32289 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32294 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32295 * clicking the expand dialog button.
32297 expand : function(){
32298 if(this.collapsed){
32299 this.collapsed = false;
32300 this.el.removeClass("x-dlg-collapsed");
32301 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32306 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32307 * @return {Roo.TabPanel} The tabs component
32309 initTabs : function(){
32310 var tabs = this.getTabs();
32311 while(tabs.getTab(0)){
32314 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32316 tabs.addTab(Roo.id(dom), dom.title);
32324 beforeResize : function(){
32325 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32329 onResize : function(){
32330 this.refreshSize();
32331 this.syncBodyHeight();
32332 this.adjustAssets();
32334 this.fireEvent("resize", this, this.size.width, this.size.height);
32338 onKeyDown : function(e){
32339 if(this.isVisible()){
32340 this.fireEvent("keydown", this, e);
32345 * Resizes the dialog.
32346 * @param {Number} width
32347 * @param {Number} height
32348 * @return {Roo.BasicDialog} this
32350 resizeTo : function(width, height){
32351 this.el.setSize(width, height);
32352 this.size = {width: width, height: height};
32353 this.syncBodyHeight();
32354 if(this.fixedcenter){
32357 if(this.isVisible()){
32358 this.constrainXY();
32359 this.adjustAssets();
32361 this.fireEvent("resize", this, width, height);
32367 * Resizes the dialog to fit the specified content size.
32368 * @param {Number} width
32369 * @param {Number} height
32370 * @return {Roo.BasicDialog} this
32372 setContentSize : function(w, h){
32373 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32374 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32375 //if(!this.el.isBorderBox()){
32376 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32377 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32380 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32381 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32383 this.resizeTo(w, h);
32388 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32389 * executed in response to a particular key being pressed while the dialog is active.
32390 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32391 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32392 * @param {Function} fn The function to call
32393 * @param {Object} scope (optional) The scope of the function
32394 * @return {Roo.BasicDialog} this
32396 addKeyListener : function(key, fn, scope){
32397 var keyCode, shift, ctrl, alt;
32398 if(typeof key == "object" && !(key instanceof Array)){
32399 keyCode = key["key"];
32400 shift = key["shift"];
32401 ctrl = key["ctrl"];
32406 var handler = function(dlg, e){
32407 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32408 var k = e.getKey();
32409 if(keyCode instanceof Array){
32410 for(var i = 0, len = keyCode.length; i < len; i++){
32411 if(keyCode[i] == k){
32412 fn.call(scope || window, dlg, k, e);
32418 fn.call(scope || window, dlg, k, e);
32423 this.on("keydown", handler);
32428 * Returns the TabPanel component (creates it if it doesn't exist).
32429 * Note: If you wish to simply check for the existence of tabs without creating them,
32430 * check for a null 'tabs' property.
32431 * @return {Roo.TabPanel} The tabs component
32433 getTabs : function(){
32435 this.el.addClass("x-dlg-auto-tabs");
32436 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32437 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32443 * Adds a button to the footer section of the dialog.
32444 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32445 * object or a valid Roo.DomHelper element config
32446 * @param {Function} handler The function called when the button is clicked
32447 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32448 * @return {Roo.Button} The new button
32450 addButton : function(config, handler, scope){
32451 var dh = Roo.DomHelper;
32453 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32455 if(!this.btnContainer){
32456 var tb = this.footer.createChild({
32458 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32459 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32461 this.btnContainer = tb.firstChild.firstChild.firstChild;
32466 minWidth: this.minButtonWidth,
32469 if(typeof config == "string"){
32470 bconfig.text = config;
32473 bconfig.dhconfig = config;
32475 Roo.apply(bconfig, config);
32479 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32480 bconfig.position = Math.max(0, bconfig.position);
32481 fc = this.btnContainer.childNodes[bconfig.position];
32484 var btn = new Roo.Button(
32486 this.btnContainer.insertBefore(document.createElement("td"),fc)
32487 : this.btnContainer.appendChild(document.createElement("td")),
32488 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32491 this.syncBodyHeight();
32494 * Array of all the buttons that have been added to this dialog via addButton
32499 this.buttons.push(btn);
32504 * Sets the default button to be focused when the dialog is displayed.
32505 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32506 * @return {Roo.BasicDialog} this
32508 setDefaultButton : function(btn){
32509 this.defaultButton = btn;
32514 getHeaderFooterHeight : function(safe){
32517 height += this.header.getHeight();
32520 var fm = this.footer.getMargins();
32521 height += (this.footer.getHeight()+fm.top+fm.bottom);
32523 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32524 height += this.centerBg.getPadding("tb");
32529 syncBodyHeight : function()
32531 var bd = this.body, // the text
32532 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32534 var height = this.size.height - this.getHeaderFooterHeight(false);
32535 bd.setHeight(height-bd.getMargins("tb"));
32536 var hh = this.header.getHeight();
32537 var h = this.size.height-hh;
32540 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32541 bw.setHeight(h-cb.getPadding("tb"));
32543 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32544 bd.setWidth(bw.getWidth(true));
32546 this.tabs.syncHeight();
32548 this.tabs.el.repaint();
32554 * Restores the previous state of the dialog if Roo.state is configured.
32555 * @return {Roo.BasicDialog} this
32557 restoreState : function(){
32558 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32559 if(box && box.width){
32560 this.xy = [box.x, box.y];
32561 this.resizeTo(box.width, box.height);
32567 beforeShow : function(){
32569 if(this.fixedcenter){
32570 this.xy = this.el.getCenterXY(true);
32573 Roo.get(document.body).addClass("x-body-masked");
32574 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32577 this.constrainXY();
32581 animShow : function(){
32582 var b = Roo.get(this.animateTarget).getBox();
32583 this.proxy.setSize(b.width, b.height);
32584 this.proxy.setLocation(b.x, b.y);
32586 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32587 true, .35, this.showEl.createDelegate(this));
32591 * Shows the dialog.
32592 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32593 * @return {Roo.BasicDialog} this
32595 show : function(animateTarget){
32596 if (this.fireEvent("beforeshow", this) === false){
32599 if(this.syncHeightBeforeShow){
32600 this.syncBodyHeight();
32601 }else if(this.firstShow){
32602 this.firstShow = false;
32603 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32605 this.animateTarget = animateTarget || this.animateTarget;
32606 if(!this.el.isVisible()){
32608 if(this.animateTarget && Roo.get(this.animateTarget)){
32618 showEl : function(){
32620 this.el.setXY(this.xy);
32622 this.adjustAssets(true);
32625 // IE peekaboo bug - fix found by Dave Fenwick
32629 this.fireEvent("show", this);
32633 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32634 * dialog itself will receive focus.
32636 focus : function(){
32637 if(this.defaultButton){
32638 this.defaultButton.focus();
32640 this.focusEl.focus();
32645 constrainXY : function(){
32646 if(this.constraintoviewport !== false){
32647 if(!this.viewSize){
32648 if(this.container){
32649 var s = this.container.getSize();
32650 this.viewSize = [s.width, s.height];
32652 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32655 var s = Roo.get(this.container||document).getScroll();
32657 var x = this.xy[0], y = this.xy[1];
32658 var w = this.size.width, h = this.size.height;
32659 var vw = this.viewSize[0], vh = this.viewSize[1];
32660 // only move it if it needs it
32662 // first validate right/bottom
32663 if(x + w > vw+s.left){
32667 if(y + h > vh+s.top){
32671 // then make sure top/left isn't negative
32683 if(this.isVisible()){
32684 this.el.setLocation(x, y);
32685 this.adjustAssets();
32692 onDrag : function(){
32693 if(!this.proxyDrag){
32694 this.xy = this.el.getXY();
32695 this.adjustAssets();
32700 adjustAssets : function(doShow){
32701 var x = this.xy[0], y = this.xy[1];
32702 var w = this.size.width, h = this.size.height;
32703 if(doShow === true){
32705 this.shadow.show(this.el);
32711 if(this.shadow && this.shadow.isVisible()){
32712 this.shadow.show(this.el);
32714 if(this.shim && this.shim.isVisible()){
32715 this.shim.setBounds(x, y, w, h);
32720 adjustViewport : function(w, h){
32722 w = Roo.lib.Dom.getViewWidth();
32723 h = Roo.lib.Dom.getViewHeight();
32726 this.viewSize = [w, h];
32727 if(this.modal && this.mask.isVisible()){
32728 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32729 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32731 if(this.isVisible()){
32732 this.constrainXY();
32737 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32738 * shadow, proxy, mask, etc.) Also removes all event listeners.
32739 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32741 destroy : function(removeEl){
32742 if(this.isVisible()){
32743 this.animateTarget = null;
32746 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32748 this.tabs.destroy(removeEl);
32761 for(var i = 0, len = this.buttons.length; i < len; i++){
32762 this.buttons[i].destroy();
32765 this.el.removeAllListeners();
32766 if(removeEl === true){
32767 this.el.update("");
32770 Roo.DialogManager.unregister(this);
32774 startMove : function(){
32775 if(this.proxyDrag){
32778 if(this.constraintoviewport !== false){
32779 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32784 endMove : function(){
32785 if(!this.proxyDrag){
32786 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32788 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32791 this.refreshSize();
32792 this.adjustAssets();
32794 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32798 * Brings this dialog to the front of any other visible dialogs
32799 * @return {Roo.BasicDialog} this
32801 toFront : function(){
32802 Roo.DialogManager.bringToFront(this);
32807 * Sends this dialog to the back (under) of any other visible dialogs
32808 * @return {Roo.BasicDialog} this
32810 toBack : function(){
32811 Roo.DialogManager.sendToBack(this);
32816 * Centers this dialog in the viewport
32817 * @return {Roo.BasicDialog} this
32819 center : function(){
32820 var xy = this.el.getCenterXY(true);
32821 this.moveTo(xy[0], xy[1]);
32826 * Moves the dialog's top-left corner to the specified point
32827 * @param {Number} x
32828 * @param {Number} y
32829 * @return {Roo.BasicDialog} this
32831 moveTo : function(x, y){
32833 if(this.isVisible()){
32834 this.el.setXY(this.xy);
32835 this.adjustAssets();
32841 * Aligns the dialog to the specified element
32842 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32843 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32844 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32845 * @return {Roo.BasicDialog} this
32847 alignTo : function(element, position, offsets){
32848 this.xy = this.el.getAlignToXY(element, position, offsets);
32849 if(this.isVisible()){
32850 this.el.setXY(this.xy);
32851 this.adjustAssets();
32857 * Anchors an element to another element and realigns it when the window is resized.
32858 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32859 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32860 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32861 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32862 * is a number, it is used as the buffer delay (defaults to 50ms).
32863 * @return {Roo.BasicDialog} this
32865 anchorTo : function(el, alignment, offsets, monitorScroll){
32866 var action = function(){
32867 this.alignTo(el, alignment, offsets);
32869 Roo.EventManager.onWindowResize(action, this);
32870 var tm = typeof monitorScroll;
32871 if(tm != 'undefined'){
32872 Roo.EventManager.on(window, 'scroll', action, this,
32873 {buffer: tm == 'number' ? monitorScroll : 50});
32880 * Returns true if the dialog is visible
32881 * @return {Boolean}
32883 isVisible : function(){
32884 return this.el.isVisible();
32888 animHide : function(callback){
32889 var b = Roo.get(this.animateTarget).getBox();
32891 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32893 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32894 this.hideEl.createDelegate(this, [callback]));
32898 * Hides the dialog.
32899 * @param {Function} callback (optional) Function to call when the dialog is hidden
32900 * @return {Roo.BasicDialog} this
32902 hide : function(callback){
32903 if (this.fireEvent("beforehide", this) === false){
32907 this.shadow.hide();
32912 // sometimes animateTarget seems to get set.. causing problems...
32913 // this just double checks..
32914 if(this.animateTarget && Roo.get(this.animateTarget)) {
32915 this.animHide(callback);
32918 this.hideEl(callback);
32924 hideEl : function(callback){
32928 Roo.get(document.body).removeClass("x-body-masked");
32930 this.fireEvent("hide", this);
32931 if(typeof callback == "function"){
32937 hideAction : function(){
32938 this.setLeft("-10000px");
32939 this.setTop("-10000px");
32940 this.setStyle("visibility", "hidden");
32944 refreshSize : function(){
32945 this.size = this.el.getSize();
32946 this.xy = this.el.getXY();
32947 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32951 // z-index is managed by the DialogManager and may be overwritten at any time
32952 setZIndex : function(index){
32954 this.mask.setStyle("z-index", index);
32957 this.shim.setStyle("z-index", ++index);
32960 this.shadow.setZIndex(++index);
32962 this.el.setStyle("z-index", ++index);
32964 this.proxy.setStyle("z-index", ++index);
32967 this.resizer.proxy.setStyle("z-index", ++index);
32970 this.lastZIndex = index;
32974 * Returns the element for this dialog
32975 * @return {Roo.Element} The underlying dialog Element
32977 getEl : function(){
32983 * @class Roo.DialogManager
32984 * Provides global access to BasicDialogs that have been created and
32985 * support for z-indexing (layering) multiple open dialogs.
32987 Roo.DialogManager = function(){
32989 var accessList = [];
32993 var sortDialogs = function(d1, d2){
32994 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32998 var orderDialogs = function(){
32999 accessList.sort(sortDialogs);
33000 var seed = Roo.DialogManager.zseed;
33001 for(var i = 0, len = accessList.length; i < len; i++){
33002 var dlg = accessList[i];
33004 dlg.setZIndex(seed + (i*10));
33011 * The starting z-index for BasicDialogs (defaults to 9000)
33012 * @type Number The z-index value
33017 register : function(dlg){
33018 list[dlg.id] = dlg;
33019 accessList.push(dlg);
33023 unregister : function(dlg){
33024 delete list[dlg.id];
33027 if(!accessList.indexOf){
33028 for( i = 0, len = accessList.length; i < len; i++){
33029 if(accessList[i] == dlg){
33030 accessList.splice(i, 1);
33035 i = accessList.indexOf(dlg);
33037 accessList.splice(i, 1);
33043 * Gets a registered dialog by id
33044 * @param {String/Object} id The id of the dialog or a dialog
33045 * @return {Roo.BasicDialog} this
33047 get : function(id){
33048 return typeof id == "object" ? id : list[id];
33052 * Brings the specified dialog to the front
33053 * @param {String/Object} dlg The id of the dialog or a dialog
33054 * @return {Roo.BasicDialog} this
33056 bringToFront : function(dlg){
33057 dlg = this.get(dlg);
33060 dlg._lastAccess = new Date().getTime();
33067 * Sends the specified dialog to the back
33068 * @param {String/Object} dlg The id of the dialog or a dialog
33069 * @return {Roo.BasicDialog} this
33071 sendToBack : function(dlg){
33072 dlg = this.get(dlg);
33073 dlg._lastAccess = -(new Date().getTime());
33079 * Hides all dialogs
33081 hideAll : function(){
33082 for(var id in list){
33083 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33092 * @class Roo.LayoutDialog
33093 * @extends Roo.BasicDialog
33094 * Dialog which provides adjustments for working with a layout in a Dialog.
33095 * Add your necessary layout config options to the dialog's config.<br>
33096 * Example usage (including a nested layout):
33099 dialog = new Roo.LayoutDialog("download-dlg", {
33108 // layout config merges with the dialog config
33110 tabPosition: "top",
33111 alwaysShowTabs: true
33114 dialog.addKeyListener(27, dialog.hide, dialog);
33115 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33116 dialog.addButton("Build It!", this.getDownload, this);
33118 // we can even add nested layouts
33119 var innerLayout = new Roo.BorderLayout("dl-inner", {
33129 innerLayout.beginUpdate();
33130 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33131 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33132 innerLayout.endUpdate(true);
33134 var layout = dialog.getLayout();
33135 layout.beginUpdate();
33136 layout.add("center", new Roo.ContentPanel("standard-panel",
33137 {title: "Download the Source", fitToFrame:true}));
33138 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33139 {title: "Build your own roo.js"}));
33140 layout.getRegion("center").showPanel(sp);
33141 layout.endUpdate();
33145 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33146 * @param {Object} config configuration options
33148 Roo.LayoutDialog = function(el, cfg){
33151 if (typeof(cfg) == 'undefined') {
33152 config = Roo.apply({}, el);
33153 // not sure why we use documentElement here.. - it should always be body.
33154 // IE7 borks horribly if we use documentElement.
33155 // webkit also does not like documentElement - it creates a body element...
33156 el = Roo.get( document.body || document.documentElement ).createChild();
33157 //config.autoCreate = true;
33161 config.autoTabs = false;
33162 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33163 this.body.setStyle({overflow:"hidden", position:"relative"});
33164 this.layout = new Roo.BorderLayout(this.body.dom, config);
33165 this.layout.monitorWindowResize = false;
33166 this.el.addClass("x-dlg-auto-layout");
33167 // fix case when center region overwrites center function
33168 this.center = Roo.BasicDialog.prototype.center;
33169 this.on("show", this.layout.layout, this.layout, true);
33170 if (config.items) {
33171 var xitems = config.items;
33172 delete config.items;
33173 Roo.each(xitems, this.addxtype, this);
33178 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33180 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33183 endUpdate : function(){
33184 this.layout.endUpdate();
33188 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33191 beginUpdate : function(){
33192 this.layout.beginUpdate();
33196 * Get the BorderLayout for this dialog
33197 * @return {Roo.BorderLayout}
33199 getLayout : function(){
33200 return this.layout;
33203 showEl : function(){
33204 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33206 this.layout.layout();
33211 // Use the syncHeightBeforeShow config option to control this automatically
33212 syncBodyHeight : function(){
33213 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33214 if(this.layout){this.layout.layout();}
33218 * Add an xtype element (actually adds to the layout.)
33219 * @return {Object} xdata xtype object data.
33222 addxtype : function(c) {
33223 return this.layout.addxtype(c);
33227 * Ext JS Library 1.1.1
33228 * Copyright(c) 2006-2007, Ext JS, LLC.
33230 * Originally Released Under LGPL - original licence link has changed is not relivant.
33233 * <script type="text/javascript">
33237 * @class Roo.MessageBox
33238 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33242 Roo.Msg.alert('Status', 'Changes saved successfully.');
33244 // Prompt for user data:
33245 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33247 // process text value...
33251 // Show a dialog using config options:
33253 title:'Save Changes?',
33254 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33255 buttons: Roo.Msg.YESNOCANCEL,
33262 Roo.MessageBox = function(){
33263 var dlg, opt, mask, waitTimer;
33264 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33265 var buttons, activeTextEl, bwidth;
33268 var handleButton = function(button){
33270 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33274 var handleHide = function(){
33275 if(opt && opt.cls){
33276 dlg.el.removeClass(opt.cls);
33279 Roo.TaskMgr.stop(waitTimer);
33285 var updateButtons = function(b){
33288 buttons["ok"].hide();
33289 buttons["cancel"].hide();
33290 buttons["yes"].hide();
33291 buttons["no"].hide();
33292 dlg.footer.dom.style.display = 'none';
33295 dlg.footer.dom.style.display = '';
33296 for(var k in buttons){
33297 if(typeof buttons[k] != "function"){
33300 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33301 width += buttons[k].el.getWidth()+15;
33311 var handleEsc = function(d, k, e){
33312 if(opt && opt.closable !== false){
33322 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33323 * @return {Roo.BasicDialog} The BasicDialog element
33325 getDialog : function(){
33327 dlg = new Roo.BasicDialog("x-msg-box", {
33332 constraintoviewport:false,
33334 collapsible : false,
33337 width:400, height:100,
33338 buttonAlign:"center",
33339 closeClick : function(){
33340 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33341 handleButton("no");
33343 handleButton("cancel");
33347 dlg.on("hide", handleHide);
33349 dlg.addKeyListener(27, handleEsc);
33351 var bt = this.buttonText;
33352 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33353 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33354 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33355 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33356 bodyEl = dlg.body.createChild({
33358 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>'
33360 msgEl = bodyEl.dom.firstChild;
33361 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33362 textboxEl.enableDisplayMode();
33363 textboxEl.addKeyListener([10,13], function(){
33364 if(dlg.isVisible() && opt && opt.buttons){
33365 if(opt.buttons.ok){
33366 handleButton("ok");
33367 }else if(opt.buttons.yes){
33368 handleButton("yes");
33372 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33373 textareaEl.enableDisplayMode();
33374 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33375 progressEl.enableDisplayMode();
33376 var pf = progressEl.dom.firstChild;
33378 pp = Roo.get(pf.firstChild);
33379 pp.setHeight(pf.offsetHeight);
33387 * Updates the message box body text
33388 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33389 * the XHTML-compliant non-breaking space character '&#160;')
33390 * @return {Roo.MessageBox} This message box
33392 updateText : function(text){
33393 if(!dlg.isVisible() && !opt.width){
33394 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33396 msgEl.innerHTML = text || ' ';
33398 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33399 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33401 Math.min(opt.width || cw , this.maxWidth),
33402 Math.max(opt.minWidth || this.minWidth, bwidth)
33405 activeTextEl.setWidth(w);
33407 if(dlg.isVisible()){
33408 dlg.fixedcenter = false;
33410 // to big, make it scroll. = But as usual stupid IE does not support
33413 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33414 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33415 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33417 bodyEl.dom.style.height = '';
33418 bodyEl.dom.style.overflowY = '';
33421 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33423 bodyEl.dom.style.overflowX = '';
33426 dlg.setContentSize(w, bodyEl.getHeight());
33427 if(dlg.isVisible()){
33428 dlg.fixedcenter = true;
33434 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33435 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33436 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33437 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33438 * @return {Roo.MessageBox} This message box
33440 updateProgress : function(value, text){
33442 this.updateText(text);
33444 if (pp) { // weird bug on my firefox - for some reason this is not defined
33445 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33451 * Returns true if the message box is currently displayed
33452 * @return {Boolean} True if the message box is visible, else false
33454 isVisible : function(){
33455 return dlg && dlg.isVisible();
33459 * Hides the message box if it is displayed
33462 if(this.isVisible()){
33468 * Displays a new message box, or reinitializes an existing message box, based on the config options
33469 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33470 * The following config object properties are supported:
33472 Property Type Description
33473 ---------- --------------- ------------------------------------------------------------------------------------
33474 animEl String/Element An id or Element from which the message box should animate as it opens and
33475 closes (defaults to undefined)
33476 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33477 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33478 closable Boolean False to hide the top-right close button (defaults to true). Note that
33479 progress and wait dialogs will ignore this property and always hide the
33480 close button as they can only be closed programmatically.
33481 cls String A custom CSS class to apply to the message box element
33482 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33483 displayed (defaults to 75)
33484 fn Function A callback function to execute after closing the dialog. The arguments to the
33485 function will be btn (the name of the button that was clicked, if applicable,
33486 e.g. "ok"), and text (the value of the active text field, if applicable).
33487 Progress and wait dialogs will ignore this option since they do not respond to
33488 user actions and can only be closed programmatically, so any required function
33489 should be called by the same code after it closes the dialog.
33490 icon String A CSS class that provides a background image to be used as an icon for
33491 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33492 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33493 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33494 modal Boolean False to allow user interaction with the page while the message box is
33495 displayed (defaults to true)
33496 msg String A string that will replace the existing message box body text (defaults
33497 to the XHTML-compliant non-breaking space character ' ')
33498 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33499 progress Boolean True to display a progress bar (defaults to false)
33500 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33501 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33502 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33503 title String The title text
33504 value String The string value to set into the active textbox element if displayed
33505 wait Boolean True to display a progress bar (defaults to false)
33506 width Number The width of the dialog in pixels
33513 msg: 'Please enter your address:',
33515 buttons: Roo.MessageBox.OKCANCEL,
33518 animEl: 'addAddressBtn'
33521 * @param {Object} config Configuration options
33522 * @return {Roo.MessageBox} This message box
33524 show : function(options)
33527 // this causes nightmares if you show one dialog after another
33528 // especially on callbacks..
33530 if(this.isVisible()){
33533 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33534 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33535 Roo.log("New Dialog Message:" + options.msg )
33536 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33537 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33540 var d = this.getDialog();
33542 d.setTitle(opt.title || " ");
33543 d.close.setDisplayed(opt.closable !== false);
33544 activeTextEl = textboxEl;
33545 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33550 textareaEl.setHeight(typeof opt.multiline == "number" ?
33551 opt.multiline : this.defaultTextHeight);
33552 activeTextEl = textareaEl;
33561 progressEl.setDisplayed(opt.progress === true);
33562 this.updateProgress(0);
33563 activeTextEl.dom.value = opt.value || "";
33565 dlg.setDefaultButton(activeTextEl);
33567 var bs = opt.buttons;
33570 db = buttons["ok"];
33571 }else if(bs && bs.yes){
33572 db = buttons["yes"];
33574 dlg.setDefaultButton(db);
33576 bwidth = updateButtons(opt.buttons);
33577 this.updateText(opt.msg);
33579 d.el.addClass(opt.cls);
33581 d.proxyDrag = opt.proxyDrag === true;
33582 d.modal = opt.modal !== false;
33583 d.mask = opt.modal !== false ? mask : false;
33584 if(!d.isVisible()){
33585 // force it to the end of the z-index stack so it gets a cursor in FF
33586 document.body.appendChild(dlg.el.dom);
33587 d.animateTarget = null;
33588 d.show(options.animEl);
33594 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33595 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33596 * and closing the message box when the process is complete.
33597 * @param {String} title The title bar text
33598 * @param {String} msg The message box body text
33599 * @return {Roo.MessageBox} This message box
33601 progress : function(title, msg){
33608 minWidth: this.minProgressWidth,
33615 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33616 * If a callback function is passed it will be called after the user clicks the button, and the
33617 * id of the button that was clicked will be passed as the only parameter to the callback
33618 * (could also be the top-right close button).
33619 * @param {String} title The title bar text
33620 * @param {String} msg The message box body text
33621 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33622 * @param {Object} scope (optional) The scope of the callback function
33623 * @return {Roo.MessageBox} This message box
33625 alert : function(title, msg, fn, scope){
33638 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33639 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33640 * You are responsible for closing the message box when the process is complete.
33641 * @param {String} msg The message box body text
33642 * @param {String} title (optional) The title bar text
33643 * @return {Roo.MessageBox} This message box
33645 wait : function(msg, title){
33656 waitTimer = Roo.TaskMgr.start({
33658 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33666 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33667 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33668 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33669 * @param {String} title The title bar text
33670 * @param {String} msg The message box body text
33671 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33672 * @param {Object} scope (optional) The scope of the callback function
33673 * @return {Roo.MessageBox} This message box
33675 confirm : function(title, msg, fn, scope){
33679 buttons: this.YESNO,
33688 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33689 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33690 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33691 * (could also be the top-right close button) and the text that was entered will be passed as the two
33692 * parameters to the callback.
33693 * @param {String} title The title bar text
33694 * @param {String} msg The message box body text
33695 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33696 * @param {Object} scope (optional) The scope of the callback function
33697 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33698 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33699 * @return {Roo.MessageBox} This message box
33701 prompt : function(title, msg, fn, scope, multiline){
33705 buttons: this.OKCANCEL,
33710 multiline: multiline,
33717 * Button config that displays a single OK button
33722 * Button config that displays Yes and No buttons
33725 YESNO : {yes:true, no:true},
33727 * Button config that displays OK and Cancel buttons
33730 OKCANCEL : {ok:true, cancel:true},
33732 * Button config that displays Yes, No and Cancel buttons
33735 YESNOCANCEL : {yes:true, no:true, cancel:true},
33738 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33741 defaultTextHeight : 75,
33743 * The maximum width in pixels of the message box (defaults to 600)
33748 * The minimum width in pixels of the message box (defaults to 100)
33753 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33754 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33757 minProgressWidth : 250,
33759 * An object containing the default button text strings that can be overriden for localized language support.
33760 * Supported properties are: ok, cancel, yes and no.
33761 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33774 * Shorthand for {@link Roo.MessageBox}
33776 Roo.Msg = Roo.MessageBox;/*
33778 * Ext JS Library 1.1.1
33779 * Copyright(c) 2006-2007, Ext JS, LLC.
33781 * Originally Released Under LGPL - original licence link has changed is not relivant.
33784 * <script type="text/javascript">
33787 * @class Roo.QuickTips
33788 * Provides attractive and customizable tooltips for any element.
33791 Roo.QuickTips = function(){
33792 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33793 var ce, bd, xy, dd;
33794 var visible = false, disabled = true, inited = false;
33795 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33797 var onOver = function(e){
33801 var t = e.getTarget();
33802 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33805 if(ce && t == ce.el){
33806 clearTimeout(hideProc);
33809 if(t && tagEls[t.id]){
33810 tagEls[t.id].el = t;
33811 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33814 var ttp, et = Roo.fly(t);
33815 var ns = cfg.namespace;
33816 if(tm.interceptTitles && t.title){
33819 t.removeAttribute("title");
33820 e.preventDefault();
33822 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33825 showProc = show.defer(tm.showDelay, tm, [{
33827 text: ttp.replace(/\\n/g,'<br/>'),
33828 width: et.getAttributeNS(ns, cfg.width),
33829 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33830 title: et.getAttributeNS(ns, cfg.title),
33831 cls: et.getAttributeNS(ns, cfg.cls)
33836 var onOut = function(e){
33837 clearTimeout(showProc);
33838 var t = e.getTarget();
33839 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33840 hideProc = setTimeout(hide, tm.hideDelay);
33844 var onMove = function(e){
33850 if(tm.trackMouse && ce){
33855 var onDown = function(e){
33856 clearTimeout(showProc);
33857 clearTimeout(hideProc);
33859 if(tm.hideOnClick){
33862 tm.enable.defer(100, tm);
33867 var getPad = function(){
33868 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33871 var show = function(o){
33875 clearTimeout(dismissProc);
33877 if(removeCls){ // in case manually hidden
33878 el.removeClass(removeCls);
33882 el.addClass(ce.cls);
33883 removeCls = ce.cls;
33886 tipTitle.update(ce.title);
33889 tipTitle.update('');
33892 el.dom.style.width = tm.maxWidth+'px';
33893 //tipBody.dom.style.width = '';
33894 tipBodyText.update(o.text);
33895 var p = getPad(), w = ce.width;
33897 var td = tipBodyText.dom;
33898 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33899 if(aw > tm.maxWidth){
33901 }else if(aw < tm.minWidth){
33907 //tipBody.setWidth(w);
33908 el.setWidth(parseInt(w, 10) + p);
33909 if(ce.autoHide === false){
33910 close.setDisplayed(true);
33915 close.setDisplayed(false);
33921 el.avoidY = xy[1]-18;
33926 el.setStyle("visibility", "visible");
33927 el.fadeIn({callback: afterShow});
33933 var afterShow = function(){
33937 if(tm.autoDismiss && ce.autoHide !== false){
33938 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33943 var hide = function(noanim){
33944 clearTimeout(dismissProc);
33945 clearTimeout(hideProc);
33947 if(el.isVisible()){
33949 if(noanim !== true && tm.animate){
33950 el.fadeOut({callback: afterHide});
33957 var afterHide = function(){
33960 el.removeClass(removeCls);
33967 * @cfg {Number} minWidth
33968 * The minimum width of the quick tip (defaults to 40)
33972 * @cfg {Number} maxWidth
33973 * The maximum width of the quick tip (defaults to 300)
33977 * @cfg {Boolean} interceptTitles
33978 * True to automatically use the element's DOM title value if available (defaults to false)
33980 interceptTitles : false,
33982 * @cfg {Boolean} trackMouse
33983 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33985 trackMouse : false,
33987 * @cfg {Boolean} hideOnClick
33988 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33990 hideOnClick : true,
33992 * @cfg {Number} showDelay
33993 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33997 * @cfg {Number} hideDelay
33998 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34002 * @cfg {Boolean} autoHide
34003 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34004 * Used in conjunction with hideDelay.
34009 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34010 * (defaults to true). Used in conjunction with autoDismissDelay.
34012 autoDismiss : true,
34015 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34017 autoDismissDelay : 5000,
34019 * @cfg {Boolean} animate
34020 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34025 * @cfg {String} title
34026 * Title text to display (defaults to ''). This can be any valid HTML markup.
34030 * @cfg {String} text
34031 * Body text to display (defaults to ''). This can be any valid HTML markup.
34035 * @cfg {String} cls
34036 * A CSS class to apply to the base quick tip element (defaults to '').
34040 * @cfg {Number} width
34041 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34042 * minWidth or maxWidth.
34047 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34048 * or display QuickTips in a page.
34051 tm = Roo.QuickTips;
34052 cfg = tm.tagConfig;
34054 if(!Roo.isReady){ // allow calling of init() before onReady
34055 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34058 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34059 el.fxDefaults = {stopFx: true};
34060 // maximum custom styling
34061 //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>');
34062 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>');
34063 tipTitle = el.child('h3');
34064 tipTitle.enableDisplayMode("block");
34065 tipBody = el.child('div.x-tip-bd');
34066 tipBodyText = el.child('div.x-tip-bd-inner');
34067 //bdLeft = el.child('div.x-tip-bd-left');
34068 //bdRight = el.child('div.x-tip-bd-right');
34069 close = el.child('div.x-tip-close');
34070 close.enableDisplayMode("block");
34071 close.on("click", hide);
34072 var d = Roo.get(document);
34073 d.on("mousedown", onDown);
34074 d.on("mouseover", onOver);
34075 d.on("mouseout", onOut);
34076 d.on("mousemove", onMove);
34077 esc = d.addKeyListener(27, hide);
34080 dd = el.initDD("default", null, {
34081 onDrag : function(){
34085 dd.setHandleElId(tipTitle.id);
34094 * Configures a new quick tip instance and assigns it to a target element. The following config options
34097 Property Type Description
34098 ---------- --------------------- ------------------------------------------------------------------------
34099 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34101 * @param {Object} config The config object
34103 register : function(config){
34104 var cs = config instanceof Array ? config : arguments;
34105 for(var i = 0, len = cs.length; i < len; i++) {
34107 var target = c.target;
34109 if(target instanceof Array){
34110 for(var j = 0, jlen = target.length; j < jlen; j++){
34111 tagEls[target[j]] = c;
34114 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34121 * Removes this quick tip from its element and destroys it.
34122 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34124 unregister : function(el){
34125 delete tagEls[Roo.id(el)];
34129 * Enable this quick tip.
34131 enable : function(){
34132 if(inited && disabled){
34134 if(locks.length < 1){
34141 * Disable this quick tip.
34143 disable : function(){
34145 clearTimeout(showProc);
34146 clearTimeout(hideProc);
34147 clearTimeout(dismissProc);
34155 * Returns true if the quick tip is enabled, else false.
34157 isEnabled : function(){
34163 namespace : "roo", // was ext?? this may break..
34164 alt_namespace : "ext",
34165 attribute : "qtip",
34175 // backwards compat
34176 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34178 * Ext JS Library 1.1.1
34179 * Copyright(c) 2006-2007, Ext JS, LLC.
34181 * Originally Released Under LGPL - original licence link has changed is not relivant.
34184 * <script type="text/javascript">
34189 * @class Roo.tree.TreePanel
34190 * @extends Roo.data.Tree
34192 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34193 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34194 * @cfg {Boolean} enableDD true to enable drag and drop
34195 * @cfg {Boolean} enableDrag true to enable just drag
34196 * @cfg {Boolean} enableDrop true to enable just drop
34197 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34198 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34199 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34200 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34201 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34202 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34203 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34204 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34205 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34206 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34207 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34208 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34209 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34210 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34211 * @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>
34212 * @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>
34215 * @param {String/HTMLElement/Element} el The container element
34216 * @param {Object} config
34218 Roo.tree.TreePanel = function(el, config){
34220 var loader = false;
34222 root = config.root;
34223 delete config.root;
34225 if (config.loader) {
34226 loader = config.loader;
34227 delete config.loader;
34230 Roo.apply(this, config);
34231 Roo.tree.TreePanel.superclass.constructor.call(this);
34232 this.el = Roo.get(el);
34233 this.el.addClass('x-tree');
34234 //console.log(root);
34236 this.setRootNode( Roo.factory(root, Roo.tree));
34239 this.loader = Roo.factory(loader, Roo.tree);
34242 * Read-only. The id of the container element becomes this TreePanel's id.
34244 this.id = this.el.id;
34247 * @event beforeload
34248 * Fires before a node is loaded, return false to cancel
34249 * @param {Node} node The node being loaded
34251 "beforeload" : true,
34254 * Fires when a node is loaded
34255 * @param {Node} node The node that was loaded
34259 * @event textchange
34260 * Fires when the text for a node is changed
34261 * @param {Node} node The node
34262 * @param {String} text The new text
34263 * @param {String} oldText The old text
34265 "textchange" : true,
34267 * @event beforeexpand
34268 * Fires before a node is expanded, return false to cancel.
34269 * @param {Node} node The node
34270 * @param {Boolean} deep
34271 * @param {Boolean} anim
34273 "beforeexpand" : true,
34275 * @event beforecollapse
34276 * Fires before a node is collapsed, return false to cancel.
34277 * @param {Node} node The node
34278 * @param {Boolean} deep
34279 * @param {Boolean} anim
34281 "beforecollapse" : true,
34284 * Fires when a node is expanded
34285 * @param {Node} node The node
34289 * @event disabledchange
34290 * Fires when the disabled status of a node changes
34291 * @param {Node} node The node
34292 * @param {Boolean} disabled
34294 "disabledchange" : true,
34297 * Fires when a node is collapsed
34298 * @param {Node} node The node
34302 * @event beforeclick
34303 * Fires before click processing on a node. Return false to cancel the default action.
34304 * @param {Node} node The node
34305 * @param {Roo.EventObject} e The event object
34307 "beforeclick":true,
34309 * @event checkchange
34310 * Fires when a node with a checkbox's checked property changes
34311 * @param {Node} this This node
34312 * @param {Boolean} checked
34314 "checkchange":true,
34317 * Fires when a node is clicked
34318 * @param {Node} node The node
34319 * @param {Roo.EventObject} e The event object
34324 * Fires when a node is double clicked
34325 * @param {Node} node The node
34326 * @param {Roo.EventObject} e The event object
34330 * @event contextmenu
34331 * Fires when a node is right clicked
34332 * @param {Node} node The node
34333 * @param {Roo.EventObject} e The event object
34335 "contextmenu":true,
34337 * @event beforechildrenrendered
34338 * Fires right before the child nodes for a node are rendered
34339 * @param {Node} node The node
34341 "beforechildrenrendered":true,
34344 * Fires when a node starts being dragged
34345 * @param {Roo.tree.TreePanel} this
34346 * @param {Roo.tree.TreeNode} node
34347 * @param {event} e The raw browser event
34349 "startdrag" : true,
34352 * Fires when a drag operation is complete
34353 * @param {Roo.tree.TreePanel} this
34354 * @param {Roo.tree.TreeNode} node
34355 * @param {event} e The raw browser event
34360 * Fires when a dragged node is dropped on a valid DD target
34361 * @param {Roo.tree.TreePanel} this
34362 * @param {Roo.tree.TreeNode} node
34363 * @param {DD} dd The dd it was dropped on
34364 * @param {event} e The raw browser event
34368 * @event beforenodedrop
34369 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34370 * passed to handlers has the following properties:<br />
34371 * <ul style="padding:5px;padding-left:16px;">
34372 * <li>tree - The TreePanel</li>
34373 * <li>target - The node being targeted for the drop</li>
34374 * <li>data - The drag data from the drag source</li>
34375 * <li>point - The point of the drop - append, above or below</li>
34376 * <li>source - The drag source</li>
34377 * <li>rawEvent - Raw mouse event</li>
34378 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34379 * to be inserted by setting them on this object.</li>
34380 * <li>cancel - Set this to true to cancel the drop.</li>
34382 * @param {Object} dropEvent
34384 "beforenodedrop" : true,
34387 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34388 * passed to handlers has the following properties:<br />
34389 * <ul style="padding:5px;padding-left:16px;">
34390 * <li>tree - The TreePanel</li>
34391 * <li>target - The node being targeted for the drop</li>
34392 * <li>data - The drag data from the drag source</li>
34393 * <li>point - The point of the drop - append, above or below</li>
34394 * <li>source - The drag source</li>
34395 * <li>rawEvent - Raw mouse event</li>
34396 * <li>dropNode - Dropped node(s).</li>
34398 * @param {Object} dropEvent
34402 * @event nodedragover
34403 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34404 * passed to handlers has the following properties:<br />
34405 * <ul style="padding:5px;padding-left:16px;">
34406 * <li>tree - The TreePanel</li>
34407 * <li>target - The node being targeted for the drop</li>
34408 * <li>data - The drag data from the drag source</li>
34409 * <li>point - The point of the drop - append, above or below</li>
34410 * <li>source - The drag source</li>
34411 * <li>rawEvent - Raw mouse event</li>
34412 * <li>dropNode - Drop node(s) provided by the source.</li>
34413 * <li>cancel - Set this to true to signal drop not allowed.</li>
34415 * @param {Object} dragOverEvent
34417 "nodedragover" : true,
34419 * @event appendnode
34420 * Fires when append node to the tree
34421 * @param {Roo.tree.TreePanel} this
34422 * @param {Roo.tree.TreeNode} node
34423 * @param {Number} index The index of the newly appended node
34425 "appendnode" : true
34428 if(this.singleExpand){
34429 this.on("beforeexpand", this.restrictExpand, this);
34432 this.editor.tree = this;
34433 this.editor = Roo.factory(this.editor, Roo.tree);
34436 if (this.selModel) {
34437 this.selModel = Roo.factory(this.selModel, Roo.tree);
34441 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34442 rootVisible : true,
34443 animate: Roo.enableFx,
34446 hlDrop : Roo.enableFx,
34450 rendererTip: false,
34452 restrictExpand : function(node){
34453 var p = node.parentNode;
34455 if(p.expandedChild && p.expandedChild.parentNode == p){
34456 p.expandedChild.collapse();
34458 p.expandedChild = node;
34462 // private override
34463 setRootNode : function(node){
34464 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34465 if(!this.rootVisible){
34466 node.ui = new Roo.tree.RootTreeNodeUI(node);
34472 * Returns the container element for this TreePanel
34474 getEl : function(){
34479 * Returns the default TreeLoader for this TreePanel
34481 getLoader : function(){
34482 return this.loader;
34488 expandAll : function(){
34489 this.root.expand(true);
34493 * Collapse all nodes
34495 collapseAll : function(){
34496 this.root.collapse(true);
34500 * Returns the selection model used by this TreePanel
34502 getSelectionModel : function(){
34503 if(!this.selModel){
34504 this.selModel = new Roo.tree.DefaultSelectionModel();
34506 return this.selModel;
34510 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34511 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34512 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34515 getChecked : function(a, startNode){
34516 startNode = startNode || this.root;
34518 var f = function(){
34519 if(this.attributes.checked){
34520 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34523 startNode.cascade(f);
34528 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34529 * @param {String} path
34530 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34531 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34532 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34534 expandPath : function(path, attr, callback){
34535 attr = attr || "id";
34536 var keys = path.split(this.pathSeparator);
34537 var curNode = this.root;
34538 if(curNode.attributes[attr] != keys[1]){ // invalid root
34540 callback(false, null);
34545 var f = function(){
34546 if(++index == keys.length){
34548 callback(true, curNode);
34552 var c = curNode.findChild(attr, keys[index]);
34555 callback(false, curNode);
34560 c.expand(false, false, f);
34562 curNode.expand(false, false, f);
34566 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34567 * @param {String} path
34568 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34569 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34570 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34572 selectPath : function(path, attr, callback){
34573 attr = attr || "id";
34574 var keys = path.split(this.pathSeparator);
34575 var v = keys.pop();
34576 if(keys.length > 0){
34577 var f = function(success, node){
34578 if(success && node){
34579 var n = node.findChild(attr, v);
34585 }else if(callback){
34586 callback(false, n);
34590 callback(false, n);
34594 this.expandPath(keys.join(this.pathSeparator), attr, f);
34596 this.root.select();
34598 callback(true, this.root);
34603 getTreeEl : function(){
34608 * Trigger rendering of this TreePanel
34610 render : function(){
34611 if (this.innerCt) {
34612 return this; // stop it rendering more than once!!
34615 this.innerCt = this.el.createChild({tag:"ul",
34616 cls:"x-tree-root-ct " +
34617 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34619 if(this.containerScroll){
34620 Roo.dd.ScrollManager.register(this.el);
34622 if((this.enableDD || this.enableDrop) && !this.dropZone){
34624 * The dropZone used by this tree if drop is enabled
34625 * @type Roo.tree.TreeDropZone
34627 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34628 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34631 if((this.enableDD || this.enableDrag) && !this.dragZone){
34633 * The dragZone used by this tree if drag is enabled
34634 * @type Roo.tree.TreeDragZone
34636 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34637 ddGroup: this.ddGroup || "TreeDD",
34638 scroll: this.ddScroll
34641 this.getSelectionModel().init(this);
34643 Roo.log("ROOT not set in tree");
34646 this.root.render();
34647 if(!this.rootVisible){
34648 this.root.renderChildren();
34654 * Ext JS Library 1.1.1
34655 * Copyright(c) 2006-2007, Ext JS, LLC.
34657 * Originally Released Under LGPL - original licence link has changed is not relivant.
34660 * <script type="text/javascript">
34665 * @class Roo.tree.DefaultSelectionModel
34666 * @extends Roo.util.Observable
34667 * The default single selection for a TreePanel.
34668 * @param {Object} cfg Configuration
34670 Roo.tree.DefaultSelectionModel = function(cfg){
34671 this.selNode = null;
34677 * @event selectionchange
34678 * Fires when the selected node changes
34679 * @param {DefaultSelectionModel} this
34680 * @param {TreeNode} node the new selection
34682 "selectionchange" : true,
34685 * @event beforeselect
34686 * Fires before the selected node changes, return false to cancel the change
34687 * @param {DefaultSelectionModel} this
34688 * @param {TreeNode} node the new selection
34689 * @param {TreeNode} node the old selection
34691 "beforeselect" : true
34694 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34697 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34698 init : function(tree){
34700 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34701 tree.on("click", this.onNodeClick, this);
34704 onNodeClick : function(node, e){
34705 if (e.ctrlKey && this.selNode == node) {
34706 this.unselect(node);
34714 * @param {TreeNode} node The node to select
34715 * @return {TreeNode} The selected node
34717 select : function(node){
34718 var last = this.selNode;
34719 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34721 last.ui.onSelectedChange(false);
34723 this.selNode = node;
34724 node.ui.onSelectedChange(true);
34725 this.fireEvent("selectionchange", this, node, last);
34732 * @param {TreeNode} node The node to unselect
34734 unselect : function(node){
34735 if(this.selNode == node){
34736 this.clearSelections();
34741 * Clear all selections
34743 clearSelections : function(){
34744 var n = this.selNode;
34746 n.ui.onSelectedChange(false);
34747 this.selNode = null;
34748 this.fireEvent("selectionchange", this, null);
34754 * Get the selected node
34755 * @return {TreeNode} The selected node
34757 getSelectedNode : function(){
34758 return this.selNode;
34762 * Returns true if the node is selected
34763 * @param {TreeNode} node The node to check
34764 * @return {Boolean}
34766 isSelected : function(node){
34767 return this.selNode == node;
34771 * Selects the node above the selected node in the tree, intelligently walking the nodes
34772 * @return TreeNode The new selection
34774 selectPrevious : function(){
34775 var s = this.selNode || this.lastSelNode;
34779 var ps = s.previousSibling;
34781 if(!ps.isExpanded() || ps.childNodes.length < 1){
34782 return this.select(ps);
34784 var lc = ps.lastChild;
34785 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34788 return this.select(lc);
34790 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34791 return this.select(s.parentNode);
34797 * Selects the node above the selected node in the tree, intelligently walking the nodes
34798 * @return TreeNode The new selection
34800 selectNext : function(){
34801 var s = this.selNode || this.lastSelNode;
34805 if(s.firstChild && s.isExpanded()){
34806 return this.select(s.firstChild);
34807 }else if(s.nextSibling){
34808 return this.select(s.nextSibling);
34809 }else if(s.parentNode){
34811 s.parentNode.bubble(function(){
34812 if(this.nextSibling){
34813 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34822 onKeyDown : function(e){
34823 var s = this.selNode || this.lastSelNode;
34824 // undesirable, but required
34829 var k = e.getKey();
34837 this.selectPrevious();
34840 e.preventDefault();
34841 if(s.hasChildNodes()){
34842 if(!s.isExpanded()){
34844 }else if(s.firstChild){
34845 this.select(s.firstChild, e);
34850 e.preventDefault();
34851 if(s.hasChildNodes() && s.isExpanded()){
34853 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34854 this.select(s.parentNode, e);
34862 * @class Roo.tree.MultiSelectionModel
34863 * @extends Roo.util.Observable
34864 * Multi selection for a TreePanel.
34865 * @param {Object} cfg Configuration
34867 Roo.tree.MultiSelectionModel = function(){
34868 this.selNodes = [];
34872 * @event selectionchange
34873 * Fires when the selected nodes change
34874 * @param {MultiSelectionModel} this
34875 * @param {Array} nodes Array of the selected nodes
34877 "selectionchange" : true
34879 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34883 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34884 init : function(tree){
34886 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34887 tree.on("click", this.onNodeClick, this);
34890 onNodeClick : function(node, e){
34891 this.select(node, e, e.ctrlKey);
34896 * @param {TreeNode} node The node to select
34897 * @param {EventObject} e (optional) An event associated with the selection
34898 * @param {Boolean} keepExisting True to retain existing selections
34899 * @return {TreeNode} The selected node
34901 select : function(node, e, keepExisting){
34902 if(keepExisting !== true){
34903 this.clearSelections(true);
34905 if(this.isSelected(node)){
34906 this.lastSelNode = node;
34909 this.selNodes.push(node);
34910 this.selMap[node.id] = node;
34911 this.lastSelNode = node;
34912 node.ui.onSelectedChange(true);
34913 this.fireEvent("selectionchange", this, this.selNodes);
34919 * @param {TreeNode} node The node to unselect
34921 unselect : function(node){
34922 if(this.selMap[node.id]){
34923 node.ui.onSelectedChange(false);
34924 var sn = this.selNodes;
34927 index = sn.indexOf(node);
34929 for(var i = 0, len = sn.length; i < len; i++){
34937 this.selNodes.splice(index, 1);
34939 delete this.selMap[node.id];
34940 this.fireEvent("selectionchange", this, this.selNodes);
34945 * Clear all selections
34947 clearSelections : function(suppressEvent){
34948 var sn = this.selNodes;
34950 for(var i = 0, len = sn.length; i < len; i++){
34951 sn[i].ui.onSelectedChange(false);
34953 this.selNodes = [];
34955 if(suppressEvent !== true){
34956 this.fireEvent("selectionchange", this, this.selNodes);
34962 * Returns true if the node is selected
34963 * @param {TreeNode} node The node to check
34964 * @return {Boolean}
34966 isSelected : function(node){
34967 return this.selMap[node.id] ? true : false;
34971 * Returns an array of the selected nodes
34974 getSelectedNodes : function(){
34975 return this.selNodes;
34978 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34980 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34982 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34985 * Ext JS Library 1.1.1
34986 * Copyright(c) 2006-2007, Ext JS, LLC.
34988 * Originally Released Under LGPL - original licence link has changed is not relivant.
34991 * <script type="text/javascript">
34995 * @class Roo.tree.TreeNode
34996 * @extends Roo.data.Node
34997 * @cfg {String} text The text for this node
34998 * @cfg {Boolean} expanded true to start the node expanded
34999 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35000 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35001 * @cfg {Boolean} disabled true to start the node disabled
35002 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35003 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35004 * @cfg {String} cls A css class to be added to the node
35005 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35006 * @cfg {String} href URL of the link used for the node (defaults to #)
35007 * @cfg {String} hrefTarget target frame for the link
35008 * @cfg {String} qtip An Ext QuickTip for the node
35009 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35010 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35011 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35012 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35013 * (defaults to undefined with no checkbox rendered)
35015 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35017 Roo.tree.TreeNode = function(attributes){
35018 attributes = attributes || {};
35019 if(typeof attributes == "string"){
35020 attributes = {text: attributes};
35022 this.childrenRendered = false;
35023 this.rendered = false;
35024 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35025 this.expanded = attributes.expanded === true;
35026 this.isTarget = attributes.isTarget !== false;
35027 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35028 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35031 * Read-only. The text for this node. To change it use setText().
35034 this.text = attributes.text;
35036 * True if this node is disabled.
35039 this.disabled = attributes.disabled === true;
35043 * @event textchange
35044 * Fires when the text for this node is changed
35045 * @param {Node} this This node
35046 * @param {String} text The new text
35047 * @param {String} oldText The old text
35049 "textchange" : true,
35051 * @event beforeexpand
35052 * Fires before this node is expanded, return false to cancel.
35053 * @param {Node} this This node
35054 * @param {Boolean} deep
35055 * @param {Boolean} anim
35057 "beforeexpand" : true,
35059 * @event beforecollapse
35060 * Fires before this node is collapsed, return false to cancel.
35061 * @param {Node} this This node
35062 * @param {Boolean} deep
35063 * @param {Boolean} anim
35065 "beforecollapse" : true,
35068 * Fires when this node is expanded
35069 * @param {Node} this This node
35073 * @event disabledchange
35074 * Fires when the disabled status of this node changes
35075 * @param {Node} this This node
35076 * @param {Boolean} disabled
35078 "disabledchange" : true,
35081 * Fires when this node is collapsed
35082 * @param {Node} this This node
35086 * @event beforeclick
35087 * Fires before click processing. Return false to cancel the default action.
35088 * @param {Node} this This node
35089 * @param {Roo.EventObject} e The event object
35091 "beforeclick":true,
35093 * @event checkchange
35094 * Fires when a node with a checkbox's checked property changes
35095 * @param {Node} this This node
35096 * @param {Boolean} checked
35098 "checkchange":true,
35101 * Fires when this node is clicked
35102 * @param {Node} this This node
35103 * @param {Roo.EventObject} e The event object
35108 * Fires when this node is double clicked
35109 * @param {Node} this This node
35110 * @param {Roo.EventObject} e The event object
35114 * @event contextmenu
35115 * Fires when this node is right clicked
35116 * @param {Node} this This node
35117 * @param {Roo.EventObject} e The event object
35119 "contextmenu":true,
35121 * @event beforechildrenrendered
35122 * Fires right before the child nodes for this node are rendered
35123 * @param {Node} this This node
35125 "beforechildrenrendered":true
35128 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35131 * Read-only. The UI for this node
35134 this.ui = new uiClass(this);
35136 // finally support items[]
35137 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35142 Roo.each(this.attributes.items, function(c) {
35143 this.appendChild(Roo.factory(c,Roo.Tree));
35145 delete this.attributes.items;
35150 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35151 preventHScroll: true,
35153 * Returns true if this node is expanded
35154 * @return {Boolean}
35156 isExpanded : function(){
35157 return this.expanded;
35161 * Returns the UI object for this node
35162 * @return {TreeNodeUI}
35164 getUI : function(){
35168 // private override
35169 setFirstChild : function(node){
35170 var of = this.firstChild;
35171 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35172 if(this.childrenRendered && of && node != of){
35173 of.renderIndent(true, true);
35176 this.renderIndent(true, true);
35180 // private override
35181 setLastChild : function(node){
35182 var ol = this.lastChild;
35183 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35184 if(this.childrenRendered && ol && node != ol){
35185 ol.renderIndent(true, true);
35188 this.renderIndent(true, true);
35192 // these methods are overridden to provide lazy rendering support
35193 // private override
35194 appendChild : function()
35196 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35197 if(node && this.childrenRendered){
35200 this.ui.updateExpandIcon();
35204 // private override
35205 removeChild : function(node){
35206 this.ownerTree.getSelectionModel().unselect(node);
35207 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35208 // if it's been rendered remove dom node
35209 if(this.childrenRendered){
35212 if(this.childNodes.length < 1){
35213 this.collapse(false, false);
35215 this.ui.updateExpandIcon();
35217 if(!this.firstChild) {
35218 this.childrenRendered = false;
35223 // private override
35224 insertBefore : function(node, refNode){
35225 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35226 if(newNode && refNode && this.childrenRendered){
35229 this.ui.updateExpandIcon();
35234 * Sets the text for this node
35235 * @param {String} text
35237 setText : function(text){
35238 var oldText = this.text;
35240 this.attributes.text = text;
35241 if(this.rendered){ // event without subscribing
35242 this.ui.onTextChange(this, text, oldText);
35244 this.fireEvent("textchange", this, text, oldText);
35248 * Triggers selection of this node
35250 select : function(){
35251 this.getOwnerTree().getSelectionModel().select(this);
35255 * Triggers deselection of this node
35257 unselect : function(){
35258 this.getOwnerTree().getSelectionModel().unselect(this);
35262 * Returns true if this node is selected
35263 * @return {Boolean}
35265 isSelected : function(){
35266 return this.getOwnerTree().getSelectionModel().isSelected(this);
35270 * Expand this node.
35271 * @param {Boolean} deep (optional) True to expand all children as well
35272 * @param {Boolean} anim (optional) false to cancel the default animation
35273 * @param {Function} callback (optional) A callback to be called when
35274 * expanding this node completes (does not wait for deep expand to complete).
35275 * Called with 1 parameter, this node.
35277 expand : function(deep, anim, callback){
35278 if(!this.expanded){
35279 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35282 if(!this.childrenRendered){
35283 this.renderChildren();
35285 this.expanded = true;
35287 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35288 this.ui.animExpand(function(){
35289 this.fireEvent("expand", this);
35290 if(typeof callback == "function"){
35294 this.expandChildNodes(true);
35296 }.createDelegate(this));
35300 this.fireEvent("expand", this);
35301 if(typeof callback == "function"){
35306 if(typeof callback == "function"){
35311 this.expandChildNodes(true);
35315 isHiddenRoot : function(){
35316 return this.isRoot && !this.getOwnerTree().rootVisible;
35320 * Collapse this node.
35321 * @param {Boolean} deep (optional) True to collapse all children as well
35322 * @param {Boolean} anim (optional) false to cancel the default animation
35324 collapse : function(deep, anim){
35325 if(this.expanded && !this.isHiddenRoot()){
35326 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35329 this.expanded = false;
35330 if((this.getOwnerTree().animate && anim !== false) || anim){
35331 this.ui.animCollapse(function(){
35332 this.fireEvent("collapse", this);
35334 this.collapseChildNodes(true);
35336 }.createDelegate(this));
35339 this.ui.collapse();
35340 this.fireEvent("collapse", this);
35344 var cs = this.childNodes;
35345 for(var i = 0, len = cs.length; i < len; i++) {
35346 cs[i].collapse(true, false);
35352 delayedExpand : function(delay){
35353 if(!this.expandProcId){
35354 this.expandProcId = this.expand.defer(delay, this);
35359 cancelExpand : function(){
35360 if(this.expandProcId){
35361 clearTimeout(this.expandProcId);
35363 this.expandProcId = false;
35367 * Toggles expanded/collapsed state of the node
35369 toggle : function(){
35378 * Ensures all parent nodes are expanded
35380 ensureVisible : function(callback){
35381 var tree = this.getOwnerTree();
35382 tree.expandPath(this.parentNode.getPath(), false, function(){
35383 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35384 Roo.callback(callback);
35385 }.createDelegate(this));
35389 * Expand all child nodes
35390 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35392 expandChildNodes : function(deep){
35393 var cs = this.childNodes;
35394 for(var i = 0, len = cs.length; i < len; i++) {
35395 cs[i].expand(deep);
35400 * Collapse all child nodes
35401 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35403 collapseChildNodes : function(deep){
35404 var cs = this.childNodes;
35405 for(var i = 0, len = cs.length; i < len; i++) {
35406 cs[i].collapse(deep);
35411 * Disables this node
35413 disable : function(){
35414 this.disabled = true;
35416 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35417 this.ui.onDisableChange(this, true);
35419 this.fireEvent("disabledchange", this, true);
35423 * Enables this node
35425 enable : function(){
35426 this.disabled = false;
35427 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35428 this.ui.onDisableChange(this, false);
35430 this.fireEvent("disabledchange", this, false);
35434 renderChildren : function(suppressEvent){
35435 if(suppressEvent !== false){
35436 this.fireEvent("beforechildrenrendered", this);
35438 var cs = this.childNodes;
35439 for(var i = 0, len = cs.length; i < len; i++){
35440 cs[i].render(true);
35442 this.childrenRendered = true;
35446 sort : function(fn, scope){
35447 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35448 if(this.childrenRendered){
35449 var cs = this.childNodes;
35450 for(var i = 0, len = cs.length; i < len; i++){
35451 cs[i].render(true);
35457 render : function(bulkRender){
35458 this.ui.render(bulkRender);
35459 if(!this.rendered){
35460 this.rendered = true;
35462 this.expanded = false;
35463 this.expand(false, false);
35469 renderIndent : function(deep, refresh){
35471 this.ui.childIndent = null;
35473 this.ui.renderIndent();
35474 if(deep === true && this.childrenRendered){
35475 var cs = this.childNodes;
35476 for(var i = 0, len = cs.length; i < len; i++){
35477 cs[i].renderIndent(true, refresh);
35483 * Ext JS Library 1.1.1
35484 * Copyright(c) 2006-2007, Ext JS, LLC.
35486 * Originally Released Under LGPL - original licence link has changed is not relivant.
35489 * <script type="text/javascript">
35493 * @class Roo.tree.AsyncTreeNode
35494 * @extends Roo.tree.TreeNode
35495 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35497 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35499 Roo.tree.AsyncTreeNode = function(config){
35500 this.loaded = false;
35501 this.loading = false;
35502 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35504 * @event beforeload
35505 * Fires before this node is loaded, return false to cancel
35506 * @param {Node} this This node
35508 this.addEvents({'beforeload':true, 'load': true});
35511 * Fires when this node is loaded
35512 * @param {Node} this This node
35515 * The loader used by this node (defaults to using the tree's defined loader)
35520 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35521 expand : function(deep, anim, callback){
35522 if(this.loading){ // if an async load is already running, waiting til it's done
35524 var f = function(){
35525 if(!this.loading){ // done loading
35526 clearInterval(timer);
35527 this.expand(deep, anim, callback);
35529 }.createDelegate(this);
35530 timer = setInterval(f, 200);
35534 if(this.fireEvent("beforeload", this) === false){
35537 this.loading = true;
35538 this.ui.beforeLoad(this);
35539 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35541 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35545 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35549 * Returns true if this node is currently loading
35550 * @return {Boolean}
35552 isLoading : function(){
35553 return this.loading;
35556 loadComplete : function(deep, anim, callback){
35557 this.loading = false;
35558 this.loaded = true;
35559 this.ui.afterLoad(this);
35560 this.fireEvent("load", this);
35561 this.expand(deep, anim, callback);
35565 * Returns true if this node has been loaded
35566 * @return {Boolean}
35568 isLoaded : function(){
35569 return this.loaded;
35572 hasChildNodes : function(){
35573 if(!this.isLeaf() && !this.loaded){
35576 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35581 * Trigger a reload for this node
35582 * @param {Function} callback
35584 reload : function(callback){
35585 this.collapse(false, false);
35586 while(this.firstChild){
35587 this.removeChild(this.firstChild);
35589 this.childrenRendered = false;
35590 this.loaded = false;
35591 if(this.isHiddenRoot()){
35592 this.expanded = false;
35594 this.expand(false, false, callback);
35598 * Ext JS Library 1.1.1
35599 * Copyright(c) 2006-2007, Ext JS, LLC.
35601 * Originally Released Under LGPL - original licence link has changed is not relivant.
35604 * <script type="text/javascript">
35608 * @class Roo.tree.TreeNodeUI
35610 * @param {Object} node The node to render
35611 * The TreeNode UI implementation is separate from the
35612 * tree implementation. Unless you are customizing the tree UI,
35613 * you should never have to use this directly.
35615 Roo.tree.TreeNodeUI = function(node){
35617 this.rendered = false;
35618 this.animating = false;
35619 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35622 Roo.tree.TreeNodeUI.prototype = {
35623 removeChild : function(node){
35625 this.ctNode.removeChild(node.ui.getEl());
35629 beforeLoad : function(){
35630 this.addClass("x-tree-node-loading");
35633 afterLoad : function(){
35634 this.removeClass("x-tree-node-loading");
35637 onTextChange : function(node, text, oldText){
35639 this.textNode.innerHTML = text;
35643 onDisableChange : function(node, state){
35644 this.disabled = state;
35646 this.addClass("x-tree-node-disabled");
35648 this.removeClass("x-tree-node-disabled");
35652 onSelectedChange : function(state){
35655 this.addClass("x-tree-selected");
35658 this.removeClass("x-tree-selected");
35662 onMove : function(tree, node, oldParent, newParent, index, refNode){
35663 this.childIndent = null;
35665 var targetNode = newParent.ui.getContainer();
35666 if(!targetNode){//target not rendered
35667 this.holder = document.createElement("div");
35668 this.holder.appendChild(this.wrap);
35671 var insertBefore = refNode ? refNode.ui.getEl() : null;
35673 targetNode.insertBefore(this.wrap, insertBefore);
35675 targetNode.appendChild(this.wrap);
35677 this.node.renderIndent(true);
35681 addClass : function(cls){
35683 Roo.fly(this.elNode).addClass(cls);
35687 removeClass : function(cls){
35689 Roo.fly(this.elNode).removeClass(cls);
35693 remove : function(){
35695 this.holder = document.createElement("div");
35696 this.holder.appendChild(this.wrap);
35700 fireEvent : function(){
35701 return this.node.fireEvent.apply(this.node, arguments);
35704 initEvents : function(){
35705 this.node.on("move", this.onMove, this);
35706 var E = Roo.EventManager;
35707 var a = this.anchor;
35709 var el = Roo.fly(a, '_treeui');
35711 if(Roo.isOpera){ // opera render bug ignores the CSS
35712 el.setStyle("text-decoration", "none");
35715 el.on("click", this.onClick, this);
35716 el.on("dblclick", this.onDblClick, this);
35719 Roo.EventManager.on(this.checkbox,
35720 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35723 el.on("contextmenu", this.onContextMenu, this);
35725 var icon = Roo.fly(this.iconNode);
35726 icon.on("click", this.onClick, this);
35727 icon.on("dblclick", this.onDblClick, this);
35728 icon.on("contextmenu", this.onContextMenu, this);
35729 E.on(this.ecNode, "click", this.ecClick, this, true);
35731 if(this.node.disabled){
35732 this.addClass("x-tree-node-disabled");
35734 if(this.node.hidden){
35735 this.addClass("x-tree-node-disabled");
35737 var ot = this.node.getOwnerTree();
35738 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35739 if(dd && (!this.node.isRoot || ot.rootVisible)){
35740 Roo.dd.Registry.register(this.elNode, {
35742 handles: this.getDDHandles(),
35748 getDDHandles : function(){
35749 return [this.iconNode, this.textNode];
35754 this.wrap.style.display = "none";
35760 this.wrap.style.display = "";
35764 onContextMenu : function(e){
35765 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35766 e.preventDefault();
35768 this.fireEvent("contextmenu", this.node, e);
35772 onClick : function(e){
35777 if(this.fireEvent("beforeclick", this.node, e) !== false){
35778 if(!this.disabled && this.node.attributes.href){
35779 this.fireEvent("click", this.node, e);
35782 e.preventDefault();
35787 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35788 this.node.toggle();
35791 this.fireEvent("click", this.node, e);
35797 onDblClick : function(e){
35798 e.preventDefault();
35803 this.toggleCheck();
35805 if(!this.animating && this.node.hasChildNodes()){
35806 this.node.toggle();
35808 this.fireEvent("dblclick", this.node, e);
35811 onCheckChange : function(){
35812 var checked = this.checkbox.checked;
35813 this.node.attributes.checked = checked;
35814 this.fireEvent('checkchange', this.node, checked);
35817 ecClick : function(e){
35818 if(!this.animating && this.node.hasChildNodes()){
35819 this.node.toggle();
35823 startDrop : function(){
35824 this.dropping = true;
35827 // delayed drop so the click event doesn't get fired on a drop
35828 endDrop : function(){
35829 setTimeout(function(){
35830 this.dropping = false;
35831 }.createDelegate(this), 50);
35834 expand : function(){
35835 this.updateExpandIcon();
35836 this.ctNode.style.display = "";
35839 focus : function(){
35840 if(!this.node.preventHScroll){
35841 try{this.anchor.focus();
35843 }else if(!Roo.isIE){
35845 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35846 var l = noscroll.scrollLeft;
35847 this.anchor.focus();
35848 noscroll.scrollLeft = l;
35853 toggleCheck : function(value){
35854 var cb = this.checkbox;
35856 cb.checked = (value === undefined ? !cb.checked : value);
35862 this.anchor.blur();
35866 animExpand : function(callback){
35867 var ct = Roo.get(this.ctNode);
35869 if(!this.node.hasChildNodes()){
35870 this.updateExpandIcon();
35871 this.ctNode.style.display = "";
35872 Roo.callback(callback);
35875 this.animating = true;
35876 this.updateExpandIcon();
35879 callback : function(){
35880 this.animating = false;
35881 Roo.callback(callback);
35884 duration: this.node.ownerTree.duration || .25
35888 highlight : function(){
35889 var tree = this.node.getOwnerTree();
35890 Roo.fly(this.wrap).highlight(
35891 tree.hlColor || "C3DAF9",
35892 {endColor: tree.hlBaseColor}
35896 collapse : function(){
35897 this.updateExpandIcon();
35898 this.ctNode.style.display = "none";
35901 animCollapse : function(callback){
35902 var ct = Roo.get(this.ctNode);
35903 ct.enableDisplayMode('block');
35906 this.animating = true;
35907 this.updateExpandIcon();
35910 callback : function(){
35911 this.animating = false;
35912 Roo.callback(callback);
35915 duration: this.node.ownerTree.duration || .25
35919 getContainer : function(){
35920 return this.ctNode;
35923 getEl : function(){
35927 appendDDGhost : function(ghostNode){
35928 ghostNode.appendChild(this.elNode.cloneNode(true));
35931 getDDRepairXY : function(){
35932 return Roo.lib.Dom.getXY(this.iconNode);
35935 onRender : function(){
35939 render : function(bulkRender){
35940 var n = this.node, a = n.attributes;
35941 var targetNode = n.parentNode ?
35942 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35944 if(!this.rendered){
35945 this.rendered = true;
35947 this.renderElements(n, a, targetNode, bulkRender);
35950 if(this.textNode.setAttributeNS){
35951 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35953 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35956 this.textNode.setAttribute("ext:qtip", a.qtip);
35958 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35961 }else if(a.qtipCfg){
35962 a.qtipCfg.target = Roo.id(this.textNode);
35963 Roo.QuickTips.register(a.qtipCfg);
35966 if(!this.node.expanded){
35967 this.updateExpandIcon();
35970 if(bulkRender === true) {
35971 targetNode.appendChild(this.wrap);
35976 renderElements : function(n, a, targetNode, bulkRender)
35978 // add some indent caching, this helps performance when rendering a large tree
35979 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35980 var t = n.getOwnerTree();
35981 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35982 if (typeof(n.attributes.html) != 'undefined') {
35983 txt = n.attributes.html;
35985 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
35986 var cb = typeof a.checked == 'boolean';
35987 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35988 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35989 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35990 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35991 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35992 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35993 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35994 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35995 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35996 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35999 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36000 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36001 n.nextSibling.ui.getEl(), buf.join(""));
36003 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36006 this.elNode = this.wrap.childNodes[0];
36007 this.ctNode = this.wrap.childNodes[1];
36008 var cs = this.elNode.childNodes;
36009 this.indentNode = cs[0];
36010 this.ecNode = cs[1];
36011 this.iconNode = cs[2];
36014 this.checkbox = cs[3];
36017 this.anchor = cs[index];
36018 this.textNode = cs[index].firstChild;
36021 getAnchor : function(){
36022 return this.anchor;
36025 getTextEl : function(){
36026 return this.textNode;
36029 getIconEl : function(){
36030 return this.iconNode;
36033 isChecked : function(){
36034 return this.checkbox ? this.checkbox.checked : false;
36037 updateExpandIcon : function(){
36039 var n = this.node, c1, c2;
36040 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36041 var hasChild = n.hasChildNodes();
36045 c1 = "x-tree-node-collapsed";
36046 c2 = "x-tree-node-expanded";
36049 c1 = "x-tree-node-expanded";
36050 c2 = "x-tree-node-collapsed";
36053 this.removeClass("x-tree-node-leaf");
36054 this.wasLeaf = false;
36056 if(this.c1 != c1 || this.c2 != c2){
36057 Roo.fly(this.elNode).replaceClass(c1, c2);
36058 this.c1 = c1; this.c2 = c2;
36061 // this changes non-leafs into leafs if they have no children.
36062 // it's not very rational behaviour..
36064 if(!this.wasLeaf && this.node.leaf){
36065 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36068 this.wasLeaf = true;
36071 var ecc = "x-tree-ec-icon "+cls;
36072 if(this.ecc != ecc){
36073 this.ecNode.className = ecc;
36079 getChildIndent : function(){
36080 if(!this.childIndent){
36084 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36086 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36088 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36093 this.childIndent = buf.join("");
36095 return this.childIndent;
36098 renderIndent : function(){
36101 var p = this.node.parentNode;
36103 indent = p.ui.getChildIndent();
36105 if(this.indentMarkup != indent){ // don't rerender if not required
36106 this.indentNode.innerHTML = indent;
36107 this.indentMarkup = indent;
36109 this.updateExpandIcon();
36114 Roo.tree.RootTreeNodeUI = function(){
36115 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36117 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36118 render : function(){
36119 if(!this.rendered){
36120 var targetNode = this.node.ownerTree.innerCt.dom;
36121 this.node.expanded = true;
36122 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36123 this.wrap = this.ctNode = targetNode.firstChild;
36126 collapse : function(){
36128 expand : function(){
36132 * Ext JS Library 1.1.1
36133 * Copyright(c) 2006-2007, Ext JS, LLC.
36135 * Originally Released Under LGPL - original licence link has changed is not relivant.
36138 * <script type="text/javascript">
36141 * @class Roo.tree.TreeLoader
36142 * @extends Roo.util.Observable
36143 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36144 * nodes from a specified URL. The response must be a javascript Array definition
36145 * who's elements are node definition objects. eg:
36150 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36151 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36158 * The old style respose with just an array is still supported, but not recommended.
36161 * A server request is sent, and child nodes are loaded only when a node is expanded.
36162 * The loading node's id is passed to the server under the parameter name "node" to
36163 * enable the server to produce the correct child nodes.
36165 * To pass extra parameters, an event handler may be attached to the "beforeload"
36166 * event, and the parameters specified in the TreeLoader's baseParams property:
36168 myTreeLoader.on("beforeload", function(treeLoader, node) {
36169 this.baseParams.category = node.attributes.category;
36174 * This would pass an HTTP parameter called "category" to the server containing
36175 * the value of the Node's "category" attribute.
36177 * Creates a new Treeloader.
36178 * @param {Object} config A config object containing config properties.
36180 Roo.tree.TreeLoader = function(config){
36181 this.baseParams = {};
36182 this.requestMethod = "POST";
36183 Roo.apply(this, config);
36188 * @event beforeload
36189 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36190 * @param {Object} This TreeLoader object.
36191 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36192 * @param {Object} callback The callback function specified in the {@link #load} call.
36197 * Fires when the node has been successfuly loaded.
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.
36204 * @event loadexception
36205 * Fires if the network request failed.
36206 * @param {Object} This TreeLoader object.
36207 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36208 * @param {Object} response The response object containing the data from the server.
36210 loadexception : true,
36213 * Fires before a node is created, enabling you to return custom Node types
36214 * @param {Object} This TreeLoader object.
36215 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36220 Roo.tree.TreeLoader.superclass.constructor.call(this);
36223 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36225 * @cfg {String} dataUrl The URL from which to request a Json string which
36226 * specifies an array of node definition object representing the child nodes
36230 * @cfg {String} requestMethod either GET or POST
36231 * defaults to POST (due to BC)
36235 * @cfg {Object} baseParams (optional) An object containing properties which
36236 * specify HTTP parameters to be passed to each request for child nodes.
36239 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36240 * created by this loader. If the attributes sent by the server have an attribute in this object,
36241 * they take priority.
36244 * @cfg {Object} uiProviders (optional) An object containing properties which
36246 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36247 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36248 * <i>uiProvider</i> attribute of a returned child node is a string rather
36249 * than a reference to a TreeNodeUI implementation, this that string value
36250 * is used as a property name in the uiProviders object. You can define the provider named
36251 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36256 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36257 * child nodes before loading.
36259 clearOnLoad : true,
36262 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36263 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36264 * Grid query { data : [ .....] }
36269 * @cfg {String} queryParam (optional)
36270 * Name of the query as it will be passed on the querystring (defaults to 'node')
36271 * eg. the request will be ?node=[id]
36278 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36279 * This is called automatically when a node is expanded, but may be used to reload
36280 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36281 * @param {Roo.tree.TreeNode} node
36282 * @param {Function} callback
36284 load : function(node, callback){
36285 if(this.clearOnLoad){
36286 while(node.firstChild){
36287 node.removeChild(node.firstChild);
36290 if(node.attributes.children){ // preloaded json children
36291 var cs = node.attributes.children;
36292 for(var i = 0, len = cs.length; i < len; i++){
36293 node.appendChild(this.createNode(cs[i]));
36295 if(typeof callback == "function"){
36298 }else if(this.dataUrl){
36299 this.requestData(node, callback);
36303 getParams: function(node){
36304 var buf = [], bp = this.baseParams;
36305 for(var key in bp){
36306 if(typeof bp[key] != "function"){
36307 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36310 var n = this.queryParam === false ? 'node' : this.queryParam;
36311 buf.push(n + "=", encodeURIComponent(node.id));
36312 return buf.join("");
36315 requestData : function(node, callback){
36316 if(this.fireEvent("beforeload", this, node, callback) !== false){
36317 this.transId = Roo.Ajax.request({
36318 method:this.requestMethod,
36319 url: this.dataUrl||this.url,
36320 success: this.handleResponse,
36321 failure: this.handleFailure,
36323 argument: {callback: callback, node: node},
36324 params: this.getParams(node)
36327 // if the load is cancelled, make sure we notify
36328 // the node that we are done
36329 if(typeof callback == "function"){
36335 isLoading : function(){
36336 return this.transId ? true : false;
36339 abort : function(){
36340 if(this.isLoading()){
36341 Roo.Ajax.abort(this.transId);
36346 createNode : function(attr)
36348 // apply baseAttrs, nice idea Corey!
36349 if(this.baseAttrs){
36350 Roo.applyIf(attr, this.baseAttrs);
36352 if(this.applyLoader !== false){
36353 attr.loader = this;
36355 // uiProvider = depreciated..
36357 if(typeof(attr.uiProvider) == 'string'){
36358 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36359 /** eval:var:attr */ eval(attr.uiProvider);
36361 if(typeof(this.uiProviders['default']) != 'undefined') {
36362 attr.uiProvider = this.uiProviders['default'];
36365 this.fireEvent('create', this, attr);
36367 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36369 new Roo.tree.TreeNode(attr) :
36370 new Roo.tree.AsyncTreeNode(attr));
36373 processResponse : function(response, node, callback)
36375 var json = response.responseText;
36378 var o = Roo.decode(json);
36380 if (this.root === false && typeof(o.success) != undefined) {
36381 this.root = 'data'; // the default behaviour for list like data..
36384 if (this.root !== false && !o.success) {
36385 // it's a failure condition.
36386 var a = response.argument;
36387 this.fireEvent("loadexception", this, a.node, response);
36388 Roo.log("Load failed - should have a handler really");
36394 if (this.root !== false) {
36398 for(var i = 0, len = o.length; i < len; i++){
36399 var n = this.createNode(o[i]);
36401 node.appendChild(n);
36404 if(typeof callback == "function"){
36405 callback(this, node);
36408 this.handleFailure(response);
36412 handleResponse : function(response){
36413 this.transId = false;
36414 var a = response.argument;
36415 this.processResponse(response, a.node, a.callback);
36416 this.fireEvent("load", this, a.node, response);
36419 handleFailure : function(response)
36421 // should handle failure better..
36422 this.transId = false;
36423 var a = response.argument;
36424 this.fireEvent("loadexception", this, a.node, response);
36425 if(typeof a.callback == "function"){
36426 a.callback(this, a.node);
36431 * Ext JS Library 1.1.1
36432 * Copyright(c) 2006-2007, Ext JS, LLC.
36434 * Originally Released Under LGPL - original licence link has changed is not relivant.
36437 * <script type="text/javascript">
36441 * @class Roo.tree.TreeFilter
36442 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36443 * @param {TreePanel} tree
36444 * @param {Object} config (optional)
36446 Roo.tree.TreeFilter = function(tree, config){
36448 this.filtered = {};
36449 Roo.apply(this, config);
36452 Roo.tree.TreeFilter.prototype = {
36459 * Filter the data by a specific attribute.
36460 * @param {String/RegExp} value Either string that the attribute value
36461 * should start with or a RegExp to test against the attribute
36462 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36463 * @param {TreeNode} startNode (optional) The node to start the filter at.
36465 filter : function(value, attr, startNode){
36466 attr = attr || "text";
36468 if(typeof value == "string"){
36469 var vlen = value.length;
36470 // auto clear empty filter
36471 if(vlen == 0 && this.clearBlank){
36475 value = value.toLowerCase();
36477 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36479 }else if(value.exec){ // regex?
36481 return value.test(n.attributes[attr]);
36484 throw 'Illegal filter type, must be string or regex';
36486 this.filterBy(f, null, startNode);
36490 * Filter by a function. The passed function will be called with each
36491 * node in the tree (or from the startNode). If the function returns true, the node is kept
36492 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36493 * @param {Function} fn The filter function
36494 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36496 filterBy : function(fn, scope, startNode){
36497 startNode = startNode || this.tree.root;
36498 if(this.autoClear){
36501 var af = this.filtered, rv = this.reverse;
36502 var f = function(n){
36503 if(n == startNode){
36509 var m = fn.call(scope || n, n);
36517 startNode.cascade(f);
36520 if(typeof id != "function"){
36522 if(n && n.parentNode){
36523 n.parentNode.removeChild(n);
36531 * Clears the current filter. Note: with the "remove" option
36532 * set a filter cannot be cleared.
36534 clear : function(){
36536 var af = this.filtered;
36538 if(typeof id != "function"){
36545 this.filtered = {};
36550 * Ext JS Library 1.1.1
36551 * Copyright(c) 2006-2007, Ext JS, LLC.
36553 * Originally Released Under LGPL - original licence link has changed is not relivant.
36556 * <script type="text/javascript">
36561 * @class Roo.tree.TreeSorter
36562 * Provides sorting of nodes in a TreePanel
36564 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36565 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36566 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36567 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36568 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36569 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36571 * @param {TreePanel} tree
36572 * @param {Object} config
36574 Roo.tree.TreeSorter = function(tree, config){
36575 Roo.apply(this, config);
36576 tree.on("beforechildrenrendered", this.doSort, this);
36577 tree.on("append", this.updateSort, this);
36578 tree.on("insert", this.updateSort, this);
36580 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36581 var p = this.property || "text";
36582 var sortType = this.sortType;
36583 var fs = this.folderSort;
36584 var cs = this.caseSensitive === true;
36585 var leafAttr = this.leafAttr || 'leaf';
36587 this.sortFn = function(n1, n2){
36589 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36592 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36596 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36597 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36599 return dsc ? +1 : -1;
36601 return dsc ? -1 : +1;
36608 Roo.tree.TreeSorter.prototype = {
36609 doSort : function(node){
36610 node.sort(this.sortFn);
36613 compareNodes : function(n1, n2){
36614 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36617 updateSort : function(tree, node){
36618 if(node.childrenRendered){
36619 this.doSort.defer(1, this, [node]);
36624 * Ext JS Library 1.1.1
36625 * Copyright(c) 2006-2007, Ext JS, LLC.
36627 * Originally Released Under LGPL - original licence link has changed is not relivant.
36630 * <script type="text/javascript">
36633 if(Roo.dd.DropZone){
36635 Roo.tree.TreeDropZone = function(tree, config){
36636 this.allowParentInsert = false;
36637 this.allowContainerDrop = false;
36638 this.appendOnly = false;
36639 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36641 this.lastInsertClass = "x-tree-no-status";
36642 this.dragOverData = {};
36645 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36646 ddGroup : "TreeDD",
36649 expandDelay : 1000,
36651 expandNode : function(node){
36652 if(node.hasChildNodes() && !node.isExpanded()){
36653 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36657 queueExpand : function(node){
36658 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36661 cancelExpand : function(){
36662 if(this.expandProcId){
36663 clearTimeout(this.expandProcId);
36664 this.expandProcId = false;
36668 isValidDropPoint : function(n, pt, dd, e, data){
36669 if(!n || !data){ return false; }
36670 var targetNode = n.node;
36671 var dropNode = data.node;
36672 // default drop rules
36673 if(!(targetNode && targetNode.isTarget && pt)){
36676 if(pt == "append" && targetNode.allowChildren === false){
36679 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36682 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36685 // reuse the object
36686 var overEvent = this.dragOverData;
36687 overEvent.tree = this.tree;
36688 overEvent.target = targetNode;
36689 overEvent.data = data;
36690 overEvent.point = pt;
36691 overEvent.source = dd;
36692 overEvent.rawEvent = e;
36693 overEvent.dropNode = dropNode;
36694 overEvent.cancel = false;
36695 var result = this.tree.fireEvent("nodedragover", overEvent);
36696 return overEvent.cancel === false && result !== false;
36699 getDropPoint : function(e, n, dd)
36703 return tn.allowChildren !== false ? "append" : false; // always append for root
36705 var dragEl = n.ddel;
36706 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36707 var y = Roo.lib.Event.getPageY(e);
36708 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36710 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36711 var noAppend = tn.allowChildren === false;
36712 if(this.appendOnly || tn.parentNode.allowChildren === false){
36713 return noAppend ? false : "append";
36715 var noBelow = false;
36716 if(!this.allowParentInsert){
36717 noBelow = tn.hasChildNodes() && tn.isExpanded();
36719 var q = (b - t) / (noAppend ? 2 : 3);
36720 if(y >= t && y < (t + q)){
36722 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36729 onNodeEnter : function(n, dd, e, data)
36731 this.cancelExpand();
36734 onNodeOver : function(n, dd, e, data)
36737 var pt = this.getDropPoint(e, n, dd);
36740 // auto node expand check
36741 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36742 this.queueExpand(node);
36743 }else if(pt != "append"){
36744 this.cancelExpand();
36747 // set the insert point style on the target node
36748 var returnCls = this.dropNotAllowed;
36749 if(this.isValidDropPoint(n, pt, dd, e, data)){
36754 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36755 cls = "x-tree-drag-insert-above";
36756 }else if(pt == "below"){
36757 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36758 cls = "x-tree-drag-insert-below";
36760 returnCls = "x-tree-drop-ok-append";
36761 cls = "x-tree-drag-append";
36763 if(this.lastInsertClass != cls){
36764 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36765 this.lastInsertClass = cls;
36772 onNodeOut : function(n, dd, e, data){
36774 this.cancelExpand();
36775 this.removeDropIndicators(n);
36778 onNodeDrop : function(n, dd, e, data){
36779 var point = this.getDropPoint(e, n, dd);
36780 var targetNode = n.node;
36781 targetNode.ui.startDrop();
36782 if(!this.isValidDropPoint(n, point, dd, e, data)){
36783 targetNode.ui.endDrop();
36786 // first try to find the drop node
36787 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36790 target: targetNode,
36795 dropNode: dropNode,
36798 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36799 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36800 targetNode.ui.endDrop();
36803 // allow target changing
36804 targetNode = dropEvent.target;
36805 if(point == "append" && !targetNode.isExpanded()){
36806 targetNode.expand(false, null, function(){
36807 this.completeDrop(dropEvent);
36808 }.createDelegate(this));
36810 this.completeDrop(dropEvent);
36815 completeDrop : function(de){
36816 var ns = de.dropNode, p = de.point, t = de.target;
36817 if(!(ns instanceof Array)){
36821 for(var i = 0, len = ns.length; i < len; i++){
36824 t.parentNode.insertBefore(n, t);
36825 }else if(p == "below"){
36826 t.parentNode.insertBefore(n, t.nextSibling);
36832 if(this.tree.hlDrop){
36836 this.tree.fireEvent("nodedrop", de);
36839 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36840 if(this.tree.hlDrop){
36841 dropNode.ui.focus();
36842 dropNode.ui.highlight();
36844 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36847 getTree : function(){
36851 removeDropIndicators : function(n){
36854 Roo.fly(el).removeClass([
36855 "x-tree-drag-insert-above",
36856 "x-tree-drag-insert-below",
36857 "x-tree-drag-append"]);
36858 this.lastInsertClass = "_noclass";
36862 beforeDragDrop : function(target, e, id){
36863 this.cancelExpand();
36867 afterRepair : function(data){
36868 if(data && Roo.enableFx){
36869 data.node.ui.highlight();
36879 * Ext JS Library 1.1.1
36880 * Copyright(c) 2006-2007, Ext JS, LLC.
36882 * Originally Released Under LGPL - original licence link has changed is not relivant.
36885 * <script type="text/javascript">
36889 if(Roo.dd.DragZone){
36890 Roo.tree.TreeDragZone = function(tree, config){
36891 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36895 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36896 ddGroup : "TreeDD",
36898 onBeforeDrag : function(data, e){
36900 return n && n.draggable && !n.disabled;
36904 onInitDrag : function(e){
36905 var data = this.dragData;
36906 this.tree.getSelectionModel().select(data.node);
36907 this.proxy.update("");
36908 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36909 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36912 getRepairXY : function(e, data){
36913 return data.node.ui.getDDRepairXY();
36916 onEndDrag : function(data, e){
36917 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36922 onValidDrop : function(dd, e, id){
36923 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36927 beforeInvalidDrop : function(e, id){
36928 // this scrolls the original position back into view
36929 var sm = this.tree.getSelectionModel();
36930 sm.clearSelections();
36931 sm.select(this.dragData.node);
36936 * Ext JS Library 1.1.1
36937 * Copyright(c) 2006-2007, Ext JS, LLC.
36939 * Originally Released Under LGPL - original licence link has changed is not relivant.
36942 * <script type="text/javascript">
36945 * @class Roo.tree.TreeEditor
36946 * @extends Roo.Editor
36947 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36948 * as the editor field.
36950 * @param {Object} config (used to be the tree panel.)
36951 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36953 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36954 * @cfg {Roo.form.TextField|Object} field The field configuration
36958 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36961 if (oldconfig) { // old style..
36962 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36965 tree = config.tree;
36966 config.field = config.field || {};
36967 config.field.xtype = 'TextField';
36968 field = Roo.factory(config.field, Roo.form);
36970 config = config || {};
36975 * @event beforenodeedit
36976 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36977 * false from the handler of this event.
36978 * @param {Editor} this
36979 * @param {Roo.tree.Node} node
36981 "beforenodeedit" : true
36985 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36989 tree.on('beforeclick', this.beforeNodeClick, this);
36990 tree.getTreeEl().on('mousedown', this.hide, this);
36991 this.on('complete', this.updateNode, this);
36992 this.on('beforestartedit', this.fitToTree, this);
36993 this.on('startedit', this.bindScroll, this, {delay:10});
36994 this.on('specialkey', this.onSpecialKey, this);
36997 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36999 * @cfg {String} alignment
37000 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37006 * @cfg {Boolean} hideEl
37007 * True to hide the bound element while the editor is displayed (defaults to false)
37011 * @cfg {String} cls
37012 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37014 cls: "x-small-editor x-tree-editor",
37016 * @cfg {Boolean} shim
37017 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37023 * @cfg {Number} maxWidth
37024 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37025 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37026 * scroll and client offsets into account prior to each edit.
37033 fitToTree : function(ed, el){
37034 var td = this.tree.getTreeEl().dom, nd = el.dom;
37035 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37036 td.scrollLeft = nd.offsetLeft;
37040 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37041 this.setSize(w, '');
37043 return this.fireEvent('beforenodeedit', this, this.editNode);
37048 triggerEdit : function(node){
37049 this.completeEdit();
37050 this.editNode = node;
37051 this.startEdit(node.ui.textNode, node.text);
37055 bindScroll : function(){
37056 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37060 beforeNodeClick : function(node, e){
37061 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37062 this.lastClick = new Date();
37063 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37065 this.triggerEdit(node);
37072 updateNode : function(ed, value){
37073 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37074 this.editNode.setText(value);
37078 onHide : function(){
37079 Roo.tree.TreeEditor.superclass.onHide.call(this);
37081 this.editNode.ui.focus();
37086 onSpecialKey : function(field, e){
37087 var k = e.getKey();
37091 }else if(k == e.ENTER && !e.hasModifier()){
37093 this.completeEdit();
37096 });//<Script type="text/javascript">
37099 * Ext JS Library 1.1.1
37100 * Copyright(c) 2006-2007, Ext JS, LLC.
37102 * Originally Released Under LGPL - original licence link has changed is not relivant.
37105 * <script type="text/javascript">
37109 * Not documented??? - probably should be...
37112 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37113 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37115 renderElements : function(n, a, targetNode, bulkRender){
37116 //consel.log("renderElements?");
37117 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37119 var t = n.getOwnerTree();
37120 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37122 var cols = t.columns;
37123 var bw = t.borderWidth;
37125 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37126 var cb = typeof a.checked == "boolean";
37127 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37128 var colcls = 'x-t-' + tid + '-c0';
37130 '<li class="x-tree-node">',
37133 '<div class="x-tree-node-el ', a.cls,'">',
37135 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37138 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37139 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37140 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37141 (a.icon ? ' x-tree-node-inline-icon' : ''),
37142 (a.iconCls ? ' '+a.iconCls : ''),
37143 '" unselectable="on" />',
37144 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37145 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37147 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37148 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37149 '<span unselectable="on" qtip="' + tx + '">',
37153 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37154 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37156 for(var i = 1, len = cols.length; i < len; i++){
37158 colcls = 'x-t-' + tid + '-c' +i;
37159 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37160 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37161 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37167 '<div class="x-clear"></div></div>',
37168 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37171 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37172 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37173 n.nextSibling.ui.getEl(), buf.join(""));
37175 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37177 var el = this.wrap.firstChild;
37179 this.elNode = el.firstChild;
37180 this.ranchor = el.childNodes[1];
37181 this.ctNode = this.wrap.childNodes[1];
37182 var cs = el.firstChild.childNodes;
37183 this.indentNode = cs[0];
37184 this.ecNode = cs[1];
37185 this.iconNode = cs[2];
37188 this.checkbox = cs[3];
37191 this.anchor = cs[index];
37193 this.textNode = cs[index].firstChild;
37195 //el.on("click", this.onClick, this);
37196 //el.on("dblclick", this.onDblClick, this);
37199 // console.log(this);
37201 initEvents : function(){
37202 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37205 var a = this.ranchor;
37207 var el = Roo.get(a);
37209 if(Roo.isOpera){ // opera render bug ignores the CSS
37210 el.setStyle("text-decoration", "none");
37213 el.on("click", this.onClick, this);
37214 el.on("dblclick", this.onDblClick, this);
37215 el.on("contextmenu", this.onContextMenu, this);
37219 /*onSelectedChange : function(state){
37222 this.addClass("x-tree-selected");
37225 this.removeClass("x-tree-selected");
37228 addClass : function(cls){
37230 Roo.fly(this.elRow).addClass(cls);
37236 removeClass : function(cls){
37238 Roo.fly(this.elRow).removeClass(cls);
37244 });//<Script type="text/javascript">
37248 * Ext JS Library 1.1.1
37249 * Copyright(c) 2006-2007, Ext JS, LLC.
37251 * Originally Released Under LGPL - original licence link has changed is not relivant.
37254 * <script type="text/javascript">
37259 * @class Roo.tree.ColumnTree
37260 * @extends Roo.data.TreePanel
37261 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37262 * @cfg {int} borderWidth compined right/left border allowance
37264 * @param {String/HTMLElement/Element} el The container element
37265 * @param {Object} config
37267 Roo.tree.ColumnTree = function(el, config)
37269 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37273 * Fire this event on a container when it resizes
37274 * @param {int} w Width
37275 * @param {int} h Height
37279 this.on('resize', this.onResize, this);
37282 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37286 borderWidth: Roo.isBorderBox ? 0 : 2,
37289 render : function(){
37290 // add the header.....
37292 Roo.tree.ColumnTree.superclass.render.apply(this);
37294 this.el.addClass('x-column-tree');
37296 this.headers = this.el.createChild(
37297 {cls:'x-tree-headers'},this.innerCt.dom);
37299 var cols = this.columns, c;
37300 var totalWidth = 0;
37302 var len = cols.length;
37303 for(var i = 0; i < len; i++){
37305 totalWidth += c.width;
37306 this.headEls.push(this.headers.createChild({
37307 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37309 cls:'x-tree-hd-text',
37312 style:'width:'+(c.width-this.borderWidth)+'px;'
37315 this.headers.createChild({cls:'x-clear'});
37316 // prevent floats from wrapping when clipped
37317 this.headers.setWidth(totalWidth);
37318 //this.innerCt.setWidth(totalWidth);
37319 this.innerCt.setStyle({ overflow: 'auto' });
37320 this.onResize(this.width, this.height);
37324 onResize : function(w,h)
37329 this.innerCt.setWidth(this.width);
37330 this.innerCt.setHeight(this.height-20);
37333 var cols = this.columns, c;
37334 var totalWidth = 0;
37336 var len = cols.length;
37337 for(var i = 0; i < len; i++){
37339 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37340 // it's the expander..
37341 expEl = this.headEls[i];
37344 totalWidth += c.width;
37348 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37350 this.headers.setWidth(w-20);
37359 * Ext JS Library 1.1.1
37360 * Copyright(c) 2006-2007, Ext JS, LLC.
37362 * Originally Released Under LGPL - original licence link has changed is not relivant.
37365 * <script type="text/javascript">
37369 * @class Roo.menu.Menu
37370 * @extends Roo.util.Observable
37371 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37372 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37374 * Creates a new Menu
37375 * @param {Object} config Configuration options
37377 Roo.menu.Menu = function(config){
37379 Roo.menu.Menu.superclass.constructor.call(this, config);
37381 this.id = this.id || Roo.id();
37384 * @event beforeshow
37385 * Fires before this menu is displayed
37386 * @param {Roo.menu.Menu} this
37390 * @event beforehide
37391 * Fires before this menu is hidden
37392 * @param {Roo.menu.Menu} this
37397 * Fires after this menu is displayed
37398 * @param {Roo.menu.Menu} this
37403 * Fires after this menu is hidden
37404 * @param {Roo.menu.Menu} this
37409 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37410 * @param {Roo.menu.Menu} this
37411 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37412 * @param {Roo.EventObject} e
37417 * Fires when the mouse is hovering over 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 the mouse exits this menu
37426 * @param {Roo.menu.Menu} this
37427 * @param {Roo.EventObject} e
37428 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37433 * Fires when a menu item contained in this menu is clicked
37434 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37435 * @param {Roo.EventObject} e
37439 if (this.registerMenu) {
37440 Roo.menu.MenuMgr.register(this);
37443 var mis = this.items;
37444 this.items = new Roo.util.MixedCollection();
37446 this.add.apply(this, mis);
37450 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37452 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37456 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37457 * for bottom-right shadow (defaults to "sides")
37461 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37462 * this menu (defaults to "tl-tr?")
37464 subMenuAlign : "tl-tr?",
37466 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37467 * relative to its element of origin (defaults to "tl-bl?")
37469 defaultAlign : "tl-bl?",
37471 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37473 allowOtherMenus : false,
37475 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37477 registerMenu : true,
37482 render : function(){
37486 var el = this.el = new Roo.Layer({
37488 shadow:this.shadow,
37490 parentEl: this.parentEl || document.body,
37494 this.keyNav = new Roo.menu.MenuNav(this);
37497 el.addClass("x-menu-plain");
37500 el.addClass(this.cls);
37502 // generic focus element
37503 this.focusEl = el.createChild({
37504 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37506 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37507 //disabling touch- as it's causing issues ..
37508 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37509 ul.on('click' , this.onClick, this);
37512 ul.on("mouseover", this.onMouseOver, this);
37513 ul.on("mouseout", this.onMouseOut, this);
37514 this.items.each(function(item){
37519 var li = document.createElement("li");
37520 li.className = "x-menu-list-item";
37521 ul.dom.appendChild(li);
37522 item.render(li, this);
37529 autoWidth : function(){
37530 var el = this.el, ul = this.ul;
37534 var w = this.width;
37537 }else if(Roo.isIE){
37538 el.setWidth(this.minWidth);
37539 var t = el.dom.offsetWidth; // force recalc
37540 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37545 delayAutoWidth : function(){
37548 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37550 this.awTask.delay(20);
37555 findTargetItem : function(e){
37556 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37557 if(t && t.menuItemId){
37558 return this.items.get(t.menuItemId);
37563 onClick : function(e){
37564 Roo.log("menu.onClick");
37565 var t = this.findTargetItem(e);
37570 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37571 if(t == this.activeItem && t.shouldDeactivate(e)){
37572 this.activeItem.deactivate();
37573 delete this.activeItem;
37577 this.setActiveItem(t, true);
37585 this.fireEvent("click", this, t, e);
37589 setActiveItem : function(item, autoExpand){
37590 if(item != this.activeItem){
37591 if(this.activeItem){
37592 this.activeItem.deactivate();
37594 this.activeItem = item;
37595 item.activate(autoExpand);
37596 }else if(autoExpand){
37602 tryActivate : function(start, step){
37603 var items = this.items;
37604 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37605 var item = items.get(i);
37606 if(!item.disabled && item.canActivate){
37607 this.setActiveItem(item, false);
37615 onMouseOver : function(e){
37617 if(t = this.findTargetItem(e)){
37618 if(t.canActivate && !t.disabled){
37619 this.setActiveItem(t, true);
37622 this.fireEvent("mouseover", this, e, t);
37626 onMouseOut : function(e){
37628 if(t = this.findTargetItem(e)){
37629 if(t == this.activeItem && t.shouldDeactivate(e)){
37630 this.activeItem.deactivate();
37631 delete this.activeItem;
37634 this.fireEvent("mouseout", this, e, t);
37638 * Read-only. Returns true if the menu is currently displayed, else false.
37641 isVisible : function(){
37642 return this.el && !this.hidden;
37646 * Displays this menu relative to another element
37647 * @param {String/HTMLElement/Roo.Element} element The element to align to
37648 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37649 * the element (defaults to this.defaultAlign)
37650 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37652 show : function(el, pos, parentMenu){
37653 this.parentMenu = parentMenu;
37657 this.fireEvent("beforeshow", this);
37658 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37662 * Displays this menu at a specific xy position
37663 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37664 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37666 showAt : function(xy, parentMenu, /* private: */_e){
37667 this.parentMenu = parentMenu;
37672 this.fireEvent("beforeshow", this);
37673 xy = this.el.adjustForConstraints(xy);
37677 this.hidden = false;
37679 this.fireEvent("show", this);
37682 focus : function(){
37684 this.doFocus.defer(50, this);
37688 doFocus : function(){
37690 this.focusEl.focus();
37695 * Hides this menu and optionally all parent menus
37696 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37698 hide : function(deep){
37699 if(this.el && this.isVisible()){
37700 this.fireEvent("beforehide", this);
37701 if(this.activeItem){
37702 this.activeItem.deactivate();
37703 this.activeItem = null;
37706 this.hidden = true;
37707 this.fireEvent("hide", this);
37709 if(deep === true && this.parentMenu){
37710 this.parentMenu.hide(true);
37715 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37716 * Any of the following are valid:
37718 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37719 * <li>An HTMLElement object which will be converted to a menu item</li>
37720 * <li>A menu item config object that will be created as a new menu item</li>
37721 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37722 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37727 var menu = new Roo.menu.Menu();
37729 // Create a menu item to add by reference
37730 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37732 // Add a bunch of items at once using different methods.
37733 // Only the last item added will be returned.
37734 var item = menu.add(
37735 menuItem, // add existing item by ref
37736 'Dynamic Item', // new TextItem
37737 '-', // new separator
37738 { text: 'Config Item' } // new item by config
37741 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37742 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37745 var a = arguments, l = a.length, item;
37746 for(var i = 0; i < l; i++){
37748 if ((typeof(el) == "object") && el.xtype && el.xns) {
37749 el = Roo.factory(el, Roo.menu);
37752 if(el.render){ // some kind of Item
37753 item = this.addItem(el);
37754 }else if(typeof el == "string"){ // string
37755 if(el == "separator" || el == "-"){
37756 item = this.addSeparator();
37758 item = this.addText(el);
37760 }else if(el.tagName || el.el){ // element
37761 item = this.addElement(el);
37762 }else if(typeof el == "object"){ // must be menu item config?
37763 item = this.addMenuItem(el);
37770 * Returns this menu's underlying {@link Roo.Element} object
37771 * @return {Roo.Element} The element
37773 getEl : function(){
37781 * Adds a separator bar to the menu
37782 * @return {Roo.menu.Item} The menu item that was added
37784 addSeparator : function(){
37785 return this.addItem(new Roo.menu.Separator());
37789 * Adds an {@link Roo.Element} object to the menu
37790 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37791 * @return {Roo.menu.Item} The menu item that was added
37793 addElement : function(el){
37794 return this.addItem(new Roo.menu.BaseItem(el));
37798 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37799 * @param {Roo.menu.Item} item The menu item to add
37800 * @return {Roo.menu.Item} The menu item that was added
37802 addItem : function(item){
37803 this.items.add(item);
37805 var li = document.createElement("li");
37806 li.className = "x-menu-list-item";
37807 this.ul.dom.appendChild(li);
37808 item.render(li, this);
37809 this.delayAutoWidth();
37815 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37816 * @param {Object} config A MenuItem config object
37817 * @return {Roo.menu.Item} The menu item that was added
37819 addMenuItem : function(config){
37820 if(!(config instanceof Roo.menu.Item)){
37821 if(typeof config.checked == "boolean"){ // must be check menu item config?
37822 config = new Roo.menu.CheckItem(config);
37824 config = new Roo.menu.Item(config);
37827 return this.addItem(config);
37831 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37832 * @param {String} text The text to display in the menu item
37833 * @return {Roo.menu.Item} The menu item that was added
37835 addText : function(text){
37836 return this.addItem(new Roo.menu.TextItem({ text : text }));
37840 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37841 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37842 * @param {Roo.menu.Item} item The menu item to add
37843 * @return {Roo.menu.Item} The menu item that was added
37845 insert : function(index, item){
37846 this.items.insert(index, item);
37848 var li = document.createElement("li");
37849 li.className = "x-menu-list-item";
37850 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37851 item.render(li, this);
37852 this.delayAutoWidth();
37858 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37859 * @param {Roo.menu.Item} item The menu item to remove
37861 remove : function(item){
37862 this.items.removeKey(item.id);
37867 * Removes and destroys all items in the menu
37869 removeAll : function(){
37871 while(f = this.items.first()){
37877 // MenuNav is a private utility class used internally by the Menu
37878 Roo.menu.MenuNav = function(menu){
37879 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37880 this.scope = this.menu = menu;
37883 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37884 doRelay : function(e, h){
37885 var k = e.getKey();
37886 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37887 this.menu.tryActivate(0, 1);
37890 return h.call(this.scope || this, e, this.menu);
37893 up : function(e, m){
37894 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37895 m.tryActivate(m.items.length-1, -1);
37899 down : function(e, m){
37900 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37901 m.tryActivate(0, 1);
37905 right : function(e, m){
37907 m.activeItem.expandMenu(true);
37911 left : function(e, m){
37913 if(m.parentMenu && m.parentMenu.activeItem){
37914 m.parentMenu.activeItem.activate();
37918 enter : function(e, m){
37920 e.stopPropagation();
37921 m.activeItem.onClick(e);
37922 m.fireEvent("click", this, m.activeItem);
37928 * Ext JS Library 1.1.1
37929 * Copyright(c) 2006-2007, Ext JS, LLC.
37931 * Originally Released Under LGPL - original licence link has changed is not relivant.
37934 * <script type="text/javascript">
37938 * @class Roo.menu.MenuMgr
37939 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37942 Roo.menu.MenuMgr = function(){
37943 var menus, active, groups = {}, attached = false, lastShow = new Date();
37945 // private - called when first menu is created
37948 active = new Roo.util.MixedCollection();
37949 Roo.get(document).addKeyListener(27, function(){
37950 if(active.length > 0){
37957 function hideAll(){
37958 if(active && active.length > 0){
37959 var c = active.clone();
37960 c.each(function(m){
37967 function onHide(m){
37969 if(active.length < 1){
37970 Roo.get(document).un("mousedown", onMouseDown);
37976 function onShow(m){
37977 var last = active.last();
37978 lastShow = new Date();
37981 Roo.get(document).on("mousedown", onMouseDown);
37985 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37986 m.parentMenu.activeChild = m;
37987 }else if(last && last.isVisible()){
37988 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37993 function onBeforeHide(m){
37995 m.activeChild.hide();
37997 if(m.autoHideTimer){
37998 clearTimeout(m.autoHideTimer);
37999 delete m.autoHideTimer;
38004 function onBeforeShow(m){
38005 var pm = m.parentMenu;
38006 if(!pm && !m.allowOtherMenus){
38008 }else if(pm && pm.activeChild && active != m){
38009 pm.activeChild.hide();
38014 function onMouseDown(e){
38015 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38021 function onBeforeCheck(mi, state){
38023 var g = groups[mi.group];
38024 for(var i = 0, l = g.length; i < l; i++){
38026 g[i].setChecked(false);
38035 * Hides all menus that are currently visible
38037 hideAll : function(){
38042 register : function(menu){
38046 menus[menu.id] = menu;
38047 menu.on("beforehide", onBeforeHide);
38048 menu.on("hide", onHide);
38049 menu.on("beforeshow", onBeforeShow);
38050 menu.on("show", onShow);
38051 var g = menu.group;
38052 if(g && menu.events["checkchange"]){
38056 groups[g].push(menu);
38057 menu.on("checkchange", onCheck);
38062 * Returns a {@link Roo.menu.Menu} object
38063 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38064 * be used to generate and return a new Menu instance.
38066 get : function(menu){
38067 if(typeof menu == "string"){ // menu id
38068 return menus[menu];
38069 }else if(menu.events){ // menu instance
38071 }else if(typeof menu.length == 'number'){ // array of menu items?
38072 return new Roo.menu.Menu({items:menu});
38073 }else{ // otherwise, must be a config
38074 return new Roo.menu.Menu(menu);
38079 unregister : function(menu){
38080 delete menus[menu.id];
38081 menu.un("beforehide", onBeforeHide);
38082 menu.un("hide", onHide);
38083 menu.un("beforeshow", onBeforeShow);
38084 menu.un("show", onShow);
38085 var g = menu.group;
38086 if(g && menu.events["checkchange"]){
38087 groups[g].remove(menu);
38088 menu.un("checkchange", onCheck);
38093 registerCheckable : function(menuItem){
38094 var g = menuItem.group;
38099 groups[g].push(menuItem);
38100 menuItem.on("beforecheckchange", onBeforeCheck);
38105 unregisterCheckable : function(menuItem){
38106 var g = menuItem.group;
38108 groups[g].remove(menuItem);
38109 menuItem.un("beforecheckchange", onBeforeCheck);
38115 * Ext JS Library 1.1.1
38116 * Copyright(c) 2006-2007, Ext JS, LLC.
38118 * Originally Released Under LGPL - original licence link has changed is not relivant.
38121 * <script type="text/javascript">
38126 * @class Roo.menu.BaseItem
38127 * @extends Roo.Component
38128 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38129 * management and base configuration options shared by all menu components.
38131 * Creates a new BaseItem
38132 * @param {Object} config Configuration options
38134 Roo.menu.BaseItem = function(config){
38135 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38140 * Fires when this item is clicked
38141 * @param {Roo.menu.BaseItem} this
38142 * @param {Roo.EventObject} e
38147 * Fires when this item is activated
38148 * @param {Roo.menu.BaseItem} this
38152 * @event deactivate
38153 * Fires when this item is deactivated
38154 * @param {Roo.menu.BaseItem} this
38160 this.on("click", this.handler, this.scope, true);
38164 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38166 * @cfg {Function} handler
38167 * A function that will handle the click event of this menu item (defaults to undefined)
38170 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38172 canActivate : false,
38175 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38180 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38182 activeClass : "x-menu-item-active",
38184 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38186 hideOnClick : true,
38188 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38193 ctype: "Roo.menu.BaseItem",
38196 actionMode : "container",
38199 render : function(container, parentMenu){
38200 this.parentMenu = parentMenu;
38201 Roo.menu.BaseItem.superclass.render.call(this, container);
38202 this.container.menuItemId = this.id;
38206 onRender : function(container, position){
38207 this.el = Roo.get(this.el);
38208 container.dom.appendChild(this.el.dom);
38212 onClick : function(e){
38213 if(!this.disabled && this.fireEvent("click", this, e) !== false
38214 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38215 this.handleClick(e);
38222 activate : function(){
38226 var li = this.container;
38227 li.addClass(this.activeClass);
38228 this.region = li.getRegion().adjust(2, 2, -2, -2);
38229 this.fireEvent("activate", this);
38234 deactivate : function(){
38235 this.container.removeClass(this.activeClass);
38236 this.fireEvent("deactivate", this);
38240 shouldDeactivate : function(e){
38241 return !this.region || !this.region.contains(e.getPoint());
38245 handleClick : function(e){
38246 if(this.hideOnClick){
38247 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38252 expandMenu : function(autoActivate){
38257 hideMenu : function(){
38262 * Ext JS Library 1.1.1
38263 * Copyright(c) 2006-2007, Ext JS, LLC.
38265 * Originally Released Under LGPL - original licence link has changed is not relivant.
38268 * <script type="text/javascript">
38272 * @class Roo.menu.Adapter
38273 * @extends Roo.menu.BaseItem
38274 * 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.
38275 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38277 * Creates a new Adapter
38278 * @param {Object} config Configuration options
38280 Roo.menu.Adapter = function(component, config){
38281 Roo.menu.Adapter.superclass.constructor.call(this, config);
38282 this.component = component;
38284 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38286 canActivate : true,
38289 onRender : function(container, position){
38290 this.component.render(container);
38291 this.el = this.component.getEl();
38295 activate : function(){
38299 this.component.focus();
38300 this.fireEvent("activate", this);
38305 deactivate : function(){
38306 this.fireEvent("deactivate", this);
38310 disable : function(){
38311 this.component.disable();
38312 Roo.menu.Adapter.superclass.disable.call(this);
38316 enable : function(){
38317 this.component.enable();
38318 Roo.menu.Adapter.superclass.enable.call(this);
38322 * Ext JS Library 1.1.1
38323 * Copyright(c) 2006-2007, Ext JS, LLC.
38325 * Originally Released Under LGPL - original licence link has changed is not relivant.
38328 * <script type="text/javascript">
38332 * @class Roo.menu.TextItem
38333 * @extends Roo.menu.BaseItem
38334 * Adds a static text string to a menu, usually used as either a heading or group separator.
38335 * Note: old style constructor with text is still supported.
38338 * Creates a new TextItem
38339 * @param {Object} cfg Configuration
38341 Roo.menu.TextItem = function(cfg){
38342 if (typeof(cfg) == 'string') {
38345 Roo.apply(this,cfg);
38348 Roo.menu.TextItem.superclass.constructor.call(this);
38351 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38353 * @cfg {Boolean} text Text to show on item.
38358 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38360 hideOnClick : false,
38362 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38364 itemCls : "x-menu-text",
38367 onRender : function(){
38368 var s = document.createElement("span");
38369 s.className = this.itemCls;
38370 s.innerHTML = this.text;
38372 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38376 * Ext JS Library 1.1.1
38377 * Copyright(c) 2006-2007, Ext JS, LLC.
38379 * Originally Released Under LGPL - original licence link has changed is not relivant.
38382 * <script type="text/javascript">
38386 * @class Roo.menu.Separator
38387 * @extends Roo.menu.BaseItem
38388 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38389 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38391 * @param {Object} config Configuration options
38393 Roo.menu.Separator = function(config){
38394 Roo.menu.Separator.superclass.constructor.call(this, config);
38397 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38399 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38401 itemCls : "x-menu-sep",
38403 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38405 hideOnClick : false,
38408 onRender : function(li){
38409 var s = document.createElement("span");
38410 s.className = this.itemCls;
38411 s.innerHTML = " ";
38413 li.addClass("x-menu-sep-li");
38414 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38418 * Ext JS Library 1.1.1
38419 * Copyright(c) 2006-2007, Ext JS, LLC.
38421 * Originally Released Under LGPL - original licence link has changed is not relivant.
38424 * <script type="text/javascript">
38427 * @class Roo.menu.Item
38428 * @extends Roo.menu.BaseItem
38429 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38430 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38431 * activation and click handling.
38433 * Creates a new Item
38434 * @param {Object} config Configuration options
38436 Roo.menu.Item = function(config){
38437 Roo.menu.Item.superclass.constructor.call(this, config);
38439 this.menu = Roo.menu.MenuMgr.get(this.menu);
38442 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38445 * @cfg {String} text
38446 * The text to show on the menu item.
38450 * @cfg {String} HTML to render in menu
38451 * The text to show on the menu item (HTML version).
38455 * @cfg {String} icon
38456 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38460 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38462 itemCls : "x-menu-item",
38464 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38466 canActivate : true,
38468 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38471 // doc'd in BaseItem
38475 ctype: "Roo.menu.Item",
38478 onRender : function(container, position){
38479 var el = document.createElement("a");
38480 el.hideFocus = true;
38481 el.unselectable = "on";
38482 el.href = this.href || "#";
38483 if(this.hrefTarget){
38484 el.target = this.hrefTarget;
38486 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38488 var html = this.html.length ? this.html : String.format('{0}',this.text);
38490 el.innerHTML = String.format(
38491 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38492 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38494 Roo.menu.Item.superclass.onRender.call(this, container, position);
38498 * Sets the text to display in this menu item
38499 * @param {String} text The text to display
38500 * @param {Boolean} isHTML true to indicate text is pure html.
38502 setText : function(text, isHTML){
38510 var html = this.html.length ? this.html : String.format('{0}',this.text);
38512 this.el.update(String.format(
38513 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38514 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38515 this.parentMenu.autoWidth();
38520 handleClick : function(e){
38521 if(!this.href){ // if no link defined, stop the event automatically
38524 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38528 activate : function(autoExpand){
38529 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38539 shouldDeactivate : function(e){
38540 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38541 if(this.menu && this.menu.isVisible()){
38542 return !this.menu.getEl().getRegion().contains(e.getPoint());
38550 deactivate : function(){
38551 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38556 expandMenu : function(autoActivate){
38557 if(!this.disabled && this.menu){
38558 clearTimeout(this.hideTimer);
38559 delete this.hideTimer;
38560 if(!this.menu.isVisible() && !this.showTimer){
38561 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38562 }else if (this.menu.isVisible() && autoActivate){
38563 this.menu.tryActivate(0, 1);
38569 deferExpand : function(autoActivate){
38570 delete this.showTimer;
38571 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38573 this.menu.tryActivate(0, 1);
38578 hideMenu : function(){
38579 clearTimeout(this.showTimer);
38580 delete this.showTimer;
38581 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38582 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38587 deferHide : function(){
38588 delete this.hideTimer;
38593 * Ext JS Library 1.1.1
38594 * Copyright(c) 2006-2007, Ext JS, LLC.
38596 * Originally Released Under LGPL - original licence link has changed is not relivant.
38599 * <script type="text/javascript">
38603 * @class Roo.menu.CheckItem
38604 * @extends Roo.menu.Item
38605 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38607 * Creates a new CheckItem
38608 * @param {Object} config Configuration options
38610 Roo.menu.CheckItem = function(config){
38611 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38614 * @event beforecheckchange
38615 * Fires before the checked value is set, providing an opportunity to cancel if needed
38616 * @param {Roo.menu.CheckItem} this
38617 * @param {Boolean} checked The new checked value that will be set
38619 "beforecheckchange" : true,
38621 * @event checkchange
38622 * Fires after the checked value has been set
38623 * @param {Roo.menu.CheckItem} this
38624 * @param {Boolean} checked The checked value that was set
38626 "checkchange" : true
38628 if(this.checkHandler){
38629 this.on('checkchange', this.checkHandler, this.scope);
38632 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38634 * @cfg {String} group
38635 * All check items with the same group name will automatically be grouped into a single-select
38636 * radio button group (defaults to '')
38639 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38641 itemCls : "x-menu-item x-menu-check-item",
38643 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38645 groupClass : "x-menu-group-item",
38648 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38649 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38650 * initialized with checked = true will be rendered as checked.
38655 ctype: "Roo.menu.CheckItem",
38658 onRender : function(c){
38659 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38661 this.el.addClass(this.groupClass);
38663 Roo.menu.MenuMgr.registerCheckable(this);
38665 this.checked = false;
38666 this.setChecked(true, true);
38671 destroy : function(){
38673 Roo.menu.MenuMgr.unregisterCheckable(this);
38675 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38679 * Set the checked state of this item
38680 * @param {Boolean} checked The new checked value
38681 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38683 setChecked : function(state, suppressEvent){
38684 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38685 if(this.container){
38686 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38688 this.checked = state;
38689 if(suppressEvent !== true){
38690 this.fireEvent("checkchange", this, state);
38696 handleClick : function(e){
38697 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38698 this.setChecked(!this.checked);
38700 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38704 * Ext JS Library 1.1.1
38705 * Copyright(c) 2006-2007, Ext JS, LLC.
38707 * Originally Released Under LGPL - original licence link has changed is not relivant.
38710 * <script type="text/javascript">
38714 * @class Roo.menu.DateItem
38715 * @extends Roo.menu.Adapter
38716 * A menu item that wraps the {@link Roo.DatPicker} component.
38718 * Creates a new DateItem
38719 * @param {Object} config Configuration options
38721 Roo.menu.DateItem = function(config){
38722 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38723 /** The Roo.DatePicker object @type Roo.DatePicker */
38724 this.picker = this.component;
38725 this.addEvents({select: true});
38727 this.picker.on("render", function(picker){
38728 picker.getEl().swallowEvent("click");
38729 picker.container.addClass("x-menu-date-item");
38732 this.picker.on("select", this.onSelect, this);
38735 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38737 onSelect : function(picker, date){
38738 this.fireEvent("select", this, date, picker);
38739 Roo.menu.DateItem.superclass.handleClick.call(this);
38743 * Ext JS Library 1.1.1
38744 * Copyright(c) 2006-2007, Ext JS, LLC.
38746 * Originally Released Under LGPL - original licence link has changed is not relivant.
38749 * <script type="text/javascript">
38753 * @class Roo.menu.ColorItem
38754 * @extends Roo.menu.Adapter
38755 * A menu item that wraps the {@link Roo.ColorPalette} component.
38757 * Creates a new ColorItem
38758 * @param {Object} config Configuration options
38760 Roo.menu.ColorItem = function(config){
38761 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38762 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38763 this.palette = this.component;
38764 this.relayEvents(this.palette, ["select"]);
38765 if(this.selectHandler){
38766 this.on('select', this.selectHandler, this.scope);
38769 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38771 * Ext JS Library 1.1.1
38772 * Copyright(c) 2006-2007, Ext JS, LLC.
38774 * Originally Released Under LGPL - original licence link has changed is not relivant.
38777 * <script type="text/javascript">
38782 * @class Roo.menu.DateMenu
38783 * @extends Roo.menu.Menu
38784 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38786 * Creates a new DateMenu
38787 * @param {Object} config Configuration options
38789 Roo.menu.DateMenu = function(config){
38790 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38792 var di = new Roo.menu.DateItem(config);
38795 * The {@link Roo.DatePicker} instance for this DateMenu
38798 this.picker = di.picker;
38801 * @param {DatePicker} picker
38802 * @param {Date} date
38804 this.relayEvents(di, ["select"]);
38805 this.on('beforeshow', function(){
38807 this.picker.hideMonthPicker(false);
38811 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38815 * Ext JS Library 1.1.1
38816 * Copyright(c) 2006-2007, Ext JS, LLC.
38818 * Originally Released Under LGPL - original licence link has changed is not relivant.
38821 * <script type="text/javascript">
38826 * @class Roo.menu.ColorMenu
38827 * @extends Roo.menu.Menu
38828 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38830 * Creates a new ColorMenu
38831 * @param {Object} config Configuration options
38833 Roo.menu.ColorMenu = function(config){
38834 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38836 var ci = new Roo.menu.ColorItem(config);
38839 * The {@link Roo.ColorPalette} instance for this ColorMenu
38840 * @type ColorPalette
38842 this.palette = ci.palette;
38845 * @param {ColorPalette} palette
38846 * @param {String} color
38848 this.relayEvents(ci, ["select"]);
38850 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38852 * Ext JS Library 1.1.1
38853 * Copyright(c) 2006-2007, Ext JS, LLC.
38855 * Originally Released Under LGPL - original licence link has changed is not relivant.
38858 * <script type="text/javascript">
38862 * @class Roo.form.TextItem
38863 * @extends Roo.BoxComponent
38864 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38866 * Creates a new TextItem
38867 * @param {Object} config Configuration options
38869 Roo.form.TextItem = function(config){
38870 Roo.form.TextItem.superclass.constructor.call(this, config);
38873 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
38876 * @cfg {String} tag the tag for this item (default div)
38880 * @cfg {String} html the content for this item
38884 getAutoCreate : function()
38897 onRender : function(ct, position)
38899 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
38902 var cfg = this.getAutoCreate();
38904 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38906 if (!cfg.name.length) {
38909 this.el = ct.createChild(cfg, position);
38914 * @param {String} html update the Contents of the element.
38916 setHTML : function(html)
38918 this.fieldEl.dom.innerHTML = html;
38923 * Ext JS Library 1.1.1
38924 * Copyright(c) 2006-2007, Ext JS, LLC.
38926 * Originally Released Under LGPL - original licence link has changed is not relivant.
38929 * <script type="text/javascript">
38933 * @class Roo.form.Field
38934 * @extends Roo.BoxComponent
38935 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38937 * Creates a new Field
38938 * @param {Object} config Configuration options
38940 Roo.form.Field = function(config){
38941 Roo.form.Field.superclass.constructor.call(this, config);
38944 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38946 * @cfg {String} fieldLabel Label to use when rendering a form.
38949 * @cfg {String} qtip Mouse over tip
38953 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38955 invalidClass : "x-form-invalid",
38957 * @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")
38959 invalidText : "The value in this field is invalid",
38961 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38963 focusClass : "x-form-focus",
38965 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38966 automatic validation (defaults to "keyup").
38968 validationEvent : "keyup",
38970 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38972 validateOnBlur : true,
38974 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38976 validationDelay : 250,
38978 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38979 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38981 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38983 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38985 fieldClass : "x-form-field",
38987 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38990 ----------- ----------------------------------------------------------------------
38991 qtip Display a quick tip when the user hovers over the field
38992 title Display a default browser title attribute popup
38993 under Add a block div beneath the field containing the error text
38994 side Add an error icon to the right of the field with a popup on hover
38995 [element id] Add the error text directly to the innerHTML of the specified element
38998 msgTarget : 'qtip',
39000 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39005 * @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.
39010 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39015 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39017 inputType : undefined,
39020 * @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).
39022 tabIndex : undefined,
39025 isFormField : true,
39030 * @property {Roo.Element} fieldEl
39031 * Element Containing the rendered Field (with label etc.)
39034 * @cfg {Mixed} value A value to initialize this field with.
39039 * @cfg {String} name The field's HTML name attribute.
39042 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39045 loadedValue : false,
39049 initComponent : function(){
39050 Roo.form.Field.superclass.initComponent.call(this);
39054 * Fires when this field receives input focus.
39055 * @param {Roo.form.Field} this
39060 * Fires when this field loses input focus.
39061 * @param {Roo.form.Field} this
39065 * @event specialkey
39066 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39067 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39068 * @param {Roo.form.Field} this
39069 * @param {Roo.EventObject} e The event object
39074 * Fires just before the field blurs if the field value has changed.
39075 * @param {Roo.form.Field} this
39076 * @param {Mixed} newValue The new value
39077 * @param {Mixed} oldValue The original value
39082 * Fires after the field has been marked as invalid.
39083 * @param {Roo.form.Field} this
39084 * @param {String} msg The validation message
39089 * Fires after the field has been validated with no errors.
39090 * @param {Roo.form.Field} this
39095 * Fires after the key up
39096 * @param {Roo.form.Field} this
39097 * @param {Roo.EventObject} e The event Object
39104 * Returns the name attribute of the field if available
39105 * @return {String} name The field name
39107 getName: function(){
39108 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39112 onRender : function(ct, position){
39113 Roo.form.Field.superclass.onRender.call(this, ct, position);
39115 var cfg = this.getAutoCreate();
39117 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39119 if (!cfg.name.length) {
39122 if(this.inputType){
39123 cfg.type = this.inputType;
39125 this.el = ct.createChild(cfg, position);
39127 var type = this.el.dom.type;
39129 if(type == 'password'){
39132 this.el.addClass('x-form-'+type);
39135 this.el.dom.readOnly = true;
39137 if(this.tabIndex !== undefined){
39138 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39141 this.el.addClass([this.fieldClass, this.cls]);
39146 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39147 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39148 * @return {Roo.form.Field} this
39150 applyTo : function(target){
39151 this.allowDomMove = false;
39152 this.el = Roo.get(target);
39153 this.render(this.el.dom.parentNode);
39158 initValue : function(){
39159 if(this.value !== undefined){
39160 this.setValue(this.value);
39161 }else if(this.el.dom.value.length > 0){
39162 this.setValue(this.el.dom.value);
39167 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39168 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39170 isDirty : function() {
39171 if(this.disabled) {
39174 return String(this.getValue()) !== String(this.originalValue);
39178 * stores the current value in loadedValue
39180 resetHasChanged : function()
39182 this.loadedValue = String(this.getValue());
39185 * checks the current value against the 'loaded' value.
39186 * Note - will return false if 'resetHasChanged' has not been called first.
39188 hasChanged : function()
39190 if(this.disabled || this.readOnly) {
39193 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39199 afterRender : function(){
39200 Roo.form.Field.superclass.afterRender.call(this);
39205 fireKey : function(e){
39206 //Roo.log('field ' + e.getKey());
39207 if(e.isNavKeyPress()){
39208 this.fireEvent("specialkey", this, e);
39213 * Resets the current field value to the originally loaded value and clears any validation messages
39215 reset : function(){
39216 this.setValue(this.resetValue);
39217 this.originalValue = this.getValue();
39218 this.clearInvalid();
39222 initEvents : function(){
39223 // safari killled keypress - so keydown is now used..
39224 this.el.on("keydown" , this.fireKey, this);
39225 this.el.on("focus", this.onFocus, this);
39226 this.el.on("blur", this.onBlur, this);
39227 this.el.relayEvent('keyup', this);
39229 // reference to original value for reset
39230 this.originalValue = this.getValue();
39231 this.resetValue = this.getValue();
39235 onFocus : function(){
39236 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39237 this.el.addClass(this.focusClass);
39239 if(!this.hasFocus){
39240 this.hasFocus = true;
39241 this.startValue = this.getValue();
39242 this.fireEvent("focus", this);
39246 beforeBlur : Roo.emptyFn,
39249 onBlur : function(){
39251 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39252 this.el.removeClass(this.focusClass);
39254 this.hasFocus = false;
39255 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39258 var v = this.getValue();
39259 if(String(v) !== String(this.startValue)){
39260 this.fireEvent('change', this, v, this.startValue);
39262 this.fireEvent("blur", this);
39266 * Returns whether or not the field value is currently valid
39267 * @param {Boolean} preventMark True to disable marking the field invalid
39268 * @return {Boolean} True if the value is valid, else false
39270 isValid : function(preventMark){
39274 var restore = this.preventMark;
39275 this.preventMark = preventMark === true;
39276 var v = this.validateValue(this.processValue(this.getRawValue()));
39277 this.preventMark = restore;
39282 * Validates the field value
39283 * @return {Boolean} True if the value is valid, else false
39285 validate : function(){
39286 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39287 this.clearInvalid();
39293 processValue : function(value){
39298 // Subclasses should provide the validation implementation by overriding this
39299 validateValue : function(value){
39304 * Mark this field as invalid
39305 * @param {String} msg The validation message
39307 markInvalid : function(msg){
39308 if(!this.rendered || this.preventMark){ // not rendered
39312 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39314 obj.el.addClass(this.invalidClass);
39315 msg = msg || this.invalidText;
39316 switch(this.msgTarget){
39318 obj.el.dom.qtip = msg;
39319 obj.el.dom.qclass = 'x-form-invalid-tip';
39320 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39321 Roo.QuickTips.enable();
39325 this.el.dom.title = msg;
39329 var elp = this.el.findParent('.x-form-element', 5, true);
39330 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39331 this.errorEl.setWidth(elp.getWidth(true)-20);
39333 this.errorEl.update(msg);
39334 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39337 if(!this.errorIcon){
39338 var elp = this.el.findParent('.x-form-element', 5, true);
39339 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39341 this.alignErrorIcon();
39342 this.errorIcon.dom.qtip = msg;
39343 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39344 this.errorIcon.show();
39345 this.on('resize', this.alignErrorIcon, this);
39348 var t = Roo.getDom(this.msgTarget);
39350 t.style.display = this.msgDisplay;
39353 this.fireEvent('invalid', this, msg);
39357 alignErrorIcon : function(){
39358 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39362 * Clear any invalid styles/messages for this field
39364 clearInvalid : function(){
39365 if(!this.rendered || this.preventMark){ // not rendered
39368 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39370 obj.el.removeClass(this.invalidClass);
39371 switch(this.msgTarget){
39373 obj.el.dom.qtip = '';
39376 this.el.dom.title = '';
39380 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39384 if(this.errorIcon){
39385 this.errorIcon.dom.qtip = '';
39386 this.errorIcon.hide();
39387 this.un('resize', this.alignErrorIcon, this);
39391 var t = Roo.getDom(this.msgTarget);
39393 t.style.display = 'none';
39396 this.fireEvent('valid', this);
39400 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39401 * @return {Mixed} value The field value
39403 getRawValue : function(){
39404 var v = this.el.getValue();
39410 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39411 * @return {Mixed} value The field value
39413 getValue : function(){
39414 var v = this.el.getValue();
39420 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39421 * @param {Mixed} value The value to set
39423 setRawValue : function(v){
39424 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39428 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39429 * @param {Mixed} value The value to set
39431 setValue : function(v){
39434 this.el.dom.value = (v === null || v === undefined ? '' : v);
39439 adjustSize : function(w, h){
39440 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39441 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39445 adjustWidth : function(tag, w){
39446 tag = tag.toLowerCase();
39447 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39448 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39449 if(tag == 'input'){
39452 if(tag == 'textarea'){
39455 }else if(Roo.isOpera){
39456 if(tag == 'input'){
39459 if(tag == 'textarea'){
39469 // anything other than normal should be considered experimental
39470 Roo.form.Field.msgFx = {
39472 show: function(msgEl, f){
39473 msgEl.setDisplayed('block');
39476 hide : function(msgEl, f){
39477 msgEl.setDisplayed(false).update('');
39482 show: function(msgEl, f){
39483 msgEl.slideIn('t', {stopFx:true});
39486 hide : function(msgEl, f){
39487 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39492 show: function(msgEl, f){
39493 msgEl.fixDisplay();
39494 msgEl.alignTo(f.el, 'tl-tr');
39495 msgEl.slideIn('l', {stopFx:true});
39498 hide : function(msgEl, f){
39499 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39504 * Ext JS Library 1.1.1
39505 * Copyright(c) 2006-2007, Ext JS, LLC.
39507 * Originally Released Under LGPL - original licence link has changed is not relivant.
39510 * <script type="text/javascript">
39515 * @class Roo.form.TextField
39516 * @extends Roo.form.Field
39517 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39518 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39520 * Creates a new TextField
39521 * @param {Object} config Configuration options
39523 Roo.form.TextField = function(config){
39524 Roo.form.TextField.superclass.constructor.call(this, config);
39528 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39529 * according to the default logic, but this event provides a hook for the developer to apply additional
39530 * logic at runtime to resize the field if needed.
39531 * @param {Roo.form.Field} this This text field
39532 * @param {Number} width The new field width
39538 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39540 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39544 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39548 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39552 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39556 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39560 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39562 disableKeyFilter : false,
39564 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39568 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39572 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39574 maxLength : Number.MAX_VALUE,
39576 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39578 minLengthText : "The minimum length for this field is {0}",
39580 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39582 maxLengthText : "The maximum length for this field is {0}",
39584 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39586 selectOnFocus : false,
39588 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39590 allowLeadingSpace : false,
39592 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39594 blankText : "This field is required",
39596 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39597 * If available, this function will be called only after the basic validators all return true, and will be passed the
39598 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39602 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39603 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39604 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39608 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39612 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39618 initEvents : function()
39620 if (this.emptyText) {
39621 this.el.attr('placeholder', this.emptyText);
39624 Roo.form.TextField.superclass.initEvents.call(this);
39625 if(this.validationEvent == 'keyup'){
39626 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39627 this.el.on('keyup', this.filterValidation, this);
39629 else if(this.validationEvent !== false){
39630 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39633 if(this.selectOnFocus){
39634 this.on("focus", this.preFocus, this);
39636 if (!this.allowLeadingSpace) {
39637 this.on('blur', this.cleanLeadingSpace, this);
39640 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39641 this.el.on("keypress", this.filterKeys, this);
39644 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39645 this.el.on("click", this.autoSize, this);
39647 if(this.el.is('input[type=password]') && Roo.isSafari){
39648 this.el.on('keydown', this.SafariOnKeyDown, this);
39652 processValue : function(value){
39653 if(this.stripCharsRe){
39654 var newValue = value.replace(this.stripCharsRe, '');
39655 if(newValue !== value){
39656 this.setRawValue(newValue);
39663 filterValidation : function(e){
39664 if(!e.isNavKeyPress()){
39665 this.validationTask.delay(this.validationDelay);
39670 onKeyUp : function(e){
39671 if(!e.isNavKeyPress()){
39675 // private - clean the leading white space
39676 cleanLeadingSpace : function(e)
39678 if ( this.inputType == 'file') {
39682 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39685 * Resets the current field value to the originally-loaded value and clears any validation messages.
39688 reset : function(){
39689 Roo.form.TextField.superclass.reset.call(this);
39693 preFocus : function(){
39695 if(this.selectOnFocus){
39696 this.el.dom.select();
39702 filterKeys : function(e){
39703 var k = e.getKey();
39704 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39707 var c = e.getCharCode(), cc = String.fromCharCode(c);
39708 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39711 if(!this.maskRe.test(cc)){
39716 setValue : function(v){
39718 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39724 * Validates a value according to the field's validation rules and marks the field as invalid
39725 * if the validation fails
39726 * @param {Mixed} value The value to validate
39727 * @return {Boolean} True if the value is valid, else false
39729 validateValue : function(value){
39730 if(value.length < 1) { // if it's blank
39731 if(this.allowBlank){
39732 this.clearInvalid();
39735 this.markInvalid(this.blankText);
39739 if(value.length < this.minLength){
39740 this.markInvalid(String.format(this.minLengthText, this.minLength));
39743 if(value.length > this.maxLength){
39744 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39748 var vt = Roo.form.VTypes;
39749 if(!vt[this.vtype](value, this)){
39750 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39754 if(typeof this.validator == "function"){
39755 var msg = this.validator(value);
39757 this.markInvalid(msg);
39761 if(this.regex && !this.regex.test(value)){
39762 this.markInvalid(this.regexText);
39769 * Selects text in this field
39770 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39771 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39773 selectText : function(start, end){
39774 var v = this.getRawValue();
39776 start = start === undefined ? 0 : start;
39777 end = end === undefined ? v.length : end;
39778 var d = this.el.dom;
39779 if(d.setSelectionRange){
39780 d.setSelectionRange(start, end);
39781 }else if(d.createTextRange){
39782 var range = d.createTextRange();
39783 range.moveStart("character", start);
39784 range.moveEnd("character", v.length-end);
39791 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39792 * This only takes effect if grow = true, and fires the autosize event.
39794 autoSize : function(){
39795 if(!this.grow || !this.rendered){
39799 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39802 var v = el.dom.value;
39803 var d = document.createElement('div');
39804 d.appendChild(document.createTextNode(v));
39808 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39809 this.el.setWidth(w);
39810 this.fireEvent("autosize", this, w);
39814 SafariOnKeyDown : function(event)
39816 // this is a workaround for a password hang bug on chrome/ webkit.
39818 var isSelectAll = false;
39820 if(this.el.dom.selectionEnd > 0){
39821 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39823 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39824 event.preventDefault();
39829 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39831 event.preventDefault();
39832 // this is very hacky as keydown always get's upper case.
39834 var cc = String.fromCharCode(event.getCharCode());
39837 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39845 * Ext JS Library 1.1.1
39846 * Copyright(c) 2006-2007, Ext JS, LLC.
39848 * Originally Released Under LGPL - original licence link has changed is not relivant.
39851 * <script type="text/javascript">
39855 * @class Roo.form.Hidden
39856 * @extends Roo.form.TextField
39857 * Simple Hidden element used on forms
39859 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39862 * Creates a new Hidden form element.
39863 * @param {Object} config Configuration options
39868 // easy hidden field...
39869 Roo.form.Hidden = function(config){
39870 Roo.form.Hidden.superclass.constructor.call(this, config);
39873 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39875 inputType: 'hidden',
39878 labelSeparator: '',
39880 itemCls : 'x-form-item-display-none'
39888 * Ext JS Library 1.1.1
39889 * Copyright(c) 2006-2007, Ext JS, LLC.
39891 * Originally Released Under LGPL - original licence link has changed is not relivant.
39894 * <script type="text/javascript">
39898 * @class Roo.form.TriggerField
39899 * @extends Roo.form.TextField
39900 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39901 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39902 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39903 * for which you can provide a custom implementation. For example:
39905 var trigger = new Roo.form.TriggerField();
39906 trigger.onTriggerClick = myTriggerFn;
39907 trigger.applyTo('my-field');
39910 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39911 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39912 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39913 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39915 * Create a new TriggerField.
39916 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39917 * to the base TextField)
39919 Roo.form.TriggerField = function(config){
39920 this.mimicing = false;
39921 Roo.form.TriggerField.superclass.constructor.call(this, config);
39924 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39926 * @cfg {String} triggerClass A CSS class to apply to the trigger
39929 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39930 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39932 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39934 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39938 /** @cfg {Boolean} grow @hide */
39939 /** @cfg {Number} growMin @hide */
39940 /** @cfg {Number} growMax @hide */
39946 autoSize: Roo.emptyFn,
39950 deferHeight : true,
39953 actionMode : 'wrap',
39955 onResize : function(w, h){
39956 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39957 if(typeof w == 'number'){
39958 var x = w - this.trigger.getWidth();
39959 this.el.setWidth(this.adjustWidth('input', x));
39960 this.trigger.setStyle('left', x+'px');
39965 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39968 getResizeEl : function(){
39973 getPositionEl : function(){
39978 alignErrorIcon : function(){
39979 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39983 onRender : function(ct, position){
39984 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39985 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39986 this.trigger = this.wrap.createChild(this.triggerConfig ||
39987 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39988 if(this.hideTrigger){
39989 this.trigger.setDisplayed(false);
39991 this.initTrigger();
39993 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39998 initTrigger : function(){
39999 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40000 this.trigger.addClassOnOver('x-form-trigger-over');
40001 this.trigger.addClassOnClick('x-form-trigger-click');
40005 onDestroy : function(){
40007 this.trigger.removeAllListeners();
40008 this.trigger.remove();
40011 this.wrap.remove();
40013 Roo.form.TriggerField.superclass.onDestroy.call(this);
40017 onFocus : function(){
40018 Roo.form.TriggerField.superclass.onFocus.call(this);
40019 if(!this.mimicing){
40020 this.wrap.addClass('x-trigger-wrap-focus');
40021 this.mimicing = true;
40022 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40023 if(this.monitorTab){
40024 this.el.on("keydown", this.checkTab, this);
40030 checkTab : function(e){
40031 if(e.getKey() == e.TAB){
40032 this.triggerBlur();
40037 onBlur : function(){
40042 mimicBlur : function(e, t){
40043 if(!this.wrap.contains(t) && this.validateBlur()){
40044 this.triggerBlur();
40049 triggerBlur : function(){
40050 this.mimicing = false;
40051 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40052 if(this.monitorTab){
40053 this.el.un("keydown", this.checkTab, this);
40055 this.wrap.removeClass('x-trigger-wrap-focus');
40056 Roo.form.TriggerField.superclass.onBlur.call(this);
40060 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40061 validateBlur : function(e, t){
40066 onDisable : function(){
40067 Roo.form.TriggerField.superclass.onDisable.call(this);
40069 this.wrap.addClass('x-item-disabled');
40074 onEnable : function(){
40075 Roo.form.TriggerField.superclass.onEnable.call(this);
40077 this.wrap.removeClass('x-item-disabled');
40082 onShow : function(){
40083 var ae = this.getActionEl();
40086 ae.dom.style.display = '';
40087 ae.dom.style.visibility = 'visible';
40093 onHide : function(){
40094 var ae = this.getActionEl();
40095 ae.dom.style.display = 'none';
40099 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40100 * by an implementing function.
40102 * @param {EventObject} e
40104 onTriggerClick : Roo.emptyFn
40107 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40108 // to be extended by an implementing class. For an example of implementing this class, see the custom
40109 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40110 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40111 initComponent : function(){
40112 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40114 this.triggerConfig = {
40115 tag:'span', cls:'x-form-twin-triggers', cn:[
40116 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40117 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40121 getTrigger : function(index){
40122 return this.triggers[index];
40125 initTrigger : function(){
40126 var ts = this.trigger.select('.x-form-trigger', true);
40127 this.wrap.setStyle('overflow', 'hidden');
40128 var triggerField = this;
40129 ts.each(function(t, all, index){
40130 t.hide = function(){
40131 var w = triggerField.wrap.getWidth();
40132 this.dom.style.display = 'none';
40133 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40135 t.show = function(){
40136 var w = triggerField.wrap.getWidth();
40137 this.dom.style.display = '';
40138 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40140 var triggerIndex = 'Trigger'+(index+1);
40142 if(this['hide'+triggerIndex]){
40143 t.dom.style.display = 'none';
40145 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40146 t.addClassOnOver('x-form-trigger-over');
40147 t.addClassOnClick('x-form-trigger-click');
40149 this.triggers = ts.elements;
40152 onTrigger1Click : Roo.emptyFn,
40153 onTrigger2Click : Roo.emptyFn
40156 * Ext JS Library 1.1.1
40157 * Copyright(c) 2006-2007, Ext JS, LLC.
40159 * Originally Released Under LGPL - original licence link has changed is not relivant.
40162 * <script type="text/javascript">
40166 * @class Roo.form.TextArea
40167 * @extends Roo.form.TextField
40168 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40169 * support for auto-sizing.
40171 * Creates a new TextArea
40172 * @param {Object} config Configuration options
40174 Roo.form.TextArea = function(config){
40175 Roo.form.TextArea.superclass.constructor.call(this, config);
40176 // these are provided exchanges for backwards compat
40177 // minHeight/maxHeight were replaced by growMin/growMax to be
40178 // compatible with TextField growing config values
40179 if(this.minHeight !== undefined){
40180 this.growMin = this.minHeight;
40182 if(this.maxHeight !== undefined){
40183 this.growMax = this.maxHeight;
40187 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40189 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40193 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40197 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40198 * in the field (equivalent to setting overflow: hidden, defaults to false)
40200 preventScrollbars: false,
40202 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40203 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40207 onRender : function(ct, position){
40209 this.defaultAutoCreate = {
40211 style:"width:300px;height:60px;",
40212 autocomplete: "new-password"
40215 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40217 this.textSizeEl = Roo.DomHelper.append(document.body, {
40218 tag: "pre", cls: "x-form-grow-sizer"
40220 if(this.preventScrollbars){
40221 this.el.setStyle("overflow", "hidden");
40223 this.el.setHeight(this.growMin);
40227 onDestroy : function(){
40228 if(this.textSizeEl){
40229 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40231 Roo.form.TextArea.superclass.onDestroy.call(this);
40235 onKeyUp : function(e){
40236 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40242 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40243 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40245 autoSize : function(){
40246 if(!this.grow || !this.textSizeEl){
40250 var v = el.dom.value;
40251 var ts = this.textSizeEl;
40254 ts.appendChild(document.createTextNode(v));
40257 Roo.fly(ts).setWidth(this.el.getWidth());
40259 v = "  ";
40262 v = v.replace(/\n/g, '<p> </p>');
40264 v += " \n ";
40267 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40268 if(h != this.lastHeight){
40269 this.lastHeight = h;
40270 this.el.setHeight(h);
40271 this.fireEvent("autosize", this, h);
40276 * Ext JS Library 1.1.1
40277 * Copyright(c) 2006-2007, Ext JS, LLC.
40279 * Originally Released Under LGPL - original licence link has changed is not relivant.
40282 * <script type="text/javascript">
40287 * @class Roo.form.NumberField
40288 * @extends Roo.form.TextField
40289 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40291 * Creates a new NumberField
40292 * @param {Object} config Configuration options
40294 Roo.form.NumberField = function(config){
40295 Roo.form.NumberField.superclass.constructor.call(this, config);
40298 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40300 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40302 fieldClass: "x-form-field x-form-num-field",
40304 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40306 allowDecimals : true,
40308 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40310 decimalSeparator : ".",
40312 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40314 decimalPrecision : 2,
40316 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40318 allowNegative : true,
40320 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40322 minValue : Number.NEGATIVE_INFINITY,
40324 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40326 maxValue : Number.MAX_VALUE,
40328 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40330 minText : "The minimum value for this field is {0}",
40332 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40334 maxText : "The maximum value for this field is {0}",
40336 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40337 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40339 nanText : "{0} is not a valid number",
40342 initEvents : function(){
40343 Roo.form.NumberField.superclass.initEvents.call(this);
40344 var allowed = "0123456789";
40345 if(this.allowDecimals){
40346 allowed += this.decimalSeparator;
40348 if(this.allowNegative){
40351 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40352 var keyPress = function(e){
40353 var k = e.getKey();
40354 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40357 var c = e.getCharCode();
40358 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40362 this.el.on("keypress", keyPress, this);
40366 validateValue : function(value){
40367 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40370 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40373 var num = this.parseValue(value);
40375 this.markInvalid(String.format(this.nanText, value));
40378 if(num < this.minValue){
40379 this.markInvalid(String.format(this.minText, this.minValue));
40382 if(num > this.maxValue){
40383 this.markInvalid(String.format(this.maxText, this.maxValue));
40389 getValue : function(){
40390 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40394 parseValue : function(value){
40395 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40396 return isNaN(value) ? '' : value;
40400 fixPrecision : function(value){
40401 var nan = isNaN(value);
40402 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40403 return nan ? '' : value;
40405 return parseFloat(value).toFixed(this.decimalPrecision);
40408 setValue : function(v){
40409 v = this.fixPrecision(v);
40410 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40414 decimalPrecisionFcn : function(v){
40415 return Math.floor(v);
40418 beforeBlur : function(){
40419 var v = this.parseValue(this.getRawValue());
40426 * Ext JS Library 1.1.1
40427 * Copyright(c) 2006-2007, Ext JS, LLC.
40429 * Originally Released Under LGPL - original licence link has changed is not relivant.
40432 * <script type="text/javascript">
40436 * @class Roo.form.DateField
40437 * @extends Roo.form.TriggerField
40438 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40440 * Create a new DateField
40441 * @param {Object} config
40443 Roo.form.DateField = function(config)
40445 Roo.form.DateField.superclass.constructor.call(this, config);
40451 * Fires when a date is selected
40452 * @param {Roo.form.DateField} combo This combo box
40453 * @param {Date} date The date selected
40460 if(typeof this.minValue == "string") {
40461 this.minValue = this.parseDate(this.minValue);
40463 if(typeof this.maxValue == "string") {
40464 this.maxValue = this.parseDate(this.maxValue);
40466 this.ddMatch = null;
40467 if(this.disabledDates){
40468 var dd = this.disabledDates;
40470 for(var i = 0; i < dd.length; i++){
40472 if(i != dd.length-1) {
40476 this.ddMatch = new RegExp(re + ")");
40480 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40482 * @cfg {String} format
40483 * The default date format string which can be overriden for localization support. The format must be
40484 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40488 * @cfg {String} altFormats
40489 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40490 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40492 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40494 * @cfg {Array} disabledDays
40495 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40497 disabledDays : null,
40499 * @cfg {String} disabledDaysText
40500 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40502 disabledDaysText : "Disabled",
40504 * @cfg {Array} disabledDates
40505 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40506 * expression so they are very powerful. Some examples:
40508 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40509 * <li>["03/08", "09/16"] would disable those days for every year</li>
40510 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40511 * <li>["03/../2006"] would disable every day in March 2006</li>
40512 * <li>["^03"] would disable every day in every March</li>
40514 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40515 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40517 disabledDates : null,
40519 * @cfg {String} disabledDatesText
40520 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40522 disabledDatesText : "Disabled",
40524 * @cfg {Date/String} minValue
40525 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40526 * valid format (defaults to null).
40530 * @cfg {Date/String} maxValue
40531 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40532 * valid format (defaults to null).
40536 * @cfg {String} minText
40537 * The error text to display when the date in the cell is before minValue (defaults to
40538 * 'The date in this field must be after {minValue}').
40540 minText : "The date in this field must be equal to or after {0}",
40542 * @cfg {String} maxText
40543 * The error text to display when the date in the cell is after maxValue (defaults to
40544 * 'The date in this field must be before {maxValue}').
40546 maxText : "The date in this field must be equal to or before {0}",
40548 * @cfg {String} invalidText
40549 * The error text to display when the date in the field is invalid (defaults to
40550 * '{value} is not a valid date - it must be in the format {format}').
40552 invalidText : "{0} is not a valid date - it must be in the format {1}",
40554 * @cfg {String} triggerClass
40555 * An additional CSS class used to style the trigger button. The trigger will always get the
40556 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40557 * which displays a calendar icon).
40559 triggerClass : 'x-form-date-trigger',
40563 * @cfg {Boolean} useIso
40564 * if enabled, then the date field will use a hidden field to store the
40565 * real value as iso formated date. default (false)
40569 * @cfg {String/Object} autoCreate
40570 * A DomHelper element spec, or true for a default element spec (defaults to
40571 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40574 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40577 hiddenField: false,
40579 onRender : function(ct, position)
40581 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40583 //this.el.dom.removeAttribute('name');
40584 Roo.log("Changing name?");
40585 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40586 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40588 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40589 // prevent input submission
40590 this.hiddenName = this.name;
40597 validateValue : function(value)
40599 value = this.formatDate(value);
40600 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40601 Roo.log('super failed');
40604 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40607 var svalue = value;
40608 value = this.parseDate(value);
40610 Roo.log('parse date failed' + svalue);
40611 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40614 var time = value.getTime();
40615 if(this.minValue && time < this.minValue.getTime()){
40616 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40619 if(this.maxValue && time > this.maxValue.getTime()){
40620 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40623 if(this.disabledDays){
40624 var day = value.getDay();
40625 for(var i = 0; i < this.disabledDays.length; i++) {
40626 if(day === this.disabledDays[i]){
40627 this.markInvalid(this.disabledDaysText);
40632 var fvalue = this.formatDate(value);
40633 if(this.ddMatch && this.ddMatch.test(fvalue)){
40634 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40641 // Provides logic to override the default TriggerField.validateBlur which just returns true
40642 validateBlur : function(){
40643 return !this.menu || !this.menu.isVisible();
40646 getName: function()
40648 // returns hidden if it's set..
40649 if (!this.rendered) {return ''};
40650 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40655 * Returns the current date value of the date field.
40656 * @return {Date} The date value
40658 getValue : function(){
40660 return this.hiddenField ?
40661 this.hiddenField.value :
40662 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40666 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40667 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40668 * (the default format used is "m/d/y").
40671 //All of these calls set the same date value (May 4, 2006)
40673 //Pass a date object:
40674 var dt = new Date('5/4/06');
40675 dateField.setValue(dt);
40677 //Pass a date string (default format):
40678 dateField.setValue('5/4/06');
40680 //Pass a date string (custom format):
40681 dateField.format = 'Y-m-d';
40682 dateField.setValue('2006-5-4');
40684 * @param {String/Date} date The date or valid date string
40686 setValue : function(date){
40687 if (this.hiddenField) {
40688 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40690 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40691 // make sure the value field is always stored as a date..
40692 this.value = this.parseDate(date);
40698 parseDate : function(value){
40699 if(!value || value instanceof Date){
40702 var v = Date.parseDate(value, this.format);
40703 if (!v && this.useIso) {
40704 v = Date.parseDate(value, 'Y-m-d');
40706 if(!v && this.altFormats){
40707 if(!this.altFormatsArray){
40708 this.altFormatsArray = this.altFormats.split("|");
40710 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40711 v = Date.parseDate(value, this.altFormatsArray[i]);
40718 formatDate : function(date, fmt){
40719 return (!date || !(date instanceof Date)) ?
40720 date : date.dateFormat(fmt || this.format);
40725 select: function(m, d){
40728 this.fireEvent('select', this, d);
40730 show : function(){ // retain focus styling
40734 this.focus.defer(10, this);
40735 var ml = this.menuListeners;
40736 this.menu.un("select", ml.select, this);
40737 this.menu.un("show", ml.show, this);
40738 this.menu.un("hide", ml.hide, this);
40743 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40744 onTriggerClick : function(){
40748 if(this.menu == null){
40749 this.menu = new Roo.menu.DateMenu();
40751 Roo.apply(this.menu.picker, {
40752 showClear: this.allowBlank,
40753 minDate : this.minValue,
40754 maxDate : this.maxValue,
40755 disabledDatesRE : this.ddMatch,
40756 disabledDatesText : this.disabledDatesText,
40757 disabledDays : this.disabledDays,
40758 disabledDaysText : this.disabledDaysText,
40759 format : this.useIso ? 'Y-m-d' : this.format,
40760 minText : String.format(this.minText, this.formatDate(this.minValue)),
40761 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40763 this.menu.on(Roo.apply({}, this.menuListeners, {
40766 this.menu.picker.setValue(this.getValue() || new Date());
40767 this.menu.show(this.el, "tl-bl?");
40770 beforeBlur : function(){
40771 var v = this.parseDate(this.getRawValue());
40781 isDirty : function() {
40782 if(this.disabled) {
40786 if(typeof(this.startValue) === 'undefined'){
40790 return String(this.getValue()) !== String(this.startValue);
40794 cleanLeadingSpace : function(e)
40801 * Ext JS Library 1.1.1
40802 * Copyright(c) 2006-2007, Ext JS, LLC.
40804 * Originally Released Under LGPL - original licence link has changed is not relivant.
40807 * <script type="text/javascript">
40811 * @class Roo.form.MonthField
40812 * @extends Roo.form.TriggerField
40813 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40815 * Create a new MonthField
40816 * @param {Object} config
40818 Roo.form.MonthField = function(config){
40820 Roo.form.MonthField.superclass.constructor.call(this, config);
40826 * Fires when a date is selected
40827 * @param {Roo.form.MonthFieeld} combo This combo box
40828 * @param {Date} date The date selected
40835 if(typeof this.minValue == "string") {
40836 this.minValue = this.parseDate(this.minValue);
40838 if(typeof this.maxValue == "string") {
40839 this.maxValue = this.parseDate(this.maxValue);
40841 this.ddMatch = null;
40842 if(this.disabledDates){
40843 var dd = this.disabledDates;
40845 for(var i = 0; i < dd.length; i++){
40847 if(i != dd.length-1) {
40851 this.ddMatch = new RegExp(re + ")");
40855 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40857 * @cfg {String} format
40858 * The default date format string which can be overriden for localization support. The format must be
40859 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40863 * @cfg {String} altFormats
40864 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40865 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40867 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40869 * @cfg {Array} disabledDays
40870 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40872 disabledDays : [0,1,2,3,4,5,6],
40874 * @cfg {String} disabledDaysText
40875 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40877 disabledDaysText : "Disabled",
40879 * @cfg {Array} disabledDates
40880 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40881 * expression so they are very powerful. Some examples:
40883 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40884 * <li>["03/08", "09/16"] would disable those days for every year</li>
40885 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40886 * <li>["03/../2006"] would disable every day in March 2006</li>
40887 * <li>["^03"] would disable every day in every March</li>
40889 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40890 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40892 disabledDates : null,
40894 * @cfg {String} disabledDatesText
40895 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40897 disabledDatesText : "Disabled",
40899 * @cfg {Date/String} minValue
40900 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40901 * valid format (defaults to null).
40905 * @cfg {Date/String} maxValue
40906 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40907 * valid format (defaults to null).
40911 * @cfg {String} minText
40912 * The error text to display when the date in the cell is before minValue (defaults to
40913 * 'The date in this field must be after {minValue}').
40915 minText : "The date in this field must be equal to or after {0}",
40917 * @cfg {String} maxTextf
40918 * The error text to display when the date in the cell is after maxValue (defaults to
40919 * 'The date in this field must be before {maxValue}').
40921 maxText : "The date in this field must be equal to or before {0}",
40923 * @cfg {String} invalidText
40924 * The error text to display when the date in the field is invalid (defaults to
40925 * '{value} is not a valid date - it must be in the format {format}').
40927 invalidText : "{0} is not a valid date - it must be in the format {1}",
40929 * @cfg {String} triggerClass
40930 * An additional CSS class used to style the trigger button. The trigger will always get the
40931 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40932 * which displays a calendar icon).
40934 triggerClass : 'x-form-date-trigger',
40938 * @cfg {Boolean} useIso
40939 * if enabled, then the date field will use a hidden field to store the
40940 * real value as iso formated date. default (true)
40944 * @cfg {String/Object} autoCreate
40945 * A DomHelper element spec, or true for a default element spec (defaults to
40946 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40949 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40952 hiddenField: false,
40954 hideMonthPicker : false,
40956 onRender : function(ct, position)
40958 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40960 this.el.dom.removeAttribute('name');
40961 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40963 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40964 // prevent input submission
40965 this.hiddenName = this.name;
40972 validateValue : function(value)
40974 value = this.formatDate(value);
40975 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40978 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40981 var svalue = value;
40982 value = this.parseDate(value);
40984 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40987 var time = value.getTime();
40988 if(this.minValue && time < this.minValue.getTime()){
40989 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40992 if(this.maxValue && time > this.maxValue.getTime()){
40993 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40996 /*if(this.disabledDays){
40997 var day = value.getDay();
40998 for(var i = 0; i < this.disabledDays.length; i++) {
40999 if(day === this.disabledDays[i]){
41000 this.markInvalid(this.disabledDaysText);
41006 var fvalue = this.formatDate(value);
41007 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41008 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41016 // Provides logic to override the default TriggerField.validateBlur which just returns true
41017 validateBlur : function(){
41018 return !this.menu || !this.menu.isVisible();
41022 * Returns the current date value of the date field.
41023 * @return {Date} The date value
41025 getValue : function(){
41029 return this.hiddenField ?
41030 this.hiddenField.value :
41031 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41035 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41036 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41037 * (the default format used is "m/d/y").
41040 //All of these calls set the same date value (May 4, 2006)
41042 //Pass a date object:
41043 var dt = new Date('5/4/06');
41044 monthField.setValue(dt);
41046 //Pass a date string (default format):
41047 monthField.setValue('5/4/06');
41049 //Pass a date string (custom format):
41050 monthField.format = 'Y-m-d';
41051 monthField.setValue('2006-5-4');
41053 * @param {String/Date} date The date or valid date string
41055 setValue : function(date){
41056 Roo.log('month setValue' + date);
41057 // can only be first of month..
41059 var val = this.parseDate(date);
41061 if (this.hiddenField) {
41062 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41064 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41065 this.value = this.parseDate(date);
41069 parseDate : function(value){
41070 if(!value || value instanceof Date){
41071 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41074 var v = Date.parseDate(value, this.format);
41075 if (!v && this.useIso) {
41076 v = Date.parseDate(value, 'Y-m-d');
41080 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41084 if(!v && this.altFormats){
41085 if(!this.altFormatsArray){
41086 this.altFormatsArray = this.altFormats.split("|");
41088 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41089 v = Date.parseDate(value, this.altFormatsArray[i]);
41096 formatDate : function(date, fmt){
41097 return (!date || !(date instanceof Date)) ?
41098 date : date.dateFormat(fmt || this.format);
41103 select: function(m, d){
41105 this.fireEvent('select', this, d);
41107 show : function(){ // retain focus styling
41111 this.focus.defer(10, this);
41112 var ml = this.menuListeners;
41113 this.menu.un("select", ml.select, this);
41114 this.menu.un("show", ml.show, this);
41115 this.menu.un("hide", ml.hide, this);
41119 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41120 onTriggerClick : function(){
41124 if(this.menu == null){
41125 this.menu = new Roo.menu.DateMenu();
41129 Roo.apply(this.menu.picker, {
41131 showClear: this.allowBlank,
41132 minDate : this.minValue,
41133 maxDate : this.maxValue,
41134 disabledDatesRE : this.ddMatch,
41135 disabledDatesText : this.disabledDatesText,
41137 format : this.useIso ? 'Y-m-d' : this.format,
41138 minText : String.format(this.minText, this.formatDate(this.minValue)),
41139 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41142 this.menu.on(Roo.apply({}, this.menuListeners, {
41150 // hide month picker get's called when we called by 'before hide';
41152 var ignorehide = true;
41153 p.hideMonthPicker = function(disableAnim){
41157 if(this.monthPicker){
41158 Roo.log("hideMonthPicker called");
41159 if(disableAnim === true){
41160 this.monthPicker.hide();
41162 this.monthPicker.slideOut('t', {duration:.2});
41163 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41164 p.fireEvent("select", this, this.value);
41170 Roo.log('picker set value');
41171 Roo.log(this.getValue());
41172 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41173 m.show(this.el, 'tl-bl?');
41174 ignorehide = false;
41175 // this will trigger hideMonthPicker..
41178 // hidden the day picker
41179 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41185 p.showMonthPicker.defer(100, p);
41191 beforeBlur : function(){
41192 var v = this.parseDate(this.getRawValue());
41198 /** @cfg {Boolean} grow @hide */
41199 /** @cfg {Number} growMin @hide */
41200 /** @cfg {Number} growMax @hide */
41207 * Ext JS Library 1.1.1
41208 * Copyright(c) 2006-2007, Ext JS, LLC.
41210 * Originally Released Under LGPL - original licence link has changed is not relivant.
41213 * <script type="text/javascript">
41218 * @class Roo.form.ComboBox
41219 * @extends Roo.form.TriggerField
41220 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41222 * Create a new ComboBox.
41223 * @param {Object} config Configuration options
41225 Roo.form.ComboBox = function(config){
41226 Roo.form.ComboBox.superclass.constructor.call(this, config);
41230 * Fires when the dropdown list is expanded
41231 * @param {Roo.form.ComboBox} combo This combo box
41236 * Fires when the dropdown list is collapsed
41237 * @param {Roo.form.ComboBox} combo This combo box
41241 * @event beforeselect
41242 * Fires before a list item is selected. Return false to cancel the selection.
41243 * @param {Roo.form.ComboBox} combo This combo box
41244 * @param {Roo.data.Record} record The data record returned from the underlying store
41245 * @param {Number} index The index of the selected item in the dropdown list
41247 'beforeselect' : true,
41250 * Fires when a list item is selected
41251 * @param {Roo.form.ComboBox} combo This combo box
41252 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41253 * @param {Number} index The index of the selected item in the dropdown list
41257 * @event beforequery
41258 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41259 * The event object passed has these properties:
41260 * @param {Roo.form.ComboBox} combo This combo box
41261 * @param {String} query The query
41262 * @param {Boolean} forceAll true to force "all" query
41263 * @param {Boolean} cancel true to cancel the query
41264 * @param {Object} e The query event object
41266 'beforequery': true,
41269 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41270 * @param {Roo.form.ComboBox} combo This combo box
41275 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41276 * @param {Roo.form.ComboBox} combo This combo box
41277 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41283 if(this.transform){
41284 this.allowDomMove = false;
41285 var s = Roo.getDom(this.transform);
41286 if(!this.hiddenName){
41287 this.hiddenName = s.name;
41290 this.mode = 'local';
41291 var d = [], opts = s.options;
41292 for(var i = 0, len = opts.length;i < len; i++){
41294 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41296 this.value = value;
41298 d.push([value, o.text]);
41300 this.store = new Roo.data.SimpleStore({
41302 fields: ['value', 'text'],
41305 this.valueField = 'value';
41306 this.displayField = 'text';
41308 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41309 if(!this.lazyRender){
41310 this.target = true;
41311 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41312 s.parentNode.removeChild(s); // remove it
41313 this.render(this.el.parentNode);
41315 s.parentNode.removeChild(s); // remove it
41320 this.store = Roo.factory(this.store, Roo.data);
41323 this.selectedIndex = -1;
41324 if(this.mode == 'local'){
41325 if(config.queryDelay === undefined){
41326 this.queryDelay = 10;
41328 if(config.minChars === undefined){
41334 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41336 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41339 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41340 * rendering into an Roo.Editor, defaults to false)
41343 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41344 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41347 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41350 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41351 * the dropdown list (defaults to undefined, with no header element)
41355 * @cfg {String/Roo.Template} tpl The template to use to render the output
41359 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41361 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41363 listWidth: undefined,
41365 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41366 * mode = 'remote' or 'text' if mode = 'local')
41368 displayField: undefined,
41370 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41371 * mode = 'remote' or 'value' if mode = 'local').
41372 * Note: use of a valueField requires the user make a selection
41373 * in order for a value to be mapped.
41375 valueField: undefined,
41379 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41380 * field's data value (defaults to the underlying DOM element's name)
41382 hiddenName: undefined,
41384 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41388 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41390 selectedClass: 'x-combo-selected',
41392 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41393 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41394 * which displays a downward arrow icon).
41396 triggerClass : 'x-form-arrow-trigger',
41398 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41402 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41403 * anchor positions (defaults to 'tl-bl')
41405 listAlign: 'tl-bl?',
41407 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41411 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41412 * query specified by the allQuery config option (defaults to 'query')
41414 triggerAction: 'query',
41416 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41417 * (defaults to 4, does not apply if editable = false)
41421 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41422 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41426 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41427 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41431 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41432 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41436 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41437 * when editable = true (defaults to false)
41439 selectOnFocus:false,
41441 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41443 queryParam: 'query',
41445 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41446 * when mode = 'remote' (defaults to 'Loading...')
41448 loadingText: 'Loading...',
41450 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41454 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41458 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41459 * traditional select (defaults to true)
41463 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41467 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41471 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41472 * listWidth has a higher value)
41476 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41477 * allow the user to set arbitrary text into the field (defaults to false)
41479 forceSelection:false,
41481 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41482 * if typeAhead = true (defaults to 250)
41484 typeAheadDelay : 250,
41486 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41487 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41489 valueNotFoundText : undefined,
41491 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41493 blockFocus : false,
41496 * @cfg {Boolean} disableClear Disable showing of clear button.
41498 disableClear : false,
41500 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41502 alwaysQuery : false,
41508 // element that contains real text value.. (when hidden is used..)
41511 onRender : function(ct, position)
41513 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41515 if(this.hiddenName){
41516 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41518 this.hiddenField.value =
41519 this.hiddenValue !== undefined ? this.hiddenValue :
41520 this.value !== undefined ? this.value : '';
41522 // prevent input submission
41523 this.el.dom.removeAttribute('name');
41529 this.el.dom.setAttribute('autocomplete', 'off');
41532 var cls = 'x-combo-list';
41534 this.list = new Roo.Layer({
41535 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41538 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41539 this.list.setWidth(lw);
41540 this.list.swallowEvent('mousewheel');
41541 this.assetHeight = 0;
41544 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41545 this.assetHeight += this.header.getHeight();
41548 this.innerList = this.list.createChild({cls:cls+'-inner'});
41549 this.innerList.on('mouseover', this.onViewOver, this);
41550 this.innerList.on('mousemove', this.onViewMove, this);
41551 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41553 if(this.allowBlank && !this.pageSize && !this.disableClear){
41554 this.footer = this.list.createChild({cls:cls+'-ft'});
41555 this.pageTb = new Roo.Toolbar(this.footer);
41559 this.footer = this.list.createChild({cls:cls+'-ft'});
41560 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41561 {pageSize: this.pageSize});
41565 if (this.pageTb && this.allowBlank && !this.disableClear) {
41567 this.pageTb.add(new Roo.Toolbar.Fill(), {
41568 cls: 'x-btn-icon x-btn-clear',
41570 handler: function()
41573 _this.clearValue();
41574 _this.onSelect(false, -1);
41579 this.assetHeight += this.footer.getHeight();
41584 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41587 this.view = new Roo.View(this.innerList, this.tpl, {
41590 selectedClass: this.selectedClass
41593 this.view.on('click', this.onViewClick, this);
41595 this.store.on('beforeload', this.onBeforeLoad, this);
41596 this.store.on('load', this.onLoad, this);
41597 this.store.on('loadexception', this.onLoadException, this);
41599 if(this.resizable){
41600 this.resizer = new Roo.Resizable(this.list, {
41601 pinned:true, handles:'se'
41603 this.resizer.on('resize', function(r, w, h){
41604 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41605 this.listWidth = w;
41606 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41607 this.restrictHeight();
41609 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41611 if(!this.editable){
41612 this.editable = true;
41613 this.setEditable(false);
41617 if (typeof(this.events.add.listeners) != 'undefined') {
41619 this.addicon = this.wrap.createChild(
41620 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41622 this.addicon.on('click', function(e) {
41623 this.fireEvent('add', this);
41626 if (typeof(this.events.edit.listeners) != 'undefined') {
41628 this.editicon = this.wrap.createChild(
41629 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41630 if (this.addicon) {
41631 this.editicon.setStyle('margin-left', '40px');
41633 this.editicon.on('click', function(e) {
41635 // we fire even if inothing is selected..
41636 this.fireEvent('edit', this, this.lastData );
41646 initEvents : function(){
41647 Roo.form.ComboBox.superclass.initEvents.call(this);
41649 this.keyNav = new Roo.KeyNav(this.el, {
41650 "up" : function(e){
41651 this.inKeyMode = true;
41655 "down" : function(e){
41656 if(!this.isExpanded()){
41657 this.onTriggerClick();
41659 this.inKeyMode = true;
41664 "enter" : function(e){
41665 this.onViewClick();
41669 "esc" : function(e){
41673 "tab" : function(e){
41674 this.onViewClick(false);
41675 this.fireEvent("specialkey", this, e);
41681 doRelay : function(foo, bar, hname){
41682 if(hname == 'down' || this.scope.isExpanded()){
41683 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41690 this.queryDelay = Math.max(this.queryDelay || 10,
41691 this.mode == 'local' ? 10 : 250);
41692 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41693 if(this.typeAhead){
41694 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41696 if(this.editable !== false){
41697 this.el.on("keyup", this.onKeyUp, this);
41699 if(this.forceSelection){
41700 this.on('blur', this.doForce, this);
41704 onDestroy : function(){
41706 this.view.setStore(null);
41707 this.view.el.removeAllListeners();
41708 this.view.el.remove();
41709 this.view.purgeListeners();
41712 this.list.destroy();
41715 this.store.un('beforeload', this.onBeforeLoad, this);
41716 this.store.un('load', this.onLoad, this);
41717 this.store.un('loadexception', this.onLoadException, this);
41719 Roo.form.ComboBox.superclass.onDestroy.call(this);
41723 fireKey : function(e){
41724 if(e.isNavKeyPress() && !this.list.isVisible()){
41725 this.fireEvent("specialkey", this, e);
41730 onResize: function(w, h){
41731 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41733 if(typeof w != 'number'){
41734 // we do not handle it!?!?
41737 var tw = this.trigger.getWidth();
41738 tw += this.addicon ? this.addicon.getWidth() : 0;
41739 tw += this.editicon ? this.editicon.getWidth() : 0;
41741 this.el.setWidth( this.adjustWidth('input', x));
41743 this.trigger.setStyle('left', x+'px');
41745 if(this.list && this.listWidth === undefined){
41746 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41747 this.list.setWidth(lw);
41748 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41756 * Allow or prevent the user from directly editing the field text. If false is passed,
41757 * the user will only be able to select from the items defined in the dropdown list. This method
41758 * is the runtime equivalent of setting the 'editable' config option at config time.
41759 * @param {Boolean} value True to allow the user to directly edit the field text
41761 setEditable : function(value){
41762 if(value == this.editable){
41765 this.editable = value;
41767 this.el.dom.setAttribute('readOnly', true);
41768 this.el.on('mousedown', this.onTriggerClick, this);
41769 this.el.addClass('x-combo-noedit');
41771 this.el.dom.setAttribute('readOnly', false);
41772 this.el.un('mousedown', this.onTriggerClick, this);
41773 this.el.removeClass('x-combo-noedit');
41778 onBeforeLoad : function(){
41779 if(!this.hasFocus){
41782 this.innerList.update(this.loadingText ?
41783 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41784 this.restrictHeight();
41785 this.selectedIndex = -1;
41789 onLoad : function(){
41790 if(!this.hasFocus){
41793 if(this.store.getCount() > 0){
41795 this.restrictHeight();
41796 if(this.lastQuery == this.allQuery){
41798 this.el.dom.select();
41800 if(!this.selectByValue(this.value, true)){
41801 this.select(0, true);
41805 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41806 this.taTask.delay(this.typeAheadDelay);
41810 this.onEmptyResults();
41815 onLoadException : function()
41818 Roo.log(this.store.reader.jsonData);
41819 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41820 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41826 onTypeAhead : function(){
41827 if(this.store.getCount() > 0){
41828 var r = this.store.getAt(0);
41829 var newValue = r.data[this.displayField];
41830 var len = newValue.length;
41831 var selStart = this.getRawValue().length;
41832 if(selStart != len){
41833 this.setRawValue(newValue);
41834 this.selectText(selStart, newValue.length);
41840 onSelect : function(record, index){
41841 if(this.fireEvent('beforeselect', this, record, index) !== false){
41842 this.setFromData(index > -1 ? record.data : false);
41844 this.fireEvent('select', this, record, index);
41849 * Returns the currently selected field value or empty string if no value is set.
41850 * @return {String} value The selected value
41852 getValue : function(){
41853 if(this.valueField){
41854 return typeof this.value != 'undefined' ? this.value : '';
41856 return Roo.form.ComboBox.superclass.getValue.call(this);
41860 * Clears any text/value currently set in the field
41862 clearValue : function(){
41863 if(this.hiddenField){
41864 this.hiddenField.value = '';
41867 this.setRawValue('');
41868 this.lastSelectionText = '';
41873 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41874 * will be displayed in the field. If the value does not match the data value of an existing item,
41875 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41876 * Otherwise the field will be blank (although the value will still be set).
41877 * @param {String} value The value to match
41879 setValue : function(v){
41881 if(this.valueField){
41882 var r = this.findRecord(this.valueField, v);
41884 text = r.data[this.displayField];
41885 }else if(this.valueNotFoundText !== undefined){
41886 text = this.valueNotFoundText;
41889 this.lastSelectionText = text;
41890 if(this.hiddenField){
41891 this.hiddenField.value = v;
41893 Roo.form.ComboBox.superclass.setValue.call(this, text);
41897 * @property {Object} the last set data for the element
41902 * Sets the value of the field based on a object which is related to the record format for the store.
41903 * @param {Object} value the value to set as. or false on reset?
41905 setFromData : function(o){
41906 var dv = ''; // display value
41907 var vv = ''; // value value..
41909 if (this.displayField) {
41910 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41912 // this is an error condition!!!
41913 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41916 if(this.valueField){
41917 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41919 if(this.hiddenField){
41920 this.hiddenField.value = vv;
41922 this.lastSelectionText = dv;
41923 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41927 // no hidden field.. - we store the value in 'value', but still display
41928 // display field!!!!
41929 this.lastSelectionText = dv;
41930 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41936 reset : function(){
41937 // overridden so that last data is reset..
41938 this.setValue(this.resetValue);
41939 this.originalValue = this.getValue();
41940 this.clearInvalid();
41941 this.lastData = false;
41943 this.view.clearSelections();
41947 findRecord : function(prop, value){
41949 if(this.store.getCount() > 0){
41950 this.store.each(function(r){
41951 if(r.data[prop] == value){
41961 getName: function()
41963 // returns hidden if it's set..
41964 if (!this.rendered) {return ''};
41965 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41969 onViewMove : function(e, t){
41970 this.inKeyMode = false;
41974 onViewOver : function(e, t){
41975 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41978 var item = this.view.findItemFromChild(t);
41980 var index = this.view.indexOf(item);
41981 this.select(index, false);
41986 onViewClick : function(doFocus)
41988 var index = this.view.getSelectedIndexes()[0];
41989 var r = this.store.getAt(index);
41991 this.onSelect(r, index);
41993 if(doFocus !== false && !this.blockFocus){
41999 restrictHeight : function(){
42000 this.innerList.dom.style.height = '';
42001 var inner = this.innerList.dom;
42002 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42003 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42004 this.list.beginUpdate();
42005 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42006 this.list.alignTo(this.el, this.listAlign);
42007 this.list.endUpdate();
42011 onEmptyResults : function(){
42016 * Returns true if the dropdown list is expanded, else false.
42018 isExpanded : function(){
42019 return this.list.isVisible();
42023 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42024 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42025 * @param {String} value The data value of the item to select
42026 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42027 * selected item if it is not currently in view (defaults to true)
42028 * @return {Boolean} True if the value matched an item in the list, else false
42030 selectByValue : function(v, scrollIntoView){
42031 if(v !== undefined && v !== null){
42032 var r = this.findRecord(this.valueField || this.displayField, v);
42034 this.select(this.store.indexOf(r), scrollIntoView);
42042 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42043 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42044 * @param {Number} index The zero-based index of the list item to select
42045 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42046 * selected item if it is not currently in view (defaults to true)
42048 select : function(index, scrollIntoView){
42049 this.selectedIndex = index;
42050 this.view.select(index);
42051 if(scrollIntoView !== false){
42052 var el = this.view.getNode(index);
42054 this.innerList.scrollChildIntoView(el, false);
42060 selectNext : function(){
42061 var ct = this.store.getCount();
42063 if(this.selectedIndex == -1){
42065 }else if(this.selectedIndex < ct-1){
42066 this.select(this.selectedIndex+1);
42072 selectPrev : function(){
42073 var ct = this.store.getCount();
42075 if(this.selectedIndex == -1){
42077 }else if(this.selectedIndex != 0){
42078 this.select(this.selectedIndex-1);
42084 onKeyUp : function(e){
42085 if(this.editable !== false && !e.isSpecialKey()){
42086 this.lastKey = e.getKey();
42087 this.dqTask.delay(this.queryDelay);
42092 validateBlur : function(){
42093 return !this.list || !this.list.isVisible();
42097 initQuery : function(){
42098 this.doQuery(this.getRawValue());
42102 doForce : function(){
42103 if(this.el.dom.value.length > 0){
42104 this.el.dom.value =
42105 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42111 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42112 * query allowing the query action to be canceled if needed.
42113 * @param {String} query The SQL query to execute
42114 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42115 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42116 * saved in the current store (defaults to false)
42118 doQuery : function(q, forceAll){
42119 if(q === undefined || q === null){
42124 forceAll: forceAll,
42128 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42132 forceAll = qe.forceAll;
42133 if(forceAll === true || (q.length >= this.minChars)){
42134 if(this.lastQuery != q || this.alwaysQuery){
42135 this.lastQuery = q;
42136 if(this.mode == 'local'){
42137 this.selectedIndex = -1;
42139 this.store.clearFilter();
42141 this.store.filter(this.displayField, q);
42145 this.store.baseParams[this.queryParam] = q;
42147 params: this.getParams(q)
42152 this.selectedIndex = -1;
42159 getParams : function(q){
42161 //p[this.queryParam] = q;
42164 p.limit = this.pageSize;
42170 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42172 collapse : function(){
42173 if(!this.isExpanded()){
42177 Roo.get(document).un('mousedown', this.collapseIf, this);
42178 Roo.get(document).un('mousewheel', this.collapseIf, this);
42179 if (!this.editable) {
42180 Roo.get(document).un('keydown', this.listKeyPress, this);
42182 this.fireEvent('collapse', this);
42186 collapseIf : function(e){
42187 if(!e.within(this.wrap) && !e.within(this.list)){
42193 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42195 expand : function(){
42196 if(this.isExpanded() || !this.hasFocus){
42199 this.list.alignTo(this.el, this.listAlign);
42201 Roo.get(document).on('mousedown', this.collapseIf, this);
42202 Roo.get(document).on('mousewheel', this.collapseIf, this);
42203 if (!this.editable) {
42204 Roo.get(document).on('keydown', this.listKeyPress, this);
42207 this.fireEvent('expand', this);
42211 // Implements the default empty TriggerField.onTriggerClick function
42212 onTriggerClick : function(){
42216 if(this.isExpanded()){
42218 if (!this.blockFocus) {
42223 this.hasFocus = true;
42224 if(this.triggerAction == 'all') {
42225 this.doQuery(this.allQuery, true);
42227 this.doQuery(this.getRawValue());
42229 if (!this.blockFocus) {
42234 listKeyPress : function(e)
42236 //Roo.log('listkeypress');
42237 // scroll to first matching element based on key pres..
42238 if (e.isSpecialKey()) {
42241 var k = String.fromCharCode(e.getKey()).toUpperCase();
42244 var csel = this.view.getSelectedNodes();
42245 var cselitem = false;
42247 var ix = this.view.indexOf(csel[0]);
42248 cselitem = this.store.getAt(ix);
42249 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42255 this.store.each(function(v) {
42257 // start at existing selection.
42258 if (cselitem.id == v.id) {
42264 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42265 match = this.store.indexOf(v);
42270 if (match === false) {
42271 return true; // no more action?
42274 this.view.select(match);
42275 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42276 sn.scrollIntoView(sn.dom.parentNode, false);
42280 * @cfg {Boolean} grow
42284 * @cfg {Number} growMin
42288 * @cfg {Number} growMax
42296 * Copyright(c) 2010-2012, Roo J Solutions Limited
42303 * @class Roo.form.ComboBoxArray
42304 * @extends Roo.form.TextField
42305 * A facebook style adder... for lists of email / people / countries etc...
42306 * pick multiple items from a combo box, and shows each one.
42308 * Fred [x] Brian [x] [Pick another |v]
42311 * For this to work: it needs various extra information
42312 * - normal combo problay has
42314 * + displayField, valueField
42316 * For our purpose...
42319 * If we change from 'extends' to wrapping...
42326 * Create a new ComboBoxArray.
42327 * @param {Object} config Configuration options
42331 Roo.form.ComboBoxArray = function(config)
42335 * @event beforeremove
42336 * Fires before remove the value from the list
42337 * @param {Roo.form.ComboBoxArray} _self This combo box array
42338 * @param {Roo.form.ComboBoxArray.Item} item removed item
42340 'beforeremove' : true,
42343 * Fires when remove the value from the list
42344 * @param {Roo.form.ComboBoxArray} _self This combo box array
42345 * @param {Roo.form.ComboBoxArray.Item} item removed item
42352 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42354 this.items = new Roo.util.MixedCollection(false);
42356 // construct the child combo...
42366 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42369 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42374 // behavies liek a hiddne field
42375 inputType: 'hidden',
42377 * @cfg {Number} width The width of the box that displays the selected element
42384 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42388 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42390 hiddenName : false,
42392 * @cfg {String} seperator The value seperator normally ','
42396 // private the array of items that are displayed..
42398 // private - the hidden field el.
42400 // private - the filed el..
42403 //validateValue : function() { return true; }, // all values are ok!
42404 //onAddClick: function() { },
42406 onRender : function(ct, position)
42409 // create the standard hidden element
42410 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42413 // give fake names to child combo;
42414 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42415 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42417 this.combo = Roo.factory(this.combo, Roo.form);
42418 this.combo.onRender(ct, position);
42419 if (typeof(this.combo.width) != 'undefined') {
42420 this.combo.onResize(this.combo.width,0);
42423 this.combo.initEvents();
42425 // assigned so form know we need to do this..
42426 this.store = this.combo.store;
42427 this.valueField = this.combo.valueField;
42428 this.displayField = this.combo.displayField ;
42431 this.combo.wrap.addClass('x-cbarray-grp');
42433 var cbwrap = this.combo.wrap.createChild(
42434 {tag: 'div', cls: 'x-cbarray-cb'},
42439 this.hiddenEl = this.combo.wrap.createChild({
42440 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42442 this.el = this.combo.wrap.createChild({
42443 tag: 'input', type:'hidden' , name: this.name, value : ''
42445 // this.el.dom.removeAttribute("name");
42448 this.outerWrap = this.combo.wrap;
42449 this.wrap = cbwrap;
42451 this.outerWrap.setWidth(this.width);
42452 this.outerWrap.dom.removeChild(this.el.dom);
42454 this.wrap.dom.appendChild(this.el.dom);
42455 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42456 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42458 this.combo.trigger.setStyle('position','relative');
42459 this.combo.trigger.setStyle('left', '0px');
42460 this.combo.trigger.setStyle('top', '2px');
42462 this.combo.el.setStyle('vertical-align', 'text-bottom');
42464 //this.trigger.setStyle('vertical-align', 'top');
42466 // this should use the code from combo really... on('add' ....)
42470 this.adder = this.outerWrap.createChild(
42471 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42473 this.adder.on('click', function(e) {
42474 _t.fireEvent('adderclick', this, e);
42478 //this.adder.on('click', this.onAddClick, _t);
42481 this.combo.on('select', function(cb, rec, ix) {
42482 this.addItem(rec.data);
42485 cb.el.dom.value = '';
42486 //cb.lastData = rec.data;
42495 getName: function()
42497 // returns hidden if it's set..
42498 if (!this.rendered) {return ''};
42499 return this.hiddenName ? this.hiddenName : this.name;
42504 onResize: function(w, h){
42507 // not sure if this is needed..
42508 //this.combo.onResize(w,h);
42510 if(typeof w != 'number'){
42511 // we do not handle it!?!?
42514 var tw = this.combo.trigger.getWidth();
42515 tw += this.addicon ? this.addicon.getWidth() : 0;
42516 tw += this.editicon ? this.editicon.getWidth() : 0;
42518 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42520 this.combo.trigger.setStyle('left', '0px');
42522 if(this.list && this.listWidth === undefined){
42523 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42524 this.list.setWidth(lw);
42525 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42532 addItem: function(rec)
42534 var valueField = this.combo.valueField;
42535 var displayField = this.combo.displayField;
42537 if (this.items.indexOfKey(rec[valueField]) > -1) {
42538 //console.log("GOT " + rec.data.id);
42542 var x = new Roo.form.ComboBoxArray.Item({
42543 //id : rec[this.idField],
42545 displayField : displayField ,
42546 tipField : displayField ,
42550 this.items.add(rec[valueField],x);
42551 // add it before the element..
42552 this.updateHiddenEl();
42553 x.render(this.outerWrap, this.wrap.dom);
42554 // add the image handler..
42557 updateHiddenEl : function()
42560 if (!this.hiddenEl) {
42564 var idField = this.combo.valueField;
42566 this.items.each(function(f) {
42567 ar.push(f.data[idField]);
42569 this.hiddenEl.dom.value = ar.join(this.seperator);
42575 this.items.clear();
42577 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42581 this.el.dom.value = '';
42582 if (this.hiddenEl) {
42583 this.hiddenEl.dom.value = '';
42587 getValue: function()
42589 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42591 setValue: function(v) // not a valid action - must use addItems..
42596 if (this.store.isLocal && (typeof(v) == 'string')) {
42597 // then we can use the store to find the values..
42598 // comma seperated at present.. this needs to allow JSON based encoding..
42599 this.hiddenEl.value = v;
42601 Roo.each(v.split(this.seperator), function(k) {
42602 Roo.log("CHECK " + this.valueField + ',' + k);
42603 var li = this.store.query(this.valueField, k);
42608 add[this.valueField] = k;
42609 add[this.displayField] = li.item(0).data[this.displayField];
42615 if (typeof(v) == 'object' ) {
42616 // then let's assume it's an array of objects..
42617 Roo.each(v, function(l) {
42619 if (typeof(l) == 'string') {
42621 add[this.valueField] = l;
42622 add[this.displayField] = l
42631 setFromData: function(v)
42633 // this recieves an object, if setValues is called.
42635 this.el.dom.value = v[this.displayField];
42636 this.hiddenEl.dom.value = v[this.valueField];
42637 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42640 var kv = v[this.valueField];
42641 var dv = v[this.displayField];
42642 kv = typeof(kv) != 'string' ? '' : kv;
42643 dv = typeof(dv) != 'string' ? '' : dv;
42646 var keys = kv.split(this.seperator);
42647 var display = dv.split(this.seperator);
42648 for (var i = 0 ; i < keys.length; i++) {
42650 add[this.valueField] = keys[i];
42651 add[this.displayField] = display[i];
42659 * Validates the combox array value
42660 * @return {Boolean} True if the value is valid, else false
42662 validate : function(){
42663 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42664 this.clearInvalid();
42670 validateValue : function(value){
42671 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42679 isDirty : function() {
42680 if(this.disabled) {
42685 var d = Roo.decode(String(this.originalValue));
42687 return String(this.getValue()) !== String(this.originalValue);
42690 var originalValue = [];
42692 for (var i = 0; i < d.length; i++){
42693 originalValue.push(d[i][this.valueField]);
42696 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42705 * @class Roo.form.ComboBoxArray.Item
42706 * @extends Roo.BoxComponent
42707 * A selected item in the list
42708 * Fred [x] Brian [x] [Pick another |v]
42711 * Create a new item.
42712 * @param {Object} config Configuration options
42715 Roo.form.ComboBoxArray.Item = function(config) {
42716 config.id = Roo.id();
42717 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42720 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42723 displayField : false,
42727 defaultAutoCreate : {
42729 cls: 'x-cbarray-item',
42736 src : Roo.BLANK_IMAGE_URL ,
42744 onRender : function(ct, position)
42746 Roo.form.Field.superclass.onRender.call(this, ct, position);
42749 var cfg = this.getAutoCreate();
42750 this.el = ct.createChild(cfg, position);
42753 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42755 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42756 this.cb.renderer(this.data) :
42757 String.format('{0}',this.data[this.displayField]);
42760 this.el.child('div').dom.setAttribute('qtip',
42761 String.format('{0}',this.data[this.tipField])
42764 this.el.child('img').on('click', this.remove, this);
42768 remove : function()
42770 if(this.cb.disabled){
42774 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42775 this.cb.items.remove(this);
42776 this.el.child('img').un('click', this.remove, this);
42778 this.cb.updateHiddenEl();
42780 this.cb.fireEvent('remove', this.cb, this);
42785 * RooJS Library 1.1.1
42786 * Copyright(c) 2008-2011 Alan Knowles
42793 * @class Roo.form.ComboNested
42794 * @extends Roo.form.ComboBox
42795 * A combobox for that allows selection of nested items in a list,
42810 * Create a new ComboNested
42811 * @param {Object} config Configuration options
42813 Roo.form.ComboNested = function(config){
42814 Roo.form.ComboCheck.superclass.constructor.call(this, config);
42815 // should verify some data...
42817 // hiddenName = required..
42818 // displayField = required
42819 // valudField == required
42820 var req= [ 'hiddenName', 'displayField', 'valueField' ];
42822 Roo.each(req, function(e) {
42823 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
42824 throw "Roo.form.ComboNested : missing value for: " + e;
42831 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
42834 * @config {Number} max Number of columns to show
42839 list : null, // the outermost div..
42840 innerLists : null, // the
42844 loadingChildren : false,
42846 onRender : function(ct, position)
42848 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
42850 if(this.hiddenName){
42851 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42853 this.hiddenField.value =
42854 this.hiddenValue !== undefined ? this.hiddenValue :
42855 this.value !== undefined ? this.value : '';
42857 // prevent input submission
42858 this.el.dom.removeAttribute('name');
42864 this.el.dom.setAttribute('autocomplete', 'off');
42867 var cls = 'x-combo-list';
42869 this.list = new Roo.Layer({
42870 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
42873 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
42874 this.list.setWidth(lw);
42875 this.list.swallowEvent('mousewheel');
42876 this.assetHeight = 0;
42879 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
42880 this.assetHeight += this.header.getHeight();
42882 this.innerLists = [];
42885 for (var i =0 ; i < this.maxColumns; i++) {
42886 this.onRenderList( cls, i);
42889 // always needs footer, as we are going to have an 'OK' button.
42890 this.footer = this.list.createChild({cls:cls+'-ft'});
42891 this.pageTb = new Roo.Toolbar(this.footer);
42896 handler: function()
42902 if ( this.allowBlank && !this.disableClear) {
42904 this.pageTb.add(new Roo.Toolbar.Fill(), {
42905 cls: 'x-btn-icon x-btn-clear',
42907 handler: function()
42910 _this.clearValue();
42911 _this.onSelect(false, -1);
42916 this.assetHeight += this.footer.getHeight();
42920 onRenderList : function ( cls, i)
42923 var lw = Math.floor(
42924 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
42927 this.list.setWidth(lw); // default to '1'
42929 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
42930 //il.on('mouseover', this.onViewOver, this, { list: i });
42931 //il.on('mousemove', this.onViewMove, this, { list: i });
42933 il.setStyle({ 'overflow-x' : 'hidden'});
42936 this.tpl = new Roo.Template({
42937 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
42938 isEmpty: function (value, allValues) {
42940 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
42941 return dl ? 'has-children' : 'no-children'
42946 var store = this.store;
42948 store = new Roo.data.SimpleStore({
42949 //fields : this.store.reader.meta.fields,
42950 reader : this.store.reader,
42954 this.stores[i] = store;
42956 var view = this.views[i] = new Roo.View(
42962 selectedClass: this.selectedClass
42965 view.getEl().setWidth(lw);
42966 view.getEl().setStyle({
42967 position: i < 1 ? 'relative' : 'absolute',
42969 left: (i * lw ) + 'px',
42970 display : i > 0 ? 'none' : 'block'
42972 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
42973 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
42974 //view.on('click', this.onViewClick, this, { list : i });
42976 store.on('beforeload', this.onBeforeLoad, this);
42977 store.on('load', this.onLoad, this, { list : i});
42978 store.on('loadexception', this.onLoadException, this);
42980 // hide the other vies..
42986 restrictHeight : function()
42989 Roo.each(this.innerLists, function(il,i) {
42990 var el = this.views[i].getEl();
42991 el.dom.style.height = '';
42992 var inner = el.dom;
42993 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
42994 // only adjust heights on other ones..
42995 mh = Math.max(h, mh);
42998 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42999 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43006 this.list.beginUpdate();
43007 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43008 this.list.alignTo(this.el, this.listAlign);
43009 this.list.endUpdate();
43014 // -- store handlers..
43016 onBeforeLoad : function()
43018 if(!this.hasFocus){
43021 this.innerLists[0].update(this.loadingText ?
43022 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43023 this.restrictHeight();
43024 this.selectedIndex = -1;
43027 onLoad : function(a,b,c,d)
43029 if (!this.loadingChildren) {
43030 // then we are loading the top level. - hide the children
43031 for (var i = 1;i < this.views.length; i++) {
43032 this.views[i].getEl().setStyle({ display : 'none' });
43034 var lw = Math.floor(
43035 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43038 this.list.setWidth(lw); // default to '1'
43042 if(!this.hasFocus){
43046 if(this.store.getCount() > 0) {
43048 this.restrictHeight();
43050 this.onEmptyResults();
43053 if (!this.loadingChildren) {
43054 this.selectActive();
43057 this.stores[1].loadData([]);
43058 this.stores[2].loadData([]);
43067 onLoadException : function()
43070 Roo.log(this.store.reader.jsonData);
43071 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43072 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43077 // no cleaning of leading spaces on blur here.
43078 cleanLeadingSpace : function(e) { },
43081 onSelectChange : function (view, sels, opts )
43083 var ix = view.getSelectedIndexes();
43085 if (opts.list > this.maxColumns - 2) {
43086 if (view.store.getCount()< 1) {
43087 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43091 // used to clear ?? but if we are loading unselected
43092 this.setFromData(view.store.getAt(ix[0]).data);
43101 // this get's fired when trigger opens..
43102 // this.setFromData({});
43103 var str = this.stores[opts.list+1];
43104 str.data.clear(); // removeall wihtout the fire events..
43108 var rec = view.store.getAt(ix[0]);
43110 this.setFromData(rec.data);
43111 this.fireEvent('select', this, rec, ix[0]);
43113 var lw = Math.floor(
43115 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43116 ) / this.maxColumns
43118 this.loadingChildren = true;
43119 this.stores[opts.list+1].loadDataFromChildren( rec );
43120 this.loadingChildren = false;
43121 var dl = this.stores[opts.list+1]. getTotalCount();
43123 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43125 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43126 for (var i = opts.list+2; i < this.views.length;i++) {
43127 this.views[i].getEl().setStyle({ display : 'none' });
43130 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43131 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43133 if (this.isLoading) {
43134 // this.selectActive(opts.list);
43142 onDoubleClick : function()
43144 this.collapse(); //??
43152 recordToStack : function(store, prop, value, stack)
43154 var cstore = new Roo.data.SimpleStore({
43155 //fields : this.store.reader.meta.fields, // we need array reader.. for
43156 reader : this.store.reader,
43160 var record = false;
43162 if(store.getCount() < 1){
43165 store.each(function(r){
43166 if(r.data[prop] == value){
43171 if (r.data.cn && r.data.cn.length) {
43172 cstore.loadDataFromChildren( r);
43173 var cret = _this.recordToStack(cstore, prop, value, stack);
43174 if (cret !== false) {
43183 if (record == false) {
43186 stack.unshift(srec);
43191 * find the stack of stores that match our value.
43196 selectActive : function ()
43198 // if store is not loaded, then we will need to wait for that to happen first.
43200 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43201 for (var i = 0; i < stack.length; i++ ) {
43202 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43214 * Ext JS Library 1.1.1
43215 * Copyright(c) 2006-2007, Ext JS, LLC.
43217 * Originally Released Under LGPL - original licence link has changed is not relivant.
43220 * <script type="text/javascript">
43223 * @class Roo.form.Checkbox
43224 * @extends Roo.form.Field
43225 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43227 * Creates a new Checkbox
43228 * @param {Object} config Configuration options
43230 Roo.form.Checkbox = function(config){
43231 Roo.form.Checkbox.superclass.constructor.call(this, config);
43235 * Fires when the checkbox is checked or unchecked.
43236 * @param {Roo.form.Checkbox} this This checkbox
43237 * @param {Boolean} checked The new checked value
43243 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43245 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43247 focusClass : undefined,
43249 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43251 fieldClass: "x-form-field",
43253 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43257 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43258 * {tag: "input", type: "checkbox", autocomplete: "off"})
43260 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43262 * @cfg {String} boxLabel The text that appears beside the checkbox
43266 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43270 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43272 valueOff: '0', // value when not checked..
43274 actionMode : 'viewEl',
43277 itemCls : 'x-menu-check-item x-form-item',
43278 groupClass : 'x-menu-group-item',
43279 inputType : 'hidden',
43282 inSetChecked: false, // check that we are not calling self...
43284 inputElement: false, // real input element?
43285 basedOn: false, // ????
43287 isFormField: true, // not sure where this is needed!!!!
43289 onResize : function(){
43290 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43291 if(!this.boxLabel){
43292 this.el.alignTo(this.wrap, 'c-c');
43296 initEvents : function(){
43297 Roo.form.Checkbox.superclass.initEvents.call(this);
43298 this.el.on("click", this.onClick, this);
43299 this.el.on("change", this.onClick, this);
43303 getResizeEl : function(){
43307 getPositionEl : function(){
43312 onRender : function(ct, position){
43313 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43315 if(this.inputValue !== undefined){
43316 this.el.dom.value = this.inputValue;
43319 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43320 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43321 var viewEl = this.wrap.createChild({
43322 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43323 this.viewEl = viewEl;
43324 this.wrap.on('click', this.onClick, this);
43326 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43327 this.el.on('propertychange', this.setFromHidden, this); //ie
43332 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43333 // viewEl.on('click', this.onClick, this);
43335 //if(this.checked){
43336 this.setChecked(this.checked);
43338 //this.checked = this.el.dom;
43344 initValue : Roo.emptyFn,
43347 * Returns the checked state of the checkbox.
43348 * @return {Boolean} True if checked, else false
43350 getValue : function(){
43352 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43354 return this.valueOff;
43359 onClick : function(){
43360 if (this.disabled) {
43363 this.setChecked(!this.checked);
43365 //if(this.el.dom.checked != this.checked){
43366 // this.setValue(this.el.dom.checked);
43371 * Sets the checked state of the checkbox.
43372 * On is always based on a string comparison between inputValue and the param.
43373 * @param {Boolean/String} value - the value to set
43374 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43376 setValue : function(v,suppressEvent){
43379 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43380 //if(this.el && this.el.dom){
43381 // this.el.dom.checked = this.checked;
43382 // this.el.dom.defaultChecked = this.checked;
43384 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43385 //this.fireEvent("check", this, this.checked);
43388 setChecked : function(state,suppressEvent)
43390 if (this.inSetChecked) {
43391 this.checked = state;
43397 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43399 this.checked = state;
43400 if(suppressEvent !== true){
43401 this.fireEvent('check', this, state);
43403 this.inSetChecked = true;
43404 this.el.dom.value = state ? this.inputValue : this.valueOff;
43405 this.inSetChecked = false;
43408 // handle setting of hidden value by some other method!!?!?
43409 setFromHidden: function()
43414 //console.log("SET FROM HIDDEN");
43415 //alert('setFrom hidden');
43416 this.setValue(this.el.dom.value);
43419 onDestroy : function()
43422 Roo.get(this.viewEl).remove();
43425 Roo.form.Checkbox.superclass.onDestroy.call(this);
43428 setBoxLabel : function(str)
43430 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43435 * Ext JS Library 1.1.1
43436 * Copyright(c) 2006-2007, Ext JS, LLC.
43438 * Originally Released Under LGPL - original licence link has changed is not relivant.
43441 * <script type="text/javascript">
43445 * @class Roo.form.Radio
43446 * @extends Roo.form.Checkbox
43447 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43448 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43450 * Creates a new Radio
43451 * @param {Object} config Configuration options
43453 Roo.form.Radio = function(){
43454 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43456 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43457 inputType: 'radio',
43460 * If this radio is part of a group, it will return the selected value
43463 getGroupValue : function(){
43464 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43468 onRender : function(ct, position){
43469 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43471 if(this.inputValue !== undefined){
43472 this.el.dom.value = this.inputValue;
43475 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43476 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43477 //var viewEl = this.wrap.createChild({
43478 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43479 //this.viewEl = viewEl;
43480 //this.wrap.on('click', this.onClick, this);
43482 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43483 //this.el.on('propertychange', this.setFromHidden, this); //ie
43488 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43489 // viewEl.on('click', this.onClick, this);
43492 this.el.dom.checked = 'checked' ;
43498 });//<script type="text/javascript">
43501 * Based Ext JS Library 1.1.1
43502 * Copyright(c) 2006-2007, Ext JS, LLC.
43508 * @class Roo.HtmlEditorCore
43509 * @extends Roo.Component
43510 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43512 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43515 Roo.HtmlEditorCore = function(config){
43518 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43523 * @event initialize
43524 * Fires when the editor is fully initialized (including the iframe)
43525 * @param {Roo.HtmlEditorCore} this
43530 * Fires when the editor is first receives the focus. Any insertion must wait
43531 * until after this event.
43532 * @param {Roo.HtmlEditorCore} this
43536 * @event beforesync
43537 * Fires before the textarea is updated with content from the editor iframe. Return false
43538 * to cancel the sync.
43539 * @param {Roo.HtmlEditorCore} this
43540 * @param {String} html
43544 * @event beforepush
43545 * Fires before the iframe editor is updated with content from the textarea. Return false
43546 * to cancel the push.
43547 * @param {Roo.HtmlEditorCore} this
43548 * @param {String} html
43553 * Fires when the textarea is updated with content from the editor iframe.
43554 * @param {Roo.HtmlEditorCore} this
43555 * @param {String} html
43560 * Fires when the iframe editor is updated with content from the textarea.
43561 * @param {Roo.HtmlEditorCore} this
43562 * @param {String} html
43567 * @event editorevent
43568 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43569 * @param {Roo.HtmlEditorCore} this
43575 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43577 // defaults : white / black...
43578 this.applyBlacklists();
43585 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43589 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43595 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43600 * @cfg {Number} height (in pixels)
43604 * @cfg {Number} width (in pixels)
43609 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43612 stylesheets: false,
43617 // private properties
43618 validationEvent : false,
43620 initialized : false,
43622 sourceEditMode : false,
43623 onFocus : Roo.emptyFn,
43625 hideMode:'offsets',
43629 // blacklist + whitelisted elements..
43636 * Protected method that will not generally be called directly. It
43637 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43638 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43640 getDocMarkup : function(){
43644 // inherit styels from page...??
43645 if (this.stylesheets === false) {
43647 Roo.get(document.head).select('style').each(function(node) {
43648 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43651 Roo.get(document.head).select('link').each(function(node) {
43652 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43655 } else if (!this.stylesheets.length) {
43657 st = '<style type="text/css">' +
43658 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43661 for (var i in this.stylesheets) {
43662 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43667 st += '<style type="text/css">' +
43668 'IMG { cursor: pointer } ' +
43671 var cls = 'roo-htmleditor-body';
43673 if(this.bodyCls.length){
43674 cls += ' ' + this.bodyCls;
43677 return '<html><head>' + st +
43678 //<style type="text/css">' +
43679 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43681 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43685 onRender : function(ct, position)
43688 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43689 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43692 this.el.dom.style.border = '0 none';
43693 this.el.dom.setAttribute('tabIndex', -1);
43694 this.el.addClass('x-hidden hide');
43698 if(Roo.isIE){ // fix IE 1px bogus margin
43699 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43703 this.frameId = Roo.id();
43707 var iframe = this.owner.wrap.createChild({
43709 cls: 'form-control', // bootstrap..
43711 name: this.frameId,
43712 frameBorder : 'no',
43713 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43718 this.iframe = iframe.dom;
43720 this.assignDocWin();
43722 this.doc.designMode = 'on';
43725 this.doc.write(this.getDocMarkup());
43729 var task = { // must defer to wait for browser to be ready
43731 //console.log("run task?" + this.doc.readyState);
43732 this.assignDocWin();
43733 if(this.doc.body || this.doc.readyState == 'complete'){
43735 this.doc.designMode="on";
43739 Roo.TaskMgr.stop(task);
43740 this.initEditor.defer(10, this);
43747 Roo.TaskMgr.start(task);
43752 onResize : function(w, h)
43754 Roo.log('resize: ' +w + ',' + h );
43755 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43759 if(typeof w == 'number'){
43761 this.iframe.style.width = w + 'px';
43763 if(typeof h == 'number'){
43765 this.iframe.style.height = h + 'px';
43767 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43774 * Toggles the editor between standard and source edit mode.
43775 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43777 toggleSourceEdit : function(sourceEditMode){
43779 this.sourceEditMode = sourceEditMode === true;
43781 if(this.sourceEditMode){
43783 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43786 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43787 //this.iframe.className = '';
43790 //this.setSize(this.owner.wrap.getSize());
43791 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43798 * Protected method that will not generally be called directly. If you need/want
43799 * custom HTML cleanup, this is the method you should override.
43800 * @param {String} html The HTML to be cleaned
43801 * return {String} The cleaned HTML
43803 cleanHtml : function(html){
43804 html = String(html);
43805 if(html.length > 5){
43806 if(Roo.isSafari){ // strip safari nonsense
43807 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43810 if(html == ' '){
43817 * HTML Editor -> Textarea
43818 * Protected method that will not generally be called directly. Syncs the contents
43819 * of the editor iframe with the textarea.
43821 syncValue : function(){
43822 if(this.initialized){
43823 var bd = (this.doc.body || this.doc.documentElement);
43824 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43825 var html = bd.innerHTML;
43827 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43828 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43830 html = '<div style="'+m[0]+'">' + html + '</div>';
43833 html = this.cleanHtml(html);
43834 // fix up the special chars.. normaly like back quotes in word...
43835 // however we do not want to do this with chinese..
43836 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
43838 var cc = match.charCodeAt();
43840 // Get the character value, handling surrogate pairs
43841 if (match.length == 2) {
43842 // It's a surrogate pair, calculate the Unicode code point
43843 var high = match.charCodeAt(0) - 0xD800;
43844 var low = match.charCodeAt(1) - 0xDC00;
43845 cc = (high * 0x400) + low + 0x10000;
43847 (cc >= 0x4E00 && cc < 0xA000 ) ||
43848 (cc >= 0x3400 && cc < 0x4E00 ) ||
43849 (cc >= 0xf900 && cc < 0xfb00 )
43854 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
43855 return "&#" + cc + ";";
43862 if(this.owner.fireEvent('beforesync', this, html) !== false){
43863 this.el.dom.value = html;
43864 this.owner.fireEvent('sync', this, html);
43870 * Protected method that will not generally be called directly. Pushes the value of the textarea
43871 * into the iframe editor.
43873 pushValue : function(){
43874 if(this.initialized){
43875 var v = this.el.dom.value.trim();
43877 // if(v.length < 1){
43881 if(this.owner.fireEvent('beforepush', this, v) !== false){
43882 var d = (this.doc.body || this.doc.documentElement);
43884 this.cleanUpPaste();
43885 this.el.dom.value = d.innerHTML;
43886 this.owner.fireEvent('push', this, v);
43892 deferFocus : function(){
43893 this.focus.defer(10, this);
43897 focus : function(){
43898 if(this.win && !this.sourceEditMode){
43905 assignDocWin: function()
43907 var iframe = this.iframe;
43910 this.doc = iframe.contentWindow.document;
43911 this.win = iframe.contentWindow;
43913 // if (!Roo.get(this.frameId)) {
43916 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43917 // this.win = Roo.get(this.frameId).dom.contentWindow;
43919 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43923 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43924 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43929 initEditor : function(){
43930 //console.log("INIT EDITOR");
43931 this.assignDocWin();
43935 this.doc.designMode="on";
43937 this.doc.write(this.getDocMarkup());
43940 var dbody = (this.doc.body || this.doc.documentElement);
43941 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43942 // this copies styles from the containing element into thsi one..
43943 // not sure why we need all of this..
43944 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43946 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43947 //ss['background-attachment'] = 'fixed'; // w3c
43948 dbody.bgProperties = 'fixed'; // ie
43949 //Roo.DomHelper.applyStyles(dbody, ss);
43950 Roo.EventManager.on(this.doc, {
43951 //'mousedown': this.onEditorEvent,
43952 'mouseup': this.onEditorEvent,
43953 'dblclick': this.onEditorEvent,
43954 'click': this.onEditorEvent,
43955 'keyup': this.onEditorEvent,
43960 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43962 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43963 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43965 this.initialized = true;
43967 this.owner.fireEvent('initialize', this);
43972 onDestroy : function(){
43978 //for (var i =0; i < this.toolbars.length;i++) {
43979 // // fixme - ask toolbars for heights?
43980 // this.toolbars[i].onDestroy();
43983 //this.wrap.dom.innerHTML = '';
43984 //this.wrap.remove();
43989 onFirstFocus : function(){
43991 this.assignDocWin();
43994 this.activated = true;
43997 if(Roo.isGecko){ // prevent silly gecko errors
43999 var s = this.win.getSelection();
44000 if(!s.focusNode || s.focusNode.nodeType != 3){
44001 var r = s.getRangeAt(0);
44002 r.selectNodeContents((this.doc.body || this.doc.documentElement));
44007 this.execCmd('useCSS', true);
44008 this.execCmd('styleWithCSS', false);
44011 this.owner.fireEvent('activate', this);
44015 adjustFont: function(btn){
44016 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44017 //if(Roo.isSafari){ // safari
44020 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44021 if(Roo.isSafari){ // safari
44022 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44023 v = (v < 10) ? 10 : v;
44024 v = (v > 48) ? 48 : v;
44025 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44030 v = Math.max(1, v+adjust);
44032 this.execCmd('FontSize', v );
44035 onEditorEvent : function(e)
44037 this.owner.fireEvent('editorevent', this, e);
44038 // this.updateToolbar();
44039 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44042 insertTag : function(tg)
44044 // could be a bit smarter... -> wrap the current selected tRoo..
44045 if (tg.toLowerCase() == 'span' ||
44046 tg.toLowerCase() == 'code' ||
44047 tg.toLowerCase() == 'sup' ||
44048 tg.toLowerCase() == 'sub'
44051 range = this.createRange(this.getSelection());
44052 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44053 wrappingNode.appendChild(range.extractContents());
44054 range.insertNode(wrappingNode);
44061 this.execCmd("formatblock", tg);
44065 insertText : function(txt)
44069 var range = this.createRange();
44070 range.deleteContents();
44071 //alert(Sender.getAttribute('label'));
44073 range.insertNode(this.doc.createTextNode(txt));
44079 * Executes a Midas editor command on the editor document and performs necessary focus and
44080 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44081 * @param {String} cmd The Midas command
44082 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44084 relayCmd : function(cmd, value){
44086 this.execCmd(cmd, value);
44087 this.owner.fireEvent('editorevent', this);
44088 //this.updateToolbar();
44089 this.owner.deferFocus();
44093 * Executes a Midas editor command directly on the editor document.
44094 * For visual commands, you should use {@link #relayCmd} instead.
44095 * <b>This should only be called after the editor is initialized.</b>
44096 * @param {String} cmd The Midas command
44097 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44099 execCmd : function(cmd, value){
44100 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44107 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44109 * @param {String} text | dom node..
44111 insertAtCursor : function(text)
44114 if(!this.activated){
44120 var r = this.doc.selection.createRange();
44131 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44135 // from jquery ui (MIT licenced)
44137 var win = this.win;
44139 if (win.getSelection && win.getSelection().getRangeAt) {
44140 range = win.getSelection().getRangeAt(0);
44141 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44142 range.insertNode(node);
44143 } else if (win.document.selection && win.document.selection.createRange) {
44144 // no firefox support
44145 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44146 win.document.selection.createRange().pasteHTML(txt);
44148 // no firefox support
44149 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44150 this.execCmd('InsertHTML', txt);
44159 mozKeyPress : function(e){
44161 var c = e.getCharCode(), cmd;
44164 c = String.fromCharCode(c).toLowerCase();
44178 this.cleanUpPaste.defer(100, this);
44186 e.preventDefault();
44194 fixKeys : function(){ // load time branching for fastest keydown performance
44196 return function(e){
44197 var k = e.getKey(), r;
44200 r = this.doc.selection.createRange();
44203 r.pasteHTML('    ');
44210 r = this.doc.selection.createRange();
44212 var target = r.parentElement();
44213 if(!target || target.tagName.toLowerCase() != 'li'){
44215 r.pasteHTML('<br />');
44221 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44222 this.cleanUpPaste.defer(100, this);
44228 }else if(Roo.isOpera){
44229 return function(e){
44230 var k = e.getKey();
44234 this.execCmd('InsertHTML','    ');
44237 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44238 this.cleanUpPaste.defer(100, this);
44243 }else if(Roo.isSafari){
44244 return function(e){
44245 var k = e.getKey();
44249 this.execCmd('InsertText','\t');
44253 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44254 this.cleanUpPaste.defer(100, this);
44262 getAllAncestors: function()
44264 var p = this.getSelectedNode();
44267 a.push(p); // push blank onto stack..
44268 p = this.getParentElement();
44272 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44276 a.push(this.doc.body);
44280 lastSelNode : false,
44283 getSelection : function()
44285 this.assignDocWin();
44286 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44289 getSelectedNode: function()
44291 // this may only work on Gecko!!!
44293 // should we cache this!!!!
44298 var range = this.createRange(this.getSelection()).cloneRange();
44301 var parent = range.parentElement();
44303 var testRange = range.duplicate();
44304 testRange.moveToElementText(parent);
44305 if (testRange.inRange(range)) {
44308 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44311 parent = parent.parentElement;
44316 // is ancestor a text element.
44317 var ac = range.commonAncestorContainer;
44318 if (ac.nodeType == 3) {
44319 ac = ac.parentNode;
44322 var ar = ac.childNodes;
44325 var other_nodes = [];
44326 var has_other_nodes = false;
44327 for (var i=0;i<ar.length;i++) {
44328 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44331 // fullly contained node.
44333 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44338 // probably selected..
44339 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44340 other_nodes.push(ar[i]);
44344 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44349 has_other_nodes = true;
44351 if (!nodes.length && other_nodes.length) {
44352 nodes= other_nodes;
44354 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44360 createRange: function(sel)
44362 // this has strange effects when using with
44363 // top toolbar - not sure if it's a great idea.
44364 //this.editor.contentWindow.focus();
44365 if (typeof sel != "undefined") {
44367 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44369 return this.doc.createRange();
44372 return this.doc.createRange();
44375 getParentElement: function()
44378 this.assignDocWin();
44379 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44381 var range = this.createRange(sel);
44384 var p = range.commonAncestorContainer;
44385 while (p.nodeType == 3) { // text node
44396 * Range intersection.. the hard stuff...
44400 * [ -- selected range --- ]
44404 * if end is before start or hits it. fail.
44405 * if start is after end or hits it fail.
44407 * if either hits (but other is outside. - then it's not
44413 // @see http://www.thismuchiknow.co.uk/?p=64.
44414 rangeIntersectsNode : function(range, node)
44416 var nodeRange = node.ownerDocument.createRange();
44418 nodeRange.selectNode(node);
44420 nodeRange.selectNodeContents(node);
44423 var rangeStartRange = range.cloneRange();
44424 rangeStartRange.collapse(true);
44426 var rangeEndRange = range.cloneRange();
44427 rangeEndRange.collapse(false);
44429 var nodeStartRange = nodeRange.cloneRange();
44430 nodeStartRange.collapse(true);
44432 var nodeEndRange = nodeRange.cloneRange();
44433 nodeEndRange.collapse(false);
44435 return rangeStartRange.compareBoundaryPoints(
44436 Range.START_TO_START, nodeEndRange) == -1 &&
44437 rangeEndRange.compareBoundaryPoints(
44438 Range.START_TO_START, nodeStartRange) == 1;
44442 rangeCompareNode : function(range, node)
44444 var nodeRange = node.ownerDocument.createRange();
44446 nodeRange.selectNode(node);
44448 nodeRange.selectNodeContents(node);
44452 range.collapse(true);
44454 nodeRange.collapse(true);
44456 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44457 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44459 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44461 var nodeIsBefore = ss == 1;
44462 var nodeIsAfter = ee == -1;
44464 if (nodeIsBefore && nodeIsAfter) {
44467 if (!nodeIsBefore && nodeIsAfter) {
44468 return 1; //right trailed.
44471 if (nodeIsBefore && !nodeIsAfter) {
44472 return 2; // left trailed.
44478 // private? - in a new class?
44479 cleanUpPaste : function()
44481 // cleans up the whole document..
44482 Roo.log('cleanuppaste');
44484 this.cleanUpChildren(this.doc.body);
44485 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44486 if (clean != this.doc.body.innerHTML) {
44487 this.doc.body.innerHTML = clean;
44492 cleanWordChars : function(input) {// change the chars to hex code
44493 var he = Roo.HtmlEditorCore;
44495 var output = input;
44496 Roo.each(he.swapCodes, function(sw) {
44497 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44499 output = output.replace(swapper, sw[1]);
44506 cleanUpChildren : function (n)
44508 if (!n.childNodes.length) {
44511 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44512 this.cleanUpChild(n.childNodes[i]);
44519 cleanUpChild : function (node)
44522 //console.log(node);
44523 if (node.nodeName == "#text") {
44524 // clean up silly Windows -- stuff?
44527 if (node.nodeName == "#comment") {
44528 node.parentNode.removeChild(node);
44529 // clean up silly Windows -- stuff?
44532 var lcname = node.tagName.toLowerCase();
44533 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44534 // whitelist of tags..
44536 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44538 node.parentNode.removeChild(node);
44543 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44545 // spans with no attributes - just remove them..
44546 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44547 remove_keep_children = true;
44550 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44551 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44553 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44554 // remove_keep_children = true;
44557 if (remove_keep_children) {
44558 this.cleanUpChildren(node);
44559 // inserts everything just before this node...
44560 while (node.childNodes.length) {
44561 var cn = node.childNodes[0];
44562 node.removeChild(cn);
44563 node.parentNode.insertBefore(cn, node);
44565 node.parentNode.removeChild(node);
44569 if (!node.attributes || !node.attributes.length) {
44574 this.cleanUpChildren(node);
44578 function cleanAttr(n,v)
44581 if (v.match(/^\./) || v.match(/^\//)) {
44584 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44587 if (v.match(/^#/)) {
44590 if (v.match(/^\{/)) { // allow template editing.
44593 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44594 node.removeAttribute(n);
44598 var cwhite = this.cwhite;
44599 var cblack = this.cblack;
44601 function cleanStyle(n,v)
44603 if (v.match(/expression/)) { //XSS?? should we even bother..
44604 node.removeAttribute(n);
44608 var parts = v.split(/;/);
44611 Roo.each(parts, function(p) {
44612 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44616 var l = p.split(':').shift().replace(/\s+/g,'');
44617 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44619 if ( cwhite.length && cblack.indexOf(l) > -1) {
44620 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44621 //node.removeAttribute(n);
44625 // only allow 'c whitelisted system attributes'
44626 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44627 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44628 //node.removeAttribute(n);
44638 if (clean.length) {
44639 node.setAttribute(n, clean.join(';'));
44641 node.removeAttribute(n);
44647 for (var i = node.attributes.length-1; i > -1 ; i--) {
44648 var a = node.attributes[i];
44651 if (a.name.toLowerCase().substr(0,2)=='on') {
44652 node.removeAttribute(a.name);
44655 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44656 node.removeAttribute(a.name);
44659 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44660 cleanAttr(a.name,a.value); // fixme..
44663 if (a.name == 'style') {
44664 cleanStyle(a.name,a.value);
44667 /// clean up MS crap..
44668 // tecnically this should be a list of valid class'es..
44671 if (a.name == 'class') {
44672 if (a.value.match(/^Mso/)) {
44673 node.removeAttribute('class');
44676 if (a.value.match(/^body$/)) {
44677 node.removeAttribute('class');
44688 this.cleanUpChildren(node);
44694 * Clean up MS wordisms...
44696 cleanWord : function(node)
44699 this.cleanWord(this.doc.body);
44704 node.nodeName == 'SPAN' &&
44705 !node.hasAttributes() &&
44706 node.childNodes.length == 1 &&
44707 node.firstChild.nodeName == "#text"
44709 var textNode = node.firstChild;
44710 node.removeChild(textNode);
44711 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44712 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44714 node.parentNode.insertBefore(textNode, node);
44715 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44716 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44718 node.parentNode.removeChild(node);
44721 if (node.nodeName == "#text") {
44722 // clean up silly Windows -- stuff?
44725 if (node.nodeName == "#comment") {
44726 node.parentNode.removeChild(node);
44727 // clean up silly Windows -- stuff?
44731 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44732 node.parentNode.removeChild(node);
44735 //Roo.log(node.tagName);
44736 // remove - but keep children..
44737 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44738 //Roo.log('-- removed');
44739 while (node.childNodes.length) {
44740 var cn = node.childNodes[0];
44741 node.removeChild(cn);
44742 node.parentNode.insertBefore(cn, node);
44743 // move node to parent - and clean it..
44744 this.cleanWord(cn);
44746 node.parentNode.removeChild(node);
44747 /// no need to iterate chidlren = it's got none..
44748 //this.iterateChildren(node, this.cleanWord);
44752 if (node.className.length) {
44754 var cn = node.className.split(/\W+/);
44756 Roo.each(cn, function(cls) {
44757 if (cls.match(/Mso[a-zA-Z]+/)) {
44762 node.className = cna.length ? cna.join(' ') : '';
44764 node.removeAttribute("class");
44768 if (node.hasAttribute("lang")) {
44769 node.removeAttribute("lang");
44772 if (node.hasAttribute("style")) {
44774 var styles = node.getAttribute("style").split(";");
44776 Roo.each(styles, function(s) {
44777 if (!s.match(/:/)) {
44780 var kv = s.split(":");
44781 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44784 // what ever is left... we allow.
44787 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44788 if (!nstyle.length) {
44789 node.removeAttribute('style');
44792 this.iterateChildren(node, this.cleanWord);
44798 * iterateChildren of a Node, calling fn each time, using this as the scole..
44799 * @param {DomNode} node node to iterate children of.
44800 * @param {Function} fn method of this class to call on each item.
44802 iterateChildren : function(node, fn)
44804 if (!node.childNodes.length) {
44807 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44808 fn.call(this, node.childNodes[i])
44814 * cleanTableWidths.
44816 * Quite often pasting from word etc.. results in tables with column and widths.
44817 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44820 cleanTableWidths : function(node)
44825 this.cleanTableWidths(this.doc.body);
44830 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44833 Roo.log(node.tagName);
44834 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44835 this.iterateChildren(node, this.cleanTableWidths);
44838 if (node.hasAttribute('width')) {
44839 node.removeAttribute('width');
44843 if (node.hasAttribute("style")) {
44846 var styles = node.getAttribute("style").split(";");
44848 Roo.each(styles, function(s) {
44849 if (!s.match(/:/)) {
44852 var kv = s.split(":");
44853 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44856 // what ever is left... we allow.
44859 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44860 if (!nstyle.length) {
44861 node.removeAttribute('style');
44865 this.iterateChildren(node, this.cleanTableWidths);
44873 domToHTML : function(currentElement, depth, nopadtext) {
44875 depth = depth || 0;
44876 nopadtext = nopadtext || false;
44878 if (!currentElement) {
44879 return this.domToHTML(this.doc.body);
44882 //Roo.log(currentElement);
44884 var allText = false;
44885 var nodeName = currentElement.nodeName;
44886 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44888 if (nodeName == '#text') {
44890 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44895 if (nodeName != 'BODY') {
44898 // Prints the node tagName, such as <A>, <IMG>, etc
44901 for(i = 0; i < currentElement.attributes.length;i++) {
44903 var aname = currentElement.attributes.item(i).name;
44904 if (!currentElement.attributes.item(i).value.length) {
44907 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44910 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44919 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44922 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44927 // Traverse the tree
44929 var currentElementChild = currentElement.childNodes.item(i);
44930 var allText = true;
44931 var innerHTML = '';
44933 while (currentElementChild) {
44934 // Formatting code (indent the tree so it looks nice on the screen)
44935 var nopad = nopadtext;
44936 if (lastnode == 'SPAN') {
44940 if (currentElementChild.nodeName == '#text') {
44941 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44942 toadd = nopadtext ? toadd : toadd.trim();
44943 if (!nopad && toadd.length > 80) {
44944 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44946 innerHTML += toadd;
44949 currentElementChild = currentElement.childNodes.item(i);
44955 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44957 // Recursively traverse the tree structure of the child node
44958 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44959 lastnode = currentElementChild.nodeName;
44961 currentElementChild=currentElement.childNodes.item(i);
44967 // The remaining code is mostly for formatting the tree
44968 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44973 ret+= "</"+tagName+">";
44979 applyBlacklists : function()
44981 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44982 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44986 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44987 if (b.indexOf(tag) > -1) {
44990 this.white.push(tag);
44994 Roo.each(w, function(tag) {
44995 if (b.indexOf(tag) > -1) {
44998 if (this.white.indexOf(tag) > -1) {
45001 this.white.push(tag);
45006 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
45007 if (w.indexOf(tag) > -1) {
45010 this.black.push(tag);
45014 Roo.each(b, function(tag) {
45015 if (w.indexOf(tag) > -1) {
45018 if (this.black.indexOf(tag) > -1) {
45021 this.black.push(tag);
45026 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45027 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45031 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45032 if (b.indexOf(tag) > -1) {
45035 this.cwhite.push(tag);
45039 Roo.each(w, function(tag) {
45040 if (b.indexOf(tag) > -1) {
45043 if (this.cwhite.indexOf(tag) > -1) {
45046 this.cwhite.push(tag);
45051 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45052 if (w.indexOf(tag) > -1) {
45055 this.cblack.push(tag);
45059 Roo.each(b, function(tag) {
45060 if (w.indexOf(tag) > -1) {
45063 if (this.cblack.indexOf(tag) > -1) {
45066 this.cblack.push(tag);
45071 setStylesheets : function(stylesheets)
45073 if(typeof(stylesheets) == 'string'){
45074 Roo.get(this.iframe.contentDocument.head).createChild({
45076 rel : 'stylesheet',
45085 Roo.each(stylesheets, function(s) {
45090 Roo.get(_this.iframe.contentDocument.head).createChild({
45092 rel : 'stylesheet',
45101 removeStylesheets : function()
45105 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45110 setStyle : function(style)
45112 Roo.get(this.iframe.contentDocument.head).createChild({
45121 // hide stuff that is not compatible
45135 * @event specialkey
45139 * @cfg {String} fieldClass @hide
45142 * @cfg {String} focusClass @hide
45145 * @cfg {String} autoCreate @hide
45148 * @cfg {String} inputType @hide
45151 * @cfg {String} invalidClass @hide
45154 * @cfg {String} invalidText @hide
45157 * @cfg {String} msgFx @hide
45160 * @cfg {String} validateOnBlur @hide
45164 Roo.HtmlEditorCore.white = [
45165 'area', 'br', 'img', 'input', 'hr', 'wbr',
45167 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45168 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45169 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45170 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45171 'table', 'ul', 'xmp',
45173 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45176 'dir', 'menu', 'ol', 'ul', 'dl',
45182 Roo.HtmlEditorCore.black = [
45183 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45185 'base', 'basefont', 'bgsound', 'blink', 'body',
45186 'frame', 'frameset', 'head', 'html', 'ilayer',
45187 'iframe', 'layer', 'link', 'meta', 'object',
45188 'script', 'style' ,'title', 'xml' // clean later..
45190 Roo.HtmlEditorCore.clean = [
45191 'script', 'style', 'title', 'xml'
45193 Roo.HtmlEditorCore.remove = [
45198 Roo.HtmlEditorCore.ablack = [
45202 Roo.HtmlEditorCore.aclean = [
45203 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45207 Roo.HtmlEditorCore.pwhite= [
45208 'http', 'https', 'mailto'
45211 // white listed style attributes.
45212 Roo.HtmlEditorCore.cwhite= [
45213 // 'text-align', /// default is to allow most things..
45219 // black listed style attributes.
45220 Roo.HtmlEditorCore.cblack= [
45221 // 'font-size' -- this can be set by the project
45225 Roo.HtmlEditorCore.swapCodes =[
45236 //<script type="text/javascript">
45239 * Ext JS Library 1.1.1
45240 * Copyright(c) 2006-2007, Ext JS, LLC.
45246 Roo.form.HtmlEditor = function(config){
45250 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45252 if (!this.toolbars) {
45253 this.toolbars = [];
45255 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45261 * @class Roo.form.HtmlEditor
45262 * @extends Roo.form.Field
45263 * Provides a lightweight HTML Editor component.
45265 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45267 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45268 * supported by this editor.</b><br/><br/>
45269 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45270 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45272 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45274 * @cfg {Boolean} clearUp
45278 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45283 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45288 * @cfg {Number} height (in pixels)
45292 * @cfg {Number} width (in pixels)
45297 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45300 stylesheets: false,
45304 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45309 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45315 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45320 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45328 // private properties
45329 validationEvent : false,
45331 initialized : false,
45334 onFocus : Roo.emptyFn,
45336 hideMode:'offsets',
45338 actionMode : 'container', // defaults to hiding it...
45340 defaultAutoCreate : { // modified by initCompnoent..
45342 style:"width:500px;height:300px;",
45343 autocomplete: "new-password"
45347 initComponent : function(){
45350 * @event initialize
45351 * Fires when the editor is fully initialized (including the iframe)
45352 * @param {HtmlEditor} this
45357 * Fires when the editor is first receives the focus. Any insertion must wait
45358 * until after this event.
45359 * @param {HtmlEditor} this
45363 * @event beforesync
45364 * Fires before the textarea is updated with content from the editor iframe. Return false
45365 * to cancel the sync.
45366 * @param {HtmlEditor} this
45367 * @param {String} html
45371 * @event beforepush
45372 * Fires before the iframe editor is updated with content from the textarea. Return false
45373 * to cancel the push.
45374 * @param {HtmlEditor} this
45375 * @param {String} html
45380 * Fires when the textarea is updated with content from the editor iframe.
45381 * @param {HtmlEditor} this
45382 * @param {String} html
45387 * Fires when the iframe editor is updated with content from the textarea.
45388 * @param {HtmlEditor} this
45389 * @param {String} html
45393 * @event editmodechange
45394 * Fires when the editor switches edit modes
45395 * @param {HtmlEditor} this
45396 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45398 editmodechange: true,
45400 * @event editorevent
45401 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45402 * @param {HtmlEditor} this
45406 * @event firstfocus
45407 * Fires when on first focus - needed by toolbars..
45408 * @param {HtmlEditor} this
45413 * Auto save the htmlEditor value as a file into Events
45414 * @param {HtmlEditor} this
45418 * @event savedpreview
45419 * preview the saved version of htmlEditor
45420 * @param {HtmlEditor} this
45422 savedpreview: true,
45425 * @event stylesheetsclick
45426 * Fires when press the Sytlesheets button
45427 * @param {Roo.HtmlEditorCore} this
45429 stylesheetsclick: true
45431 this.defaultAutoCreate = {
45433 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45434 autocomplete: "new-password"
45439 * Protected method that will not generally be called directly. It
45440 * is called when the editor creates its toolbar. Override this method if you need to
45441 * add custom toolbar buttons.
45442 * @param {HtmlEditor} editor
45444 createToolbar : function(editor){
45445 Roo.log("create toolbars");
45446 if (!editor.toolbars || !editor.toolbars.length) {
45447 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45450 for (var i =0 ; i < editor.toolbars.length;i++) {
45451 editor.toolbars[i] = Roo.factory(
45452 typeof(editor.toolbars[i]) == 'string' ?
45453 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45454 Roo.form.HtmlEditor);
45455 editor.toolbars[i].init(editor);
45463 onRender : function(ct, position)
45466 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45468 this.wrap = this.el.wrap({
45469 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45472 this.editorcore.onRender(ct, position);
45474 if (this.resizable) {
45475 this.resizeEl = new Roo.Resizable(this.wrap, {
45479 minHeight : this.height,
45480 height: this.height,
45481 handles : this.resizable,
45484 resize : function(r, w, h) {
45485 _t.onResize(w,h); // -something
45491 this.createToolbar(this);
45495 this.setSize(this.wrap.getSize());
45497 if (this.resizeEl) {
45498 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45499 // should trigger onReize..
45502 this.keyNav = new Roo.KeyNav(this.el, {
45504 "tab" : function(e){
45505 e.preventDefault();
45507 var value = this.getValue();
45509 var start = this.el.dom.selectionStart;
45510 var end = this.el.dom.selectionEnd;
45514 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45515 this.el.dom.setSelectionRange(end + 1, end + 1);
45519 var f = value.substring(0, start).split("\t");
45521 if(f.pop().length != 0){
45525 this.setValue(f.join("\t") + value.substring(end));
45526 this.el.dom.setSelectionRange(start - 1, start - 1);
45530 "home" : function(e){
45531 e.preventDefault();
45533 var curr = this.el.dom.selectionStart;
45534 var lines = this.getValue().split("\n");
45541 this.el.dom.setSelectionRange(0, 0);
45547 for (var i = 0; i < lines.length;i++) {
45548 pos += lines[i].length;
45558 pos -= lines[i].length;
45564 this.el.dom.setSelectionRange(pos, pos);
45568 this.el.dom.selectionStart = pos;
45569 this.el.dom.selectionEnd = curr;
45572 "end" : function(e){
45573 e.preventDefault();
45575 var curr = this.el.dom.selectionStart;
45576 var lines = this.getValue().split("\n");
45583 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45589 for (var i = 0; i < lines.length;i++) {
45591 pos += lines[i].length;
45605 this.el.dom.setSelectionRange(pos, pos);
45609 this.el.dom.selectionStart = curr;
45610 this.el.dom.selectionEnd = pos;
45615 doRelay : function(foo, bar, hname){
45616 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45622 // if(this.autosave && this.w){
45623 // this.autoSaveFn = setInterval(this.autosave, 1000);
45628 onResize : function(w, h)
45630 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45635 if(typeof w == 'number'){
45636 var aw = w - this.wrap.getFrameWidth('lr');
45637 this.el.setWidth(this.adjustWidth('textarea', aw));
45640 if(typeof h == 'number'){
45642 for (var i =0; i < this.toolbars.length;i++) {
45643 // fixme - ask toolbars for heights?
45644 tbh += this.toolbars[i].tb.el.getHeight();
45645 if (this.toolbars[i].footer) {
45646 tbh += this.toolbars[i].footer.el.getHeight();
45653 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45654 ah -= 5; // knock a few pixes off for look..
45656 this.el.setHeight(this.adjustWidth('textarea', ah));
45660 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45661 this.editorcore.onResize(ew,eh);
45666 * Toggles the editor between standard and source edit mode.
45667 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45669 toggleSourceEdit : function(sourceEditMode)
45671 this.editorcore.toggleSourceEdit(sourceEditMode);
45673 if(this.editorcore.sourceEditMode){
45674 Roo.log('editor - showing textarea');
45677 // Roo.log(this.syncValue());
45678 this.editorcore.syncValue();
45679 this.el.removeClass('x-hidden');
45680 this.el.dom.removeAttribute('tabIndex');
45683 for (var i = 0; i < this.toolbars.length; i++) {
45684 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45685 this.toolbars[i].tb.hide();
45686 this.toolbars[i].footer.hide();
45691 Roo.log('editor - hiding textarea');
45693 // Roo.log(this.pushValue());
45694 this.editorcore.pushValue();
45696 this.el.addClass('x-hidden');
45697 this.el.dom.setAttribute('tabIndex', -1);
45699 for (var i = 0; i < this.toolbars.length; i++) {
45700 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45701 this.toolbars[i].tb.show();
45702 this.toolbars[i].footer.show();
45706 //this.deferFocus();
45709 this.setSize(this.wrap.getSize());
45710 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45712 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45715 // private (for BoxComponent)
45716 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45718 // private (for BoxComponent)
45719 getResizeEl : function(){
45723 // private (for BoxComponent)
45724 getPositionEl : function(){
45729 initEvents : function(){
45730 this.originalValue = this.getValue();
45734 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45737 markInvalid : Roo.emptyFn,
45739 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45742 clearInvalid : Roo.emptyFn,
45744 setValue : function(v){
45745 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45746 this.editorcore.pushValue();
45751 deferFocus : function(){
45752 this.focus.defer(10, this);
45756 focus : function(){
45757 this.editorcore.focus();
45763 onDestroy : function(){
45769 for (var i =0; i < this.toolbars.length;i++) {
45770 // fixme - ask toolbars for heights?
45771 this.toolbars[i].onDestroy();
45774 this.wrap.dom.innerHTML = '';
45775 this.wrap.remove();
45780 onFirstFocus : function(){
45781 //Roo.log("onFirstFocus");
45782 this.editorcore.onFirstFocus();
45783 for (var i =0; i < this.toolbars.length;i++) {
45784 this.toolbars[i].onFirstFocus();
45790 syncValue : function()
45792 this.editorcore.syncValue();
45795 pushValue : function()
45797 this.editorcore.pushValue();
45800 setStylesheets : function(stylesheets)
45802 this.editorcore.setStylesheets(stylesheets);
45805 removeStylesheets : function()
45807 this.editorcore.removeStylesheets();
45811 // hide stuff that is not compatible
45825 * @event specialkey
45829 * @cfg {String} fieldClass @hide
45832 * @cfg {String} focusClass @hide
45835 * @cfg {String} autoCreate @hide
45838 * @cfg {String} inputType @hide
45841 * @cfg {String} invalidClass @hide
45844 * @cfg {String} invalidText @hide
45847 * @cfg {String} msgFx @hide
45850 * @cfg {String} validateOnBlur @hide
45854 // <script type="text/javascript">
45857 * Ext JS Library 1.1.1
45858 * Copyright(c) 2006-2007, Ext JS, LLC.
45864 * @class Roo.form.HtmlEditorToolbar1
45869 new Roo.form.HtmlEditor({
45872 new Roo.form.HtmlEditorToolbar1({
45873 disable : { fonts: 1 , format: 1, ..., ... , ...],
45879 * @cfg {Object} disable List of elements to disable..
45880 * @cfg {Array} btns List of additional buttons.
45884 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45887 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45890 Roo.apply(this, config);
45892 // default disabled, based on 'good practice'..
45893 this.disable = this.disable || {};
45894 Roo.applyIf(this.disable, {
45897 specialElements : true
45901 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45902 // dont call parent... till later.
45905 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45912 editorcore : false,
45914 * @cfg {Object} disable List of toolbar elements to disable
45921 * @cfg {String} createLinkText The default text for the create link prompt
45923 createLinkText : 'Please enter the URL for the link:',
45925 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45927 defaultLinkValue : 'http:/'+'/',
45931 * @cfg {Array} fontFamilies An array of available font families
45949 // "á" , ?? a acute?
45954 "°" // , // degrees
45956 // "é" , // e ecute
45957 // "ú" , // u ecute?
45960 specialElements : [
45962 text: "Insert Table",
45965 ihtml : '<table><tr><td>Cell</td></tr></table>'
45969 text: "Insert Image",
45972 ihtml : '<img src="about:blank"/>'
45981 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45982 "input:submit", "input:button", "select", "textarea", "label" ],
45985 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45987 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45996 * @cfg {String} defaultFont default font to use.
45998 defaultFont: 'tahoma',
46000 fontSelect : false,
46003 formatCombo : false,
46005 init : function(editor)
46007 this.editor = editor;
46008 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46009 var editorcore = this.editorcore;
46013 var fid = editorcore.frameId;
46015 function btn(id, toggle, handler){
46016 var xid = fid + '-'+ id ;
46020 cls : 'x-btn-icon x-edit-'+id,
46021 enableToggle:toggle !== false,
46022 scope: _t, // was editor...
46023 handler:handler||_t.relayBtnCmd,
46024 clickEvent:'mousedown',
46025 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46032 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46034 // stop form submits
46035 tb.el.on('click', function(e){
46036 e.preventDefault(); // what does this do?
46039 if(!this.disable.font) { // && !Roo.isSafari){
46040 /* why no safari for fonts
46041 editor.fontSelect = tb.el.createChild({
46044 cls:'x-font-select',
46045 html: this.createFontOptions()
46048 editor.fontSelect.on('change', function(){
46049 var font = editor.fontSelect.dom.value;
46050 editor.relayCmd('fontname', font);
46051 editor.deferFocus();
46055 editor.fontSelect.dom,
46061 if(!this.disable.formats){
46062 this.formatCombo = new Roo.form.ComboBox({
46063 store: new Roo.data.SimpleStore({
46066 data : this.formats // from states.js
46070 //autoCreate : {tag: "div", size: "20"},
46071 displayField:'tag',
46075 triggerAction: 'all',
46076 emptyText:'Add tag',
46077 selectOnFocus:true,
46080 'select': function(c, r, i) {
46081 editorcore.insertTag(r.get('tag'));
46087 tb.addField(this.formatCombo);
46091 if(!this.disable.format){
46096 btn('strikethrough')
46099 if(!this.disable.fontSize){
46104 btn('increasefontsize', false, editorcore.adjustFont),
46105 btn('decreasefontsize', false, editorcore.adjustFont)
46110 if(!this.disable.colors){
46113 id:editorcore.frameId +'-forecolor',
46114 cls:'x-btn-icon x-edit-forecolor',
46115 clickEvent:'mousedown',
46116 tooltip: this.buttonTips['forecolor'] || undefined,
46118 menu : new Roo.menu.ColorMenu({
46119 allowReselect: true,
46120 focus: Roo.emptyFn,
46123 selectHandler: function(cp, color){
46124 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46125 editor.deferFocus();
46128 clickEvent:'mousedown'
46131 id:editorcore.frameId +'backcolor',
46132 cls:'x-btn-icon x-edit-backcolor',
46133 clickEvent:'mousedown',
46134 tooltip: this.buttonTips['backcolor'] || undefined,
46136 menu : new Roo.menu.ColorMenu({
46137 focus: Roo.emptyFn,
46140 allowReselect: true,
46141 selectHandler: function(cp, color){
46143 editorcore.execCmd('useCSS', false);
46144 editorcore.execCmd('hilitecolor', color);
46145 editorcore.execCmd('useCSS', true);
46146 editor.deferFocus();
46148 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46149 Roo.isSafari || Roo.isIE ? '#'+color : color);
46150 editor.deferFocus();
46154 clickEvent:'mousedown'
46159 // now add all the items...
46162 if(!this.disable.alignments){
46165 btn('justifyleft'),
46166 btn('justifycenter'),
46167 btn('justifyright')
46171 //if(!Roo.isSafari){
46172 if(!this.disable.links){
46175 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46179 if(!this.disable.lists){
46182 btn('insertorderedlist'),
46183 btn('insertunorderedlist')
46186 if(!this.disable.sourceEdit){
46189 btn('sourceedit', true, function(btn){
46190 this.toggleSourceEdit(btn.pressed);
46197 // special menu.. - needs to be tidied up..
46198 if (!this.disable.special) {
46201 cls: 'x-edit-none',
46207 for (var i =0; i < this.specialChars.length; i++) {
46208 smenu.menu.items.push({
46210 html: this.specialChars[i],
46211 handler: function(a,b) {
46212 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46213 //editor.insertAtCursor(a.html);
46227 if (!this.disable.cleanStyles) {
46229 cls: 'x-btn-icon x-btn-clear',
46235 for (var i =0; i < this.cleanStyles.length; i++) {
46236 cmenu.menu.items.push({
46237 actiontype : this.cleanStyles[i],
46238 html: 'Remove ' + this.cleanStyles[i],
46239 handler: function(a,b) {
46242 var c = Roo.get(editorcore.doc.body);
46243 c.select('[style]').each(function(s) {
46244 s.dom.style.removeProperty(a.actiontype);
46246 editorcore.syncValue();
46251 cmenu.menu.items.push({
46252 actiontype : 'tablewidths',
46253 html: 'Remove Table Widths',
46254 handler: function(a,b) {
46255 editorcore.cleanTableWidths();
46256 editorcore.syncValue();
46260 cmenu.menu.items.push({
46261 actiontype : 'word',
46262 html: 'Remove MS Word Formating',
46263 handler: function(a,b) {
46264 editorcore.cleanWord();
46265 editorcore.syncValue();
46270 cmenu.menu.items.push({
46271 actiontype : 'all',
46272 html: 'Remove All Styles',
46273 handler: function(a,b) {
46275 var c = Roo.get(editorcore.doc.body);
46276 c.select('[style]').each(function(s) {
46277 s.dom.removeAttribute('style');
46279 editorcore.syncValue();
46284 cmenu.menu.items.push({
46285 actiontype : 'all',
46286 html: 'Remove All CSS Classes',
46287 handler: function(a,b) {
46289 var c = Roo.get(editorcore.doc.body);
46290 c.select('[class]').each(function(s) {
46291 s.dom.removeAttribute('class');
46293 editorcore.cleanWord();
46294 editorcore.syncValue();
46299 cmenu.menu.items.push({
46300 actiontype : 'tidy',
46301 html: 'Tidy HTML Source',
46302 handler: function(a,b) {
46303 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46304 editorcore.syncValue();
46313 if (!this.disable.specialElements) {
46316 cls: 'x-edit-none',
46321 for (var i =0; i < this.specialElements.length; i++) {
46322 semenu.menu.items.push(
46324 handler: function(a,b) {
46325 editor.insertAtCursor(this.ihtml);
46327 }, this.specialElements[i])
46339 for(var i =0; i< this.btns.length;i++) {
46340 var b = Roo.factory(this.btns[i],Roo.form);
46341 b.cls = 'x-edit-none';
46343 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46344 b.cls += ' x-init-enable';
46347 b.scope = editorcore;
46355 // disable everything...
46357 this.tb.items.each(function(item){
46360 item.id != editorcore.frameId+ '-sourceedit' &&
46361 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46367 this.rendered = true;
46369 // the all the btns;
46370 editor.on('editorevent', this.updateToolbar, this);
46371 // other toolbars need to implement this..
46372 //editor.on('editmodechange', this.updateToolbar, this);
46376 relayBtnCmd : function(btn) {
46377 this.editorcore.relayCmd(btn.cmd);
46379 // private used internally
46380 createLink : function(){
46381 Roo.log("create link?");
46382 var url = prompt(this.createLinkText, this.defaultLinkValue);
46383 if(url && url != 'http:/'+'/'){
46384 this.editorcore.relayCmd('createlink', url);
46390 * Protected method that will not generally be called directly. It triggers
46391 * a toolbar update by reading the markup state of the current selection in the editor.
46393 updateToolbar: function(){
46395 if(!this.editorcore.activated){
46396 this.editor.onFirstFocus();
46400 var btns = this.tb.items.map,
46401 doc = this.editorcore.doc,
46402 frameId = this.editorcore.frameId;
46404 if(!this.disable.font && !Roo.isSafari){
46406 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46407 if(name != this.fontSelect.dom.value){
46408 this.fontSelect.dom.value = name;
46412 if(!this.disable.format){
46413 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46414 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46415 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46416 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46418 if(!this.disable.alignments){
46419 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46420 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46421 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46423 if(!Roo.isSafari && !this.disable.lists){
46424 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46425 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46428 var ans = this.editorcore.getAllAncestors();
46429 if (this.formatCombo) {
46432 var store = this.formatCombo.store;
46433 this.formatCombo.setValue("");
46434 for (var i =0; i < ans.length;i++) {
46435 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46437 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46445 // hides menus... - so this cant be on a menu...
46446 Roo.menu.MenuMgr.hideAll();
46448 //this.editorsyncValue();
46452 createFontOptions : function(){
46453 var buf = [], fs = this.fontFamilies, ff, lc;
46457 for(var i = 0, len = fs.length; i< len; i++){
46459 lc = ff.toLowerCase();
46461 '<option value="',lc,'" style="font-family:',ff,';"',
46462 (this.defaultFont == lc ? ' selected="true">' : '>'),
46467 return buf.join('');
46470 toggleSourceEdit : function(sourceEditMode){
46472 Roo.log("toolbar toogle");
46473 if(sourceEditMode === undefined){
46474 sourceEditMode = !this.sourceEditMode;
46476 this.sourceEditMode = sourceEditMode === true;
46477 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46478 // just toggle the button?
46479 if(btn.pressed !== this.sourceEditMode){
46480 btn.toggle(this.sourceEditMode);
46484 if(sourceEditMode){
46485 Roo.log("disabling buttons");
46486 this.tb.items.each(function(item){
46487 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46493 Roo.log("enabling buttons");
46494 if(this.editorcore.initialized){
46495 this.tb.items.each(function(item){
46501 Roo.log("calling toggole on editor");
46502 // tell the editor that it's been pressed..
46503 this.editor.toggleSourceEdit(sourceEditMode);
46507 * Object collection of toolbar tooltips for the buttons in the editor. The key
46508 * is the command id associated with that button and the value is a valid QuickTips object.
46513 title: 'Bold (Ctrl+B)',
46514 text: 'Make the selected text bold.',
46515 cls: 'x-html-editor-tip'
46518 title: 'Italic (Ctrl+I)',
46519 text: 'Make the selected text italic.',
46520 cls: 'x-html-editor-tip'
46528 title: 'Bold (Ctrl+B)',
46529 text: 'Make the selected text bold.',
46530 cls: 'x-html-editor-tip'
46533 title: 'Italic (Ctrl+I)',
46534 text: 'Make the selected text italic.',
46535 cls: 'x-html-editor-tip'
46538 title: 'Underline (Ctrl+U)',
46539 text: 'Underline the selected text.',
46540 cls: 'x-html-editor-tip'
46543 title: 'Strikethrough',
46544 text: 'Strikethrough the selected text.',
46545 cls: 'x-html-editor-tip'
46547 increasefontsize : {
46548 title: 'Grow Text',
46549 text: 'Increase the font size.',
46550 cls: 'x-html-editor-tip'
46552 decreasefontsize : {
46553 title: 'Shrink Text',
46554 text: 'Decrease the font size.',
46555 cls: 'x-html-editor-tip'
46558 title: 'Text Highlight Color',
46559 text: 'Change the background color of the selected text.',
46560 cls: 'x-html-editor-tip'
46563 title: 'Font Color',
46564 text: 'Change the color of the selected text.',
46565 cls: 'x-html-editor-tip'
46568 title: 'Align Text Left',
46569 text: 'Align text to the left.',
46570 cls: 'x-html-editor-tip'
46573 title: 'Center Text',
46574 text: 'Center text in the editor.',
46575 cls: 'x-html-editor-tip'
46578 title: 'Align Text Right',
46579 text: 'Align text to the right.',
46580 cls: 'x-html-editor-tip'
46582 insertunorderedlist : {
46583 title: 'Bullet List',
46584 text: 'Start a bulleted list.',
46585 cls: 'x-html-editor-tip'
46587 insertorderedlist : {
46588 title: 'Numbered List',
46589 text: 'Start a numbered list.',
46590 cls: 'x-html-editor-tip'
46593 title: 'Hyperlink',
46594 text: 'Make the selected text a hyperlink.',
46595 cls: 'x-html-editor-tip'
46598 title: 'Source Edit',
46599 text: 'Switch to source editing mode.',
46600 cls: 'x-html-editor-tip'
46604 onDestroy : function(){
46607 this.tb.items.each(function(item){
46609 item.menu.removeAll();
46611 item.menu.el.destroy();
46619 onFirstFocus: function() {
46620 this.tb.items.each(function(item){
46629 // <script type="text/javascript">
46632 * Ext JS Library 1.1.1
46633 * Copyright(c) 2006-2007, Ext JS, LLC.
46640 * @class Roo.form.HtmlEditor.ToolbarContext
46645 new Roo.form.HtmlEditor({
46648 { xtype: 'ToolbarStandard', styles : {} }
46649 { xtype: 'ToolbarContext', disable : {} }
46655 * @config : {Object} disable List of elements to disable.. (not done yet.)
46656 * @config : {Object} styles Map of styles available.
46660 Roo.form.HtmlEditor.ToolbarContext = function(config)
46663 Roo.apply(this, config);
46664 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46665 // dont call parent... till later.
46666 this.styles = this.styles || {};
46671 Roo.form.HtmlEditor.ToolbarContext.types = {
46683 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46749 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46754 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46764 style : 'fontFamily',
46765 displayField: 'display',
46766 optname : 'font-family',
46815 // should we really allow this??
46816 // should this just be
46827 style : 'fontFamily',
46828 displayField: 'display',
46829 optname : 'font-family',
46836 style : 'fontFamily',
46837 displayField: 'display',
46838 optname : 'font-family',
46845 style : 'fontFamily',
46846 displayField: 'display',
46847 optname : 'font-family',
46858 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46859 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46861 Roo.form.HtmlEditor.ToolbarContext.options = {
46863 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46864 [ 'Courier New', 'Courier New'],
46865 [ 'Tahoma', 'Tahoma'],
46866 [ 'Times New Roman,serif', 'Times'],
46867 [ 'Verdana','Verdana' ]
46871 // fixme - these need to be configurable..
46874 //Roo.form.HtmlEditor.ToolbarContext.types
46877 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46884 editorcore : false,
46886 * @cfg {Object} disable List of toolbar elements to disable
46891 * @cfg {Object} styles List of styles
46892 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46894 * These must be defined in the page, so they get rendered correctly..
46905 init : function(editor)
46907 this.editor = editor;
46908 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46909 var editorcore = this.editorcore;
46911 var fid = editorcore.frameId;
46913 function btn(id, toggle, handler){
46914 var xid = fid + '-'+ id ;
46918 cls : 'x-btn-icon x-edit-'+id,
46919 enableToggle:toggle !== false,
46920 scope: editorcore, // was editor...
46921 handler:handler||editorcore.relayBtnCmd,
46922 clickEvent:'mousedown',
46923 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46927 // create a new element.
46928 var wdiv = editor.wrap.createChild({
46930 }, editor.wrap.dom.firstChild.nextSibling, true);
46932 // can we do this more than once??
46934 // stop form submits
46937 // disable everything...
46938 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46939 this.toolbars = {};
46941 for (var i in ty) {
46943 this.toolbars[i] = this.buildToolbar(ty[i],i);
46945 this.tb = this.toolbars.BODY;
46947 this.buildFooter();
46948 this.footer.show();
46949 editor.on('hide', function( ) { this.footer.hide() }, this);
46950 editor.on('show', function( ) { this.footer.show() }, this);
46953 this.rendered = true;
46955 // the all the btns;
46956 editor.on('editorevent', this.updateToolbar, this);
46957 // other toolbars need to implement this..
46958 //editor.on('editmodechange', this.updateToolbar, this);
46964 * Protected method that will not generally be called directly. It triggers
46965 * a toolbar update by reading the markup state of the current selection in the editor.
46967 * Note you can force an update by calling on('editorevent', scope, false)
46969 updateToolbar: function(editor,ev,sel){
46972 // capture mouse up - this is handy for selecting images..
46973 // perhaps should go somewhere else...
46974 if(!this.editorcore.activated){
46975 this.editor.onFirstFocus();
46981 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46982 // selectNode - might want to handle IE?
46984 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46985 ev.target && ev.target.tagName == 'IMG') {
46986 // they have click on an image...
46987 // let's see if we can change the selection...
46990 var nodeRange = sel.ownerDocument.createRange();
46992 nodeRange.selectNode(sel);
46994 nodeRange.selectNodeContents(sel);
46996 //nodeRange.collapse(true);
46997 var s = this.editorcore.win.getSelection();
46998 s.removeAllRanges();
46999 s.addRange(nodeRange);
47003 var updateFooter = sel ? false : true;
47006 var ans = this.editorcore.getAllAncestors();
47009 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47012 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47013 sel = sel ? sel : this.editorcore.doc.body;
47014 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47017 // pick a menu that exists..
47018 var tn = sel.tagName.toUpperCase();
47019 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47021 tn = sel.tagName.toUpperCase();
47023 var lastSel = this.tb.selectedNode;
47025 this.tb.selectedNode = sel;
47027 // if current menu does not match..
47029 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47032 ///console.log("show: " + tn);
47033 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47036 this.tb.items.first().el.innerHTML = tn + ': ';
47039 // update attributes
47040 if (this.tb.fields) {
47041 this.tb.fields.each(function(e) {
47043 e.setValue(sel.style[e.stylename]);
47046 e.setValue(sel.getAttribute(e.attrname));
47050 var hasStyles = false;
47051 for(var i in this.styles) {
47058 var st = this.tb.fields.item(0);
47060 st.store.removeAll();
47063 var cn = sel.className.split(/\s+/);
47066 if (this.styles['*']) {
47068 Roo.each(this.styles['*'], function(v) {
47069 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47072 if (this.styles[tn]) {
47073 Roo.each(this.styles[tn], function(v) {
47074 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47078 st.store.loadData(avs);
47082 // flag our selected Node.
47083 this.tb.selectedNode = sel;
47086 Roo.menu.MenuMgr.hideAll();
47090 if (!updateFooter) {
47091 //this.footDisp.dom.innerHTML = '';
47094 // update the footer
47098 this.footerEls = ans.reverse();
47099 Roo.each(this.footerEls, function(a,i) {
47100 if (!a) { return; }
47101 html += html.length ? ' > ' : '';
47103 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47108 var sz = this.footDisp.up('td').getSize();
47109 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47110 this.footDisp.dom.style.marginLeft = '5px';
47112 this.footDisp.dom.style.overflow = 'hidden';
47114 this.footDisp.dom.innerHTML = html;
47116 //this.editorsyncValue();
47123 onDestroy : function(){
47126 this.tb.items.each(function(item){
47128 item.menu.removeAll();
47130 item.menu.el.destroy();
47138 onFirstFocus: function() {
47139 // need to do this for all the toolbars..
47140 this.tb.items.each(function(item){
47144 buildToolbar: function(tlist, nm)
47146 var editor = this.editor;
47147 var editorcore = this.editorcore;
47148 // create a new element.
47149 var wdiv = editor.wrap.createChild({
47151 }, editor.wrap.dom.firstChild.nextSibling, true);
47154 var tb = new Roo.Toolbar(wdiv);
47157 tb.add(nm+ ": ");
47160 for(var i in this.styles) {
47165 if (styles && styles.length) {
47167 // this needs a multi-select checkbox...
47168 tb.addField( new Roo.form.ComboBox({
47169 store: new Roo.data.SimpleStore({
47171 fields: ['val', 'selected'],
47174 name : '-roo-edit-className',
47175 attrname : 'className',
47176 displayField: 'val',
47180 triggerAction: 'all',
47181 emptyText:'Select Style',
47182 selectOnFocus:true,
47185 'select': function(c, r, i) {
47186 // initial support only for on class per el..
47187 tb.selectedNode.className = r ? r.get('val') : '';
47188 editorcore.syncValue();
47195 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47196 var tbops = tbc.options;
47198 for (var i in tlist) {
47200 var item = tlist[i];
47201 tb.add(item.title + ": ");
47204 //optname == used so you can configure the options available..
47205 var opts = item.opts ? item.opts : false;
47206 if (item.optname) {
47207 opts = tbops[item.optname];
47212 // opts == pulldown..
47213 tb.addField( new Roo.form.ComboBox({
47214 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47216 fields: ['val', 'display'],
47219 name : '-roo-edit-' + i,
47221 stylename : item.style ? item.style : false,
47222 displayField: item.displayField ? item.displayField : 'val',
47223 valueField : 'val',
47225 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47227 triggerAction: 'all',
47228 emptyText:'Select',
47229 selectOnFocus:true,
47230 width: item.width ? item.width : 130,
47232 'select': function(c, r, i) {
47234 tb.selectedNode.style[c.stylename] = r.get('val');
47237 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47246 tb.addField( new Roo.form.TextField({
47249 //allowBlank:false,
47254 tb.addField( new Roo.form.TextField({
47255 name: '-roo-edit-' + i,
47262 'change' : function(f, nv, ov) {
47263 tb.selectedNode.setAttribute(f.attrname, nv);
47264 editorcore.syncValue();
47277 text: 'Stylesheets',
47280 click : function ()
47282 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47290 text: 'Remove Tag',
47293 click : function ()
47296 // undo does not work.
47298 var sn = tb.selectedNode;
47300 var pn = sn.parentNode;
47302 var stn = sn.childNodes[0];
47303 var en = sn.childNodes[sn.childNodes.length - 1 ];
47304 while (sn.childNodes.length) {
47305 var node = sn.childNodes[0];
47306 sn.removeChild(node);
47308 pn.insertBefore(node, sn);
47311 pn.removeChild(sn);
47312 var range = editorcore.createRange();
47314 range.setStart(stn,0);
47315 range.setEnd(en,0); //????
47316 //range.selectNode(sel);
47319 var selection = editorcore.getSelection();
47320 selection.removeAllRanges();
47321 selection.addRange(range);
47325 //_this.updateToolbar(null, null, pn);
47326 _this.updateToolbar(null, null, null);
47327 _this.footDisp.dom.innerHTML = '';
47337 tb.el.on('click', function(e){
47338 e.preventDefault(); // what does this do?
47340 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47343 // dont need to disable them... as they will get hidden
47348 buildFooter : function()
47351 var fel = this.editor.wrap.createChild();
47352 this.footer = new Roo.Toolbar(fel);
47353 // toolbar has scrolly on left / right?
47354 var footDisp= new Roo.Toolbar.Fill();
47360 handler : function() {
47361 _t.footDisp.scrollTo('left',0,true)
47365 this.footer.add( footDisp );
47370 handler : function() {
47372 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47376 var fel = Roo.get(footDisp.el);
47377 fel.addClass('x-editor-context');
47378 this.footDispWrap = fel;
47379 this.footDispWrap.overflow = 'hidden';
47381 this.footDisp = fel.createChild();
47382 this.footDispWrap.on('click', this.onContextClick, this)
47386 onContextClick : function (ev,dom)
47388 ev.preventDefault();
47389 var cn = dom.className;
47391 if (!cn.match(/x-ed-loc-/)) {
47394 var n = cn.split('-').pop();
47395 var ans = this.footerEls;
47399 var range = this.editorcore.createRange();
47401 range.selectNodeContents(sel);
47402 //range.selectNode(sel);
47405 var selection = this.editorcore.getSelection();
47406 selection.removeAllRanges();
47407 selection.addRange(range);
47411 this.updateToolbar(null, null, sel);
47428 * Ext JS Library 1.1.1
47429 * Copyright(c) 2006-2007, Ext JS, LLC.
47431 * Originally Released Under LGPL - original licence link has changed is not relivant.
47434 * <script type="text/javascript">
47438 * @class Roo.form.BasicForm
47439 * @extends Roo.util.Observable
47440 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47442 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47443 * @param {Object} config Configuration options
47445 Roo.form.BasicForm = function(el, config){
47446 this.allItems = [];
47447 this.childForms = [];
47448 Roo.apply(this, config);
47450 * The Roo.form.Field items in this form.
47451 * @type MixedCollection
47455 this.items = new Roo.util.MixedCollection(false, function(o){
47456 return o.id || (o.id = Roo.id());
47460 * @event beforeaction
47461 * Fires before any action is performed. Return false to cancel the action.
47462 * @param {Form} this
47463 * @param {Action} action The action to be performed
47465 beforeaction: true,
47467 * @event actionfailed
47468 * Fires when an action fails.
47469 * @param {Form} this
47470 * @param {Action} action The action that failed
47472 actionfailed : true,
47474 * @event actioncomplete
47475 * Fires when an action is completed.
47476 * @param {Form} this
47477 * @param {Action} action The action that completed
47479 actioncomplete : true
47484 Roo.form.BasicForm.superclass.constructor.call(this);
47486 Roo.form.BasicForm.popover.apply();
47489 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47491 * @cfg {String} method
47492 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47495 * @cfg {DataReader} reader
47496 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47497 * This is optional as there is built-in support for processing JSON.
47500 * @cfg {DataReader} errorReader
47501 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47502 * This is completely optional as there is built-in support for processing JSON.
47505 * @cfg {String} url
47506 * The URL to use for form actions if one isn't supplied in the action options.
47509 * @cfg {Boolean} fileUpload
47510 * Set to true if this form is a file upload.
47514 * @cfg {Object} baseParams
47515 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47520 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47525 activeAction : null,
47528 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47529 * or setValues() data instead of when the form was first created.
47531 trackResetOnLoad : false,
47535 * childForms - used for multi-tab forms
47538 childForms : false,
47541 * allItems - full list of fields.
47547 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47548 * element by passing it or its id or mask the form itself by passing in true.
47551 waitMsgTarget : false,
47556 disableMask : false,
47559 * @cfg {Boolean} errorMask (true|false) default false
47564 * @cfg {Number} maskOffset Default 100
47569 initEl : function(el){
47570 this.el = Roo.get(el);
47571 this.id = this.el.id || Roo.id();
47572 this.el.on('submit', this.onSubmit, this);
47573 this.el.addClass('x-form');
47577 onSubmit : function(e){
47582 * Returns true if client-side validation on the form is successful.
47585 isValid : function(){
47587 var target = false;
47588 this.items.each(function(f){
47595 if(!target && f.el.isVisible(true)){
47600 if(this.errorMask && !valid){
47601 Roo.form.BasicForm.popover.mask(this, target);
47607 * Returns array of invalid form fields.
47611 invalidFields : function()
47614 this.items.each(function(f){
47627 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47630 isDirty : function(){
47632 this.items.each(function(f){
47642 * Returns true if any fields in this form have changed since their original load. (New version)
47646 hasChanged : function()
47649 this.items.each(function(f){
47650 if(f.hasChanged()){
47659 * Resets all hasChanged to 'false' -
47660 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47661 * So hasChanged storage is only to be used for this purpose
47664 resetHasChanged : function()
47666 this.items.each(function(f){
47667 f.resetHasChanged();
47674 * Performs a predefined action (submit or load) or custom actions you define on this form.
47675 * @param {String} actionName The name of the action type
47676 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47677 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47678 * accept other config options):
47680 Property Type Description
47681 ---------------- --------------- ----------------------------------------------------------------------------------
47682 url String The url for the action (defaults to the form's url)
47683 method String The form method to use (defaults to the form's method, or POST if not defined)
47684 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47685 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47686 validate the form on the client (defaults to false)
47688 * @return {BasicForm} this
47690 doAction : function(action, options){
47691 if(typeof action == 'string'){
47692 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47694 if(this.fireEvent('beforeaction', this, action) !== false){
47695 this.beforeAction(action);
47696 action.run.defer(100, action);
47702 * Shortcut to do a submit action.
47703 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47704 * @return {BasicForm} this
47706 submit : function(options){
47707 this.doAction('submit', options);
47712 * Shortcut to do a load action.
47713 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47714 * @return {BasicForm} this
47716 load : function(options){
47717 this.doAction('load', options);
47722 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47723 * @param {Record} record The record to edit
47724 * @return {BasicForm} this
47726 updateRecord : function(record){
47727 record.beginEdit();
47728 var fs = record.fields;
47729 fs.each(function(f){
47730 var field = this.findField(f.name);
47732 record.set(f.name, field.getValue());
47740 * Loads an Roo.data.Record into this form.
47741 * @param {Record} record The record to load
47742 * @return {BasicForm} this
47744 loadRecord : function(record){
47745 this.setValues(record.data);
47750 beforeAction : function(action){
47751 var o = action.options;
47753 if(!this.disableMask) {
47754 if(this.waitMsgTarget === true){
47755 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47756 }else if(this.waitMsgTarget){
47757 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47758 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47760 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47768 afterAction : function(action, success){
47769 this.activeAction = null;
47770 var o = action.options;
47772 if(!this.disableMask) {
47773 if(this.waitMsgTarget === true){
47775 }else if(this.waitMsgTarget){
47776 this.waitMsgTarget.unmask();
47778 Roo.MessageBox.updateProgress(1);
47779 Roo.MessageBox.hide();
47787 Roo.callback(o.success, o.scope, [this, action]);
47788 this.fireEvent('actioncomplete', this, action);
47792 // failure condition..
47793 // we have a scenario where updates need confirming.
47794 // eg. if a locking scenario exists..
47795 // we look for { errors : { needs_confirm : true }} in the response.
47797 (typeof(action.result) != 'undefined') &&
47798 (typeof(action.result.errors) != 'undefined') &&
47799 (typeof(action.result.errors.needs_confirm) != 'undefined')
47802 Roo.MessageBox.confirm(
47803 "Change requires confirmation",
47804 action.result.errorMsg,
47809 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47819 Roo.callback(o.failure, o.scope, [this, action]);
47820 // show an error message if no failed handler is set..
47821 if (!this.hasListener('actionfailed')) {
47822 Roo.MessageBox.alert("Error",
47823 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47824 action.result.errorMsg :
47825 "Saving Failed, please check your entries or try again"
47829 this.fireEvent('actionfailed', this, action);
47835 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47836 * @param {String} id The value to search for
47839 findField : function(id){
47840 var field = this.items.get(id);
47842 this.items.each(function(f){
47843 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47849 return field || null;
47853 * Add a secondary form to this one,
47854 * Used to provide tabbed forms. One form is primary, with hidden values
47855 * which mirror the elements from the other forms.
47857 * @param {Roo.form.Form} form to add.
47860 addForm : function(form)
47863 if (this.childForms.indexOf(form) > -1) {
47867 this.childForms.push(form);
47869 Roo.each(form.allItems, function (fe) {
47871 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
47872 if (this.findField(n)) { // already added..
47875 var add = new Roo.form.Hidden({
47878 add.render(this.el);
47885 * Mark fields in this form invalid in bulk.
47886 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
47887 * @return {BasicForm} this
47889 markInvalid : function(errors){
47890 if(errors instanceof Array){
47891 for(var i = 0, len = errors.length; i < len; i++){
47892 var fieldError = errors[i];
47893 var f = this.findField(fieldError.id);
47895 f.markInvalid(fieldError.msg);
47901 if(typeof errors[id] != 'function' && (field = this.findField(id))){
47902 field.markInvalid(errors[id]);
47906 Roo.each(this.childForms || [], function (f) {
47907 f.markInvalid(errors);
47914 * Set values for fields in this form in bulk.
47915 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
47916 * @return {BasicForm} this
47918 setValues : function(values){
47919 if(values instanceof Array){ // array of objects
47920 for(var i = 0, len = values.length; i < len; i++){
47922 var f = this.findField(v.id);
47924 f.setValue(v.value);
47925 if(this.trackResetOnLoad){
47926 f.originalValue = f.getValue();
47930 }else{ // object hash
47933 if(typeof values[id] != 'function' && (field = this.findField(id))){
47935 if (field.setFromData &&
47936 field.valueField &&
47937 field.displayField &&
47938 // combos' with local stores can
47939 // be queried via setValue()
47940 // to set their value..
47941 (field.store && !field.store.isLocal)
47945 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47946 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47947 field.setFromData(sd);
47950 field.setValue(values[id]);
47954 if(this.trackResetOnLoad){
47955 field.originalValue = field.getValue();
47960 this.resetHasChanged();
47963 Roo.each(this.childForms || [], function (f) {
47964 f.setValues(values);
47965 f.resetHasChanged();
47972 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47973 * they are returned as an array.
47974 * @param {Boolean} asString
47977 getValues : function(asString){
47978 if (this.childForms) {
47979 // copy values from the child forms
47980 Roo.each(this.childForms, function (f) {
47981 this.setValues(f.getValues());
47986 if (typeof(FormData) != 'undefined' && asString !== true) {
47987 // this relies on a 'recent' version of chrome apparently...
47989 var fd = (new FormData(this.el.dom)).entries();
47991 var ent = fd.next();
47992 while (!ent.done) {
47993 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
48004 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
48005 if(asString === true){
48008 return Roo.urlDecode(fs);
48012 * Returns the fields in this form as an object with key/value pairs.
48013 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48016 getFieldValues : function(with_hidden)
48018 if (this.childForms) {
48019 // copy values from the child forms
48020 // should this call getFieldValues - probably not as we do not currently copy
48021 // hidden fields when we generate..
48022 Roo.each(this.childForms, function (f) {
48023 this.setValues(f.getValues());
48028 this.items.each(function(f){
48029 if (!f.getName()) {
48032 var v = f.getValue();
48033 if (f.inputType =='radio') {
48034 if (typeof(ret[f.getName()]) == 'undefined') {
48035 ret[f.getName()] = ''; // empty..
48038 if (!f.el.dom.checked) {
48042 v = f.el.dom.value;
48046 // not sure if this supported any more..
48047 if ((typeof(v) == 'object') && f.getRawValue) {
48048 v = f.getRawValue() ; // dates..
48050 // combo boxes where name != hiddenName...
48051 if (f.name != f.getName()) {
48052 ret[f.name] = f.getRawValue();
48054 ret[f.getName()] = v;
48061 * Clears all invalid messages in this form.
48062 * @return {BasicForm} this
48064 clearInvalid : function(){
48065 this.items.each(function(f){
48069 Roo.each(this.childForms || [], function (f) {
48078 * Resets this form.
48079 * @return {BasicForm} this
48081 reset : function(){
48082 this.items.each(function(f){
48086 Roo.each(this.childForms || [], function (f) {
48089 this.resetHasChanged();
48095 * Add Roo.form components to this form.
48096 * @param {Field} field1
48097 * @param {Field} field2 (optional)
48098 * @param {Field} etc (optional)
48099 * @return {BasicForm} this
48102 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48108 * Removes a field from the items collection (does NOT remove its markup).
48109 * @param {Field} field
48110 * @return {BasicForm} this
48112 remove : function(field){
48113 this.items.remove(field);
48118 * Looks at the fields in this form, checks them for an id attribute,
48119 * and calls applyTo on the existing dom element with that id.
48120 * @return {BasicForm} this
48122 render : function(){
48123 this.items.each(function(f){
48124 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48132 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48133 * @param {Object} values
48134 * @return {BasicForm} this
48136 applyToFields : function(o){
48137 this.items.each(function(f){
48144 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48145 * @param {Object} values
48146 * @return {BasicForm} this
48148 applyIfToFields : function(o){
48149 this.items.each(function(f){
48157 Roo.BasicForm = Roo.form.BasicForm;
48159 Roo.apply(Roo.form.BasicForm, {
48173 intervalID : false,
48179 if(this.isApplied){
48184 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48185 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48186 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48187 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48190 this.maskEl.top.enableDisplayMode("block");
48191 this.maskEl.left.enableDisplayMode("block");
48192 this.maskEl.bottom.enableDisplayMode("block");
48193 this.maskEl.right.enableDisplayMode("block");
48195 Roo.get(document.body).on('click', function(){
48199 Roo.get(document.body).on('touchstart', function(){
48203 this.isApplied = true
48206 mask : function(form, target)
48210 this.target = target;
48212 if(!this.form.errorMask || !target.el){
48216 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48218 var ot = this.target.el.calcOffsetsTo(scrollable);
48220 var scrollTo = ot[1] - this.form.maskOffset;
48222 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48224 scrollable.scrollTo('top', scrollTo);
48226 var el = this.target.wrap || this.target.el;
48228 var box = el.getBox();
48230 this.maskEl.top.setStyle('position', 'absolute');
48231 this.maskEl.top.setStyle('z-index', 10000);
48232 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48233 this.maskEl.top.setLeft(0);
48234 this.maskEl.top.setTop(0);
48235 this.maskEl.top.show();
48237 this.maskEl.left.setStyle('position', 'absolute');
48238 this.maskEl.left.setStyle('z-index', 10000);
48239 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48240 this.maskEl.left.setLeft(0);
48241 this.maskEl.left.setTop(box.y - this.padding);
48242 this.maskEl.left.show();
48244 this.maskEl.bottom.setStyle('position', 'absolute');
48245 this.maskEl.bottom.setStyle('z-index', 10000);
48246 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48247 this.maskEl.bottom.setLeft(0);
48248 this.maskEl.bottom.setTop(box.bottom + this.padding);
48249 this.maskEl.bottom.show();
48251 this.maskEl.right.setStyle('position', 'absolute');
48252 this.maskEl.right.setStyle('z-index', 10000);
48253 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48254 this.maskEl.right.setLeft(box.right + this.padding);
48255 this.maskEl.right.setTop(box.y - this.padding);
48256 this.maskEl.right.show();
48258 this.intervalID = window.setInterval(function() {
48259 Roo.form.BasicForm.popover.unmask();
48262 window.onwheel = function(){ return false;};
48264 (function(){ this.isMasked = true; }).defer(500, this);
48268 unmask : function()
48270 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48274 this.maskEl.top.setStyle('position', 'absolute');
48275 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48276 this.maskEl.top.hide();
48278 this.maskEl.left.setStyle('position', 'absolute');
48279 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48280 this.maskEl.left.hide();
48282 this.maskEl.bottom.setStyle('position', 'absolute');
48283 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48284 this.maskEl.bottom.hide();
48286 this.maskEl.right.setStyle('position', 'absolute');
48287 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48288 this.maskEl.right.hide();
48290 window.onwheel = function(){ return true;};
48292 if(this.intervalID){
48293 window.clearInterval(this.intervalID);
48294 this.intervalID = false;
48297 this.isMasked = false;
48305 * Ext JS Library 1.1.1
48306 * Copyright(c) 2006-2007, Ext JS, LLC.
48308 * Originally Released Under LGPL - original licence link has changed is not relivant.
48311 * <script type="text/javascript">
48315 * @class Roo.form.Form
48316 * @extends Roo.form.BasicForm
48317 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48319 * @param {Object} config Configuration options
48321 Roo.form.Form = function(config){
48323 if (config.items) {
48324 xitems = config.items;
48325 delete config.items;
48329 Roo.form.Form.superclass.constructor.call(this, null, config);
48330 this.url = this.url || this.action;
48332 this.root = new Roo.form.Layout(Roo.applyIf({
48336 this.active = this.root;
48338 * Array of all the buttons that have been added to this form via {@link addButton}
48342 this.allItems = [];
48345 * @event clientvalidation
48346 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48347 * @param {Form} this
48348 * @param {Boolean} valid true if the form has passed client-side validation
48350 clientvalidation: true,
48353 * Fires when the form is rendered
48354 * @param {Roo.form.Form} form
48359 if (this.progressUrl) {
48360 // push a hidden field onto the list of fields..
48364 name : 'UPLOAD_IDENTIFIER'
48369 Roo.each(xitems, this.addxtype, this);
48373 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48375 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48378 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48381 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48383 buttonAlign:'center',
48386 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48391 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48392 * This property cascades to child containers if not set.
48397 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48398 * fires a looping event with that state. This is required to bind buttons to the valid
48399 * state using the config value formBind:true on the button.
48401 monitorValid : false,
48404 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48409 * @cfg {String} progressUrl - Url to return progress data
48412 progressUrl : false,
48414 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48415 * sending a formdata with extra parameters - eg uploaded elements.
48421 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48422 * fields are added and the column is closed. If no fields are passed the column remains open
48423 * until end() is called.
48424 * @param {Object} config The config to pass to the column
48425 * @param {Field} field1 (optional)
48426 * @param {Field} field2 (optional)
48427 * @param {Field} etc (optional)
48428 * @return Column The column container object
48430 column : function(c){
48431 var col = new Roo.form.Column(c);
48433 if(arguments.length > 1){ // duplicate code required because of Opera
48434 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48441 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48442 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48443 * until end() is called.
48444 * @param {Object} config The config to pass to the fieldset
48445 * @param {Field} field1 (optional)
48446 * @param {Field} field2 (optional)
48447 * @param {Field} etc (optional)
48448 * @return FieldSet The fieldset container object
48450 fieldset : function(c){
48451 var fs = new Roo.form.FieldSet(c);
48453 if(arguments.length > 1){ // duplicate code required because of Opera
48454 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48461 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48462 * fields are added and the container is closed. If no fields are passed the container remains open
48463 * until end() is called.
48464 * @param {Object} config The config to pass to the Layout
48465 * @param {Field} field1 (optional)
48466 * @param {Field} field2 (optional)
48467 * @param {Field} etc (optional)
48468 * @return Layout The container object
48470 container : function(c){
48471 var l = new Roo.form.Layout(c);
48473 if(arguments.length > 1){ // duplicate code required because of Opera
48474 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48481 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48482 * @param {Object} container A Roo.form.Layout or subclass of Layout
48483 * @return {Form} this
48485 start : function(c){
48486 // cascade label info
48487 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48488 this.active.stack.push(c);
48489 c.ownerCt = this.active;
48495 * Closes the current open container
48496 * @return {Form} this
48499 if(this.active == this.root){
48502 this.active = this.active.ownerCt;
48507 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48508 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48509 * as the label of the field.
48510 * @param {Field} field1
48511 * @param {Field} field2 (optional)
48512 * @param {Field} etc. (optional)
48513 * @return {Form} this
48516 this.active.stack.push.apply(this.active.stack, arguments);
48517 this.allItems.push.apply(this.allItems,arguments);
48519 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48520 if(a[i].isFormField){
48525 Roo.form.Form.superclass.add.apply(this, r);
48535 * Find any element that has been added to a form, using it's ID or name
48536 * This can include framesets, columns etc. along with regular fields..
48537 * @param {String} id - id or name to find.
48539 * @return {Element} e - or false if nothing found.
48541 findbyId : function(id)
48547 Roo.each(this.allItems, function(f){
48548 if (f.id == id || f.name == id ){
48559 * Render this form into the passed container. This should only be called once!
48560 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48561 * @return {Form} this
48563 render : function(ct)
48569 var o = this.autoCreate || {
48571 method : this.method || 'POST',
48572 id : this.id || Roo.id()
48574 this.initEl(ct.createChild(o));
48576 this.root.render(this.el);
48580 this.items.each(function(f){
48581 f.render('x-form-el-'+f.id);
48584 if(this.buttons.length > 0){
48585 // tables are required to maintain order and for correct IE layout
48586 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48587 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48588 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48590 var tr = tb.getElementsByTagName('tr')[0];
48591 for(var i = 0, len = this.buttons.length; i < len; i++) {
48592 var b = this.buttons[i];
48593 var td = document.createElement('td');
48594 td.className = 'x-form-btn-td';
48595 b.render(tr.appendChild(td));
48598 if(this.monitorValid){ // initialize after render
48599 this.startMonitoring();
48601 this.fireEvent('rendered', this);
48606 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48607 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48608 * object or a valid Roo.DomHelper element config
48609 * @param {Function} handler The function called when the button is clicked
48610 * @param {Object} scope (optional) The scope of the handler function
48611 * @return {Roo.Button}
48613 addButton : function(config, handler, scope){
48617 minWidth: this.minButtonWidth,
48620 if(typeof config == "string"){
48623 Roo.apply(bc, config);
48625 var btn = new Roo.Button(null, bc);
48626 this.buttons.push(btn);
48631 * Adds a series of form elements (using the xtype property as the factory method.
48632 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48633 * @param {Object} config
48636 addxtype : function()
48638 var ar = Array.prototype.slice.call(arguments, 0);
48640 for(var i = 0; i < ar.length; i++) {
48642 continue; // skip -- if this happends something invalid got sent, we
48643 // should ignore it, as basically that interface element will not show up
48644 // and that should be pretty obvious!!
48647 if (Roo.form[ar[i].xtype]) {
48649 var fe = Roo.factory(ar[i], Roo.form);
48655 fe.store.form = this;
48660 this.allItems.push(fe);
48661 if (fe.items && fe.addxtype) {
48662 fe.addxtype.apply(fe, fe.items);
48672 // console.log('adding ' + ar[i].xtype);
48674 if (ar[i].xtype == 'Button') {
48675 //console.log('adding button');
48676 //console.log(ar[i]);
48677 this.addButton(ar[i]);
48678 this.allItems.push(fe);
48682 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48683 alert('end is not supported on xtype any more, use items');
48685 // //console.log('adding end');
48693 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48694 * option "monitorValid"
48696 startMonitoring : function(){
48699 Roo.TaskMgr.start({
48700 run : this.bindHandler,
48701 interval : this.monitorPoll || 200,
48708 * Stops monitoring of the valid state of this form
48710 stopMonitoring : function(){
48711 this.bound = false;
48715 bindHandler : function(){
48717 return false; // stops binding
48720 this.items.each(function(f){
48721 if(!f.isValid(true)){
48726 for(var i = 0, len = this.buttons.length; i < len; i++){
48727 var btn = this.buttons[i];
48728 if(btn.formBind === true && btn.disabled === valid){
48729 btn.setDisabled(!valid);
48732 this.fireEvent('clientvalidation', this, valid);
48746 Roo.Form = Roo.form.Form;
48749 * Ext JS Library 1.1.1
48750 * Copyright(c) 2006-2007, Ext JS, LLC.
48752 * Originally Released Under LGPL - original licence link has changed is not relivant.
48755 * <script type="text/javascript">
48758 // as we use this in bootstrap.
48759 Roo.namespace('Roo.form');
48761 * @class Roo.form.Action
48762 * Internal Class used to handle form actions
48764 * @param {Roo.form.BasicForm} el The form element or its id
48765 * @param {Object} config Configuration options
48770 // define the action interface
48771 Roo.form.Action = function(form, options){
48773 this.options = options || {};
48776 * Client Validation Failed
48779 Roo.form.Action.CLIENT_INVALID = 'client';
48781 * Server Validation Failed
48784 Roo.form.Action.SERVER_INVALID = 'server';
48786 * Connect to Server Failed
48789 Roo.form.Action.CONNECT_FAILURE = 'connect';
48791 * Reading Data from Server Failed
48794 Roo.form.Action.LOAD_FAILURE = 'load';
48796 Roo.form.Action.prototype = {
48798 failureType : undefined,
48799 response : undefined,
48800 result : undefined,
48802 // interface method
48803 run : function(options){
48807 // interface method
48808 success : function(response){
48812 // interface method
48813 handleResponse : function(response){
48817 // default connection failure
48818 failure : function(response){
48820 this.response = response;
48821 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48822 this.form.afterAction(this, false);
48825 processResponse : function(response){
48826 this.response = response;
48827 if(!response.responseText){
48830 this.result = this.handleResponse(response);
48831 return this.result;
48834 // utility functions used internally
48835 getUrl : function(appendParams){
48836 var url = this.options.url || this.form.url || this.form.el.dom.action;
48838 var p = this.getParams();
48840 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
48846 getMethod : function(){
48847 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
48850 getParams : function(){
48851 var bp = this.form.baseParams;
48852 var p = this.options.params;
48854 if(typeof p == "object"){
48855 p = Roo.urlEncode(Roo.applyIf(p, bp));
48856 }else if(typeof p == 'string' && bp){
48857 p += '&' + Roo.urlEncode(bp);
48860 p = Roo.urlEncode(bp);
48865 createCallback : function(){
48867 success: this.success,
48868 failure: this.failure,
48870 timeout: (this.form.timeout*1000),
48871 upload: this.form.fileUpload ? this.success : undefined
48876 Roo.form.Action.Submit = function(form, options){
48877 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
48880 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
48883 haveProgress : false,
48884 uploadComplete : false,
48886 // uploadProgress indicator.
48887 uploadProgress : function()
48889 if (!this.form.progressUrl) {
48893 if (!this.haveProgress) {
48894 Roo.MessageBox.progress("Uploading", "Uploading");
48896 if (this.uploadComplete) {
48897 Roo.MessageBox.hide();
48901 this.haveProgress = true;
48903 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
48905 var c = new Roo.data.Connection();
48907 url : this.form.progressUrl,
48912 success : function(req){
48913 //console.log(data);
48917 rdata = Roo.decode(req.responseText)
48919 Roo.log("Invalid data from server..");
48923 if (!rdata || !rdata.success) {
48925 Roo.MessageBox.alert(Roo.encode(rdata));
48928 var data = rdata.data;
48930 if (this.uploadComplete) {
48931 Roo.MessageBox.hide();
48936 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
48937 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
48940 this.uploadProgress.defer(2000,this);
48943 failure: function(data) {
48944 Roo.log('progress url failed ');
48955 // run get Values on the form, so it syncs any secondary forms.
48956 this.form.getValues();
48958 var o = this.options;
48959 var method = this.getMethod();
48960 var isPost = method == 'POST';
48961 if(o.clientValidation === false || this.form.isValid()){
48963 if (this.form.progressUrl) {
48964 this.form.findField('UPLOAD_IDENTIFIER').setValue(
48965 (new Date() * 1) + '' + Math.random());
48970 Roo.Ajax.request(Roo.apply(this.createCallback(), {
48971 form:this.form.el.dom,
48972 url:this.getUrl(!isPost),
48974 params:isPost ? this.getParams() : null,
48975 isUpload: this.form.fileUpload,
48976 formData : this.form.formData
48979 this.uploadProgress();
48981 }else if (o.clientValidation !== false){ // client validation failed
48982 this.failureType = Roo.form.Action.CLIENT_INVALID;
48983 this.form.afterAction(this, false);
48987 success : function(response)
48989 this.uploadComplete= true;
48990 if (this.haveProgress) {
48991 Roo.MessageBox.hide();
48995 var result = this.processResponse(response);
48996 if(result === true || result.success){
48997 this.form.afterAction(this, true);
49001 this.form.markInvalid(result.errors);
49002 this.failureType = Roo.form.Action.SERVER_INVALID;
49004 this.form.afterAction(this, false);
49006 failure : function(response)
49008 this.uploadComplete= true;
49009 if (this.haveProgress) {
49010 Roo.MessageBox.hide();
49013 this.response = response;
49014 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49015 this.form.afterAction(this, false);
49018 handleResponse : function(response){
49019 if(this.form.errorReader){
49020 var rs = this.form.errorReader.read(response);
49023 for(var i = 0, len = rs.records.length; i < len; i++) {
49024 var r = rs.records[i];
49025 errors[i] = r.data;
49028 if(errors.length < 1){
49032 success : rs.success,
49038 ret = Roo.decode(response.responseText);
49042 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49052 Roo.form.Action.Load = function(form, options){
49053 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49054 this.reader = this.form.reader;
49057 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49062 Roo.Ajax.request(Roo.apply(
49063 this.createCallback(), {
49064 method:this.getMethod(),
49065 url:this.getUrl(false),
49066 params:this.getParams()
49070 success : function(response){
49072 var result = this.processResponse(response);
49073 if(result === true || !result.success || !result.data){
49074 this.failureType = Roo.form.Action.LOAD_FAILURE;
49075 this.form.afterAction(this, false);
49078 this.form.clearInvalid();
49079 this.form.setValues(result.data);
49080 this.form.afterAction(this, true);
49083 handleResponse : function(response){
49084 if(this.form.reader){
49085 var rs = this.form.reader.read(response);
49086 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49088 success : rs.success,
49092 return Roo.decode(response.responseText);
49096 Roo.form.Action.ACTION_TYPES = {
49097 'load' : Roo.form.Action.Load,
49098 'submit' : Roo.form.Action.Submit
49101 * Ext JS Library 1.1.1
49102 * Copyright(c) 2006-2007, Ext JS, LLC.
49104 * Originally Released Under LGPL - original licence link has changed is not relivant.
49107 * <script type="text/javascript">
49111 * @class Roo.form.Layout
49112 * @extends Roo.Component
49113 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49115 * @param {Object} config Configuration options
49117 Roo.form.Layout = function(config){
49119 if (config.items) {
49120 xitems = config.items;
49121 delete config.items;
49123 Roo.form.Layout.superclass.constructor.call(this, config);
49125 Roo.each(xitems, this.addxtype, this);
49129 Roo.extend(Roo.form.Layout, Roo.Component, {
49131 * @cfg {String/Object} autoCreate
49132 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49135 * @cfg {String/Object/Function} style
49136 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49137 * a function which returns such a specification.
49140 * @cfg {String} labelAlign
49141 * Valid values are "left," "top" and "right" (defaults to "left")
49144 * @cfg {Number} labelWidth
49145 * Fixed width in pixels of all field labels (defaults to undefined)
49148 * @cfg {Boolean} clear
49149 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49153 * @cfg {String} labelSeparator
49154 * The separator to use after field labels (defaults to ':')
49156 labelSeparator : ':',
49158 * @cfg {Boolean} hideLabels
49159 * True to suppress the display of field labels in this layout (defaults to false)
49161 hideLabels : false,
49164 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49169 onRender : function(ct, position){
49170 if(this.el){ // from markup
49171 this.el = Roo.get(this.el);
49172 }else { // generate
49173 var cfg = this.getAutoCreate();
49174 this.el = ct.createChild(cfg, position);
49177 this.el.applyStyles(this.style);
49179 if(this.labelAlign){
49180 this.el.addClass('x-form-label-'+this.labelAlign);
49182 if(this.hideLabels){
49183 this.labelStyle = "display:none";
49184 this.elementStyle = "padding-left:0;";
49186 if(typeof this.labelWidth == 'number'){
49187 this.labelStyle = "width:"+this.labelWidth+"px;";
49188 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49190 if(this.labelAlign == 'top'){
49191 this.labelStyle = "width:auto;";
49192 this.elementStyle = "padding-left:0;";
49195 var stack = this.stack;
49196 var slen = stack.length;
49198 if(!this.fieldTpl){
49199 var t = new Roo.Template(
49200 '<div class="x-form-item {5}">',
49201 '<label for="{0}" style="{2}">{1}{4}</label>',
49202 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49204 '</div><div class="x-form-clear-left"></div>'
49206 t.disableFormats = true;
49208 Roo.form.Layout.prototype.fieldTpl = t;
49210 for(var i = 0; i < slen; i++) {
49211 if(stack[i].isFormField){
49212 this.renderField(stack[i]);
49214 this.renderComponent(stack[i]);
49219 this.el.createChild({cls:'x-form-clear'});
49224 renderField : function(f){
49225 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49228 f.labelStyle||this.labelStyle||'', //2
49229 this.elementStyle||'', //3
49230 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49231 f.itemCls||this.itemCls||'' //5
49232 ], true).getPrevSibling());
49236 renderComponent : function(c){
49237 c.render(c.isLayout ? this.el : this.el.createChild());
49240 * Adds a object form elements (using the xtype property as the factory method.)
49241 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49242 * @param {Object} config
49244 addxtype : function(o)
49246 // create the lement.
49247 o.form = this.form;
49248 var fe = Roo.factory(o, Roo.form);
49249 this.form.allItems.push(fe);
49250 this.stack.push(fe);
49252 if (fe.isFormField) {
49253 this.form.items.add(fe);
49261 * @class Roo.form.Column
49262 * @extends Roo.form.Layout
49263 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49265 * @param {Object} config Configuration options
49267 Roo.form.Column = function(config){
49268 Roo.form.Column.superclass.constructor.call(this, config);
49271 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49273 * @cfg {Number/String} width
49274 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49277 * @cfg {String/Object} autoCreate
49278 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49282 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49285 onRender : function(ct, position){
49286 Roo.form.Column.superclass.onRender.call(this, ct, position);
49288 this.el.setWidth(this.width);
49295 * @class Roo.form.Row
49296 * @extends Roo.form.Layout
49297 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49299 * @param {Object} config Configuration options
49303 Roo.form.Row = function(config){
49304 Roo.form.Row.superclass.constructor.call(this, config);
49307 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49309 * @cfg {Number/String} width
49310 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49313 * @cfg {Number/String} height
49314 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49316 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49320 onRender : function(ct, position){
49321 //console.log('row render');
49323 var t = new Roo.Template(
49324 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49325 '<label for="{0}" style="{2}">{1}{4}</label>',
49326 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49330 t.disableFormats = true;
49332 Roo.form.Layout.prototype.rowTpl = t;
49334 this.fieldTpl = this.rowTpl;
49336 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49337 var labelWidth = 100;
49339 if ((this.labelAlign != 'top')) {
49340 if (typeof this.labelWidth == 'number') {
49341 labelWidth = this.labelWidth
49343 this.padWidth = 20 + labelWidth;
49347 Roo.form.Column.superclass.onRender.call(this, ct, position);
49349 this.el.setWidth(this.width);
49352 this.el.setHeight(this.height);
49357 renderField : function(f){
49358 f.fieldEl = this.fieldTpl.append(this.el, [
49359 f.id, f.fieldLabel,
49360 f.labelStyle||this.labelStyle||'',
49361 this.elementStyle||'',
49362 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49363 f.itemCls||this.itemCls||'',
49364 f.width ? f.width + this.padWidth : 160 + this.padWidth
49371 * @class Roo.form.FieldSet
49372 * @extends Roo.form.Layout
49373 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49375 * @param {Object} config Configuration options
49377 Roo.form.FieldSet = function(config){
49378 Roo.form.FieldSet.superclass.constructor.call(this, config);
49381 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49383 * @cfg {String} legend
49384 * The text to display as the legend for the FieldSet (defaults to '')
49387 * @cfg {String/Object} autoCreate
49388 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49392 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49395 onRender : function(ct, position){
49396 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49398 this.setLegend(this.legend);
49403 setLegend : function(text){
49405 this.el.child('legend').update(text);
49410 * Ext JS Library 1.1.1
49411 * Copyright(c) 2006-2007, Ext JS, LLC.
49413 * Originally Released Under LGPL - original licence link has changed is not relivant.
49416 * <script type="text/javascript">
49419 * @class Roo.form.VTypes
49420 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49423 Roo.form.VTypes = function(){
49424 // closure these in so they are only created once.
49425 var alpha = /^[a-zA-Z_]+$/;
49426 var alphanum = /^[a-zA-Z0-9_]+$/;
49427 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49428 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49430 // All these messages and functions are configurable
49433 * The function used to validate email addresses
49434 * @param {String} value The email address
49436 'email' : function(v){
49437 return email.test(v);
49440 * The error text to display when the email validation function returns false
49443 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49445 * The keystroke filter mask to be applied on email input
49448 'emailMask' : /[a-z0-9_\.\-@]/i,
49451 * The function used to validate URLs
49452 * @param {String} value The URL
49454 'url' : function(v){
49455 return url.test(v);
49458 * The error text to display when the url validation function returns false
49461 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49464 * The function used to validate alpha values
49465 * @param {String} value The value
49467 'alpha' : function(v){
49468 return alpha.test(v);
49471 * The error text to display when the alpha validation function returns false
49474 'alphaText' : 'This field should only contain letters and _',
49476 * The keystroke filter mask to be applied on alpha input
49479 'alphaMask' : /[a-z_]/i,
49482 * The function used to validate alphanumeric values
49483 * @param {String} value The value
49485 'alphanum' : function(v){
49486 return alphanum.test(v);
49489 * The error text to display when the alphanumeric validation function returns false
49492 'alphanumText' : 'This field should only contain letters, numbers and _',
49494 * The keystroke filter mask to be applied on alphanumeric input
49497 'alphanumMask' : /[a-z0-9_]/i
49499 }();//<script type="text/javascript">
49502 * @class Roo.form.FCKeditor
49503 * @extends Roo.form.TextArea
49504 * Wrapper around the FCKEditor http://www.fckeditor.net
49506 * Creates a new FCKeditor
49507 * @param {Object} config Configuration options
49509 Roo.form.FCKeditor = function(config){
49510 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49513 * @event editorinit
49514 * Fired when the editor is initialized - you can add extra handlers here..
49515 * @param {FCKeditor} this
49516 * @param {Object} the FCK object.
49523 Roo.form.FCKeditor.editors = { };
49524 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49526 //defaultAutoCreate : {
49527 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49531 * @cfg {Object} fck options - see fck manual for details.
49536 * @cfg {Object} fck toolbar set (Basic or Default)
49538 toolbarSet : 'Basic',
49540 * @cfg {Object} fck BasePath
49542 basePath : '/fckeditor/',
49550 onRender : function(ct, position)
49553 this.defaultAutoCreate = {
49555 style:"width:300px;height:60px;",
49556 autocomplete: "new-password"
49559 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49562 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49563 if(this.preventScrollbars){
49564 this.el.setStyle("overflow", "hidden");
49566 this.el.setHeight(this.growMin);
49569 //console.log('onrender' + this.getId() );
49570 Roo.form.FCKeditor.editors[this.getId()] = this;
49573 this.replaceTextarea() ;
49577 getEditor : function() {
49578 return this.fckEditor;
49581 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49582 * @param {Mixed} value The value to set
49586 setValue : function(value)
49588 //console.log('setValue: ' + value);
49590 if(typeof(value) == 'undefined') { // not sure why this is happending...
49593 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49595 //if(!this.el || !this.getEditor()) {
49596 // this.value = value;
49597 //this.setValue.defer(100,this,[value]);
49601 if(!this.getEditor()) {
49605 this.getEditor().SetData(value);
49612 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49613 * @return {Mixed} value The field value
49615 getValue : function()
49618 if (this.frame && this.frame.dom.style.display == 'none') {
49619 return Roo.form.FCKeditor.superclass.getValue.call(this);
49622 if(!this.el || !this.getEditor()) {
49624 // this.getValue.defer(100,this);
49629 var value=this.getEditor().GetData();
49630 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49631 return Roo.form.FCKeditor.superclass.getValue.call(this);
49637 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49638 * @return {Mixed} value The field value
49640 getRawValue : function()
49642 if (this.frame && this.frame.dom.style.display == 'none') {
49643 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49646 if(!this.el || !this.getEditor()) {
49647 //this.getRawValue.defer(100,this);
49654 var value=this.getEditor().GetData();
49655 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49656 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49660 setSize : function(w,h) {
49664 //if (this.frame && this.frame.dom.style.display == 'none') {
49665 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49668 //if(!this.el || !this.getEditor()) {
49669 // this.setSize.defer(100,this, [w,h]);
49675 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49677 this.frame.dom.setAttribute('width', w);
49678 this.frame.dom.setAttribute('height', h);
49679 this.frame.setSize(w,h);
49683 toggleSourceEdit : function(value) {
49687 this.el.dom.style.display = value ? '' : 'none';
49688 this.frame.dom.style.display = value ? 'none' : '';
49693 focus: function(tag)
49695 if (this.frame.dom.style.display == 'none') {
49696 return Roo.form.FCKeditor.superclass.focus.call(this);
49698 if(!this.el || !this.getEditor()) {
49699 this.focus.defer(100,this, [tag]);
49706 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49707 this.getEditor().Focus();
49709 if (!this.getEditor().Selection.GetSelection()) {
49710 this.focus.defer(100,this, [tag]);
49715 var r = this.getEditor().EditorDocument.createRange();
49716 r.setStart(tgs[0],0);
49717 r.setEnd(tgs[0],0);
49718 this.getEditor().Selection.GetSelection().removeAllRanges();
49719 this.getEditor().Selection.GetSelection().addRange(r);
49720 this.getEditor().Focus();
49727 replaceTextarea : function()
49729 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49732 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49734 // We must check the elements firstly using the Id and then the name.
49735 var oTextarea = document.getElementById( this.getId() );
49737 var colElementsByName = document.getElementsByName( this.getId() ) ;
49739 oTextarea.style.display = 'none' ;
49741 if ( oTextarea.tabIndex ) {
49742 this.TabIndex = oTextarea.tabIndex ;
49745 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49746 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49747 this.frame = Roo.get(this.getId() + '___Frame')
49750 _getConfigHtml : function()
49754 for ( var o in this.fckconfig ) {
49755 sConfig += sConfig.length > 0 ? '&' : '';
49756 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49759 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49763 _getIFrameHtml : function()
49765 var sFile = 'fckeditor.html' ;
49766 /* no idea what this is about..
49769 if ( (/fcksource=true/i).test( window.top.location.search ) )
49770 sFile = 'fckeditor.original.html' ;
49775 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49776 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49779 var html = '<iframe id="' + this.getId() +
49780 '___Frame" src="' + sLink +
49781 '" width="' + this.width +
49782 '" height="' + this.height + '"' +
49783 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
49784 ' frameborder="0" scrolling="no"></iframe>' ;
49789 _insertHtmlBefore : function( html, element )
49791 if ( element.insertAdjacentHTML ) {
49793 element.insertAdjacentHTML( 'beforeBegin', html ) ;
49795 var oRange = document.createRange() ;
49796 oRange.setStartBefore( element ) ;
49797 var oFragment = oRange.createContextualFragment( html );
49798 element.parentNode.insertBefore( oFragment, element ) ;
49811 //Roo.reg('fckeditor', Roo.form.FCKeditor);
49813 function FCKeditor_OnComplete(editorInstance){
49814 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
49815 f.fckEditor = editorInstance;
49816 //console.log("loaded");
49817 f.fireEvent('editorinit', f, editorInstance);
49837 //<script type="text/javascript">
49839 * @class Roo.form.GridField
49840 * @extends Roo.form.Field
49841 * Embed a grid (or editable grid into a form)
49844 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
49846 * xgrid.store = Roo.data.Store
49847 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
49848 * xgrid.store.reader = Roo.data.JsonReader
49852 * Creates a new GridField
49853 * @param {Object} config Configuration options
49855 Roo.form.GridField = function(config){
49856 Roo.form.GridField.superclass.constructor.call(this, config);
49860 Roo.extend(Roo.form.GridField, Roo.form.Field, {
49862 * @cfg {Number} width - used to restrict width of grid..
49866 * @cfg {Number} height - used to restrict height of grid..
49870 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
49876 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49877 * {tag: "input", type: "checkbox", autocomplete: "off"})
49879 // defaultAutoCreate : { tag: 'div' },
49880 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
49882 * @cfg {String} addTitle Text to include for adding a title.
49886 onResize : function(){
49887 Roo.form.Field.superclass.onResize.apply(this, arguments);
49890 initEvents : function(){
49891 // Roo.form.Checkbox.superclass.initEvents.call(this);
49892 // has no events...
49897 getResizeEl : function(){
49901 getPositionEl : function(){
49906 onRender : function(ct, position){
49908 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
49909 var style = this.style;
49912 Roo.form.GridField.superclass.onRender.call(this, ct, position);
49913 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
49914 this.viewEl = this.wrap.createChild({ tag: 'div' });
49916 this.viewEl.applyStyles(style);
49919 this.viewEl.setWidth(this.width);
49922 this.viewEl.setHeight(this.height);
49924 //if(this.inputValue !== undefined){
49925 //this.setValue(this.value);
49928 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
49931 this.grid.render();
49932 this.grid.getDataSource().on('remove', this.refreshValue, this);
49933 this.grid.getDataSource().on('update', this.refreshValue, this);
49934 this.grid.on('afteredit', this.refreshValue, this);
49940 * Sets the value of the item.
49941 * @param {String} either an object or a string..
49943 setValue : function(v){
49945 v = v || []; // empty set..
49946 // this does not seem smart - it really only affects memoryproxy grids..
49947 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
49948 var ds = this.grid.getDataSource();
49949 // assumes a json reader..
49951 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
49952 ds.loadData( data);
49954 // clear selection so it does not get stale.
49955 if (this.grid.sm) {
49956 this.grid.sm.clearSelections();
49959 Roo.form.GridField.superclass.setValue.call(this, v);
49960 this.refreshValue();
49961 // should load data in the grid really....
49965 refreshValue: function() {
49967 this.grid.getDataSource().each(function(r) {
49970 this.el.dom.value = Roo.encode(val);
49978 * Ext JS Library 1.1.1
49979 * Copyright(c) 2006-2007, Ext JS, LLC.
49981 * Originally Released Under LGPL - original licence link has changed is not relivant.
49984 * <script type="text/javascript">
49987 * @class Roo.form.DisplayField
49988 * @extends Roo.form.Field
49989 * A generic Field to display non-editable data.
49990 * @cfg {Boolean} closable (true|false) default false
49992 * Creates a new Display Field item.
49993 * @param {Object} config Configuration options
49995 Roo.form.DisplayField = function(config){
49996 Roo.form.DisplayField.superclass.constructor.call(this, config);
50001 * Fires after the click the close btn
50002 * @param {Roo.form.DisplayField} this
50008 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50009 inputType: 'hidden',
50015 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50017 focusClass : undefined,
50019 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50021 fieldClass: 'x-form-field',
50024 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50026 valueRenderer: undefined,
50030 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50031 * {tag: "input", type: "checkbox", autocomplete: "off"})
50034 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50038 onResize : function(){
50039 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50043 initEvents : function(){
50044 // Roo.form.Checkbox.superclass.initEvents.call(this);
50045 // has no events...
50048 this.closeEl.on('click', this.onClose, this);
50054 getResizeEl : function(){
50058 getPositionEl : function(){
50063 onRender : function(ct, position){
50065 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50066 //if(this.inputValue !== undefined){
50067 this.wrap = this.el.wrap();
50069 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50072 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50075 if (this.bodyStyle) {
50076 this.viewEl.applyStyles(this.bodyStyle);
50078 //this.viewEl.setStyle('padding', '2px');
50080 this.setValue(this.value);
50085 initValue : Roo.emptyFn,
50090 onClick : function(){
50095 * Sets the checked state of the checkbox.
50096 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50098 setValue : function(v){
50100 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50101 // this might be called before we have a dom element..
50102 if (!this.viewEl) {
50105 this.viewEl.dom.innerHTML = html;
50106 Roo.form.DisplayField.superclass.setValue.call(this, v);
50110 onClose : function(e)
50112 e.preventDefault();
50114 this.fireEvent('close', this);
50123 * @class Roo.form.DayPicker
50124 * @extends Roo.form.Field
50125 * A Day picker show [M] [T] [W] ....
50127 * Creates a new Day Picker
50128 * @param {Object} config Configuration options
50130 Roo.form.DayPicker= function(config){
50131 Roo.form.DayPicker.superclass.constructor.call(this, config);
50135 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50137 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50139 focusClass : undefined,
50141 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50143 fieldClass: "x-form-field",
50146 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50147 * {tag: "input", type: "checkbox", autocomplete: "off"})
50149 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50152 actionMode : 'viewEl',
50156 inputType : 'hidden',
50159 inputElement: false, // real input element?
50160 basedOn: false, // ????
50162 isFormField: true, // not sure where this is needed!!!!
50164 onResize : function(){
50165 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50166 if(!this.boxLabel){
50167 this.el.alignTo(this.wrap, 'c-c');
50171 initEvents : function(){
50172 Roo.form.Checkbox.superclass.initEvents.call(this);
50173 this.el.on("click", this.onClick, this);
50174 this.el.on("change", this.onClick, this);
50178 getResizeEl : function(){
50182 getPositionEl : function(){
50188 onRender : function(ct, position){
50189 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50191 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50193 var r1 = '<table><tr>';
50194 var r2 = '<tr class="x-form-daypick-icons">';
50195 for (var i=0; i < 7; i++) {
50196 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50197 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50200 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50201 viewEl.select('img').on('click', this.onClick, this);
50202 this.viewEl = viewEl;
50205 // this will not work on Chrome!!!
50206 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50207 this.el.on('propertychange', this.setFromHidden, this); //ie
50215 initValue : Roo.emptyFn,
50218 * Returns the checked state of the checkbox.
50219 * @return {Boolean} True if checked, else false
50221 getValue : function(){
50222 return this.el.dom.value;
50227 onClick : function(e){
50228 //this.setChecked(!this.checked);
50229 Roo.get(e.target).toggleClass('x-menu-item-checked');
50230 this.refreshValue();
50231 //if(this.el.dom.checked != this.checked){
50232 // this.setValue(this.el.dom.checked);
50237 refreshValue : function()
50240 this.viewEl.select('img',true).each(function(e,i,n) {
50241 val += e.is(".x-menu-item-checked") ? String(n) : '';
50243 this.setValue(val, true);
50247 * Sets the checked state of the checkbox.
50248 * On is always based on a string comparison between inputValue and the param.
50249 * @param {Boolean/String} value - the value to set
50250 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50252 setValue : function(v,suppressEvent){
50253 if (!this.el.dom) {
50256 var old = this.el.dom.value ;
50257 this.el.dom.value = v;
50258 if (suppressEvent) {
50262 // update display..
50263 this.viewEl.select('img',true).each(function(e,i,n) {
50265 var on = e.is(".x-menu-item-checked");
50266 var newv = v.indexOf(String(n)) > -1;
50268 e.toggleClass('x-menu-item-checked');
50274 this.fireEvent('change', this, v, old);
50279 // handle setting of hidden value by some other method!!?!?
50280 setFromHidden: function()
50285 //console.log("SET FROM HIDDEN");
50286 //alert('setFrom hidden');
50287 this.setValue(this.el.dom.value);
50290 onDestroy : function()
50293 Roo.get(this.viewEl).remove();
50296 Roo.form.DayPicker.superclass.onDestroy.call(this);
50300 * RooJS Library 1.1.1
50301 * Copyright(c) 2008-2011 Alan Knowles
50308 * @class Roo.form.ComboCheck
50309 * @extends Roo.form.ComboBox
50310 * A combobox for multiple select items.
50312 * FIXME - could do with a reset button..
50315 * Create a new ComboCheck
50316 * @param {Object} config Configuration options
50318 Roo.form.ComboCheck = function(config){
50319 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50320 // should verify some data...
50322 // hiddenName = required..
50323 // displayField = required
50324 // valudField == required
50325 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50327 Roo.each(req, function(e) {
50328 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50329 throw "Roo.form.ComboCheck : missing value for: " + e;
50336 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50341 selectedClass: 'x-menu-item-checked',
50344 onRender : function(ct, position){
50350 var cls = 'x-combo-list';
50353 this.tpl = new Roo.Template({
50354 html : '<div class="'+cls+'-item x-menu-check-item">' +
50355 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50356 '<span>{' + this.displayField + '}</span>' +
50363 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50364 this.view.singleSelect = false;
50365 this.view.multiSelect = true;
50366 this.view.toggleSelect = true;
50367 this.pageTb.add(new Roo.Toolbar.Fill(), {
50370 handler: function()
50377 onViewOver : function(e, t){
50383 onViewClick : function(doFocus,index){
50387 select: function () {
50388 //Roo.log("SELECT CALLED");
50391 selectByValue : function(xv, scrollIntoView){
50392 var ar = this.getValueArray();
50395 Roo.each(ar, function(v) {
50396 if(v === undefined || v === null){
50399 var r = this.findRecord(this.valueField, v);
50401 sels.push(this.store.indexOf(r))
50405 this.view.select(sels);
50411 onSelect : function(record, index){
50412 // Roo.log("onselect Called");
50413 // this is only called by the clear button now..
50414 this.view.clearSelections();
50415 this.setValue('[]');
50416 if (this.value != this.valueBefore) {
50417 this.fireEvent('change', this, this.value, this.valueBefore);
50418 this.valueBefore = this.value;
50421 getValueArray : function()
50426 //Roo.log(this.value);
50427 if (typeof(this.value) == 'undefined') {
50430 var ar = Roo.decode(this.value);
50431 return ar instanceof Array ? ar : []; //?? valid?
50434 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50439 expand : function ()
50442 Roo.form.ComboCheck.superclass.expand.call(this);
50443 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50444 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50449 collapse : function(){
50450 Roo.form.ComboCheck.superclass.collapse.call(this);
50451 var sl = this.view.getSelectedIndexes();
50452 var st = this.store;
50456 Roo.each(sl, function(i) {
50458 nv.push(r.get(this.valueField));
50460 this.setValue(Roo.encode(nv));
50461 if (this.value != this.valueBefore) {
50463 this.fireEvent('change', this, this.value, this.valueBefore);
50464 this.valueBefore = this.value;
50469 setValue : function(v){
50473 var vals = this.getValueArray();
50475 Roo.each(vals, function(k) {
50476 var r = this.findRecord(this.valueField, k);
50478 tv.push(r.data[this.displayField]);
50479 }else if(this.valueNotFoundText !== undefined){
50480 tv.push( this.valueNotFoundText );
50485 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50486 this.hiddenField.value = v;
50492 * Ext JS Library 1.1.1
50493 * Copyright(c) 2006-2007, Ext JS, LLC.
50495 * Originally Released Under LGPL - original licence link has changed is not relivant.
50498 * <script type="text/javascript">
50502 * @class Roo.form.Signature
50503 * @extends Roo.form.Field
50507 * @param {Object} config Configuration options
50510 Roo.form.Signature = function(config){
50511 Roo.form.Signature.superclass.constructor.call(this, config);
50513 this.addEvents({// not in used??
50516 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50517 * @param {Roo.form.Signature} combo This combo box
50522 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50523 * @param {Roo.form.ComboBox} combo This combo box
50524 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50530 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50532 * @cfg {Object} labels Label to use when rendering a form.
50536 * confirm : "Confirm"
50541 confirm : "Confirm"
50544 * @cfg {Number} width The signature panel width (defaults to 300)
50548 * @cfg {Number} height The signature panel height (defaults to 100)
50552 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50554 allowBlank : false,
50557 // {Object} signPanel The signature SVG panel element (defaults to {})
50559 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50560 isMouseDown : false,
50561 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50562 isConfirmed : false,
50563 // {String} signatureTmp SVG mapping string (defaults to empty string)
50567 defaultAutoCreate : { // modified by initCompnoent..
50573 onRender : function(ct, position){
50575 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50577 this.wrap = this.el.wrap({
50578 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50581 this.createToolbar(this);
50582 this.signPanel = this.wrap.createChild({
50584 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50588 this.svgID = Roo.id();
50589 this.svgEl = this.signPanel.createChild({
50590 xmlns : 'http://www.w3.org/2000/svg',
50592 id : this.svgID + "-svg",
50594 height: this.height,
50595 viewBox: '0 0 '+this.width+' '+this.height,
50599 id: this.svgID + "-svg-r",
50601 height: this.height,
50606 id: this.svgID + "-svg-l",
50608 y1: (this.height*0.8), // start set the line in 80% of height
50609 x2: this.width, // end
50610 y2: (this.height*0.8), // end set the line in 80% of height
50612 'stroke-width': "1",
50613 'stroke-dasharray': "3",
50614 'shape-rendering': "crispEdges",
50615 'pointer-events': "none"
50619 id: this.svgID + "-svg-p",
50621 'stroke-width': "3",
50623 'pointer-events': 'none'
50628 this.svgBox = this.svgEl.dom.getScreenCTM();
50630 createSVG : function(){
50631 var svg = this.signPanel;
50632 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50635 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50636 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50637 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50638 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50639 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50640 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50641 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50644 isTouchEvent : function(e){
50645 return e.type.match(/^touch/);
50647 getCoords : function (e) {
50648 var pt = this.svgEl.dom.createSVGPoint();
50651 if (this.isTouchEvent(e)) {
50652 pt.x = e.targetTouches[0].clientX;
50653 pt.y = e.targetTouches[0].clientY;
50655 var a = this.svgEl.dom.getScreenCTM();
50656 var b = a.inverse();
50657 var mx = pt.matrixTransform(b);
50658 return mx.x + ',' + mx.y;
50660 //mouse event headler
50661 down : function (e) {
50662 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50663 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50665 this.isMouseDown = true;
50667 e.preventDefault();
50669 move : function (e) {
50670 if (this.isMouseDown) {
50671 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50672 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50675 e.preventDefault();
50677 up : function (e) {
50678 this.isMouseDown = false;
50679 var sp = this.signatureTmp.split(' ');
50682 if(!sp[sp.length-2].match(/^L/)){
50686 this.signatureTmp = sp.join(" ");
50689 if(this.getValue() != this.signatureTmp){
50690 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50691 this.isConfirmed = false;
50693 e.preventDefault();
50697 * Protected method that will not generally be called directly. It
50698 * is called when the editor creates its toolbar. Override this method if you need to
50699 * add custom toolbar buttons.
50700 * @param {HtmlEditor} editor
50702 createToolbar : function(editor){
50703 function btn(id, toggle, handler){
50704 var xid = fid + '-'+ id ;
50708 cls : 'x-btn-icon x-edit-'+id,
50709 enableToggle:toggle !== false,
50710 scope: editor, // was editor...
50711 handler:handler||editor.relayBtnCmd,
50712 clickEvent:'mousedown',
50713 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50719 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50723 cls : ' x-signature-btn x-signature-'+id,
50724 scope: editor, // was editor...
50725 handler: this.reset,
50726 clickEvent:'mousedown',
50727 text: this.labels.clear
50734 cls : ' x-signature-btn x-signature-'+id,
50735 scope: editor, // was editor...
50736 handler: this.confirmHandler,
50737 clickEvent:'mousedown',
50738 text: this.labels.confirm
50745 * when user is clicked confirm then show this image.....
50747 * @return {String} Image Data URI
50749 getImageDataURI : function(){
50750 var svg = this.svgEl.dom.parentNode.innerHTML;
50751 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50756 * @return {Boolean} this.isConfirmed
50758 getConfirmed : function(){
50759 return this.isConfirmed;
50763 * @return {Number} this.width
50765 getWidth : function(){
50770 * @return {Number} this.height
50772 getHeight : function(){
50773 return this.height;
50776 getSignature : function(){
50777 return this.signatureTmp;
50780 reset : function(){
50781 this.signatureTmp = '';
50782 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50783 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
50784 this.isConfirmed = false;
50785 Roo.form.Signature.superclass.reset.call(this);
50787 setSignature : function(s){
50788 this.signatureTmp = s;
50789 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50790 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
50792 this.isConfirmed = false;
50793 Roo.form.Signature.superclass.reset.call(this);
50796 // Roo.log(this.signPanel.dom.contentWindow.up())
50799 setConfirmed : function(){
50803 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
50806 confirmHandler : function(){
50807 if(!this.getSignature()){
50811 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
50812 this.setValue(this.getSignature());
50813 this.isConfirmed = true;
50815 this.fireEvent('confirm', this);
50818 // Subclasses should provide the validation implementation by overriding this
50819 validateValue : function(value){
50820 if(this.allowBlank){
50824 if(this.isConfirmed){
50831 * Ext JS Library 1.1.1
50832 * Copyright(c) 2006-2007, Ext JS, LLC.
50834 * Originally Released Under LGPL - original licence link has changed is not relivant.
50837 * <script type="text/javascript">
50842 * @class Roo.form.ComboBox
50843 * @extends Roo.form.TriggerField
50844 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
50846 * Create a new ComboBox.
50847 * @param {Object} config Configuration options
50849 Roo.form.Select = function(config){
50850 Roo.form.Select.superclass.constructor.call(this, config);
50854 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
50856 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
50859 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
50860 * rendering into an Roo.Editor, defaults to false)
50863 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
50864 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
50867 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
50870 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
50871 * the dropdown list (defaults to undefined, with no header element)
50875 * @cfg {String/Roo.Template} tpl The template to use to render the output
50879 defaultAutoCreate : {tag: "select" },
50881 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
50883 listWidth: undefined,
50885 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
50886 * mode = 'remote' or 'text' if mode = 'local')
50888 displayField: undefined,
50890 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
50891 * mode = 'remote' or 'value' if mode = 'local').
50892 * Note: use of a valueField requires the user make a selection
50893 * in order for a value to be mapped.
50895 valueField: undefined,
50899 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
50900 * field's data value (defaults to the underlying DOM element's name)
50902 hiddenName: undefined,
50904 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
50908 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
50910 selectedClass: 'x-combo-selected',
50912 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
50913 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
50914 * which displays a downward arrow icon).
50916 triggerClass : 'x-form-arrow-trigger',
50918 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
50922 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
50923 * anchor positions (defaults to 'tl-bl')
50925 listAlign: 'tl-bl?',
50927 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
50931 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
50932 * query specified by the allQuery config option (defaults to 'query')
50934 triggerAction: 'query',
50936 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
50937 * (defaults to 4, does not apply if editable = false)
50941 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
50942 * delay (typeAheadDelay) if it matches a known value (defaults to false)
50946 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
50947 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
50951 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
50952 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
50956 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
50957 * when editable = true (defaults to false)
50959 selectOnFocus:false,
50961 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
50963 queryParam: 'query',
50965 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
50966 * when mode = 'remote' (defaults to 'Loading...')
50968 loadingText: 'Loading...',
50970 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
50974 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
50978 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
50979 * traditional select (defaults to true)
50983 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
50987 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
50991 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
50992 * listWidth has a higher value)
50996 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
50997 * allow the user to set arbitrary text into the field (defaults to false)
50999 forceSelection:false,
51001 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
51002 * if typeAhead = true (defaults to 250)
51004 typeAheadDelay : 250,
51006 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
51007 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51009 valueNotFoundText : undefined,
51012 * @cfg {String} defaultValue The value displayed after loading the store.
51017 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51019 blockFocus : false,
51022 * @cfg {Boolean} disableClear Disable showing of clear button.
51024 disableClear : false,
51026 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51028 alwaysQuery : false,
51034 // element that contains real text value.. (when hidden is used..)
51037 onRender : function(ct, position){
51038 Roo.form.Field.prototype.onRender.call(this, ct, position);
51041 this.store.on('beforeload', this.onBeforeLoad, this);
51042 this.store.on('load', this.onLoad, this);
51043 this.store.on('loadexception', this.onLoadException, this);
51044 this.store.load({});
51052 initEvents : function(){
51053 //Roo.form.ComboBox.superclass.initEvents.call(this);
51057 onDestroy : function(){
51060 this.store.un('beforeload', this.onBeforeLoad, this);
51061 this.store.un('load', this.onLoad, this);
51062 this.store.un('loadexception', this.onLoadException, this);
51064 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51068 fireKey : function(e){
51069 if(e.isNavKeyPress() && !this.list.isVisible()){
51070 this.fireEvent("specialkey", this, e);
51075 onResize: function(w, h){
51083 * Allow or prevent the user from directly editing the field text. If false is passed,
51084 * the user will only be able to select from the items defined in the dropdown list. This method
51085 * is the runtime equivalent of setting the 'editable' config option at config time.
51086 * @param {Boolean} value True to allow the user to directly edit the field text
51088 setEditable : function(value){
51093 onBeforeLoad : function(){
51095 Roo.log("Select before load");
51098 this.innerList.update(this.loadingText ?
51099 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51100 //this.restrictHeight();
51101 this.selectedIndex = -1;
51105 onLoad : function(){
51108 var dom = this.el.dom;
51109 dom.innerHTML = '';
51110 var od = dom.ownerDocument;
51112 if (this.emptyText) {
51113 var op = od.createElement('option');
51114 op.setAttribute('value', '');
51115 op.innerHTML = String.format('{0}', this.emptyText);
51116 dom.appendChild(op);
51118 if(this.store.getCount() > 0){
51120 var vf = this.valueField;
51121 var df = this.displayField;
51122 this.store.data.each(function(r) {
51123 // which colmsn to use... testing - cdoe / title..
51124 var op = od.createElement('option');
51125 op.setAttribute('value', r.data[vf]);
51126 op.innerHTML = String.format('{0}', r.data[df]);
51127 dom.appendChild(op);
51129 if (typeof(this.defaultValue != 'undefined')) {
51130 this.setValue(this.defaultValue);
51135 //this.onEmptyResults();
51140 onLoadException : function()
51142 dom.innerHTML = '';
51144 Roo.log("Select on load exception");
51148 Roo.log(this.store.reader.jsonData);
51149 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51150 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51156 onTypeAhead : function(){
51161 onSelect : function(record, index){
51162 Roo.log('on select?');
51164 if(this.fireEvent('beforeselect', this, record, index) !== false){
51165 this.setFromData(index > -1 ? record.data : false);
51167 this.fireEvent('select', this, record, index);
51172 * Returns the currently selected field value or empty string if no value is set.
51173 * @return {String} value The selected value
51175 getValue : function(){
51176 var dom = this.el.dom;
51177 this.value = dom.options[dom.selectedIndex].value;
51183 * Clears any text/value currently set in the field
51185 clearValue : function(){
51187 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51192 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51193 * will be displayed in the field. If the value does not match the data value of an existing item,
51194 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51195 * Otherwise the field will be blank (although the value will still be set).
51196 * @param {String} value The value to match
51198 setValue : function(v){
51199 var d = this.el.dom;
51200 for (var i =0; i < d.options.length;i++) {
51201 if (v == d.options[i].value) {
51202 d.selectedIndex = i;
51210 * @property {Object} the last set data for the element
51215 * Sets the value of the field based on a object which is related to the record format for the store.
51216 * @param {Object} value the value to set as. or false on reset?
51218 setFromData : function(o){
51219 Roo.log('setfrom data?');
51225 reset : function(){
51229 findRecord : function(prop, value){
51234 if(this.store.getCount() > 0){
51235 this.store.each(function(r){
51236 if(r.data[prop] == value){
51246 getName: function()
51248 // returns hidden if it's set..
51249 if (!this.rendered) {return ''};
51250 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51258 onEmptyResults : function(){
51259 Roo.log('empty results');
51264 * Returns true if the dropdown list is expanded, else false.
51266 isExpanded : function(){
51271 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51272 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51273 * @param {String} value The data value of the item to select
51274 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51275 * selected item if it is not currently in view (defaults to true)
51276 * @return {Boolean} True if the value matched an item in the list, else false
51278 selectByValue : function(v, scrollIntoView){
51279 Roo.log('select By Value');
51282 if(v !== undefined && v !== null){
51283 var r = this.findRecord(this.valueField || this.displayField, v);
51285 this.select(this.store.indexOf(r), scrollIntoView);
51293 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51294 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51295 * @param {Number} index The zero-based index of the list item to select
51296 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51297 * selected item if it is not currently in view (defaults to true)
51299 select : function(index, scrollIntoView){
51300 Roo.log('select ');
51303 this.selectedIndex = index;
51304 this.view.select(index);
51305 if(scrollIntoView !== false){
51306 var el = this.view.getNode(index);
51308 this.innerList.scrollChildIntoView(el, false);
51316 validateBlur : function(){
51323 initQuery : function(){
51324 this.doQuery(this.getRawValue());
51328 doForce : function(){
51329 if(this.el.dom.value.length > 0){
51330 this.el.dom.value =
51331 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51337 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51338 * query allowing the query action to be canceled if needed.
51339 * @param {String} query The SQL query to execute
51340 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51341 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51342 * saved in the current store (defaults to false)
51344 doQuery : function(q, forceAll){
51346 Roo.log('doQuery?');
51347 if(q === undefined || q === null){
51352 forceAll: forceAll,
51356 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51360 forceAll = qe.forceAll;
51361 if(forceAll === true || (q.length >= this.minChars)){
51362 if(this.lastQuery != q || this.alwaysQuery){
51363 this.lastQuery = q;
51364 if(this.mode == 'local'){
51365 this.selectedIndex = -1;
51367 this.store.clearFilter();
51369 this.store.filter(this.displayField, q);
51373 this.store.baseParams[this.queryParam] = q;
51375 params: this.getParams(q)
51380 this.selectedIndex = -1;
51387 getParams : function(q){
51389 //p[this.queryParam] = q;
51392 p.limit = this.pageSize;
51398 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51400 collapse : function(){
51405 collapseIf : function(e){
51410 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51412 expand : function(){
51420 * @cfg {Boolean} grow
51424 * @cfg {Number} growMin
51428 * @cfg {Number} growMax
51436 setWidth : function()
51440 getResizeEl : function(){
51443 });//<script type="text/javasscript">
51447 * @class Roo.DDView
51448 * A DnD enabled version of Roo.View.
51449 * @param {Element/String} container The Element in which to create the View.
51450 * @param {String} tpl The template string used to create the markup for each element of the View
51451 * @param {Object} config The configuration properties. These include all the config options of
51452 * {@link Roo.View} plus some specific to this class.<br>
51454 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51455 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51457 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51458 .x-view-drag-insert-above {
51459 border-top:1px dotted #3366cc;
51461 .x-view-drag-insert-below {
51462 border-bottom:1px dotted #3366cc;
51468 Roo.DDView = function(container, tpl, config) {
51469 Roo.DDView.superclass.constructor.apply(this, arguments);
51470 this.getEl().setStyle("outline", "0px none");
51471 this.getEl().unselectable();
51472 if (this.dragGroup) {
51473 this.setDraggable(this.dragGroup.split(","));
51475 if (this.dropGroup) {
51476 this.setDroppable(this.dropGroup.split(","));
51478 if (this.deletable) {
51479 this.setDeletable();
51481 this.isDirtyFlag = false;
51487 Roo.extend(Roo.DDView, Roo.View, {
51488 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51489 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51490 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51491 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51495 reset: Roo.emptyFn,
51497 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51499 validate: function() {
51503 destroy: function() {
51504 this.purgeListeners();
51505 this.getEl.removeAllListeners();
51506 this.getEl().remove();
51507 if (this.dragZone) {
51508 if (this.dragZone.destroy) {
51509 this.dragZone.destroy();
51512 if (this.dropZone) {
51513 if (this.dropZone.destroy) {
51514 this.dropZone.destroy();
51519 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51520 getName: function() {
51524 /** Loads the View from a JSON string representing the Records to put into the Store. */
51525 setValue: function(v) {
51527 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51530 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51531 this.store.proxy = new Roo.data.MemoryProxy(data);
51535 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51536 getValue: function() {
51538 this.store.each(function(rec) {
51539 result += rec.id + ',';
51541 return result.substr(0, result.length - 1) + ')';
51544 getIds: function() {
51545 var i = 0, result = new Array(this.store.getCount());
51546 this.store.each(function(rec) {
51547 result[i++] = rec.id;
51552 isDirty: function() {
51553 return this.isDirtyFlag;
51557 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51558 * whole Element becomes the target, and this causes the drop gesture to append.
51560 getTargetFromEvent : function(e) {
51561 var target = e.getTarget();
51562 while ((target !== null) && (target.parentNode != this.el.dom)) {
51563 target = target.parentNode;
51566 target = this.el.dom.lastChild || this.el.dom;
51572 * Create the drag data which consists of an object which has the property "ddel" as
51573 * the drag proxy element.
51575 getDragData : function(e) {
51576 var target = this.findItemFromChild(e.getTarget());
51578 this.handleSelection(e);
51579 var selNodes = this.getSelectedNodes();
51582 copy: this.copy || (this.allowCopy && e.ctrlKey),
51586 var selectedIndices = this.getSelectedIndexes();
51587 for (var i = 0; i < selectedIndices.length; i++) {
51588 dragData.records.push(this.store.getAt(selectedIndices[i]));
51590 if (selNodes.length == 1) {
51591 dragData.ddel = target.cloneNode(true); // the div element
51593 var div = document.createElement('div'); // create the multi element drag "ghost"
51594 div.className = 'multi-proxy';
51595 for (var i = 0, len = selNodes.length; i < len; i++) {
51596 div.appendChild(selNodes[i].cloneNode(true));
51598 dragData.ddel = div;
51600 //console.log(dragData)
51601 //console.log(dragData.ddel.innerHTML)
51604 //console.log('nodragData')
51608 /** Specify to which ddGroup items in this DDView may be dragged. */
51609 setDraggable: function(ddGroup) {
51610 if (ddGroup instanceof Array) {
51611 Roo.each(ddGroup, this.setDraggable, this);
51614 if (this.dragZone) {
51615 this.dragZone.addToGroup(ddGroup);
51617 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51618 containerScroll: true,
51622 // Draggability implies selection. DragZone's mousedown selects the element.
51623 if (!this.multiSelect) { this.singleSelect = true; }
51625 // Wire the DragZone's handlers up to methods in *this*
51626 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51630 /** Specify from which ddGroup this DDView accepts drops. */
51631 setDroppable: function(ddGroup) {
51632 if (ddGroup instanceof Array) {
51633 Roo.each(ddGroup, this.setDroppable, this);
51636 if (this.dropZone) {
51637 this.dropZone.addToGroup(ddGroup);
51639 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51640 containerScroll: true,
51644 // Wire the DropZone's handlers up to methods in *this*
51645 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51646 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51647 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51648 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51649 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51653 /** Decide whether to drop above or below a View node. */
51654 getDropPoint : function(e, n, dd){
51655 if (n == this.el.dom) { return "above"; }
51656 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51657 var c = t + (b - t) / 2;
51658 var y = Roo.lib.Event.getPageY(e);
51666 onNodeEnter : function(n, dd, e, data){
51670 onNodeOver : function(n, dd, e, data){
51671 var pt = this.getDropPoint(e, n, dd);
51672 // set the insert point style on the target node
51673 var dragElClass = this.dropNotAllowed;
51676 if (pt == "above"){
51677 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51678 targetElClass = "x-view-drag-insert-above";
51680 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51681 targetElClass = "x-view-drag-insert-below";
51683 if (this.lastInsertClass != targetElClass){
51684 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51685 this.lastInsertClass = targetElClass;
51688 return dragElClass;
51691 onNodeOut : function(n, dd, e, data){
51692 this.removeDropIndicators(n);
51695 onNodeDrop : function(n, dd, e, data){
51696 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51699 var pt = this.getDropPoint(e, n, dd);
51700 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51701 if (pt == "below") { insertAt++; }
51702 for (var i = 0; i < data.records.length; i++) {
51703 var r = data.records[i];
51704 var dup = this.store.getById(r.id);
51705 if (dup && (dd != this.dragZone)) {
51706 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51709 this.store.insert(insertAt++, r.copy());
51711 data.source.isDirtyFlag = true;
51713 this.store.insert(insertAt++, r);
51715 this.isDirtyFlag = true;
51718 this.dragZone.cachedTarget = null;
51722 removeDropIndicators : function(n){
51724 Roo.fly(n).removeClass([
51725 "x-view-drag-insert-above",
51726 "x-view-drag-insert-below"]);
51727 this.lastInsertClass = "_noclass";
51732 * Utility method. Add a delete option to the DDView's context menu.
51733 * @param {String} imageUrl The URL of the "delete" icon image.
51735 setDeletable: function(imageUrl) {
51736 if (!this.singleSelect && !this.multiSelect) {
51737 this.singleSelect = true;
51739 var c = this.getContextMenu();
51740 this.contextMenu.on("itemclick", function(item) {
51743 this.remove(this.getSelectedIndexes());
51747 this.contextMenu.add({
51754 /** Return the context menu for this DDView. */
51755 getContextMenu: function() {
51756 if (!this.contextMenu) {
51757 // Create the View's context menu
51758 this.contextMenu = new Roo.menu.Menu({
51759 id: this.id + "-contextmenu"
51761 this.el.on("contextmenu", this.showContextMenu, this);
51763 return this.contextMenu;
51766 disableContextMenu: function() {
51767 if (this.contextMenu) {
51768 this.el.un("contextmenu", this.showContextMenu, this);
51772 showContextMenu: function(e, item) {
51773 item = this.findItemFromChild(e.getTarget());
51776 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51777 this.contextMenu.showAt(e.getXY());
51782 * Remove {@link Roo.data.Record}s at the specified indices.
51783 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
51785 remove: function(selectedIndices) {
51786 selectedIndices = [].concat(selectedIndices);
51787 for (var i = 0; i < selectedIndices.length; i++) {
51788 var rec = this.store.getAt(selectedIndices[i]);
51789 this.store.remove(rec);
51794 * Double click fires the event, but also, if this is draggable, and there is only one other
51795 * related DropZone, it transfers the selected node.
51797 onDblClick : function(e){
51798 var item = this.findItemFromChild(e.getTarget());
51800 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
51803 if (this.dragGroup) {
51804 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
51805 while (targets.indexOf(this.dropZone) > -1) {
51806 targets.remove(this.dropZone);
51808 if (targets.length == 1) {
51809 this.dragZone.cachedTarget = null;
51810 var el = Roo.get(targets[0].getEl());
51811 var box = el.getBox(true);
51812 targets[0].onNodeDrop(el.dom, {
51814 xy: [box.x, box.y + box.height - 1]
51815 }, null, this.getDragData(e));
51821 handleSelection: function(e) {
51822 this.dragZone.cachedTarget = null;
51823 var item = this.findItemFromChild(e.getTarget());
51825 this.clearSelections(true);
51828 if (item && (this.multiSelect || this.singleSelect)){
51829 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
51830 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
51831 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
51832 this.unselect(item);
51834 this.select(item, this.multiSelect && e.ctrlKey);
51835 this.lastSelection = item;
51840 onItemClick : function(item, index, e){
51841 if(this.fireEvent("beforeclick", this, index, item, e) === false){
51847 unselect : function(nodeInfo, suppressEvent){
51848 var node = this.getNode(nodeInfo);
51849 if(node && this.isSelected(node)){
51850 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
51851 Roo.fly(node).removeClass(this.selectedClass);
51852 this.selections.remove(node);
51853 if(!suppressEvent){
51854 this.fireEvent("selectionchange", this, this.selections);
51862 * Ext JS Library 1.1.1
51863 * Copyright(c) 2006-2007, Ext JS, LLC.
51865 * Originally Released Under LGPL - original licence link has changed is not relivant.
51868 * <script type="text/javascript">
51872 * @class Roo.LayoutManager
51873 * @extends Roo.util.Observable
51874 * Base class for layout managers.
51876 Roo.LayoutManager = function(container, config){
51877 Roo.LayoutManager.superclass.constructor.call(this);
51878 this.el = Roo.get(container);
51879 // ie scrollbar fix
51880 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
51881 document.body.scroll = "no";
51882 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
51883 this.el.position('relative');
51885 this.id = this.el.id;
51886 this.el.addClass("x-layout-container");
51887 /** false to disable window resize monitoring @type Boolean */
51888 this.monitorWindowResize = true;
51893 * Fires when a layout is performed.
51894 * @param {Roo.LayoutManager} this
51898 * @event regionresized
51899 * Fires when the user resizes a region.
51900 * @param {Roo.LayoutRegion} region The resized region
51901 * @param {Number} newSize The new size (width for east/west, height for north/south)
51903 "regionresized" : true,
51905 * @event regioncollapsed
51906 * Fires when a region is collapsed.
51907 * @param {Roo.LayoutRegion} region The collapsed region
51909 "regioncollapsed" : true,
51911 * @event regionexpanded
51912 * Fires when a region is expanded.
51913 * @param {Roo.LayoutRegion} region The expanded region
51915 "regionexpanded" : true
51917 this.updating = false;
51918 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
51921 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
51923 * Returns true if this layout is currently being updated
51924 * @return {Boolean}
51926 isUpdating : function(){
51927 return this.updating;
51931 * Suspend the LayoutManager from doing auto-layouts while
51932 * making multiple add or remove calls
51934 beginUpdate : function(){
51935 this.updating = true;
51939 * Restore auto-layouts and optionally disable the manager from performing a layout
51940 * @param {Boolean} noLayout true to disable a layout update
51942 endUpdate : function(noLayout){
51943 this.updating = false;
51949 layout: function(){
51953 onRegionResized : function(region, newSize){
51954 this.fireEvent("regionresized", region, newSize);
51958 onRegionCollapsed : function(region){
51959 this.fireEvent("regioncollapsed", region);
51962 onRegionExpanded : function(region){
51963 this.fireEvent("regionexpanded", region);
51967 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
51968 * performs box-model adjustments.
51969 * @return {Object} The size as an object {width: (the width), height: (the height)}
51971 getViewSize : function(){
51973 if(this.el.dom != document.body){
51974 size = this.el.getSize();
51976 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
51978 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
51979 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
51984 * Returns the Element this layout is bound to.
51985 * @return {Roo.Element}
51987 getEl : function(){
51992 * Returns the specified region.
51993 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
51994 * @return {Roo.LayoutRegion}
51996 getRegion : function(target){
51997 return this.regions[target.toLowerCase()];
52000 onWindowResize : function(){
52001 if(this.monitorWindowResize){
52007 * Ext JS Library 1.1.1
52008 * Copyright(c) 2006-2007, Ext JS, LLC.
52010 * Originally Released Under LGPL - original licence link has changed is not relivant.
52013 * <script type="text/javascript">
52016 * @class Roo.BorderLayout
52017 * @extends Roo.LayoutManager
52018 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52019 * please see: <br><br>
52020 * <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>
52021 * <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>
52024 var layout = new Roo.BorderLayout(document.body, {
52058 preferredTabWidth: 150
52063 var CP = Roo.ContentPanel;
52065 layout.beginUpdate();
52066 layout.add("north", new CP("north", "North"));
52067 layout.add("south", new CP("south", {title: "South", closable: true}));
52068 layout.add("west", new CP("west", {title: "West"}));
52069 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52070 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52071 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52072 layout.getRegion("center").showPanel("center1");
52073 layout.endUpdate();
52076 <b>The container the layout is rendered into can be either the body element or any other element.
52077 If it is not the body element, the container needs to either be an absolute positioned element,
52078 or you will need to add "position:relative" to the css of the container. You will also need to specify
52079 the container size if it is not the body element.</b>
52082 * Create a new BorderLayout
52083 * @param {String/HTMLElement/Element} container The container this layout is bound to
52084 * @param {Object} config Configuration options
52086 Roo.BorderLayout = function(container, config){
52087 config = config || {};
52088 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52089 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52090 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52091 var target = this.factory.validRegions[i];
52092 if(config[target]){
52093 this.addRegion(target, config[target]);
52098 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52100 * Creates and adds a new region if it doesn't already exist.
52101 * @param {String} target The target region key (north, south, east, west or center).
52102 * @param {Object} config The regions config object
52103 * @return {BorderLayoutRegion} The new region
52105 addRegion : function(target, config){
52106 if(!this.regions[target]){
52107 var r = this.factory.create(target, this, config);
52108 this.bindRegion(target, r);
52110 return this.regions[target];
52114 bindRegion : function(name, r){
52115 this.regions[name] = r;
52116 r.on("visibilitychange", this.layout, this);
52117 r.on("paneladded", this.layout, this);
52118 r.on("panelremoved", this.layout, this);
52119 r.on("invalidated", this.layout, this);
52120 r.on("resized", this.onRegionResized, this);
52121 r.on("collapsed", this.onRegionCollapsed, this);
52122 r.on("expanded", this.onRegionExpanded, this);
52126 * Performs a layout update.
52128 layout : function(){
52129 if(this.updating) {
52132 var size = this.getViewSize();
52133 var w = size.width;
52134 var h = size.height;
52139 //var x = 0, y = 0;
52141 var rs = this.regions;
52142 var north = rs["north"];
52143 var south = rs["south"];
52144 var west = rs["west"];
52145 var east = rs["east"];
52146 var center = rs["center"];
52147 //if(this.hideOnLayout){ // not supported anymore
52148 //c.el.setStyle("display", "none");
52150 if(north && north.isVisible()){
52151 var b = north.getBox();
52152 var m = north.getMargins();
52153 b.width = w - (m.left+m.right);
52156 centerY = b.height + b.y + m.bottom;
52157 centerH -= centerY;
52158 north.updateBox(this.safeBox(b));
52160 if(south && south.isVisible()){
52161 var b = south.getBox();
52162 var m = south.getMargins();
52163 b.width = w - (m.left+m.right);
52165 var totalHeight = (b.height + m.top + m.bottom);
52166 b.y = h - totalHeight + m.top;
52167 centerH -= totalHeight;
52168 south.updateBox(this.safeBox(b));
52170 if(west && west.isVisible()){
52171 var b = west.getBox();
52172 var m = west.getMargins();
52173 b.height = centerH - (m.top+m.bottom);
52175 b.y = centerY + m.top;
52176 var totalWidth = (b.width + m.left + m.right);
52177 centerX += totalWidth;
52178 centerW -= totalWidth;
52179 west.updateBox(this.safeBox(b));
52181 if(east && east.isVisible()){
52182 var b = east.getBox();
52183 var m = east.getMargins();
52184 b.height = centerH - (m.top+m.bottom);
52185 var totalWidth = (b.width + m.left + m.right);
52186 b.x = w - totalWidth + m.left;
52187 b.y = centerY + m.top;
52188 centerW -= totalWidth;
52189 east.updateBox(this.safeBox(b));
52192 var m = center.getMargins();
52194 x: centerX + m.left,
52195 y: centerY + m.top,
52196 width: centerW - (m.left+m.right),
52197 height: centerH - (m.top+m.bottom)
52199 //if(this.hideOnLayout){
52200 //center.el.setStyle("display", "block");
52202 center.updateBox(this.safeBox(centerBox));
52205 this.fireEvent("layout", this);
52209 safeBox : function(box){
52210 box.width = Math.max(0, box.width);
52211 box.height = Math.max(0, box.height);
52216 * Adds a ContentPanel (or subclass) to this layout.
52217 * @param {String} target The target region key (north, south, east, west or center).
52218 * @param {Roo.ContentPanel} panel The panel to add
52219 * @return {Roo.ContentPanel} The added panel
52221 add : function(target, panel){
52223 target = target.toLowerCase();
52224 return this.regions[target].add(panel);
52228 * Remove a ContentPanel (or subclass) to this layout.
52229 * @param {String} target The target region key (north, south, east, west or center).
52230 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52231 * @return {Roo.ContentPanel} The removed panel
52233 remove : function(target, panel){
52234 target = target.toLowerCase();
52235 return this.regions[target].remove(panel);
52239 * Searches all regions for a panel with the specified id
52240 * @param {String} panelId
52241 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52243 findPanel : function(panelId){
52244 var rs = this.regions;
52245 for(var target in rs){
52246 if(typeof rs[target] != "function"){
52247 var p = rs[target].getPanel(panelId);
52257 * Searches all regions for a panel with the specified id and activates (shows) it.
52258 * @param {String/ContentPanel} panelId The panels id or the panel itself
52259 * @return {Roo.ContentPanel} The shown panel or null
52261 showPanel : function(panelId) {
52262 var rs = this.regions;
52263 for(var target in rs){
52264 var r = rs[target];
52265 if(typeof r != "function"){
52266 if(r.hasPanel(panelId)){
52267 return r.showPanel(panelId);
52275 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52276 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52278 restoreState : function(provider){
52280 provider = Roo.state.Manager;
52282 var sm = new Roo.LayoutStateManager();
52283 sm.init(this, provider);
52287 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52288 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52289 * a valid ContentPanel config object. Example:
52291 // Create the main layout
52292 var layout = new Roo.BorderLayout('main-ct', {
52303 // Create and add multiple ContentPanels at once via configs
52306 id: 'source-files',
52308 title:'Ext Source Files',
52321 * @param {Object} regions An object containing ContentPanel configs by region name
52323 batchAdd : function(regions){
52324 this.beginUpdate();
52325 for(var rname in regions){
52326 var lr = this.regions[rname];
52328 this.addTypedPanels(lr, regions[rname]);
52335 addTypedPanels : function(lr, ps){
52336 if(typeof ps == 'string'){
52337 lr.add(new Roo.ContentPanel(ps));
52339 else if(ps instanceof Array){
52340 for(var i =0, len = ps.length; i < len; i++){
52341 this.addTypedPanels(lr, ps[i]);
52344 else if(!ps.events){ // raw config?
52346 delete ps.el; // prevent conflict
52347 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52349 else { // panel object assumed!
52354 * Adds a xtype elements to the layout.
52358 xtype : 'ContentPanel',
52365 xtype : 'NestedLayoutPanel',
52371 items : [ ... list of content panels or nested layout panels.. ]
52375 * @param {Object} cfg Xtype definition of item to add.
52377 addxtype : function(cfg)
52379 // basically accepts a pannel...
52380 // can accept a layout region..!?!?
52381 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52383 if (!cfg.xtype.match(/Panel$/)) {
52388 if (typeof(cfg.region) == 'undefined') {
52389 Roo.log("Failed to add Panel, region was not set");
52393 var region = cfg.region;
52399 xitems = cfg.items;
52406 case 'ContentPanel': // ContentPanel (el, cfg)
52407 case 'ScrollPanel': // ContentPanel (el, cfg)
52409 if(cfg.autoCreate) {
52410 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52412 var el = this.el.createChild();
52413 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52416 this.add(region, ret);
52420 case 'TreePanel': // our new panel!
52421 cfg.el = this.el.createChild();
52422 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52423 this.add(region, ret);
52426 case 'NestedLayoutPanel':
52427 // create a new Layout (which is a Border Layout...
52428 var el = this.el.createChild();
52429 var clayout = cfg.layout;
52431 clayout.items = clayout.items || [];
52432 // replace this exitems with the clayout ones..
52433 xitems = clayout.items;
52436 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52437 cfg.background = false;
52439 var layout = new Roo.BorderLayout(el, clayout);
52441 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52442 //console.log('adding nested layout panel ' + cfg.toSource());
52443 this.add(region, ret);
52444 nb = {}; /// find first...
52449 // needs grid and region
52451 //var el = this.getRegion(region).el.createChild();
52452 var el = this.el.createChild();
52453 // create the grid first...
52455 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52457 if (region == 'center' && this.active ) {
52458 cfg.background = false;
52460 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52462 this.add(region, ret);
52463 if (cfg.background) {
52464 ret.on('activate', function(gp) {
52465 if (!gp.grid.rendered) {
52480 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52482 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52483 this.add(region, ret);
52486 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52490 // GridPanel (grid, cfg)
52493 this.beginUpdate();
52497 Roo.each(xitems, function(i) {
52498 region = nb && i.region ? i.region : false;
52500 var add = ret.addxtype(i);
52503 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52504 if (!i.background) {
52505 abn[region] = nb[region] ;
52512 // make the last non-background panel active..
52513 //if (nb) { Roo.log(abn); }
52516 for(var r in abn) {
52517 region = this.getRegion(r);
52519 // tried using nb[r], but it does not work..
52521 region.showPanel(abn[r]);
52532 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52533 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52534 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52535 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52538 var CP = Roo.ContentPanel;
52540 var layout = Roo.BorderLayout.create({
52544 panels: [new CP("north", "North")]
52553 panels: [new CP("west", {title: "West"})]
52562 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52571 panels: [new CP("south", {title: "South", closable: true})]
52578 preferredTabWidth: 150,
52580 new CP("center1", {title: "Close Me", closable: true}),
52581 new CP("center2", {title: "Center Panel", closable: false})
52586 layout.getRegion("center").showPanel("center1");
52591 Roo.BorderLayout.create = function(config, targetEl){
52592 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52593 layout.beginUpdate();
52594 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52595 for(var j = 0, jlen = regions.length; j < jlen; j++){
52596 var lr = regions[j];
52597 if(layout.regions[lr] && config[lr].panels){
52598 var r = layout.regions[lr];
52599 var ps = config[lr].panels;
52600 layout.addTypedPanels(r, ps);
52603 layout.endUpdate();
52608 Roo.BorderLayout.RegionFactory = {
52610 validRegions : ["north","south","east","west","center"],
52613 create : function(target, mgr, config){
52614 target = target.toLowerCase();
52615 if(config.lightweight || config.basic){
52616 return new Roo.BasicLayoutRegion(mgr, config, target);
52620 return new Roo.NorthLayoutRegion(mgr, config);
52622 return new Roo.SouthLayoutRegion(mgr, config);
52624 return new Roo.EastLayoutRegion(mgr, config);
52626 return new Roo.WestLayoutRegion(mgr, config);
52628 return new Roo.CenterLayoutRegion(mgr, config);
52630 throw 'Layout region "'+target+'" not supported.';
52634 * Ext JS Library 1.1.1
52635 * Copyright(c) 2006-2007, Ext JS, LLC.
52637 * Originally Released Under LGPL - original licence link has changed is not relivant.
52640 * <script type="text/javascript">
52644 * @class Roo.BasicLayoutRegion
52645 * @extends Roo.util.Observable
52646 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52647 * and does not have a titlebar, tabs or any other features. All it does is size and position
52648 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52650 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52652 this.position = pos;
52655 * @scope Roo.BasicLayoutRegion
52659 * @event beforeremove
52660 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52661 * @param {Roo.LayoutRegion} this
52662 * @param {Roo.ContentPanel} panel The panel
52663 * @param {Object} e The cancel event object
52665 "beforeremove" : true,
52667 * @event invalidated
52668 * Fires when the layout for this region is changed.
52669 * @param {Roo.LayoutRegion} this
52671 "invalidated" : true,
52673 * @event visibilitychange
52674 * Fires when this region is shown or hidden
52675 * @param {Roo.LayoutRegion} this
52676 * @param {Boolean} visibility true or false
52678 "visibilitychange" : true,
52680 * @event paneladded
52681 * Fires when a panel is added.
52682 * @param {Roo.LayoutRegion} this
52683 * @param {Roo.ContentPanel} panel The panel
52685 "paneladded" : true,
52687 * @event panelremoved
52688 * Fires when a panel is removed.
52689 * @param {Roo.LayoutRegion} this
52690 * @param {Roo.ContentPanel} panel The panel
52692 "panelremoved" : true,
52694 * @event beforecollapse
52695 * Fires when this region before collapse.
52696 * @param {Roo.LayoutRegion} this
52698 "beforecollapse" : true,
52701 * Fires when this region is collapsed.
52702 * @param {Roo.LayoutRegion} this
52704 "collapsed" : true,
52707 * Fires when this region is expanded.
52708 * @param {Roo.LayoutRegion} this
52713 * Fires when this region is slid into view.
52714 * @param {Roo.LayoutRegion} this
52716 "slideshow" : true,
52719 * Fires when this region slides out of view.
52720 * @param {Roo.LayoutRegion} this
52722 "slidehide" : true,
52724 * @event panelactivated
52725 * Fires when a panel is activated.
52726 * @param {Roo.LayoutRegion} this
52727 * @param {Roo.ContentPanel} panel The activated panel
52729 "panelactivated" : true,
52732 * Fires when the user resizes this region.
52733 * @param {Roo.LayoutRegion} this
52734 * @param {Number} newSize The new size (width for east/west, height for north/south)
52738 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52739 this.panels = new Roo.util.MixedCollection();
52740 this.panels.getKey = this.getPanelId.createDelegate(this);
52742 this.activePanel = null;
52743 // ensure listeners are added...
52745 if (config.listeners || config.events) {
52746 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52747 listeners : config.listeners || {},
52748 events : config.events || {}
52752 if(skipConfig !== true){
52753 this.applyConfig(config);
52757 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52758 getPanelId : function(p){
52762 applyConfig : function(config){
52763 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52764 this.config = config;
52769 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
52770 * the width, for horizontal (north, south) the height.
52771 * @param {Number} newSize The new width or height
52773 resizeTo : function(newSize){
52774 var el = this.el ? this.el :
52775 (this.activePanel ? this.activePanel.getEl() : null);
52777 switch(this.position){
52780 el.setWidth(newSize);
52781 this.fireEvent("resized", this, newSize);
52785 el.setHeight(newSize);
52786 this.fireEvent("resized", this, newSize);
52792 getBox : function(){
52793 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
52796 getMargins : function(){
52797 return this.margins;
52800 updateBox : function(box){
52802 var el = this.activePanel.getEl();
52803 el.dom.style.left = box.x + "px";
52804 el.dom.style.top = box.y + "px";
52805 this.activePanel.setSize(box.width, box.height);
52809 * Returns the container element for this region.
52810 * @return {Roo.Element}
52812 getEl : function(){
52813 return this.activePanel;
52817 * Returns true if this region is currently visible.
52818 * @return {Boolean}
52820 isVisible : function(){
52821 return this.activePanel ? true : false;
52824 setActivePanel : function(panel){
52825 panel = this.getPanel(panel);
52826 if(this.activePanel && this.activePanel != panel){
52827 this.activePanel.setActiveState(false);
52828 this.activePanel.getEl().setLeftTop(-10000,-10000);
52830 this.activePanel = panel;
52831 panel.setActiveState(true);
52833 panel.setSize(this.box.width, this.box.height);
52835 this.fireEvent("panelactivated", this, panel);
52836 this.fireEvent("invalidated");
52840 * Show the specified panel.
52841 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
52842 * @return {Roo.ContentPanel} The shown panel or null
52844 showPanel : function(panel){
52845 if(panel = this.getPanel(panel)){
52846 this.setActivePanel(panel);
52852 * Get the active panel for this region.
52853 * @return {Roo.ContentPanel} The active panel or null
52855 getActivePanel : function(){
52856 return this.activePanel;
52860 * Add the passed ContentPanel(s)
52861 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52862 * @return {Roo.ContentPanel} The panel added (if only one was added)
52864 add : function(panel){
52865 if(arguments.length > 1){
52866 for(var i = 0, len = arguments.length; i < len; i++) {
52867 this.add(arguments[i]);
52871 if(this.hasPanel(panel)){
52872 this.showPanel(panel);
52875 var el = panel.getEl();
52876 if(el.dom.parentNode != this.mgr.el.dom){
52877 this.mgr.el.dom.appendChild(el.dom);
52879 if(panel.setRegion){
52880 panel.setRegion(this);
52882 this.panels.add(panel);
52883 el.setStyle("position", "absolute");
52884 if(!panel.background){
52885 this.setActivePanel(panel);
52886 if(this.config.initialSize && this.panels.getCount()==1){
52887 this.resizeTo(this.config.initialSize);
52890 this.fireEvent("paneladded", this, panel);
52895 * Returns true if the panel is in this region.
52896 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52897 * @return {Boolean}
52899 hasPanel : function(panel){
52900 if(typeof panel == "object"){ // must be panel obj
52901 panel = panel.getId();
52903 return this.getPanel(panel) ? true : false;
52907 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52908 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52909 * @param {Boolean} preservePanel Overrides the config preservePanel option
52910 * @return {Roo.ContentPanel} The panel that was removed
52912 remove : function(panel, preservePanel){
52913 panel = this.getPanel(panel);
52918 this.fireEvent("beforeremove", this, panel, e);
52919 if(e.cancel === true){
52922 var panelId = panel.getId();
52923 this.panels.removeKey(panelId);
52928 * Returns the panel specified or null if it's not in this region.
52929 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52930 * @return {Roo.ContentPanel}
52932 getPanel : function(id){
52933 if(typeof id == "object"){ // must be panel obj
52936 return this.panels.get(id);
52940 * Returns this regions position (north/south/east/west/center).
52943 getPosition: function(){
52944 return this.position;
52948 * Ext JS Library 1.1.1
52949 * Copyright(c) 2006-2007, Ext JS, LLC.
52951 * Originally Released Under LGPL - original licence link has changed is not relivant.
52954 * <script type="text/javascript">
52958 * @class Roo.LayoutRegion
52959 * @extends Roo.BasicLayoutRegion
52960 * This class represents a region in a layout manager.
52961 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
52962 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
52963 * @cfg {Boolean} floatable False to disable floating (defaults to true)
52964 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
52965 * @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})
52966 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
52967 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
52968 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
52969 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
52970 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
52971 * @cfg {String} title The title for the region (overrides panel titles)
52972 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
52973 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
52974 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
52975 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
52976 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
52977 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
52978 * the space available, similar to FireFox 1.5 tabs (defaults to false)
52979 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
52980 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
52981 * @cfg {Boolean} showPin True to show a pin button
52982 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
52983 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
52984 * @cfg {Boolean} disableTabTips True to disable tab tooltips
52985 * @cfg {Number} width For East/West panels
52986 * @cfg {Number} height For North/South panels
52987 * @cfg {Boolean} split To show the splitter
52988 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
52990 Roo.LayoutRegion = function(mgr, config, pos){
52991 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
52992 var dh = Roo.DomHelper;
52993 /** This region's container element
52994 * @type Roo.Element */
52995 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
52996 /** This region's title element
52997 * @type Roo.Element */
52999 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
53000 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
53001 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
53003 this.titleEl.enableDisplayMode();
53004 /** This region's title text element
53005 * @type HTMLElement */
53006 this.titleTextEl = this.titleEl.dom.firstChild;
53007 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53008 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53009 this.closeBtn.enableDisplayMode();
53010 this.closeBtn.on("click", this.closeClicked, this);
53011 this.closeBtn.hide();
53013 this.createBody(config);
53014 this.visible = true;
53015 this.collapsed = false;
53017 if(config.hideWhenEmpty){
53019 this.on("paneladded", this.validateVisibility, this);
53020 this.on("panelremoved", this.validateVisibility, this);
53022 this.applyConfig(config);
53025 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53027 createBody : function(){
53028 /** This region's body element
53029 * @type Roo.Element */
53030 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53033 applyConfig : function(c){
53034 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53035 var dh = Roo.DomHelper;
53036 if(c.titlebar !== false){
53037 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53038 this.collapseBtn.on("click", this.collapse, this);
53039 this.collapseBtn.enableDisplayMode();
53041 if(c.showPin === true || this.showPin){
53042 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53043 this.stickBtn.enableDisplayMode();
53044 this.stickBtn.on("click", this.expand, this);
53045 this.stickBtn.hide();
53048 /** This region's collapsed element
53049 * @type Roo.Element */
53050 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53051 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53053 if(c.floatable !== false){
53054 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53055 this.collapsedEl.on("click", this.collapseClick, this);
53058 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53059 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53060 id: "message", unselectable: "on", style:{"float":"left"}});
53061 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53063 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53064 this.expandBtn.on("click", this.expand, this);
53066 if(this.collapseBtn){
53067 this.collapseBtn.setVisible(c.collapsible == true);
53069 this.cmargins = c.cmargins || this.cmargins ||
53070 (this.position == "west" || this.position == "east" ?
53071 {top: 0, left: 2, right:2, bottom: 0} :
53072 {top: 2, left: 0, right:0, bottom: 2});
53073 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53074 this.bottomTabs = c.tabPosition != "top";
53075 this.autoScroll = c.autoScroll || false;
53076 if(this.autoScroll){
53077 this.bodyEl.setStyle("overflow", "auto");
53079 this.bodyEl.setStyle("overflow", "hidden");
53081 //if(c.titlebar !== false){
53082 if((!c.titlebar && !c.title) || c.titlebar === false){
53083 this.titleEl.hide();
53085 this.titleEl.show();
53087 this.titleTextEl.innerHTML = c.title;
53091 this.duration = c.duration || .30;
53092 this.slideDuration = c.slideDuration || .45;
53095 this.collapse(true);
53102 * Returns true if this region is currently visible.
53103 * @return {Boolean}
53105 isVisible : function(){
53106 return this.visible;
53110 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53111 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53113 setCollapsedTitle : function(title){
53114 title = title || " ";
53115 if(this.collapsedTitleTextEl){
53116 this.collapsedTitleTextEl.innerHTML = title;
53120 getBox : function(){
53122 if(!this.collapsed){
53123 b = this.el.getBox(false, true);
53125 b = this.collapsedEl.getBox(false, true);
53130 getMargins : function(){
53131 return this.collapsed ? this.cmargins : this.margins;
53134 highlight : function(){
53135 this.el.addClass("x-layout-panel-dragover");
53138 unhighlight : function(){
53139 this.el.removeClass("x-layout-panel-dragover");
53142 updateBox : function(box){
53144 if(!this.collapsed){
53145 this.el.dom.style.left = box.x + "px";
53146 this.el.dom.style.top = box.y + "px";
53147 this.updateBody(box.width, box.height);
53149 this.collapsedEl.dom.style.left = box.x + "px";
53150 this.collapsedEl.dom.style.top = box.y + "px";
53151 this.collapsedEl.setSize(box.width, box.height);
53154 this.tabs.autoSizeTabs();
53158 updateBody : function(w, h){
53160 this.el.setWidth(w);
53161 w -= this.el.getBorderWidth("rl");
53162 if(this.config.adjustments){
53163 w += this.config.adjustments[0];
53167 this.el.setHeight(h);
53168 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53169 h -= this.el.getBorderWidth("tb");
53170 if(this.config.adjustments){
53171 h += this.config.adjustments[1];
53173 this.bodyEl.setHeight(h);
53175 h = this.tabs.syncHeight(h);
53178 if(this.panelSize){
53179 w = w !== null ? w : this.panelSize.width;
53180 h = h !== null ? h : this.panelSize.height;
53182 if(this.activePanel){
53183 var el = this.activePanel.getEl();
53184 w = w !== null ? w : el.getWidth();
53185 h = h !== null ? h : el.getHeight();
53186 this.panelSize = {width: w, height: h};
53187 this.activePanel.setSize(w, h);
53189 if(Roo.isIE && this.tabs){
53190 this.tabs.el.repaint();
53195 * Returns the container element for this region.
53196 * @return {Roo.Element}
53198 getEl : function(){
53203 * Hides this region.
53206 if(!this.collapsed){
53207 this.el.dom.style.left = "-2000px";
53210 this.collapsedEl.dom.style.left = "-2000px";
53211 this.collapsedEl.hide();
53213 this.visible = false;
53214 this.fireEvent("visibilitychange", this, false);
53218 * Shows this region if it was previously hidden.
53221 if(!this.collapsed){
53224 this.collapsedEl.show();
53226 this.visible = true;
53227 this.fireEvent("visibilitychange", this, true);
53230 closeClicked : function(){
53231 if(this.activePanel){
53232 this.remove(this.activePanel);
53236 collapseClick : function(e){
53238 e.stopPropagation();
53241 e.stopPropagation();
53247 * Collapses this region.
53248 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53250 collapse : function(skipAnim, skipCheck){
53251 if(this.collapsed) {
53255 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53257 this.collapsed = true;
53259 this.split.el.hide();
53261 if(this.config.animate && skipAnim !== true){
53262 this.fireEvent("invalidated", this);
53263 this.animateCollapse();
53265 this.el.setLocation(-20000,-20000);
53267 this.collapsedEl.show();
53268 this.fireEvent("collapsed", this);
53269 this.fireEvent("invalidated", this);
53275 animateCollapse : function(){
53280 * Expands this region if it was previously collapsed.
53281 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53282 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53284 expand : function(e, skipAnim){
53286 e.stopPropagation();
53288 if(!this.collapsed || this.el.hasActiveFx()) {
53292 this.afterSlideIn();
53295 this.collapsed = false;
53296 if(this.config.animate && skipAnim !== true){
53297 this.animateExpand();
53301 this.split.el.show();
53303 this.collapsedEl.setLocation(-2000,-2000);
53304 this.collapsedEl.hide();
53305 this.fireEvent("invalidated", this);
53306 this.fireEvent("expanded", this);
53310 animateExpand : function(){
53314 initTabs : function()
53316 this.bodyEl.setStyle("overflow", "hidden");
53317 var ts = new Roo.TabPanel(
53320 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53321 disableTooltips: this.config.disableTabTips,
53322 toolbar : this.config.toolbar
53325 if(this.config.hideTabs){
53326 ts.stripWrap.setDisplayed(false);
53329 ts.resizeTabs = this.config.resizeTabs === true;
53330 ts.minTabWidth = this.config.minTabWidth || 40;
53331 ts.maxTabWidth = this.config.maxTabWidth || 250;
53332 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53333 ts.monitorResize = false;
53334 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53335 ts.bodyEl.addClass('x-layout-tabs-body');
53336 this.panels.each(this.initPanelAsTab, this);
53339 initPanelAsTab : function(panel){
53340 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53341 this.config.closeOnTab && panel.isClosable());
53342 if(panel.tabTip !== undefined){
53343 ti.setTooltip(panel.tabTip);
53345 ti.on("activate", function(){
53346 this.setActivePanel(panel);
53348 if(this.config.closeOnTab){
53349 ti.on("beforeclose", function(t, e){
53351 this.remove(panel);
53357 updatePanelTitle : function(panel, title){
53358 if(this.activePanel == panel){
53359 this.updateTitle(title);
53362 var ti = this.tabs.getTab(panel.getEl().id);
53364 if(panel.tabTip !== undefined){
53365 ti.setTooltip(panel.tabTip);
53370 updateTitle : function(title){
53371 if(this.titleTextEl && !this.config.title){
53372 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53376 setActivePanel : function(panel){
53377 panel = this.getPanel(panel);
53378 if(this.activePanel && this.activePanel != panel){
53379 this.activePanel.setActiveState(false);
53381 this.activePanel = panel;
53382 panel.setActiveState(true);
53383 if(this.panelSize){
53384 panel.setSize(this.panelSize.width, this.panelSize.height);
53387 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53389 this.updateTitle(panel.getTitle());
53391 this.fireEvent("invalidated", this);
53393 this.fireEvent("panelactivated", this, panel);
53397 * Shows the specified panel.
53398 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53399 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53401 showPanel : function(panel)
53403 panel = this.getPanel(panel);
53406 var tab = this.tabs.getTab(panel.getEl().id);
53407 if(tab.isHidden()){
53408 this.tabs.unhideTab(tab.id);
53412 this.setActivePanel(panel);
53419 * Get the active panel for this region.
53420 * @return {Roo.ContentPanel} The active panel or null
53422 getActivePanel : function(){
53423 return this.activePanel;
53426 validateVisibility : function(){
53427 if(this.panels.getCount() < 1){
53428 this.updateTitle(" ");
53429 this.closeBtn.hide();
53432 if(!this.isVisible()){
53439 * Adds the passed ContentPanel(s) to this region.
53440 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53441 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53443 add : function(panel){
53444 if(arguments.length > 1){
53445 for(var i = 0, len = arguments.length; i < len; i++) {
53446 this.add(arguments[i]);
53450 if(this.hasPanel(panel)){
53451 this.showPanel(panel);
53454 panel.setRegion(this);
53455 this.panels.add(panel);
53456 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53457 this.bodyEl.dom.appendChild(panel.getEl().dom);
53458 if(panel.background !== true){
53459 this.setActivePanel(panel);
53461 this.fireEvent("paneladded", this, panel);
53467 this.initPanelAsTab(panel);
53469 if(panel.background !== true){
53470 this.tabs.activate(panel.getEl().id);
53472 this.fireEvent("paneladded", this, panel);
53477 * Hides the tab for the specified panel.
53478 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53480 hidePanel : function(panel){
53481 if(this.tabs && (panel = this.getPanel(panel))){
53482 this.tabs.hideTab(panel.getEl().id);
53487 * Unhides the tab for a previously hidden panel.
53488 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53490 unhidePanel : function(panel){
53491 if(this.tabs && (panel = this.getPanel(panel))){
53492 this.tabs.unhideTab(panel.getEl().id);
53496 clearPanels : function(){
53497 while(this.panels.getCount() > 0){
53498 this.remove(this.panels.first());
53503 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53504 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53505 * @param {Boolean} preservePanel Overrides the config preservePanel option
53506 * @return {Roo.ContentPanel} The panel that was removed
53508 remove : function(panel, preservePanel){
53509 panel = this.getPanel(panel);
53514 this.fireEvent("beforeremove", this, panel, e);
53515 if(e.cancel === true){
53518 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53519 var panelId = panel.getId();
53520 this.panels.removeKey(panelId);
53522 document.body.appendChild(panel.getEl().dom);
53525 this.tabs.removeTab(panel.getEl().id);
53526 }else if (!preservePanel){
53527 this.bodyEl.dom.removeChild(panel.getEl().dom);
53529 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53530 var p = this.panels.first();
53531 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53532 tempEl.appendChild(p.getEl().dom);
53533 this.bodyEl.update("");
53534 this.bodyEl.dom.appendChild(p.getEl().dom);
53536 this.updateTitle(p.getTitle());
53538 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53539 this.setActivePanel(p);
53541 panel.setRegion(null);
53542 if(this.activePanel == panel){
53543 this.activePanel = null;
53545 if(this.config.autoDestroy !== false && preservePanel !== true){
53546 try{panel.destroy();}catch(e){}
53548 this.fireEvent("panelremoved", this, panel);
53553 * Returns the TabPanel component used by this region
53554 * @return {Roo.TabPanel}
53556 getTabs : function(){
53560 createTool : function(parentEl, className){
53561 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53562 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53563 btn.addClassOnOver("x-layout-tools-button-over");
53568 * Ext JS Library 1.1.1
53569 * Copyright(c) 2006-2007, Ext JS, LLC.
53571 * Originally Released Under LGPL - original licence link has changed is not relivant.
53574 * <script type="text/javascript">
53580 * @class Roo.SplitLayoutRegion
53581 * @extends Roo.LayoutRegion
53582 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53584 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53585 this.cursor = cursor;
53586 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53589 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53590 splitTip : "Drag to resize.",
53591 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53592 useSplitTips : false,
53594 applyConfig : function(config){
53595 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53598 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53599 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53600 /** The SplitBar for this region
53601 * @type Roo.SplitBar */
53602 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53603 this.split.on("moved", this.onSplitMove, this);
53604 this.split.useShim = config.useShim === true;
53605 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53606 if(this.useSplitTips){
53607 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53609 if(config.collapsible){
53610 this.split.el.on("dblclick", this.collapse, this);
53613 if(typeof config.minSize != "undefined"){
53614 this.split.minSize = config.minSize;
53616 if(typeof config.maxSize != "undefined"){
53617 this.split.maxSize = config.maxSize;
53619 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53620 this.hideSplitter();
53625 getHMaxSize : function(){
53626 var cmax = this.config.maxSize || 10000;
53627 var center = this.mgr.getRegion("center");
53628 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53631 getVMaxSize : function(){
53632 var cmax = this.config.maxSize || 10000;
53633 var center = this.mgr.getRegion("center");
53634 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53637 onSplitMove : function(split, newSize){
53638 this.fireEvent("resized", this, newSize);
53642 * Returns the {@link Roo.SplitBar} for this region.
53643 * @return {Roo.SplitBar}
53645 getSplitBar : function(){
53650 this.hideSplitter();
53651 Roo.SplitLayoutRegion.superclass.hide.call(this);
53654 hideSplitter : function(){
53656 this.split.el.setLocation(-2000,-2000);
53657 this.split.el.hide();
53663 this.split.el.show();
53665 Roo.SplitLayoutRegion.superclass.show.call(this);
53668 beforeSlide: function(){
53669 if(Roo.isGecko){// firefox overflow auto bug workaround
53670 this.bodyEl.clip();
53672 this.tabs.bodyEl.clip();
53674 if(this.activePanel){
53675 this.activePanel.getEl().clip();
53677 if(this.activePanel.beforeSlide){
53678 this.activePanel.beforeSlide();
53684 afterSlide : function(){
53685 if(Roo.isGecko){// firefox overflow auto bug workaround
53686 this.bodyEl.unclip();
53688 this.tabs.bodyEl.unclip();
53690 if(this.activePanel){
53691 this.activePanel.getEl().unclip();
53692 if(this.activePanel.afterSlide){
53693 this.activePanel.afterSlide();
53699 initAutoHide : function(){
53700 if(this.autoHide !== false){
53701 if(!this.autoHideHd){
53702 var st = new Roo.util.DelayedTask(this.slideIn, this);
53703 this.autoHideHd = {
53704 "mouseout": function(e){
53705 if(!e.within(this.el, true)){
53709 "mouseover" : function(e){
53715 this.el.on(this.autoHideHd);
53719 clearAutoHide : function(){
53720 if(this.autoHide !== false){
53721 this.el.un("mouseout", this.autoHideHd.mouseout);
53722 this.el.un("mouseover", this.autoHideHd.mouseover);
53726 clearMonitor : function(){
53727 Roo.get(document).un("click", this.slideInIf, this);
53730 // these names are backwards but not changed for compat
53731 slideOut : function(){
53732 if(this.isSlid || this.el.hasActiveFx()){
53735 this.isSlid = true;
53736 if(this.collapseBtn){
53737 this.collapseBtn.hide();
53739 this.closeBtnState = this.closeBtn.getStyle('display');
53740 this.closeBtn.hide();
53742 this.stickBtn.show();
53745 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53746 this.beforeSlide();
53747 this.el.setStyle("z-index", 10001);
53748 this.el.slideIn(this.getSlideAnchor(), {
53749 callback: function(){
53751 this.initAutoHide();
53752 Roo.get(document).on("click", this.slideInIf, this);
53753 this.fireEvent("slideshow", this);
53760 afterSlideIn : function(){
53761 this.clearAutoHide();
53762 this.isSlid = false;
53763 this.clearMonitor();
53764 this.el.setStyle("z-index", "");
53765 if(this.collapseBtn){
53766 this.collapseBtn.show();
53768 this.closeBtn.setStyle('display', this.closeBtnState);
53770 this.stickBtn.hide();
53772 this.fireEvent("slidehide", this);
53775 slideIn : function(cb){
53776 if(!this.isSlid || this.el.hasActiveFx()){
53780 this.isSlid = false;
53781 this.beforeSlide();
53782 this.el.slideOut(this.getSlideAnchor(), {
53783 callback: function(){
53784 this.el.setLeftTop(-10000, -10000);
53786 this.afterSlideIn();
53794 slideInIf : function(e){
53795 if(!e.within(this.el)){
53800 animateCollapse : function(){
53801 this.beforeSlide();
53802 this.el.setStyle("z-index", 20000);
53803 var anchor = this.getSlideAnchor();
53804 this.el.slideOut(anchor, {
53805 callback : function(){
53806 this.el.setStyle("z-index", "");
53807 this.collapsedEl.slideIn(anchor, {duration:.3});
53809 this.el.setLocation(-10000,-10000);
53811 this.fireEvent("collapsed", this);
53818 animateExpand : function(){
53819 this.beforeSlide();
53820 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
53821 this.el.setStyle("z-index", 20000);
53822 this.collapsedEl.hide({
53825 this.el.slideIn(this.getSlideAnchor(), {
53826 callback : function(){
53827 this.el.setStyle("z-index", "");
53830 this.split.el.show();
53832 this.fireEvent("invalidated", this);
53833 this.fireEvent("expanded", this);
53861 getAnchor : function(){
53862 return this.anchors[this.position];
53865 getCollapseAnchor : function(){
53866 return this.canchors[this.position];
53869 getSlideAnchor : function(){
53870 return this.sanchors[this.position];
53873 getAlignAdj : function(){
53874 var cm = this.cmargins;
53875 switch(this.position){
53891 getExpandAdj : function(){
53892 var c = this.collapsedEl, cm = this.cmargins;
53893 switch(this.position){
53895 return [-(cm.right+c.getWidth()+cm.left), 0];
53898 return [cm.right+c.getWidth()+cm.left, 0];
53901 return [0, -(cm.top+cm.bottom+c.getHeight())];
53904 return [0, cm.top+cm.bottom+c.getHeight()];
53910 * Ext JS Library 1.1.1
53911 * Copyright(c) 2006-2007, Ext JS, LLC.
53913 * Originally Released Under LGPL - original licence link has changed is not relivant.
53916 * <script type="text/javascript">
53919 * These classes are private internal classes
53921 Roo.CenterLayoutRegion = function(mgr, config){
53922 Roo.LayoutRegion.call(this, mgr, config, "center");
53923 this.visible = true;
53924 this.minWidth = config.minWidth || 20;
53925 this.minHeight = config.minHeight || 20;
53928 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
53930 // center panel can't be hidden
53934 // center panel can't be hidden
53937 getMinWidth: function(){
53938 return this.minWidth;
53941 getMinHeight: function(){
53942 return this.minHeight;
53947 Roo.NorthLayoutRegion = function(mgr, config){
53948 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
53950 this.split.placement = Roo.SplitBar.TOP;
53951 this.split.orientation = Roo.SplitBar.VERTICAL;
53952 this.split.el.addClass("x-layout-split-v");
53954 var size = config.initialSize || config.height;
53955 if(typeof size != "undefined"){
53956 this.el.setHeight(size);
53959 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
53960 orientation: Roo.SplitBar.VERTICAL,
53961 getBox : function(){
53962 if(this.collapsed){
53963 return this.collapsedEl.getBox();
53965 var box = this.el.getBox();
53967 box.height += this.split.el.getHeight();
53972 updateBox : function(box){
53973 if(this.split && !this.collapsed){
53974 box.height -= this.split.el.getHeight();
53975 this.split.el.setLeft(box.x);
53976 this.split.el.setTop(box.y+box.height);
53977 this.split.el.setWidth(box.width);
53979 if(this.collapsed){
53980 this.updateBody(box.width, null);
53982 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53986 Roo.SouthLayoutRegion = function(mgr, config){
53987 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
53989 this.split.placement = Roo.SplitBar.BOTTOM;
53990 this.split.orientation = Roo.SplitBar.VERTICAL;
53991 this.split.el.addClass("x-layout-split-v");
53993 var size = config.initialSize || config.height;
53994 if(typeof size != "undefined"){
53995 this.el.setHeight(size);
53998 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
53999 orientation: Roo.SplitBar.VERTICAL,
54000 getBox : function(){
54001 if(this.collapsed){
54002 return this.collapsedEl.getBox();
54004 var box = this.el.getBox();
54006 var sh = this.split.el.getHeight();
54013 updateBox : function(box){
54014 if(this.split && !this.collapsed){
54015 var sh = this.split.el.getHeight();
54018 this.split.el.setLeft(box.x);
54019 this.split.el.setTop(box.y-sh);
54020 this.split.el.setWidth(box.width);
54022 if(this.collapsed){
54023 this.updateBody(box.width, null);
54025 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54029 Roo.EastLayoutRegion = function(mgr, config){
54030 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54032 this.split.placement = Roo.SplitBar.RIGHT;
54033 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54034 this.split.el.addClass("x-layout-split-h");
54036 var size = config.initialSize || config.width;
54037 if(typeof size != "undefined"){
54038 this.el.setWidth(size);
54041 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54042 orientation: Roo.SplitBar.HORIZONTAL,
54043 getBox : function(){
54044 if(this.collapsed){
54045 return this.collapsedEl.getBox();
54047 var box = this.el.getBox();
54049 var sw = this.split.el.getWidth();
54056 updateBox : function(box){
54057 if(this.split && !this.collapsed){
54058 var sw = this.split.el.getWidth();
54060 this.split.el.setLeft(box.x);
54061 this.split.el.setTop(box.y);
54062 this.split.el.setHeight(box.height);
54065 if(this.collapsed){
54066 this.updateBody(null, box.height);
54068 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54072 Roo.WestLayoutRegion = function(mgr, config){
54073 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54075 this.split.placement = Roo.SplitBar.LEFT;
54076 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54077 this.split.el.addClass("x-layout-split-h");
54079 var size = config.initialSize || config.width;
54080 if(typeof size != "undefined"){
54081 this.el.setWidth(size);
54084 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
54085 orientation: Roo.SplitBar.HORIZONTAL,
54086 getBox : function(){
54087 if(this.collapsed){
54088 return this.collapsedEl.getBox();
54090 var box = this.el.getBox();
54092 box.width += this.split.el.getWidth();
54097 updateBox : function(box){
54098 if(this.split && !this.collapsed){
54099 var sw = this.split.el.getWidth();
54101 this.split.el.setLeft(box.x+box.width);
54102 this.split.el.setTop(box.y);
54103 this.split.el.setHeight(box.height);
54105 if(this.collapsed){
54106 this.updateBody(null, box.height);
54108 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54113 * Ext JS Library 1.1.1
54114 * Copyright(c) 2006-2007, Ext JS, LLC.
54116 * Originally Released Under LGPL - original licence link has changed is not relivant.
54119 * <script type="text/javascript">
54124 * Private internal class for reading and applying state
54126 Roo.LayoutStateManager = function(layout){
54127 // default empty state
54136 Roo.LayoutStateManager.prototype = {
54137 init : function(layout, provider){
54138 this.provider = provider;
54139 var state = provider.get(layout.id+"-layout-state");
54141 var wasUpdating = layout.isUpdating();
54143 layout.beginUpdate();
54145 for(var key in state){
54146 if(typeof state[key] != "function"){
54147 var rstate = state[key];
54148 var r = layout.getRegion(key);
54151 r.resizeTo(rstate.size);
54153 if(rstate.collapsed == true){
54156 r.expand(null, true);
54162 layout.endUpdate();
54164 this.state = state;
54166 this.layout = layout;
54167 layout.on("regionresized", this.onRegionResized, this);
54168 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54169 layout.on("regionexpanded", this.onRegionExpanded, this);
54172 storeState : function(){
54173 this.provider.set(this.layout.id+"-layout-state", this.state);
54176 onRegionResized : function(region, newSize){
54177 this.state[region.getPosition()].size = newSize;
54181 onRegionCollapsed : function(region){
54182 this.state[region.getPosition()].collapsed = true;
54186 onRegionExpanded : function(region){
54187 this.state[region.getPosition()].collapsed = false;
54192 * Ext JS Library 1.1.1
54193 * Copyright(c) 2006-2007, Ext JS, LLC.
54195 * Originally Released Under LGPL - original licence link has changed is not relivant.
54198 * <script type="text/javascript">
54201 * @class Roo.ContentPanel
54202 * @extends Roo.util.Observable
54203 * A basic ContentPanel element.
54204 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54205 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54206 * @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
54207 * @cfg {Boolean} closable True if the panel can be closed/removed
54208 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54209 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54210 * @cfg {Toolbar} toolbar A toolbar for this panel
54211 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54212 * @cfg {String} title The title for this panel
54213 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54214 * @cfg {String} url Calls {@link #setUrl} with this value
54215 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54216 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54217 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54218 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54219 * @cfg {String} style Extra style to add to the content panel
54222 * Create a new ContentPanel.
54223 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54224 * @param {String/Object} config A string to set only the title or a config object
54225 * @param {String} content (optional) Set the HTML content for this panel
54226 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54228 Roo.ContentPanel = function(el, config, content){
54232 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54236 if (config && config.parentLayout) {
54237 el = config.parentLayout.el.createChild();
54240 if(el.autoCreate){ // xtype is available if this is called from factory
54244 this.el = Roo.get(el);
54245 if(!this.el && config && config.autoCreate){
54246 if(typeof config.autoCreate == "object"){
54247 if(!config.autoCreate.id){
54248 config.autoCreate.id = config.id||el;
54250 this.el = Roo.DomHelper.append(document.body,
54251 config.autoCreate, true);
54253 this.el = Roo.DomHelper.append(document.body,
54254 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54259 this.closable = false;
54260 this.loaded = false;
54261 this.active = false;
54262 if(typeof config == "string"){
54263 this.title = config;
54265 Roo.apply(this, config);
54268 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54269 this.wrapEl = this.el.wrap();
54270 this.toolbar.container = this.el.insertSibling(false, 'before');
54271 this.toolbar = new Roo.Toolbar(this.toolbar);
54274 // xtype created footer. - not sure if will work as we normally have to render first..
54275 if (this.footer && !this.footer.el && this.footer.xtype) {
54276 if (!this.wrapEl) {
54277 this.wrapEl = this.el.wrap();
54280 this.footer.container = this.wrapEl.createChild();
54282 this.footer = Roo.factory(this.footer, Roo);
54287 this.resizeEl = Roo.get(this.resizeEl, true);
54289 this.resizeEl = this.el;
54291 // handle view.xtype
54299 * Fires when this panel is activated.
54300 * @param {Roo.ContentPanel} this
54304 * @event deactivate
54305 * Fires when this panel is activated.
54306 * @param {Roo.ContentPanel} this
54308 "deactivate" : true,
54312 * Fires when this panel is resized if fitToFrame is true.
54313 * @param {Roo.ContentPanel} this
54314 * @param {Number} width The width after any component adjustments
54315 * @param {Number} height The height after any component adjustments
54321 * Fires when this tab is created
54322 * @param {Roo.ContentPanel} this
54332 if(this.autoScroll){
54333 this.resizeEl.setStyle("overflow", "auto");
54335 // fix randome scrolling
54336 this.el.on('scroll', function() {
54337 Roo.log('fix random scolling');
54338 this.scrollTo('top',0);
54341 content = content || this.content;
54343 this.setContent(content);
54345 if(config && config.url){
54346 this.setUrl(this.url, this.params, this.loadOnce);
54351 Roo.ContentPanel.superclass.constructor.call(this);
54353 if (this.view && typeof(this.view.xtype) != 'undefined') {
54354 this.view.el = this.el.appendChild(document.createElement("div"));
54355 this.view = Roo.factory(this.view);
54356 this.view.render && this.view.render(false, '');
54360 this.fireEvent('render', this);
54363 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54365 setRegion : function(region){
54366 this.region = region;
54368 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54370 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54375 * Returns the toolbar for this Panel if one was configured.
54376 * @return {Roo.Toolbar}
54378 getToolbar : function(){
54379 return this.toolbar;
54382 setActiveState : function(active){
54383 this.active = active;
54385 this.fireEvent("deactivate", this);
54387 this.fireEvent("activate", this);
54391 * Updates this panel's element
54392 * @param {String} content The new content
54393 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54395 setContent : function(content, loadScripts){
54396 this.el.update(content, loadScripts);
54399 ignoreResize : function(w, h){
54400 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54403 this.lastSize = {width: w, height: h};
54408 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54409 * @return {Roo.UpdateManager} The UpdateManager
54411 getUpdateManager : function(){
54412 return this.el.getUpdateManager();
54415 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54416 * @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:
54419 url: "your-url.php",
54420 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54421 callback: yourFunction,
54422 scope: yourObject, //(optional scope)
54425 text: "Loading...",
54430 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54431 * 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.
54432 * @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}
54433 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54434 * @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.
54435 * @return {Roo.ContentPanel} this
54438 var um = this.el.getUpdateManager();
54439 um.update.apply(um, arguments);
54445 * 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.
54446 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54447 * @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)
54448 * @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)
54449 * @return {Roo.UpdateManager} The UpdateManager
54451 setUrl : function(url, params, loadOnce){
54452 if(this.refreshDelegate){
54453 this.removeListener("activate", this.refreshDelegate);
54455 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54456 this.on("activate", this.refreshDelegate);
54457 return this.el.getUpdateManager();
54460 _handleRefresh : function(url, params, loadOnce){
54461 if(!loadOnce || !this.loaded){
54462 var updater = this.el.getUpdateManager();
54463 updater.update(url, params, this._setLoaded.createDelegate(this));
54467 _setLoaded : function(){
54468 this.loaded = true;
54472 * Returns this panel's id
54475 getId : function(){
54480 * Returns this panel's element - used by regiosn to add.
54481 * @return {Roo.Element}
54483 getEl : function(){
54484 return this.wrapEl || this.el;
54487 adjustForComponents : function(width, height)
54489 //Roo.log('adjustForComponents ');
54490 if(this.resizeEl != this.el){
54491 width -= this.el.getFrameWidth('lr');
54492 height -= this.el.getFrameWidth('tb');
54495 var te = this.toolbar.getEl();
54496 height -= te.getHeight();
54497 te.setWidth(width);
54500 var te = this.footer.getEl();
54501 //Roo.log("footer:" + te.getHeight());
54503 height -= te.getHeight();
54504 te.setWidth(width);
54508 if(this.adjustments){
54509 width += this.adjustments[0];
54510 height += this.adjustments[1];
54512 return {"width": width, "height": height};
54515 setSize : function(width, height){
54516 if(this.fitToFrame && !this.ignoreResize(width, height)){
54517 if(this.fitContainer && this.resizeEl != this.el){
54518 this.el.setSize(width, height);
54520 var size = this.adjustForComponents(width, height);
54521 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54522 this.fireEvent('resize', this, size.width, size.height);
54527 * Returns this panel's title
54530 getTitle : function(){
54535 * Set this panel's title
54536 * @param {String} title
54538 setTitle : function(title){
54539 this.title = title;
54541 this.region.updatePanelTitle(this, title);
54546 * Returns true is this panel was configured to be closable
54547 * @return {Boolean}
54549 isClosable : function(){
54550 return this.closable;
54553 beforeSlide : function(){
54555 this.resizeEl.clip();
54558 afterSlide : function(){
54560 this.resizeEl.unclip();
54564 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54565 * Will fail silently if the {@link #setUrl} method has not been called.
54566 * This does not activate the panel, just updates its content.
54568 refresh : function(){
54569 if(this.refreshDelegate){
54570 this.loaded = false;
54571 this.refreshDelegate();
54576 * Destroys this panel
54578 destroy : function(){
54579 this.el.removeAllListeners();
54580 var tempEl = document.createElement("span");
54581 tempEl.appendChild(this.el.dom);
54582 tempEl.innerHTML = "";
54588 * form - if the content panel contains a form - this is a reference to it.
54589 * @type {Roo.form.Form}
54593 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54594 * This contains a reference to it.
54600 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54610 * @param {Object} cfg Xtype definition of item to add.
54613 addxtype : function(cfg) {
54615 if (cfg.xtype.match(/^Form$/)) {
54618 //if (this.footer) {
54619 // el = this.footer.container.insertSibling(false, 'before');
54621 el = this.el.createChild();
54624 this.form = new Roo.form.Form(cfg);
54627 if ( this.form.allItems.length) {
54628 this.form.render(el.dom);
54632 // should only have one of theses..
54633 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54634 // views.. should not be just added - used named prop 'view''
54636 cfg.el = this.el.appendChild(document.createElement("div"));
54639 var ret = new Roo.factory(cfg);
54641 ret.render && ret.render(false, ''); // render blank..
54650 * @class Roo.GridPanel
54651 * @extends Roo.ContentPanel
54653 * Create a new GridPanel.
54654 * @param {Roo.grid.Grid} grid The grid for this panel
54655 * @param {String/Object} config A string to set only the panel's title, or a config object
54657 Roo.GridPanel = function(grid, config){
54660 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54661 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54663 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54665 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54668 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54670 // xtype created footer. - not sure if will work as we normally have to render first..
54671 if (this.footer && !this.footer.el && this.footer.xtype) {
54673 this.footer.container = this.grid.getView().getFooterPanel(true);
54674 this.footer.dataSource = this.grid.dataSource;
54675 this.footer = Roo.factory(this.footer, Roo);
54679 grid.monitorWindowResize = false; // turn off autosizing
54680 grid.autoHeight = false;
54681 grid.autoWidth = false;
54683 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54686 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54687 getId : function(){
54688 return this.grid.id;
54692 * Returns the grid for this panel
54693 * @return {Roo.grid.Grid}
54695 getGrid : function(){
54699 setSize : function(width, height){
54700 if(!this.ignoreResize(width, height)){
54701 var grid = this.grid;
54702 var size = this.adjustForComponents(width, height);
54703 grid.getGridEl().setSize(size.width, size.height);
54708 beforeSlide : function(){
54709 this.grid.getView().scroller.clip();
54712 afterSlide : function(){
54713 this.grid.getView().scroller.unclip();
54716 destroy : function(){
54717 this.grid.destroy();
54719 Roo.GridPanel.superclass.destroy.call(this);
54725 * @class Roo.NestedLayoutPanel
54726 * @extends Roo.ContentPanel
54728 * Create a new NestedLayoutPanel.
54731 * @param {Roo.BorderLayout} layout The layout for this panel
54732 * @param {String/Object} config A string to set only the title or a config object
54734 Roo.NestedLayoutPanel = function(layout, config)
54736 // construct with only one argument..
54737 /* FIXME - implement nicer consturctors
54738 if (layout.layout) {
54740 layout = config.layout;
54741 delete config.layout;
54743 if (layout.xtype && !layout.getEl) {
54744 // then layout needs constructing..
54745 layout = Roo.factory(layout, Roo);
54750 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54752 layout.monitorWindowResize = false; // turn off autosizing
54753 this.layout = layout;
54754 this.layout.getEl().addClass("x-layout-nested-layout");
54761 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
54763 setSize : function(width, height){
54764 if(!this.ignoreResize(width, height)){
54765 var size = this.adjustForComponents(width, height);
54766 var el = this.layout.getEl();
54767 el.setSize(size.width, size.height);
54768 var touch = el.dom.offsetWidth;
54769 this.layout.layout();
54770 // ie requires a double layout on the first pass
54771 if(Roo.isIE && !this.initialized){
54772 this.initialized = true;
54773 this.layout.layout();
54778 // activate all subpanels if not currently active..
54780 setActiveState : function(active){
54781 this.active = active;
54783 this.fireEvent("deactivate", this);
54787 this.fireEvent("activate", this);
54788 // not sure if this should happen before or after..
54789 if (!this.layout) {
54790 return; // should not happen..
54793 for (var r in this.layout.regions) {
54794 reg = this.layout.getRegion(r);
54795 if (reg.getActivePanel()) {
54796 //reg.showPanel(reg.getActivePanel()); // force it to activate..
54797 reg.setActivePanel(reg.getActivePanel());
54800 if (!reg.panels.length) {
54803 reg.showPanel(reg.getPanel(0));
54812 * Returns the nested BorderLayout for this panel
54813 * @return {Roo.BorderLayout}
54815 getLayout : function(){
54816 return this.layout;
54820 * Adds a xtype elements to the layout of the nested panel
54824 xtype : 'ContentPanel',
54831 xtype : 'NestedLayoutPanel',
54837 items : [ ... list of content panels or nested layout panels.. ]
54841 * @param {Object} cfg Xtype definition of item to add.
54843 addxtype : function(cfg) {
54844 return this.layout.addxtype(cfg);
54849 Roo.ScrollPanel = function(el, config, content){
54850 config = config || {};
54851 config.fitToFrame = true;
54852 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
54854 this.el.dom.style.overflow = "hidden";
54855 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
54856 this.el.removeClass("x-layout-inactive-content");
54857 this.el.on("mousewheel", this.onWheel, this);
54859 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
54860 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
54861 up.unselectable(); down.unselectable();
54862 up.on("click", this.scrollUp, this);
54863 down.on("click", this.scrollDown, this);
54864 up.addClassOnOver("x-scroller-btn-over");
54865 down.addClassOnOver("x-scroller-btn-over");
54866 up.addClassOnClick("x-scroller-btn-click");
54867 down.addClassOnClick("x-scroller-btn-click");
54868 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
54870 this.resizeEl = this.el;
54871 this.el = wrap; this.up = up; this.down = down;
54874 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
54876 wheelIncrement : 5,
54877 scrollUp : function(){
54878 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
54881 scrollDown : function(){
54882 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
54885 afterScroll : function(){
54886 var el = this.resizeEl;
54887 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
54888 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54889 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54892 setSize : function(){
54893 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
54894 this.afterScroll();
54897 onWheel : function(e){
54898 var d = e.getWheelDelta();
54899 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
54900 this.afterScroll();
54904 setContent : function(content, loadScripts){
54905 this.resizeEl.update(content, loadScripts);
54919 * @class Roo.TreePanel
54920 * @extends Roo.ContentPanel
54922 * Create a new TreePanel. - defaults to fit/scoll contents.
54923 * @param {String/Object} config A string to set only the panel's title, or a config object
54924 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
54926 Roo.TreePanel = function(config){
54927 var el = config.el;
54928 var tree = config.tree;
54929 delete config.tree;
54930 delete config.el; // hopefull!
54932 // wrapper for IE7 strict & safari scroll issue
54934 var treeEl = el.createChild();
54935 config.resizeEl = treeEl;
54939 Roo.TreePanel.superclass.constructor.call(this, el, config);
54942 this.tree = new Roo.tree.TreePanel(treeEl , tree);
54943 //console.log(tree);
54944 this.on('activate', function()
54946 if (this.tree.rendered) {
54949 //console.log('render tree');
54950 this.tree.render();
54952 // this should not be needed.. - it's actually the 'el' that resizes?
54953 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
54955 //this.on('resize', function (cp, w, h) {
54956 // this.tree.innerCt.setWidth(w);
54957 // this.tree.innerCt.setHeight(h);
54958 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
54965 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
54982 * Ext JS Library 1.1.1
54983 * Copyright(c) 2006-2007, Ext JS, LLC.
54985 * Originally Released Under LGPL - original licence link has changed is not relivant.
54988 * <script type="text/javascript">
54993 * @class Roo.ReaderLayout
54994 * @extends Roo.BorderLayout
54995 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
54996 * center region containing two nested regions (a top one for a list view and one for item preview below),
54997 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
54998 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
54999 * expedites the setup of the overall layout and regions for this common application style.
55002 var reader = new Roo.ReaderLayout();
55003 var CP = Roo.ContentPanel; // shortcut for adding
55005 reader.beginUpdate();
55006 reader.add("north", new CP("north", "North"));
55007 reader.add("west", new CP("west", {title: "West"}));
55008 reader.add("east", new CP("east", {title: "East"}));
55010 reader.regions.listView.add(new CP("listView", "List"));
55011 reader.regions.preview.add(new CP("preview", "Preview"));
55012 reader.endUpdate();
55015 * Create a new ReaderLayout
55016 * @param {Object} config Configuration options
55017 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55018 * document.body if omitted)
55020 Roo.ReaderLayout = function(config, renderTo){
55021 var c = config || {size:{}};
55022 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55023 north: c.north !== false ? Roo.apply({
55027 }, c.north) : false,
55028 west: c.west !== false ? Roo.apply({
55036 margins:{left:5,right:0,bottom:5,top:5},
55037 cmargins:{left:5,right:5,bottom:5,top:5}
55038 }, c.west) : false,
55039 east: c.east !== false ? Roo.apply({
55047 margins:{left:0,right:5,bottom:5,top:5},
55048 cmargins:{left:5,right:5,bottom:5,top:5}
55049 }, c.east) : false,
55050 center: Roo.apply({
55051 tabPosition: 'top',
55055 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55059 this.el.addClass('x-reader');
55061 this.beginUpdate();
55063 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55064 south: c.preview !== false ? Roo.apply({
55071 cmargins:{top:5,left:0, right:0, bottom:0}
55072 }, c.preview) : false,
55073 center: Roo.apply({
55079 this.add('center', new Roo.NestedLayoutPanel(inner,
55080 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55084 this.regions.preview = inner.getRegion('south');
55085 this.regions.listView = inner.getRegion('center');
55088 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55090 * Ext JS Library 1.1.1
55091 * Copyright(c) 2006-2007, Ext JS, LLC.
55093 * Originally Released Under LGPL - original licence link has changed is not relivant.
55096 * <script type="text/javascript">
55100 * @class Roo.grid.Grid
55101 * @extends Roo.util.Observable
55102 * This class represents the primary interface of a component based grid control.
55103 * <br><br>Usage:<pre><code>
55104 var grid = new Roo.grid.Grid("my-container-id", {
55107 selModel: mySelectionModel,
55108 autoSizeColumns: true,
55109 monitorWindowResize: false,
55110 trackMouseOver: true
55115 * <b>Common Problems:</b><br/>
55116 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55117 * element will correct this<br/>
55118 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55119 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55120 * are unpredictable.<br/>
55121 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55122 * grid to calculate dimensions/offsets.<br/>
55124 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55125 * The container MUST have some type of size defined for the grid to fill. The container will be
55126 * automatically set to position relative if it isn't already.
55127 * @param {Object} config A config object that sets properties on this grid.
55129 Roo.grid.Grid = function(container, config){
55130 // initialize the container
55131 this.container = Roo.get(container);
55132 this.container.update("");
55133 this.container.setStyle("overflow", "hidden");
55134 this.container.addClass('x-grid-container');
55136 this.id = this.container.id;
55138 Roo.apply(this, config);
55139 // check and correct shorthanded configs
55141 this.dataSource = this.ds;
55145 this.colModel = this.cm;
55149 this.selModel = this.sm;
55153 if (this.selModel) {
55154 this.selModel = Roo.factory(this.selModel, Roo.grid);
55155 this.sm = this.selModel;
55156 this.sm.xmodule = this.xmodule || false;
55158 if (typeof(this.colModel.config) == 'undefined') {
55159 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55160 this.cm = this.colModel;
55161 this.cm.xmodule = this.xmodule || false;
55163 if (this.dataSource) {
55164 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55165 this.ds = this.dataSource;
55166 this.ds.xmodule = this.xmodule || false;
55173 this.container.setWidth(this.width);
55177 this.container.setHeight(this.height);
55184 * The raw click event for the entire grid.
55185 * @param {Roo.EventObject} e
55190 * The raw dblclick event for the entire grid.
55191 * @param {Roo.EventObject} e
55195 * @event contextmenu
55196 * The raw contextmenu event for the entire grid.
55197 * @param {Roo.EventObject} e
55199 "contextmenu" : true,
55202 * The raw mousedown event for the entire grid.
55203 * @param {Roo.EventObject} e
55205 "mousedown" : true,
55208 * The raw mouseup event for the entire grid.
55209 * @param {Roo.EventObject} e
55214 * The raw mouseover event for the entire grid.
55215 * @param {Roo.EventObject} e
55217 "mouseover" : true,
55220 * The raw mouseout event for the entire grid.
55221 * @param {Roo.EventObject} e
55226 * The raw keypress event for the entire grid.
55227 * @param {Roo.EventObject} e
55232 * The raw keydown event for the entire grid.
55233 * @param {Roo.EventObject} e
55241 * Fires when a cell is clicked
55242 * @param {Grid} this
55243 * @param {Number} rowIndex
55244 * @param {Number} columnIndex
55245 * @param {Roo.EventObject} e
55247 "cellclick" : true,
55249 * @event celldblclick
55250 * Fires when a cell is double clicked
55251 * @param {Grid} this
55252 * @param {Number} rowIndex
55253 * @param {Number} columnIndex
55254 * @param {Roo.EventObject} e
55256 "celldblclick" : true,
55259 * Fires when a row is clicked
55260 * @param {Grid} this
55261 * @param {Number} rowIndex
55262 * @param {Roo.EventObject} e
55266 * @event rowdblclick
55267 * Fires when a row is double clicked
55268 * @param {Grid} this
55269 * @param {Number} rowIndex
55270 * @param {Roo.EventObject} e
55272 "rowdblclick" : true,
55274 * @event headerclick
55275 * Fires when a header is clicked
55276 * @param {Grid} this
55277 * @param {Number} columnIndex
55278 * @param {Roo.EventObject} e
55280 "headerclick" : true,
55282 * @event headerdblclick
55283 * Fires when a header cell is double clicked
55284 * @param {Grid} this
55285 * @param {Number} columnIndex
55286 * @param {Roo.EventObject} e
55288 "headerdblclick" : true,
55290 * @event rowcontextmenu
55291 * Fires when a row is right clicked
55292 * @param {Grid} this
55293 * @param {Number} rowIndex
55294 * @param {Roo.EventObject} e
55296 "rowcontextmenu" : true,
55298 * @event cellcontextmenu
55299 * Fires when a cell is right clicked
55300 * @param {Grid} this
55301 * @param {Number} rowIndex
55302 * @param {Number} cellIndex
55303 * @param {Roo.EventObject} e
55305 "cellcontextmenu" : true,
55307 * @event headercontextmenu
55308 * Fires when a header is right clicked
55309 * @param {Grid} this
55310 * @param {Number} columnIndex
55311 * @param {Roo.EventObject} e
55313 "headercontextmenu" : true,
55315 * @event bodyscroll
55316 * Fires when the body element is scrolled
55317 * @param {Number} scrollLeft
55318 * @param {Number} scrollTop
55320 "bodyscroll" : true,
55322 * @event columnresize
55323 * Fires when the user resizes a column
55324 * @param {Number} columnIndex
55325 * @param {Number} newSize
55327 "columnresize" : true,
55329 * @event columnmove
55330 * Fires when the user moves a column
55331 * @param {Number} oldIndex
55332 * @param {Number} newIndex
55334 "columnmove" : true,
55337 * Fires when row(s) start being dragged
55338 * @param {Grid} this
55339 * @param {Roo.GridDD} dd The drag drop object
55340 * @param {event} e The raw browser event
55342 "startdrag" : true,
55345 * Fires when a drag operation is complete
55346 * @param {Grid} this
55347 * @param {Roo.GridDD} dd The drag drop object
55348 * @param {event} e The raw browser event
55353 * Fires when dragged row(s) are dropped on a valid DD target
55354 * @param {Grid} this
55355 * @param {Roo.GridDD} dd The drag drop object
55356 * @param {String} targetId The target drag drop object
55357 * @param {event} e The raw browser event
55362 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55363 * @param {Grid} this
55364 * @param {Roo.GridDD} dd The drag drop object
55365 * @param {String} targetId The target drag drop object
55366 * @param {event} e The raw browser event
55371 * Fires when the dragged row(s) first cross another DD target while being dragged
55372 * @param {Grid} this
55373 * @param {Roo.GridDD} dd The drag drop object
55374 * @param {String} targetId The target drag drop object
55375 * @param {event} e The raw browser event
55377 "dragenter" : true,
55380 * Fires when the dragged row(s) leave another DD target while being dragged
55381 * @param {Grid} this
55382 * @param {Roo.GridDD} dd The drag drop object
55383 * @param {String} targetId The target drag drop object
55384 * @param {event} e The raw browser event
55389 * Fires when a row is rendered, so you can change add a style to it.
55390 * @param {GridView} gridview The grid view
55391 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55397 * Fires when the grid is rendered
55398 * @param {Grid} grid
55403 Roo.grid.Grid.superclass.constructor.call(this);
55405 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55408 * @cfg {String} ddGroup - drag drop group.
55412 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55414 minColumnWidth : 25,
55417 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55418 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55419 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55421 autoSizeColumns : false,
55424 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55426 autoSizeHeaders : true,
55429 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55431 monitorWindowResize : true,
55434 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55435 * rows measured to get a columns size. Default is 0 (all rows).
55437 maxRowsToMeasure : 0,
55440 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55442 trackMouseOver : true,
55445 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55449 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55451 enableDragDrop : false,
55454 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55456 enableColumnMove : true,
55459 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55461 enableColumnHide : true,
55464 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55466 enableRowHeightSync : false,
55469 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55474 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55476 autoHeight : false,
55479 * @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.
55481 autoExpandColumn : false,
55484 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55487 autoExpandMin : 50,
55490 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55492 autoExpandMax : 1000,
55495 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55500 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55504 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55514 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55515 * of a fixed width. Default is false.
55518 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55521 * Called once after all setup has been completed and the grid is ready to be rendered.
55522 * @return {Roo.grid.Grid} this
55524 render : function()
55526 var c = this.container;
55527 // try to detect autoHeight/width mode
55528 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55529 this.autoHeight = true;
55531 var view = this.getView();
55534 c.on("click", this.onClick, this);
55535 c.on("dblclick", this.onDblClick, this);
55536 c.on("contextmenu", this.onContextMenu, this);
55537 c.on("keydown", this.onKeyDown, this);
55539 c.on("touchstart", this.onTouchStart, this);
55542 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55544 this.getSelectionModel().init(this);
55549 this.loadMask = new Roo.LoadMask(this.container,
55550 Roo.apply({store:this.dataSource}, this.loadMask));
55554 if (this.toolbar && this.toolbar.xtype) {
55555 this.toolbar.container = this.getView().getHeaderPanel(true);
55556 this.toolbar = new Roo.Toolbar(this.toolbar);
55558 if (this.footer && this.footer.xtype) {
55559 this.footer.dataSource = this.getDataSource();
55560 this.footer.container = this.getView().getFooterPanel(true);
55561 this.footer = Roo.factory(this.footer, Roo);
55563 if (this.dropTarget && this.dropTarget.xtype) {
55564 delete this.dropTarget.xtype;
55565 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55569 this.rendered = true;
55570 this.fireEvent('render', this);
55575 * Reconfigures the grid to use a different Store and Column Model.
55576 * The View will be bound to the new objects and refreshed.
55577 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55578 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55580 reconfigure : function(dataSource, colModel){
55582 this.loadMask.destroy();
55583 this.loadMask = new Roo.LoadMask(this.container,
55584 Roo.apply({store:dataSource}, this.loadMask));
55586 this.view.bind(dataSource, colModel);
55587 this.dataSource = dataSource;
55588 this.colModel = colModel;
55589 this.view.refresh(true);
55593 * Add's a column, default at the end..
55595 * @param {int} position to add (default end)
55596 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55598 addColumns : function(pos, ar)
55601 for (var i =0;i< ar.length;i++) {
55603 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55604 this.cm.lookup[cfg.id] = cfg;
55608 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55609 pos = this.cm.config.length; //this.cm.config.push(cfg);
55611 pos = Math.max(0,pos);
55614 this.cm.config.splice.apply(this.cm.config, ar);
55618 this.view.generateRules(this.cm);
55619 this.view.refresh(true);
55627 onKeyDown : function(e){
55628 this.fireEvent("keydown", e);
55632 * Destroy this grid.
55633 * @param {Boolean} removeEl True to remove the element
55635 destroy : function(removeEl, keepListeners){
55637 this.loadMask.destroy();
55639 var c = this.container;
55640 c.removeAllListeners();
55641 this.view.destroy();
55642 this.colModel.purgeListeners();
55643 if(!keepListeners){
55644 this.purgeListeners();
55647 if(removeEl === true){
55653 processEvent : function(name, e){
55654 // does this fire select???
55655 //Roo.log('grid:processEvent ' + name);
55657 if (name != 'touchstart' ) {
55658 this.fireEvent(name, e);
55661 var t = e.getTarget();
55663 var header = v.findHeaderIndex(t);
55664 if(header !== false){
55665 var ename = name == 'touchstart' ? 'click' : name;
55667 this.fireEvent("header" + ename, this, header, e);
55669 var row = v.findRowIndex(t);
55670 var cell = v.findCellIndex(t);
55671 if (name == 'touchstart') {
55672 // first touch is always a click.
55673 // hopefull this happens after selection is updated.?
55676 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55677 var cs = this.selModel.getSelectedCell();
55678 if (row == cs[0] && cell == cs[1]){
55682 if (typeof(this.selModel.getSelections) != 'undefined') {
55683 var cs = this.selModel.getSelections();
55684 var ds = this.dataSource;
55685 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55696 this.fireEvent("row" + name, this, row, e);
55697 if(cell !== false){
55698 this.fireEvent("cell" + name, this, row, cell, e);
55705 onClick : function(e){
55706 this.processEvent("click", e);
55709 onTouchStart : function(e){
55710 this.processEvent("touchstart", e);
55714 onContextMenu : function(e, t){
55715 this.processEvent("contextmenu", e);
55719 onDblClick : function(e){
55720 this.processEvent("dblclick", e);
55724 walkCells : function(row, col, step, fn, scope){
55725 var cm = this.colModel, clen = cm.getColumnCount();
55726 var ds = this.dataSource, rlen = ds.getCount(), first = true;
55738 if(fn.call(scope || this, row, col, cm) === true){
55756 if(fn.call(scope || this, row, col, cm) === true){
55768 getSelections : function(){
55769 return this.selModel.getSelections();
55773 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
55774 * but if manual update is required this method will initiate it.
55776 autoSize : function(){
55778 this.view.layout();
55779 if(this.view.adjustForScroll){
55780 this.view.adjustForScroll();
55786 * Returns the grid's underlying element.
55787 * @return {Element} The element
55789 getGridEl : function(){
55790 return this.container;
55793 // private for compatibility, overridden by editor grid
55794 stopEditing : function(){},
55797 * Returns the grid's SelectionModel.
55798 * @return {SelectionModel}
55800 getSelectionModel : function(){
55801 if(!this.selModel){
55802 this.selModel = new Roo.grid.RowSelectionModel();
55804 return this.selModel;
55808 * Returns the grid's DataSource.
55809 * @return {DataSource}
55811 getDataSource : function(){
55812 return this.dataSource;
55816 * Returns the grid's ColumnModel.
55817 * @return {ColumnModel}
55819 getColumnModel : function(){
55820 return this.colModel;
55824 * Returns the grid's GridView object.
55825 * @return {GridView}
55827 getView : function(){
55829 this.view = new Roo.grid.GridView(this.viewConfig);
55834 * Called to get grid's drag proxy text, by default returns this.ddText.
55837 getDragDropText : function(){
55838 var count = this.selModel.getCount();
55839 return String.format(this.ddText, count, count == 1 ? '' : 's');
55843 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55844 * %0 is replaced with the number of selected rows.
55847 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
55849 * Ext JS Library 1.1.1
55850 * Copyright(c) 2006-2007, Ext JS, LLC.
55852 * Originally Released Under LGPL - original licence link has changed is not relivant.
55855 * <script type="text/javascript">
55858 Roo.grid.AbstractGridView = function(){
55862 "beforerowremoved" : true,
55863 "beforerowsinserted" : true,
55864 "beforerefresh" : true,
55865 "rowremoved" : true,
55866 "rowsinserted" : true,
55867 "rowupdated" : true,
55870 Roo.grid.AbstractGridView.superclass.constructor.call(this);
55873 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
55874 rowClass : "x-grid-row",
55875 cellClass : "x-grid-cell",
55876 tdClass : "x-grid-td",
55877 hdClass : "x-grid-hd",
55878 splitClass : "x-grid-hd-split",
55880 init: function(grid){
55882 var cid = this.grid.getGridEl().id;
55883 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
55884 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
55885 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
55886 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
55889 getColumnRenderers : function(){
55890 var renderers = [];
55891 var cm = this.grid.colModel;
55892 var colCount = cm.getColumnCount();
55893 for(var i = 0; i < colCount; i++){
55894 renderers[i] = cm.getRenderer(i);
55899 getColumnIds : function(){
55901 var cm = this.grid.colModel;
55902 var colCount = cm.getColumnCount();
55903 for(var i = 0; i < colCount; i++){
55904 ids[i] = cm.getColumnId(i);
55909 getDataIndexes : function(){
55910 if(!this.indexMap){
55911 this.indexMap = this.buildIndexMap();
55913 return this.indexMap.colToData;
55916 getColumnIndexByDataIndex : function(dataIndex){
55917 if(!this.indexMap){
55918 this.indexMap = this.buildIndexMap();
55920 return this.indexMap.dataToCol[dataIndex];
55924 * Set a css style for a column dynamically.
55925 * @param {Number} colIndex The index of the column
55926 * @param {String} name The css property name
55927 * @param {String} value The css value
55929 setCSSStyle : function(colIndex, name, value){
55930 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
55931 Roo.util.CSS.updateRule(selector, name, value);
55934 generateRules : function(cm){
55935 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
55936 Roo.util.CSS.removeStyleSheet(rulesId);
55937 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55938 var cid = cm.getColumnId(i);
55939 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
55940 this.tdSelector, cid, " {\n}\n",
55941 this.hdSelector, cid, " {\n}\n",
55942 this.splitSelector, cid, " {\n}\n");
55944 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55948 * Ext JS Library 1.1.1
55949 * Copyright(c) 2006-2007, Ext JS, LLC.
55951 * Originally Released Under LGPL - original licence link has changed is not relivant.
55954 * <script type="text/javascript">
55958 // This is a support class used internally by the Grid components
55959 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
55961 this.view = grid.getView();
55962 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
55963 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
55965 this.setHandleElId(Roo.id(hd));
55966 this.setOuterHandleElId(Roo.id(hd2));
55968 this.scroll = false;
55970 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
55972 getDragData : function(e){
55973 var t = Roo.lib.Event.getTarget(e);
55974 var h = this.view.findHeaderCell(t);
55976 return {ddel: h.firstChild, header:h};
55981 onInitDrag : function(e){
55982 this.view.headersDisabled = true;
55983 var clone = this.dragData.ddel.cloneNode(true);
55984 clone.id = Roo.id();
55985 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
55986 this.proxy.update(clone);
55990 afterValidDrop : function(){
55992 setTimeout(function(){
55993 v.headersDisabled = false;
55997 afterInvalidDrop : function(){
55999 setTimeout(function(){
56000 v.headersDisabled = false;
56006 * Ext JS Library 1.1.1
56007 * Copyright(c) 2006-2007, Ext JS, LLC.
56009 * Originally Released Under LGPL - original licence link has changed is not relivant.
56012 * <script type="text/javascript">
56015 // This is a support class used internally by the Grid components
56016 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56018 this.view = grid.getView();
56019 // split the proxies so they don't interfere with mouse events
56020 this.proxyTop = Roo.DomHelper.append(document.body, {
56021 cls:"col-move-top", html:" "
56023 this.proxyBottom = Roo.DomHelper.append(document.body, {
56024 cls:"col-move-bottom", html:" "
56026 this.proxyTop.hide = this.proxyBottom.hide = function(){
56027 this.setLeftTop(-100,-100);
56028 this.setStyle("visibility", "hidden");
56030 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56031 // temporarily disabled
56032 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56033 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56035 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56036 proxyOffsets : [-4, -9],
56037 fly: Roo.Element.fly,
56039 getTargetFromEvent : function(e){
56040 var t = Roo.lib.Event.getTarget(e);
56041 var cindex = this.view.findCellIndex(t);
56042 if(cindex !== false){
56043 return this.view.getHeaderCell(cindex);
56048 nextVisible : function(h){
56049 var v = this.view, cm = this.grid.colModel;
56052 if(!cm.isHidden(v.getCellIndex(h))){
56060 prevVisible : function(h){
56061 var v = this.view, cm = this.grid.colModel;
56064 if(!cm.isHidden(v.getCellIndex(h))){
56072 positionIndicator : function(h, n, e){
56073 var x = Roo.lib.Event.getPageX(e);
56074 var r = Roo.lib.Dom.getRegion(n.firstChild);
56075 var px, pt, py = r.top + this.proxyOffsets[1];
56076 if((r.right - x) <= (r.right-r.left)/2){
56077 px = r.right+this.view.borderWidth;
56083 var oldIndex = this.view.getCellIndex(h);
56084 var newIndex = this.view.getCellIndex(n);
56086 if(this.grid.colModel.isFixed(newIndex)){
56090 var locked = this.grid.colModel.isLocked(newIndex);
56095 if(oldIndex < newIndex){
56098 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56101 px += this.proxyOffsets[0];
56102 this.proxyTop.setLeftTop(px, py);
56103 this.proxyTop.show();
56104 if(!this.bottomOffset){
56105 this.bottomOffset = this.view.mainHd.getHeight();
56107 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56108 this.proxyBottom.show();
56112 onNodeEnter : function(n, dd, e, data){
56113 if(data.header != n){
56114 this.positionIndicator(data.header, n, e);
56118 onNodeOver : function(n, dd, e, data){
56119 var result = false;
56120 if(data.header != n){
56121 result = this.positionIndicator(data.header, n, e);
56124 this.proxyTop.hide();
56125 this.proxyBottom.hide();
56127 return result ? this.dropAllowed : this.dropNotAllowed;
56130 onNodeOut : function(n, dd, e, data){
56131 this.proxyTop.hide();
56132 this.proxyBottom.hide();
56135 onNodeDrop : function(n, dd, e, data){
56136 var h = data.header;
56138 var cm = this.grid.colModel;
56139 var x = Roo.lib.Event.getPageX(e);
56140 var r = Roo.lib.Dom.getRegion(n.firstChild);
56141 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56142 var oldIndex = this.view.getCellIndex(h);
56143 var newIndex = this.view.getCellIndex(n);
56144 var locked = cm.isLocked(newIndex);
56148 if(oldIndex < newIndex){
56151 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56154 cm.setLocked(oldIndex, locked, true);
56155 cm.moveColumn(oldIndex, newIndex);
56156 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56164 * Ext JS Library 1.1.1
56165 * Copyright(c) 2006-2007, Ext JS, LLC.
56167 * Originally Released Under LGPL - original licence link has changed is not relivant.
56170 * <script type="text/javascript">
56174 * @class Roo.grid.GridView
56175 * @extends Roo.util.Observable
56178 * @param {Object} config
56180 Roo.grid.GridView = function(config){
56181 Roo.grid.GridView.superclass.constructor.call(this);
56184 Roo.apply(this, config);
56187 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56189 unselectable : 'unselectable="on"',
56190 unselectableCls : 'x-unselectable',
56193 rowClass : "x-grid-row",
56195 cellClass : "x-grid-col",
56197 tdClass : "x-grid-td",
56199 hdClass : "x-grid-hd",
56201 splitClass : "x-grid-split",
56203 sortClasses : ["sort-asc", "sort-desc"],
56205 enableMoveAnim : false,
56209 dh : Roo.DomHelper,
56211 fly : Roo.Element.fly,
56213 css : Roo.util.CSS,
56219 scrollIncrement : 22,
56221 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56223 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56225 bind : function(ds, cm){
56227 this.ds.un("load", this.onLoad, this);
56228 this.ds.un("datachanged", this.onDataChange, this);
56229 this.ds.un("add", this.onAdd, this);
56230 this.ds.un("remove", this.onRemove, this);
56231 this.ds.un("update", this.onUpdate, this);
56232 this.ds.un("clear", this.onClear, this);
56235 ds.on("load", this.onLoad, this);
56236 ds.on("datachanged", this.onDataChange, this);
56237 ds.on("add", this.onAdd, this);
56238 ds.on("remove", this.onRemove, this);
56239 ds.on("update", this.onUpdate, this);
56240 ds.on("clear", this.onClear, this);
56245 this.cm.un("widthchange", this.onColWidthChange, this);
56246 this.cm.un("headerchange", this.onHeaderChange, this);
56247 this.cm.un("hiddenchange", this.onHiddenChange, this);
56248 this.cm.un("columnmoved", this.onColumnMove, this);
56249 this.cm.un("columnlockchange", this.onColumnLock, this);
56252 this.generateRules(cm);
56253 cm.on("widthchange", this.onColWidthChange, this);
56254 cm.on("headerchange", this.onHeaderChange, this);
56255 cm.on("hiddenchange", this.onHiddenChange, this);
56256 cm.on("columnmoved", this.onColumnMove, this);
56257 cm.on("columnlockchange", this.onColumnLock, this);
56262 init: function(grid){
56263 Roo.grid.GridView.superclass.init.call(this, grid);
56265 this.bind(grid.dataSource, grid.colModel);
56267 grid.on("headerclick", this.handleHeaderClick, this);
56269 if(grid.trackMouseOver){
56270 grid.on("mouseover", this.onRowOver, this);
56271 grid.on("mouseout", this.onRowOut, this);
56273 grid.cancelTextSelection = function(){};
56274 this.gridId = grid.id;
56276 var tpls = this.templates || {};
56279 tpls.master = new Roo.Template(
56280 '<div class="x-grid" hidefocus="true">',
56281 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56282 '<div class="x-grid-topbar"></div>',
56283 '<div class="x-grid-scroller"><div></div></div>',
56284 '<div class="x-grid-locked">',
56285 '<div class="x-grid-header">{lockedHeader}</div>',
56286 '<div class="x-grid-body">{lockedBody}</div>',
56288 '<div class="x-grid-viewport">',
56289 '<div class="x-grid-header">{header}</div>',
56290 '<div class="x-grid-body">{body}</div>',
56292 '<div class="x-grid-bottombar"></div>',
56294 '<div class="x-grid-resize-proxy"> </div>',
56297 tpls.master.disableformats = true;
56301 tpls.header = new Roo.Template(
56302 '<table border="0" cellspacing="0" cellpadding="0">',
56303 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56306 tpls.header.disableformats = true;
56308 tpls.header.compile();
56311 tpls.hcell = new Roo.Template(
56312 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56313 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56316 tpls.hcell.disableFormats = true;
56318 tpls.hcell.compile();
56321 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56322 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56323 tpls.hsplit.disableFormats = true;
56325 tpls.hsplit.compile();
56328 tpls.body = new Roo.Template(
56329 '<table border="0" cellspacing="0" cellpadding="0">',
56330 "<tbody>{rows}</tbody>",
56333 tpls.body.disableFormats = true;
56335 tpls.body.compile();
56338 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56339 tpls.row.disableFormats = true;
56341 tpls.row.compile();
56344 tpls.cell = new Roo.Template(
56345 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56346 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56347 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56350 tpls.cell.disableFormats = true;
56352 tpls.cell.compile();
56354 this.templates = tpls;
56357 // remap these for backwards compat
56358 onColWidthChange : function(){
56359 this.updateColumns.apply(this, arguments);
56361 onHeaderChange : function(){
56362 this.updateHeaders.apply(this, arguments);
56364 onHiddenChange : function(){
56365 this.handleHiddenChange.apply(this, arguments);
56367 onColumnMove : function(){
56368 this.handleColumnMove.apply(this, arguments);
56370 onColumnLock : function(){
56371 this.handleLockChange.apply(this, arguments);
56374 onDataChange : function(){
56376 this.updateHeaderSortState();
56379 onClear : function(){
56383 onUpdate : function(ds, record){
56384 this.refreshRow(record);
56387 refreshRow : function(record){
56388 var ds = this.ds, index;
56389 if(typeof record == 'number'){
56391 record = ds.getAt(index);
56393 index = ds.indexOf(record);
56395 this.insertRows(ds, index, index, true);
56396 this.onRemove(ds, record, index+1, true);
56397 this.syncRowHeights(index, index);
56399 this.fireEvent("rowupdated", this, index, record);
56402 onAdd : function(ds, records, index){
56403 this.insertRows(ds, index, index + (records.length-1));
56406 onRemove : function(ds, record, index, isUpdate){
56407 if(isUpdate !== true){
56408 this.fireEvent("beforerowremoved", this, index, record);
56410 var bt = this.getBodyTable(), lt = this.getLockedTable();
56411 if(bt.rows[index]){
56412 bt.firstChild.removeChild(bt.rows[index]);
56414 if(lt.rows[index]){
56415 lt.firstChild.removeChild(lt.rows[index]);
56417 if(isUpdate !== true){
56418 this.stripeRows(index);
56419 this.syncRowHeights(index, index);
56421 this.fireEvent("rowremoved", this, index, record);
56425 onLoad : function(){
56426 this.scrollToTop();
56430 * Scrolls the grid to the top
56432 scrollToTop : function(){
56434 this.scroller.dom.scrollTop = 0;
56440 * Gets a panel in the header of the grid that can be used for toolbars etc.
56441 * After modifying the contents of this panel a call to grid.autoSize() may be
56442 * required to register any changes in size.
56443 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56444 * @return Roo.Element
56446 getHeaderPanel : function(doShow){
56448 this.headerPanel.show();
56450 return this.headerPanel;
56454 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56455 * After modifying the contents of this panel a call to grid.autoSize() may be
56456 * required to register any changes in size.
56457 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56458 * @return Roo.Element
56460 getFooterPanel : function(doShow){
56462 this.footerPanel.show();
56464 return this.footerPanel;
56467 initElements : function(){
56468 var E = Roo.Element;
56469 var el = this.grid.getGridEl().dom.firstChild;
56470 var cs = el.childNodes;
56472 this.el = new E(el);
56474 this.focusEl = new E(el.firstChild);
56475 this.focusEl.swallowEvent("click", true);
56477 this.headerPanel = new E(cs[1]);
56478 this.headerPanel.enableDisplayMode("block");
56480 this.scroller = new E(cs[2]);
56481 this.scrollSizer = new E(this.scroller.dom.firstChild);
56483 this.lockedWrap = new E(cs[3]);
56484 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56485 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56487 this.mainWrap = new E(cs[4]);
56488 this.mainHd = new E(this.mainWrap.dom.firstChild);
56489 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56491 this.footerPanel = new E(cs[5]);
56492 this.footerPanel.enableDisplayMode("block");
56494 this.resizeProxy = new E(cs[6]);
56496 this.headerSelector = String.format(
56497 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56498 this.lockedHd.id, this.mainHd.id
56501 this.splitterSelector = String.format(
56502 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56503 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56506 idToCssName : function(s)
56508 return s.replace(/[^a-z0-9]+/ig, '-');
56511 getHeaderCell : function(index){
56512 return Roo.DomQuery.select(this.headerSelector)[index];
56515 getHeaderCellMeasure : function(index){
56516 return this.getHeaderCell(index).firstChild;
56519 getHeaderCellText : function(index){
56520 return this.getHeaderCell(index).firstChild.firstChild;
56523 getLockedTable : function(){
56524 return this.lockedBody.dom.firstChild;
56527 getBodyTable : function(){
56528 return this.mainBody.dom.firstChild;
56531 getLockedRow : function(index){
56532 return this.getLockedTable().rows[index];
56535 getRow : function(index){
56536 return this.getBodyTable().rows[index];
56539 getRowComposite : function(index){
56541 this.rowEl = new Roo.CompositeElementLite();
56543 var els = [], lrow, mrow;
56544 if(lrow = this.getLockedRow(index)){
56547 if(mrow = this.getRow(index)){
56550 this.rowEl.elements = els;
56554 * Gets the 'td' of the cell
56556 * @param {Integer} rowIndex row to select
56557 * @param {Integer} colIndex column to select
56561 getCell : function(rowIndex, colIndex){
56562 var locked = this.cm.getLockedCount();
56564 if(colIndex < locked){
56565 source = this.lockedBody.dom.firstChild;
56567 source = this.mainBody.dom.firstChild;
56568 colIndex -= locked;
56570 return source.rows[rowIndex].childNodes[colIndex];
56573 getCellText : function(rowIndex, colIndex){
56574 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56577 getCellBox : function(cell){
56578 var b = this.fly(cell).getBox();
56579 if(Roo.isOpera){ // opera fails to report the Y
56580 b.y = cell.offsetTop + this.mainBody.getY();
56585 getCellIndex : function(cell){
56586 var id = String(cell.className).match(this.cellRE);
56588 return parseInt(id[1], 10);
56593 findHeaderIndex : function(n){
56594 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56595 return r ? this.getCellIndex(r) : false;
56598 findHeaderCell : function(n){
56599 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56600 return r ? r : false;
56603 findRowIndex : function(n){
56607 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56608 return r ? r.rowIndex : false;
56611 findCellIndex : function(node){
56612 var stop = this.el.dom;
56613 while(node && node != stop){
56614 if(this.findRE.test(node.className)){
56615 return this.getCellIndex(node);
56617 node = node.parentNode;
56622 getColumnId : function(index){
56623 return this.cm.getColumnId(index);
56626 getSplitters : function()
56628 if(this.splitterSelector){
56629 return Roo.DomQuery.select(this.splitterSelector);
56635 getSplitter : function(index){
56636 return this.getSplitters()[index];
56639 onRowOver : function(e, t){
56641 if((row = this.findRowIndex(t)) !== false){
56642 this.getRowComposite(row).addClass("x-grid-row-over");
56646 onRowOut : function(e, t){
56648 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56649 this.getRowComposite(row).removeClass("x-grid-row-over");
56653 renderHeaders : function(){
56655 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56656 var cb = [], lb = [], sb = [], lsb = [], p = {};
56657 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56658 p.cellId = "x-grid-hd-0-" + i;
56659 p.splitId = "x-grid-csplit-0-" + i;
56660 p.id = cm.getColumnId(i);
56661 p.value = cm.getColumnHeader(i) || "";
56662 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56663 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56664 if(!cm.isLocked(i)){
56665 cb[cb.length] = ct.apply(p);
56666 sb[sb.length] = st.apply(p);
56668 lb[lb.length] = ct.apply(p);
56669 lsb[lsb.length] = st.apply(p);
56672 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56673 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56676 updateHeaders : function(){
56677 var html = this.renderHeaders();
56678 this.lockedHd.update(html[0]);
56679 this.mainHd.update(html[1]);
56683 * Focuses the specified row.
56684 * @param {Number} row The row index
56686 focusRow : function(row)
56688 //Roo.log('GridView.focusRow');
56689 var x = this.scroller.dom.scrollLeft;
56690 this.focusCell(row, 0, false);
56691 this.scroller.dom.scrollLeft = x;
56695 * Focuses the specified cell.
56696 * @param {Number} row The row index
56697 * @param {Number} col The column index
56698 * @param {Boolean} hscroll false to disable horizontal scrolling
56700 focusCell : function(row, col, hscroll)
56702 //Roo.log('GridView.focusCell');
56703 var el = this.ensureVisible(row, col, hscroll);
56704 this.focusEl.alignTo(el, "tl-tl");
56706 this.focusEl.focus();
56708 this.focusEl.focus.defer(1, this.focusEl);
56713 * Scrolls the specified cell into view
56714 * @param {Number} row The row index
56715 * @param {Number} col The column index
56716 * @param {Boolean} hscroll false to disable horizontal scrolling
56718 ensureVisible : function(row, col, hscroll)
56720 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56721 //return null; //disable for testing.
56722 if(typeof row != "number"){
56723 row = row.rowIndex;
56725 if(row < 0 && row >= this.ds.getCount()){
56728 col = (col !== undefined ? col : 0);
56729 var cm = this.grid.colModel;
56730 while(cm.isHidden(col)){
56734 var el = this.getCell(row, col);
56738 var c = this.scroller.dom;
56740 var ctop = parseInt(el.offsetTop, 10);
56741 var cleft = parseInt(el.offsetLeft, 10);
56742 var cbot = ctop + el.offsetHeight;
56743 var cright = cleft + el.offsetWidth;
56745 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
56746 var stop = parseInt(c.scrollTop, 10);
56747 var sleft = parseInt(c.scrollLeft, 10);
56748 var sbot = stop + ch;
56749 var sright = sleft + c.clientWidth;
56751 Roo.log('GridView.ensureVisible:' +
56753 ' c.clientHeight:' + c.clientHeight +
56754 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
56762 c.scrollTop = ctop;
56763 //Roo.log("set scrolltop to ctop DISABLE?");
56764 }else if(cbot > sbot){
56765 //Roo.log("set scrolltop to cbot-ch");
56766 c.scrollTop = cbot-ch;
56769 if(hscroll !== false){
56771 c.scrollLeft = cleft;
56772 }else if(cright > sright){
56773 c.scrollLeft = cright-c.clientWidth;
56780 updateColumns : function(){
56781 this.grid.stopEditing();
56782 var cm = this.grid.colModel, colIds = this.getColumnIds();
56783 //var totalWidth = cm.getTotalWidth();
56785 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56786 //if(cm.isHidden(i)) continue;
56787 var w = cm.getColumnWidth(i);
56788 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56789 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56791 this.updateSplitters();
56794 generateRules : function(cm){
56795 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
56796 Roo.util.CSS.removeStyleSheet(rulesId);
56797 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56798 var cid = cm.getColumnId(i);
56800 if(cm.config[i].align){
56801 align = 'text-align:'+cm.config[i].align+';';
56804 if(cm.isHidden(i)){
56805 hidden = 'display:none;';
56807 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
56809 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
56810 this.hdSelector, cid, " {\n", align, width, "}\n",
56811 this.tdSelector, cid, " {\n",hidden,"\n}\n",
56812 this.splitSelector, cid, " {\n", hidden , "\n}\n");
56814 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56817 updateSplitters : function(){
56818 var cm = this.cm, s = this.getSplitters();
56819 if(s){ // splitters not created yet
56820 var pos = 0, locked = true;
56821 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56822 if(cm.isHidden(i)) {
56825 var w = cm.getColumnWidth(i); // make sure it's a number
56826 if(!cm.isLocked(i) && locked){
56831 s[i].style.left = (pos-this.splitOffset) + "px";
56836 handleHiddenChange : function(colModel, colIndex, hidden){
56838 this.hideColumn(colIndex);
56840 this.unhideColumn(colIndex);
56844 hideColumn : function(colIndex){
56845 var cid = this.getColumnId(colIndex);
56846 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
56847 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
56849 this.updateHeaders();
56851 this.updateSplitters();
56855 unhideColumn : function(colIndex){
56856 var cid = this.getColumnId(colIndex);
56857 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
56858 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
56861 this.updateHeaders();
56863 this.updateSplitters();
56867 insertRows : function(dm, firstRow, lastRow, isUpdate){
56868 if(firstRow == 0 && lastRow == dm.getCount()-1){
56872 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
56874 var s = this.getScrollState();
56875 var markup = this.renderRows(firstRow, lastRow);
56876 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
56877 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
56878 this.restoreScroll(s);
56880 this.fireEvent("rowsinserted", this, firstRow, lastRow);
56881 this.syncRowHeights(firstRow, lastRow);
56882 this.stripeRows(firstRow);
56888 bufferRows : function(markup, target, index){
56889 var before = null, trows = target.rows, tbody = target.tBodies[0];
56890 if(index < trows.length){
56891 before = trows[index];
56893 var b = document.createElement("div");
56894 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
56895 var rows = b.firstChild.rows;
56896 for(var i = 0, len = rows.length; i < len; i++){
56898 tbody.insertBefore(rows[0], before);
56900 tbody.appendChild(rows[0]);
56907 deleteRows : function(dm, firstRow, lastRow){
56908 if(dm.getRowCount()<1){
56909 this.fireEvent("beforerefresh", this);
56910 this.mainBody.update("");
56911 this.lockedBody.update("");
56912 this.fireEvent("refresh", this);
56914 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
56915 var bt = this.getBodyTable();
56916 var tbody = bt.firstChild;
56917 var rows = bt.rows;
56918 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
56919 tbody.removeChild(rows[firstRow]);
56921 this.stripeRows(firstRow);
56922 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
56926 updateRows : function(dataSource, firstRow, lastRow){
56927 var s = this.getScrollState();
56929 this.restoreScroll(s);
56932 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
56936 this.updateHeaderSortState();
56939 getScrollState : function(){
56941 var sb = this.scroller.dom;
56942 return {left: sb.scrollLeft, top: sb.scrollTop};
56945 stripeRows : function(startRow){
56946 if(!this.grid.stripeRows || this.ds.getCount() < 1){
56949 startRow = startRow || 0;
56950 var rows = this.getBodyTable().rows;
56951 var lrows = this.getLockedTable().rows;
56952 var cls = ' x-grid-row-alt ';
56953 for(var i = startRow, len = rows.length; i < len; i++){
56954 var row = rows[i], lrow = lrows[i];
56955 var isAlt = ((i+1) % 2 == 0);
56956 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
56957 if(isAlt == hasAlt){
56961 row.className += " x-grid-row-alt";
56963 row.className = row.className.replace("x-grid-row-alt", "");
56966 lrow.className = row.className;
56971 restoreScroll : function(state){
56972 //Roo.log('GridView.restoreScroll');
56973 var sb = this.scroller.dom;
56974 sb.scrollLeft = state.left;
56975 sb.scrollTop = state.top;
56979 syncScroll : function(){
56980 //Roo.log('GridView.syncScroll');
56981 var sb = this.scroller.dom;
56982 var sh = this.mainHd.dom;
56983 var bs = this.mainBody.dom;
56984 var lv = this.lockedBody.dom;
56985 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
56986 lv.scrollTop = bs.scrollTop = sb.scrollTop;
56989 handleScroll : function(e){
56991 var sb = this.scroller.dom;
56992 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
56996 handleWheel : function(e){
56997 var d = e.getWheelDelta();
56998 this.scroller.dom.scrollTop -= d*22;
56999 // set this here to prevent jumpy scrolling on large tables
57000 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
57004 renderRows : function(startRow, endRow){
57005 // pull in all the crap needed to render rows
57006 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
57007 var colCount = cm.getColumnCount();
57009 if(ds.getCount() < 1){
57013 // build a map for all the columns
57015 for(var i = 0; i < colCount; i++){
57016 var name = cm.getDataIndex(i);
57018 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57019 renderer : cm.getRenderer(i),
57020 id : cm.getColumnId(i),
57021 locked : cm.isLocked(i),
57022 has_editor : cm.isCellEditable(i)
57026 startRow = startRow || 0;
57027 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57029 // records to render
57030 var rs = ds.getRange(startRow, endRow);
57032 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57035 // As much as I hate to duplicate code, this was branched because FireFox really hates
57036 // [].join("") on strings. The performance difference was substantial enough to
57037 // branch this function
57038 doRender : Roo.isGecko ?
57039 function(cs, rs, ds, startRow, colCount, stripe){
57040 var ts = this.templates, ct = ts.cell, rt = ts.row;
57042 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57044 var hasListener = this.grid.hasListener('rowclass');
57046 for(var j = 0, len = rs.length; j < len; j++){
57047 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57048 for(var i = 0; i < colCount; i++){
57050 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57052 p.css = p.attr = "";
57053 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57054 if(p.value == undefined || p.value === "") {
57055 p.value = " ";
57058 p.css += ' x-grid-editable-cell';
57060 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57061 p.css += ' x-grid-dirty-cell';
57063 var markup = ct.apply(p);
57071 if(stripe && ((rowIndex+1) % 2 == 0)){
57072 alt.push("x-grid-row-alt")
57075 alt.push( " x-grid-dirty-row");
57078 if(this.getRowClass){
57079 alt.push(this.getRowClass(r, rowIndex));
57085 rowIndex : rowIndex,
57088 this.grid.fireEvent('rowclass', this, rowcfg);
57089 alt.push(rowcfg.rowClass);
57091 rp.alt = alt.join(" ");
57092 lbuf+= rt.apply(rp);
57094 buf+= rt.apply(rp);
57096 return [lbuf, buf];
57098 function(cs, rs, ds, startRow, colCount, stripe){
57099 var ts = this.templates, ct = ts.cell, rt = ts.row;
57101 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57102 var hasListener = this.grid.hasListener('rowclass');
57105 for(var j = 0, len = rs.length; j < len; j++){
57106 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57107 for(var i = 0; i < colCount; i++){
57109 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57111 p.css = p.attr = "";
57112 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57113 if(p.value == undefined || p.value === "") {
57114 p.value = " ";
57118 p.css += ' x-grid-editable-cell';
57120 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57121 p.css += ' x-grid-dirty-cell'
57124 var markup = ct.apply(p);
57126 cb[cb.length] = markup;
57128 lcb[lcb.length] = markup;
57132 if(stripe && ((rowIndex+1) % 2 == 0)){
57133 alt.push( "x-grid-row-alt");
57136 alt.push(" x-grid-dirty-row");
57139 if(this.getRowClass){
57140 alt.push( this.getRowClass(r, rowIndex));
57146 rowIndex : rowIndex,
57149 this.grid.fireEvent('rowclass', this, rowcfg);
57150 alt.push(rowcfg.rowClass);
57153 rp.alt = alt.join(" ");
57154 rp.cells = lcb.join("");
57155 lbuf[lbuf.length] = rt.apply(rp);
57156 rp.cells = cb.join("");
57157 buf[buf.length] = rt.apply(rp);
57159 return [lbuf.join(""), buf.join("")];
57162 renderBody : function(){
57163 var markup = this.renderRows();
57164 var bt = this.templates.body;
57165 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57169 * Refreshes the grid
57170 * @param {Boolean} headersToo
57172 refresh : function(headersToo){
57173 this.fireEvent("beforerefresh", this);
57174 this.grid.stopEditing();
57175 var result = this.renderBody();
57176 this.lockedBody.update(result[0]);
57177 this.mainBody.update(result[1]);
57178 if(headersToo === true){
57179 this.updateHeaders();
57180 this.updateColumns();
57181 this.updateSplitters();
57182 this.updateHeaderSortState();
57184 this.syncRowHeights();
57186 this.fireEvent("refresh", this);
57189 handleColumnMove : function(cm, oldIndex, newIndex){
57190 this.indexMap = null;
57191 var s = this.getScrollState();
57192 this.refresh(true);
57193 this.restoreScroll(s);
57194 this.afterMove(newIndex);
57197 afterMove : function(colIndex){
57198 if(this.enableMoveAnim && Roo.enableFx){
57199 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57201 // if multisort - fix sortOrder, and reload..
57202 if (this.grid.dataSource.multiSort) {
57203 // the we can call sort again..
57204 var dm = this.grid.dataSource;
57205 var cm = this.grid.colModel;
57207 for(var i = 0; i < cm.config.length; i++ ) {
57209 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57210 continue; // dont' bother, it's not in sort list or being set.
57213 so.push(cm.config[i].dataIndex);
57216 dm.load(dm.lastOptions);
57223 updateCell : function(dm, rowIndex, dataIndex){
57224 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57225 if(typeof colIndex == "undefined"){ // not present in grid
57228 var cm = this.grid.colModel;
57229 var cell = this.getCell(rowIndex, colIndex);
57230 var cellText = this.getCellText(rowIndex, colIndex);
57233 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57234 id : cm.getColumnId(colIndex),
57235 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57237 var renderer = cm.getRenderer(colIndex);
57238 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57239 if(typeof val == "undefined" || val === "") {
57242 cellText.innerHTML = val;
57243 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57244 this.syncRowHeights(rowIndex, rowIndex);
57247 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57249 if(this.grid.autoSizeHeaders){
57250 var h = this.getHeaderCellMeasure(colIndex);
57251 maxWidth = Math.max(maxWidth, h.scrollWidth);
57254 if(this.cm.isLocked(colIndex)){
57255 tb = this.getLockedTable();
57258 tb = this.getBodyTable();
57259 index = colIndex - this.cm.getLockedCount();
57262 var rows = tb.rows;
57263 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57264 for(var i = 0; i < stopIndex; i++){
57265 var cell = rows[i].childNodes[index].firstChild;
57266 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57269 return maxWidth + /*margin for error in IE*/ 5;
57272 * Autofit a column to its content.
57273 * @param {Number} colIndex
57274 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57276 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57277 if(this.cm.isHidden(colIndex)){
57278 return; // can't calc a hidden column
57281 var cid = this.cm.getColumnId(colIndex);
57282 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57283 if(this.grid.autoSizeHeaders){
57284 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57287 var newWidth = this.calcColumnWidth(colIndex);
57288 this.cm.setColumnWidth(colIndex,
57289 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57290 if(!suppressEvent){
57291 this.grid.fireEvent("columnresize", colIndex, newWidth);
57296 * Autofits all columns to their content and then expands to fit any extra space in the grid
57298 autoSizeColumns : function(){
57299 var cm = this.grid.colModel;
57300 var colCount = cm.getColumnCount();
57301 for(var i = 0; i < colCount; i++){
57302 this.autoSizeColumn(i, true, true);
57304 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57307 this.updateColumns();
57313 * Autofits all columns to the grid's width proportionate with their current size
57314 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57316 fitColumns : function(reserveScrollSpace){
57317 var cm = this.grid.colModel;
57318 var colCount = cm.getColumnCount();
57322 for (i = 0; i < colCount; i++){
57323 if(!cm.isHidden(i) && !cm.isFixed(i)){
57324 w = cm.getColumnWidth(i);
57330 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57331 if(reserveScrollSpace){
57334 var frac = (avail - cm.getTotalWidth())/width;
57335 while (cols.length){
57338 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57340 this.updateColumns();
57344 onRowSelect : function(rowIndex){
57345 var row = this.getRowComposite(rowIndex);
57346 row.addClass("x-grid-row-selected");
57349 onRowDeselect : function(rowIndex){
57350 var row = this.getRowComposite(rowIndex);
57351 row.removeClass("x-grid-row-selected");
57354 onCellSelect : function(row, col){
57355 var cell = this.getCell(row, col);
57357 Roo.fly(cell).addClass("x-grid-cell-selected");
57361 onCellDeselect : function(row, col){
57362 var cell = this.getCell(row, col);
57364 Roo.fly(cell).removeClass("x-grid-cell-selected");
57368 updateHeaderSortState : function(){
57370 // sort state can be single { field: xxx, direction : yyy}
57371 // or { xxx=>ASC , yyy : DESC ..... }
57374 if (!this.ds.multiSort) {
57375 var state = this.ds.getSortState();
57379 mstate[state.field] = state.direction;
57380 // FIXME... - this is not used here.. but might be elsewhere..
57381 this.sortState = state;
57384 mstate = this.ds.sortToggle;
57386 //remove existing sort classes..
57388 var sc = this.sortClasses;
57389 var hds = this.el.select(this.headerSelector).removeClass(sc);
57391 for(var f in mstate) {
57393 var sortColumn = this.cm.findColumnIndex(f);
57395 if(sortColumn != -1){
57396 var sortDir = mstate[f];
57397 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57406 handleHeaderClick : function(g, index,e){
57408 Roo.log("header click");
57411 // touch events on header are handled by context
57412 this.handleHdCtx(g,index,e);
57417 if(this.headersDisabled){
57420 var dm = g.dataSource, cm = g.colModel;
57421 if(!cm.isSortable(index)){
57426 if (dm.multiSort) {
57427 // update the sortOrder
57429 for(var i = 0; i < cm.config.length; i++ ) {
57431 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57432 continue; // dont' bother, it's not in sort list or being set.
57435 so.push(cm.config[i].dataIndex);
57441 dm.sort(cm.getDataIndex(index));
57445 destroy : function(){
57447 this.colMenu.removeAll();
57448 Roo.menu.MenuMgr.unregister(this.colMenu);
57449 this.colMenu.getEl().remove();
57450 delete this.colMenu;
57453 this.hmenu.removeAll();
57454 Roo.menu.MenuMgr.unregister(this.hmenu);
57455 this.hmenu.getEl().remove();
57458 if(this.grid.enableColumnMove){
57459 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57461 for(var dd in dds){
57462 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57463 var elid = dds[dd].dragElId;
57465 Roo.get(elid).remove();
57466 } else if(dds[dd].config.isTarget){
57467 dds[dd].proxyTop.remove();
57468 dds[dd].proxyBottom.remove();
57471 if(Roo.dd.DDM.locationCache[dd]){
57472 delete Roo.dd.DDM.locationCache[dd];
57475 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57478 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57479 this.bind(null, null);
57480 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57483 handleLockChange : function(){
57484 this.refresh(true);
57487 onDenyColumnLock : function(){
57491 onDenyColumnHide : function(){
57495 handleHdMenuClick : function(item){
57496 var index = this.hdCtxIndex;
57497 var cm = this.cm, ds = this.ds;
57500 ds.sort(cm.getDataIndex(index), "ASC");
57503 ds.sort(cm.getDataIndex(index), "DESC");
57506 var lc = cm.getLockedCount();
57507 if(cm.getColumnCount(true) <= lc+1){
57508 this.onDenyColumnLock();
57512 cm.setLocked(index, true, true);
57513 cm.moveColumn(index, lc);
57514 this.grid.fireEvent("columnmove", index, lc);
57516 cm.setLocked(index, true);
57520 var lc = cm.getLockedCount();
57521 if((lc-1) != index){
57522 cm.setLocked(index, false, true);
57523 cm.moveColumn(index, lc-1);
57524 this.grid.fireEvent("columnmove", index, lc-1);
57526 cm.setLocked(index, false);
57529 case 'wider': // used to expand cols on touch..
57531 var cw = cm.getColumnWidth(index);
57532 cw += (item.id == 'wider' ? 1 : -1) * 50;
57533 cw = Math.max(0, cw);
57534 cw = Math.min(cw,4000);
57535 cm.setColumnWidth(index, cw);
57539 index = cm.getIndexById(item.id.substr(4));
57541 if(item.checked && cm.getColumnCount(true) <= 1){
57542 this.onDenyColumnHide();
57545 cm.setHidden(index, item.checked);
57551 beforeColMenuShow : function(){
57552 var cm = this.cm, colCount = cm.getColumnCount();
57553 this.colMenu.removeAll();
57554 for(var i = 0; i < colCount; i++){
57555 this.colMenu.add(new Roo.menu.CheckItem({
57556 id: "col-"+cm.getColumnId(i),
57557 text: cm.getColumnHeader(i),
57558 checked: !cm.isHidden(i),
57564 handleHdCtx : function(g, index, e){
57566 var hd = this.getHeaderCell(index);
57567 this.hdCtxIndex = index;
57568 var ms = this.hmenu.items, cm = this.cm;
57569 ms.get("asc").setDisabled(!cm.isSortable(index));
57570 ms.get("desc").setDisabled(!cm.isSortable(index));
57571 if(this.grid.enableColLock !== false){
57572 ms.get("lock").setDisabled(cm.isLocked(index));
57573 ms.get("unlock").setDisabled(!cm.isLocked(index));
57575 this.hmenu.show(hd, "tl-bl");
57578 handleHdOver : function(e){
57579 var hd = this.findHeaderCell(e.getTarget());
57580 if(hd && !this.headersDisabled){
57581 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57582 this.fly(hd).addClass("x-grid-hd-over");
57587 handleHdOut : function(e){
57588 var hd = this.findHeaderCell(e.getTarget());
57590 this.fly(hd).removeClass("x-grid-hd-over");
57594 handleSplitDblClick : function(e, t){
57595 var i = this.getCellIndex(t);
57596 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57597 this.autoSizeColumn(i, true);
57602 render : function(){
57605 var colCount = cm.getColumnCount();
57607 if(this.grid.monitorWindowResize === true){
57608 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57610 var header = this.renderHeaders();
57611 var body = this.templates.body.apply({rows:""});
57612 var html = this.templates.master.apply({
57615 lockedHeader: header[0],
57619 //this.updateColumns();
57621 this.grid.getGridEl().dom.innerHTML = html;
57623 this.initElements();
57625 // a kludge to fix the random scolling effect in webkit
57626 this.el.on("scroll", function() {
57627 this.el.dom.scrollTop=0; // hopefully not recursive..
57630 this.scroller.on("scroll", this.handleScroll, this);
57631 this.lockedBody.on("mousewheel", this.handleWheel, this);
57632 this.mainBody.on("mousewheel", this.handleWheel, this);
57634 this.mainHd.on("mouseover", this.handleHdOver, this);
57635 this.mainHd.on("mouseout", this.handleHdOut, this);
57636 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57637 {delegate: "."+this.splitClass});
57639 this.lockedHd.on("mouseover", this.handleHdOver, this);
57640 this.lockedHd.on("mouseout", this.handleHdOut, this);
57641 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57642 {delegate: "."+this.splitClass});
57644 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57645 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57648 this.updateSplitters();
57650 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57651 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57652 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57655 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57656 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57658 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57659 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57661 if(this.grid.enableColLock !== false){
57662 this.hmenu.add('-',
57663 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57664 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57668 this.hmenu.add('-',
57669 {id:"wider", text: this.columnsWiderText},
57670 {id:"narrow", text: this.columnsNarrowText }
57676 if(this.grid.enableColumnHide !== false){
57678 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57679 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57680 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57682 this.hmenu.add('-',
57683 {id:"columns", text: this.columnsText, menu: this.colMenu}
57686 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57688 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57691 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57692 this.dd = new Roo.grid.GridDragZone(this.grid, {
57693 ddGroup : this.grid.ddGroup || 'GridDD'
57699 for(var i = 0; i < colCount; i++){
57700 if(cm.isHidden(i)){
57701 this.hideColumn(i);
57703 if(cm.config[i].align){
57704 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57705 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57709 this.updateHeaderSortState();
57711 this.beforeInitialResize();
57714 // two part rendering gives faster view to the user
57715 this.renderPhase2.defer(1, this);
57718 renderPhase2 : function(){
57719 // render the rows now
57721 if(this.grid.autoSizeColumns){
57722 this.autoSizeColumns();
57726 beforeInitialResize : function(){
57730 onColumnSplitterMoved : function(i, w){
57731 this.userResized = true;
57732 var cm = this.grid.colModel;
57733 cm.setColumnWidth(i, w, true);
57734 var cid = cm.getColumnId(i);
57735 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57736 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57737 this.updateSplitters();
57739 this.grid.fireEvent("columnresize", i, w);
57742 syncRowHeights : function(startIndex, endIndex){
57743 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
57744 startIndex = startIndex || 0;
57745 var mrows = this.getBodyTable().rows;
57746 var lrows = this.getLockedTable().rows;
57747 var len = mrows.length-1;
57748 endIndex = Math.min(endIndex || len, len);
57749 for(var i = startIndex; i <= endIndex; i++){
57750 var m = mrows[i], l = lrows[i];
57751 var h = Math.max(m.offsetHeight, l.offsetHeight);
57752 m.style.height = l.style.height = h + "px";
57757 layout : function(initialRender, is2ndPass){
57759 var auto = g.autoHeight;
57760 var scrollOffset = 16;
57761 var c = g.getGridEl(), cm = this.cm,
57762 expandCol = g.autoExpandColumn,
57764 //c.beginMeasure();
57766 if(!c.dom.offsetWidth){ // display:none?
57768 this.lockedWrap.show();
57769 this.mainWrap.show();
57774 var hasLock = this.cm.isLocked(0);
57776 var tbh = this.headerPanel.getHeight();
57777 var bbh = this.footerPanel.getHeight();
57780 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
57781 var newHeight = ch + c.getBorderWidth("tb");
57783 newHeight = Math.min(g.maxHeight, newHeight);
57785 c.setHeight(newHeight);
57789 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
57792 var s = this.scroller;
57794 var csize = c.getSize(true);
57796 this.el.setSize(csize.width, csize.height);
57798 this.headerPanel.setWidth(csize.width);
57799 this.footerPanel.setWidth(csize.width);
57801 var hdHeight = this.mainHd.getHeight();
57802 var vw = csize.width;
57803 var vh = csize.height - (tbh + bbh);
57807 var bt = this.getBodyTable();
57809 if(cm.getLockedCount() == cm.config.length){
57810 bt = this.getLockedTable();
57813 var ltWidth = hasLock ?
57814 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
57816 var scrollHeight = bt.offsetHeight;
57817 var scrollWidth = ltWidth + bt.offsetWidth;
57818 var vscroll = false, hscroll = false;
57820 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
57822 var lw = this.lockedWrap, mw = this.mainWrap;
57823 var lb = this.lockedBody, mb = this.mainBody;
57825 setTimeout(function(){
57826 var t = s.dom.offsetTop;
57827 var w = s.dom.clientWidth,
57828 h = s.dom.clientHeight;
57831 lw.setSize(ltWidth, h);
57833 mw.setLeftTop(ltWidth, t);
57834 mw.setSize(w-ltWidth, h);
57836 lb.setHeight(h-hdHeight);
57837 mb.setHeight(h-hdHeight);
57839 if(is2ndPass !== true && !gv.userResized && expandCol){
57840 // high speed resize without full column calculation
57842 var ci = cm.getIndexById(expandCol);
57844 ci = cm.findColumnIndex(expandCol);
57846 ci = Math.max(0, ci); // make sure it's got at least the first col.
57847 var expandId = cm.getColumnId(ci);
57848 var tw = cm.getTotalWidth(false);
57849 var currentWidth = cm.getColumnWidth(ci);
57850 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
57851 if(currentWidth != cw){
57852 cm.setColumnWidth(ci, cw, true);
57853 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57854 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57855 gv.updateSplitters();
57856 gv.layout(false, true);
57868 onWindowResize : function(){
57869 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
57875 appendFooter : function(parentEl){
57879 sortAscText : "Sort Ascending",
57880 sortDescText : "Sort Descending",
57881 lockText : "Lock Column",
57882 unlockText : "Unlock Column",
57883 columnsText : "Columns",
57885 columnsWiderText : "Wider",
57886 columnsNarrowText : "Thinner"
57890 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
57891 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
57892 this.proxy.el.addClass('x-grid3-col-dd');
57895 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
57896 handleMouseDown : function(e){
57900 callHandleMouseDown : function(e){
57901 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
57906 * Ext JS Library 1.1.1
57907 * Copyright(c) 2006-2007, Ext JS, LLC.
57909 * Originally Released Under LGPL - original licence link has changed is not relivant.
57912 * <script type="text/javascript">
57916 // This is a support class used internally by the Grid components
57917 Roo.grid.SplitDragZone = function(grid, hd, hd2){
57919 this.view = grid.getView();
57920 this.proxy = this.view.resizeProxy;
57921 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
57922 "gridSplitters" + this.grid.getGridEl().id, {
57923 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
57925 this.setHandleElId(Roo.id(hd));
57926 this.setOuterHandleElId(Roo.id(hd2));
57927 this.scroll = false;
57929 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
57930 fly: Roo.Element.fly,
57932 b4StartDrag : function(x, y){
57933 this.view.headersDisabled = true;
57934 this.proxy.setHeight(this.view.mainWrap.getHeight());
57935 var w = this.cm.getColumnWidth(this.cellIndex);
57936 var minw = Math.max(w-this.grid.minColumnWidth, 0);
57937 this.resetConstraints();
57938 this.setXConstraint(minw, 1000);
57939 this.setYConstraint(0, 0);
57940 this.minX = x - minw;
57941 this.maxX = x + 1000;
57943 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
57947 handleMouseDown : function(e){
57948 ev = Roo.EventObject.setEvent(e);
57949 var t = this.fly(ev.getTarget());
57950 if(t.hasClass("x-grid-split")){
57951 this.cellIndex = this.view.getCellIndex(t.dom);
57952 this.split = t.dom;
57953 this.cm = this.grid.colModel;
57954 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
57955 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
57960 endDrag : function(e){
57961 this.view.headersDisabled = false;
57962 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
57963 var diff = endX - this.startPos;
57964 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
57967 autoOffset : function(){
57968 this.setDelta(0,0);
57972 * Ext JS Library 1.1.1
57973 * Copyright(c) 2006-2007, Ext JS, LLC.
57975 * Originally Released Under LGPL - original licence link has changed is not relivant.
57978 * <script type="text/javascript">
57982 // This is a support class used internally by the Grid components
57983 Roo.grid.GridDragZone = function(grid, config){
57984 this.view = grid.getView();
57985 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
57986 if(this.view.lockedBody){
57987 this.setHandleElId(Roo.id(this.view.mainBody.dom));
57988 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
57990 this.scroll = false;
57992 this.ddel = document.createElement('div');
57993 this.ddel.className = 'x-grid-dd-wrap';
57996 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
57997 ddGroup : "GridDD",
57999 getDragData : function(e){
58000 var t = Roo.lib.Event.getTarget(e);
58001 var rowIndex = this.view.findRowIndex(t);
58002 var sm = this.grid.selModel;
58004 //Roo.log(rowIndex);
58006 if (sm.getSelectedCell) {
58007 // cell selection..
58008 if (!sm.getSelectedCell()) {
58011 if (rowIndex != sm.getSelectedCell()[0]) {
58017 if(rowIndex !== false){
58022 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58024 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58027 if (e.hasModifier()){
58028 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58031 Roo.log("getDragData");
58036 rowIndex: rowIndex,
58037 selections:sm.getSelections ? sm.getSelections() : (
58038 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
58045 onInitDrag : function(e){
58046 var data = this.dragData;
58047 this.ddel.innerHTML = this.grid.getDragDropText();
58048 this.proxy.update(this.ddel);
58049 // fire start drag?
58052 afterRepair : function(){
58053 this.dragging = false;
58056 getRepairXY : function(e, data){
58060 onEndDrag : function(data, e){
58064 onValidDrop : function(dd, e, id){
58069 beforeInvalidDrop : function(e, id){
58074 * Ext JS Library 1.1.1
58075 * Copyright(c) 2006-2007, Ext JS, LLC.
58077 * Originally Released Under LGPL - original licence link has changed is not relivant.
58080 * <script type="text/javascript">
58085 * @class Roo.grid.ColumnModel
58086 * @extends Roo.util.Observable
58087 * This is the default implementation of a ColumnModel used by the Grid. It defines
58088 * the columns in the grid.
58091 var colModel = new Roo.grid.ColumnModel([
58092 {header: "Ticker", width: 60, sortable: true, locked: true},
58093 {header: "Company Name", width: 150, sortable: true},
58094 {header: "Market Cap.", width: 100, sortable: true},
58095 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58096 {header: "Employees", width: 100, sortable: true, resizable: false}
58101 * The config options listed for this class are options which may appear in each
58102 * individual column definition.
58103 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58105 * @param {Object} config An Array of column config objects. See this class's
58106 * config objects for details.
58108 Roo.grid.ColumnModel = function(config){
58110 * The config passed into the constructor
58112 this.config = config;
58115 // if no id, create one
58116 // if the column does not have a dataIndex mapping,
58117 // map it to the order it is in the config
58118 for(var i = 0, len = config.length; i < len; i++){
58120 if(typeof c.dataIndex == "undefined"){
58123 if(typeof c.renderer == "string"){
58124 c.renderer = Roo.util.Format[c.renderer];
58126 if(typeof c.id == "undefined"){
58129 if(c.editor && c.editor.xtype){
58130 c.editor = Roo.factory(c.editor, Roo.grid);
58132 if(c.editor && c.editor.isFormField){
58133 c.editor = new Roo.grid.GridEditor(c.editor);
58135 this.lookup[c.id] = c;
58139 * The width of columns which have no width specified (defaults to 100)
58142 this.defaultWidth = 100;
58145 * Default sortable of columns which have no sortable specified (defaults to false)
58148 this.defaultSortable = false;
58152 * @event widthchange
58153 * Fires when the width of a column changes.
58154 * @param {ColumnModel} this
58155 * @param {Number} columnIndex The column index
58156 * @param {Number} newWidth The new width
58158 "widthchange": true,
58160 * @event headerchange
58161 * Fires when the text of a header changes.
58162 * @param {ColumnModel} this
58163 * @param {Number} columnIndex The column index
58164 * @param {Number} newText The new header text
58166 "headerchange": true,
58168 * @event hiddenchange
58169 * Fires when a column is hidden or "unhidden".
58170 * @param {ColumnModel} this
58171 * @param {Number} columnIndex The column index
58172 * @param {Boolean} hidden true if hidden, false otherwise
58174 "hiddenchange": true,
58176 * @event columnmoved
58177 * Fires when a column is moved.
58178 * @param {ColumnModel} this
58179 * @param {Number} oldIndex
58180 * @param {Number} newIndex
58182 "columnmoved" : true,
58184 * @event columlockchange
58185 * Fires when a column's locked state is changed
58186 * @param {ColumnModel} this
58187 * @param {Number} colIndex
58188 * @param {Boolean} locked true if locked
58190 "columnlockchange" : true
58192 Roo.grid.ColumnModel.superclass.constructor.call(this);
58194 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58196 * @cfg {String} header The header text to display in the Grid view.
58199 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58200 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58201 * specified, the column's index is used as an index into the Record's data Array.
58204 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58205 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58208 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58209 * Defaults to the value of the {@link #defaultSortable} property.
58210 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58213 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58216 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58219 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58222 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58225 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58226 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58227 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58228 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58231 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58234 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58237 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58240 * @cfg {String} cursor (Optional)
58243 * @cfg {String} tooltip (Optional)
58246 * @cfg {Number} xs (Optional)
58249 * @cfg {Number} sm (Optional)
58252 * @cfg {Number} md (Optional)
58255 * @cfg {Number} lg (Optional)
58258 * Returns the id of the column at the specified index.
58259 * @param {Number} index The column index
58260 * @return {String} the id
58262 getColumnId : function(index){
58263 return this.config[index].id;
58267 * Returns the column for a specified id.
58268 * @param {String} id The column id
58269 * @return {Object} the column
58271 getColumnById : function(id){
58272 return this.lookup[id];
58277 * Returns the column for a specified dataIndex.
58278 * @param {String} dataIndex The column dataIndex
58279 * @return {Object|Boolean} the column or false if not found
58281 getColumnByDataIndex: function(dataIndex){
58282 var index = this.findColumnIndex(dataIndex);
58283 return index > -1 ? this.config[index] : false;
58287 * Returns the index for a specified column id.
58288 * @param {String} id The column id
58289 * @return {Number} the index, or -1 if not found
58291 getIndexById : function(id){
58292 for(var i = 0, len = this.config.length; i < len; i++){
58293 if(this.config[i].id == id){
58301 * Returns the index for a specified column dataIndex.
58302 * @param {String} dataIndex The column dataIndex
58303 * @return {Number} the index, or -1 if not found
58306 findColumnIndex : function(dataIndex){
58307 for(var i = 0, len = this.config.length; i < len; i++){
58308 if(this.config[i].dataIndex == dataIndex){
58316 moveColumn : function(oldIndex, newIndex){
58317 var c = this.config[oldIndex];
58318 this.config.splice(oldIndex, 1);
58319 this.config.splice(newIndex, 0, c);
58320 this.dataMap = null;
58321 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58324 isLocked : function(colIndex){
58325 return this.config[colIndex].locked === true;
58328 setLocked : function(colIndex, value, suppressEvent){
58329 if(this.isLocked(colIndex) == value){
58332 this.config[colIndex].locked = value;
58333 if(!suppressEvent){
58334 this.fireEvent("columnlockchange", this, colIndex, value);
58338 getTotalLockedWidth : function(){
58339 var totalWidth = 0;
58340 for(var i = 0; i < this.config.length; i++){
58341 if(this.isLocked(i) && !this.isHidden(i)){
58342 this.totalWidth += this.getColumnWidth(i);
58348 getLockedCount : function(){
58349 for(var i = 0, len = this.config.length; i < len; i++){
58350 if(!this.isLocked(i)){
58355 return this.config.length;
58359 * Returns the number of columns.
58362 getColumnCount : function(visibleOnly){
58363 if(visibleOnly === true){
58365 for(var i = 0, len = this.config.length; i < len; i++){
58366 if(!this.isHidden(i)){
58372 return this.config.length;
58376 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58377 * @param {Function} fn
58378 * @param {Object} scope (optional)
58379 * @return {Array} result
58381 getColumnsBy : function(fn, scope){
58383 for(var i = 0, len = this.config.length; i < len; i++){
58384 var c = this.config[i];
58385 if(fn.call(scope||this, c, i) === true){
58393 * Returns true if the specified column is sortable.
58394 * @param {Number} col The column index
58395 * @return {Boolean}
58397 isSortable : function(col){
58398 if(typeof this.config[col].sortable == "undefined"){
58399 return this.defaultSortable;
58401 return this.config[col].sortable;
58405 * Returns the rendering (formatting) function defined for the column.
58406 * @param {Number} col The column index.
58407 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58409 getRenderer : function(col){
58410 if(!this.config[col].renderer){
58411 return Roo.grid.ColumnModel.defaultRenderer;
58413 return this.config[col].renderer;
58417 * Sets the rendering (formatting) function for a column.
58418 * @param {Number} col The column index
58419 * @param {Function} fn The function to use to process the cell's raw data
58420 * to return HTML markup for the grid view. The render function is called with
58421 * the following parameters:<ul>
58422 * <li>Data value.</li>
58423 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58424 * <li>css A CSS style string to apply to the table cell.</li>
58425 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58426 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58427 * <li>Row index</li>
58428 * <li>Column index</li>
58429 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58431 setRenderer : function(col, fn){
58432 this.config[col].renderer = fn;
58436 * Returns the width for the specified column.
58437 * @param {Number} col The column index
58440 getColumnWidth : function(col){
58441 return this.config[col].width * 1 || this.defaultWidth;
58445 * Sets the width for a column.
58446 * @param {Number} col The column index
58447 * @param {Number} width The new width
58449 setColumnWidth : function(col, width, suppressEvent){
58450 this.config[col].width = width;
58451 this.totalWidth = null;
58452 if(!suppressEvent){
58453 this.fireEvent("widthchange", this, col, width);
58458 * Returns the total width of all columns.
58459 * @param {Boolean} includeHidden True to include hidden column widths
58462 getTotalWidth : function(includeHidden){
58463 if(!this.totalWidth){
58464 this.totalWidth = 0;
58465 for(var i = 0, len = this.config.length; i < len; i++){
58466 if(includeHidden || !this.isHidden(i)){
58467 this.totalWidth += this.getColumnWidth(i);
58471 return this.totalWidth;
58475 * Returns the header for the specified column.
58476 * @param {Number} col The column index
58479 getColumnHeader : function(col){
58480 return this.config[col].header;
58484 * Sets the header for a column.
58485 * @param {Number} col The column index
58486 * @param {String} header The new header
58488 setColumnHeader : function(col, header){
58489 this.config[col].header = header;
58490 this.fireEvent("headerchange", this, col, header);
58494 * Returns the tooltip for the specified column.
58495 * @param {Number} col The column index
58498 getColumnTooltip : function(col){
58499 return this.config[col].tooltip;
58502 * Sets the tooltip for a column.
58503 * @param {Number} col The column index
58504 * @param {String} tooltip The new tooltip
58506 setColumnTooltip : function(col, tooltip){
58507 this.config[col].tooltip = tooltip;
58511 * Returns the dataIndex for the specified column.
58512 * @param {Number} col The column index
58515 getDataIndex : function(col){
58516 return this.config[col].dataIndex;
58520 * Sets the dataIndex for a column.
58521 * @param {Number} col The column index
58522 * @param {Number} dataIndex The new dataIndex
58524 setDataIndex : function(col, dataIndex){
58525 this.config[col].dataIndex = dataIndex;
58531 * Returns true if the cell is editable.
58532 * @param {Number} colIndex The column index
58533 * @param {Number} rowIndex The row index - this is nto actually used..?
58534 * @return {Boolean}
58536 isCellEditable : function(colIndex, rowIndex){
58537 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58541 * Returns the editor defined for the cell/column.
58542 * return false or null to disable editing.
58543 * @param {Number} colIndex The column index
58544 * @param {Number} rowIndex The row index
58547 getCellEditor : function(colIndex, rowIndex){
58548 return this.config[colIndex].editor;
58552 * Sets if a column is editable.
58553 * @param {Number} col The column index
58554 * @param {Boolean} editable True if the column is editable
58556 setEditable : function(col, editable){
58557 this.config[col].editable = editable;
58562 * Returns true if the column is hidden.
58563 * @param {Number} colIndex The column index
58564 * @return {Boolean}
58566 isHidden : function(colIndex){
58567 return this.config[colIndex].hidden;
58572 * Returns true if the column width cannot be changed
58574 isFixed : function(colIndex){
58575 return this.config[colIndex].fixed;
58579 * Returns true if the column can be resized
58580 * @return {Boolean}
58582 isResizable : function(colIndex){
58583 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58586 * Sets if a column is hidden.
58587 * @param {Number} colIndex The column index
58588 * @param {Boolean} hidden True if the column is hidden
58590 setHidden : function(colIndex, hidden){
58591 this.config[colIndex].hidden = hidden;
58592 this.totalWidth = null;
58593 this.fireEvent("hiddenchange", this, colIndex, hidden);
58597 * Sets the editor for a column.
58598 * @param {Number} col The column index
58599 * @param {Object} editor The editor object
58601 setEditor : function(col, editor){
58602 this.config[col].editor = editor;
58606 Roo.grid.ColumnModel.defaultRenderer = function(value)
58608 if(typeof value == "object") {
58611 if(typeof value == "string" && value.length < 1){
58615 return String.format("{0}", value);
58618 // Alias for backwards compatibility
58619 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
58622 * Ext JS Library 1.1.1
58623 * Copyright(c) 2006-2007, Ext JS, LLC.
58625 * Originally Released Under LGPL - original licence link has changed is not relivant.
58628 * <script type="text/javascript">
58632 * @class Roo.grid.AbstractSelectionModel
58633 * @extends Roo.util.Observable
58634 * Abstract base class for grid SelectionModels. It provides the interface that should be
58635 * implemented by descendant classes. This class should not be directly instantiated.
58638 Roo.grid.AbstractSelectionModel = function(){
58639 this.locked = false;
58640 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
58643 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
58644 /** @ignore Called by the grid automatically. Do not call directly. */
58645 init : function(grid){
58651 * Locks the selections.
58654 this.locked = true;
58658 * Unlocks the selections.
58660 unlock : function(){
58661 this.locked = false;
58665 * Returns true if the selections are locked.
58666 * @return {Boolean}
58668 isLocked : function(){
58669 return this.locked;
58673 * Ext JS Library 1.1.1
58674 * Copyright(c) 2006-2007, Ext JS, LLC.
58676 * Originally Released Under LGPL - original licence link has changed is not relivant.
58679 * <script type="text/javascript">
58682 * @extends Roo.grid.AbstractSelectionModel
58683 * @class Roo.grid.RowSelectionModel
58684 * The default SelectionModel used by {@link Roo.grid.Grid}.
58685 * It supports multiple selections and keyboard selection/navigation.
58687 * @param {Object} config
58689 Roo.grid.RowSelectionModel = function(config){
58690 Roo.apply(this, config);
58691 this.selections = new Roo.util.MixedCollection(false, function(o){
58696 this.lastActive = false;
58700 * @event selectionchange
58701 * Fires when the selection changes
58702 * @param {SelectionModel} this
58704 "selectionchange" : true,
58706 * @event afterselectionchange
58707 * Fires after the selection changes (eg. by key press or clicking)
58708 * @param {SelectionModel} this
58710 "afterselectionchange" : true,
58712 * @event beforerowselect
58713 * Fires when a row is selected being selected, return false to cancel.
58714 * @param {SelectionModel} this
58715 * @param {Number} rowIndex The selected index
58716 * @param {Boolean} keepExisting False if other selections will be cleared
58718 "beforerowselect" : true,
58721 * Fires when a row is selected.
58722 * @param {SelectionModel} this
58723 * @param {Number} rowIndex The selected index
58724 * @param {Roo.data.Record} r The record
58726 "rowselect" : true,
58728 * @event rowdeselect
58729 * Fires when a row is deselected.
58730 * @param {SelectionModel} this
58731 * @param {Number} rowIndex The selected index
58733 "rowdeselect" : true
58735 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
58736 this.locked = false;
58739 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
58741 * @cfg {Boolean} singleSelect
58742 * True to allow selection of only one row at a time (defaults to false)
58744 singleSelect : false,
58747 initEvents : function(){
58749 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
58750 this.grid.on("mousedown", this.handleMouseDown, this);
58751 }else{ // allow click to work like normal
58752 this.grid.on("rowclick", this.handleDragableRowClick, this);
58755 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
58756 "up" : function(e){
58758 this.selectPrevious(e.shiftKey);
58759 }else if(this.last !== false && this.lastActive !== false){
58760 var last = this.last;
58761 this.selectRange(this.last, this.lastActive-1);
58762 this.grid.getView().focusRow(this.lastActive);
58763 if(last !== false){
58767 this.selectFirstRow();
58769 this.fireEvent("afterselectionchange", this);
58771 "down" : function(e){
58773 this.selectNext(e.shiftKey);
58774 }else if(this.last !== false && this.lastActive !== false){
58775 var last = this.last;
58776 this.selectRange(this.last, this.lastActive+1);
58777 this.grid.getView().focusRow(this.lastActive);
58778 if(last !== false){
58782 this.selectFirstRow();
58784 this.fireEvent("afterselectionchange", this);
58789 var view = this.grid.view;
58790 view.on("refresh", this.onRefresh, this);
58791 view.on("rowupdated", this.onRowUpdated, this);
58792 view.on("rowremoved", this.onRemove, this);
58796 onRefresh : function(){
58797 var ds = this.grid.dataSource, i, v = this.grid.view;
58798 var s = this.selections;
58799 s.each(function(r){
58800 if((i = ds.indexOfId(r.id)) != -1){
58802 s.add(ds.getAt(i)); // updating the selection relate data
58810 onRemove : function(v, index, r){
58811 this.selections.remove(r);
58815 onRowUpdated : function(v, index, r){
58816 if(this.isSelected(r)){
58817 v.onRowSelect(index);
58823 * @param {Array} records The records to select
58824 * @param {Boolean} keepExisting (optional) True to keep existing selections
58826 selectRecords : function(records, keepExisting){
58828 this.clearSelections();
58830 var ds = this.grid.dataSource;
58831 for(var i = 0, len = records.length; i < len; i++){
58832 this.selectRow(ds.indexOf(records[i]), true);
58837 * Gets the number of selected rows.
58840 getCount : function(){
58841 return this.selections.length;
58845 * Selects the first row in the grid.
58847 selectFirstRow : function(){
58852 * Select the last row.
58853 * @param {Boolean} keepExisting (optional) True to keep existing selections
58855 selectLastRow : function(keepExisting){
58856 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
58860 * Selects the row immediately following the last selected row.
58861 * @param {Boolean} keepExisting (optional) True to keep existing selections
58863 selectNext : function(keepExisting){
58864 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
58865 this.selectRow(this.last+1, keepExisting);
58866 this.grid.getView().focusRow(this.last);
58871 * Selects the row that precedes the last selected row.
58872 * @param {Boolean} keepExisting (optional) True to keep existing selections
58874 selectPrevious : function(keepExisting){
58876 this.selectRow(this.last-1, keepExisting);
58877 this.grid.getView().focusRow(this.last);
58882 * Returns the selected records
58883 * @return {Array} Array of selected records
58885 getSelections : function(){
58886 return [].concat(this.selections.items);
58890 * Returns the first selected record.
58893 getSelected : function(){
58894 return this.selections.itemAt(0);
58899 * Clears all selections.
58901 clearSelections : function(fast){
58906 var ds = this.grid.dataSource;
58907 var s = this.selections;
58908 s.each(function(r){
58909 this.deselectRow(ds.indexOfId(r.id));
58913 this.selections.clear();
58920 * Selects all rows.
58922 selectAll : function(){
58926 this.selections.clear();
58927 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
58928 this.selectRow(i, true);
58933 * Returns True if there is a selection.
58934 * @return {Boolean}
58936 hasSelection : function(){
58937 return this.selections.length > 0;
58941 * Returns True if the specified row is selected.
58942 * @param {Number/Record} record The record or index of the record to check
58943 * @return {Boolean}
58945 isSelected : function(index){
58946 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
58947 return (r && this.selections.key(r.id) ? true : false);
58951 * Returns True if the specified record id is selected.
58952 * @param {String} id The id of record to check
58953 * @return {Boolean}
58955 isIdSelected : function(id){
58956 return (this.selections.key(id) ? true : false);
58960 handleMouseDown : function(e, t){
58961 var view = this.grid.getView(), rowIndex;
58962 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
58965 if(e.shiftKey && this.last !== false){
58966 var last = this.last;
58967 this.selectRange(last, rowIndex, e.ctrlKey);
58968 this.last = last; // reset the last
58969 view.focusRow(rowIndex);
58971 var isSelected = this.isSelected(rowIndex);
58972 if(e.button !== 0 && isSelected){
58973 view.focusRow(rowIndex);
58974 }else if(e.ctrlKey && isSelected){
58975 this.deselectRow(rowIndex);
58976 }else if(!isSelected){
58977 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
58978 view.focusRow(rowIndex);
58981 this.fireEvent("afterselectionchange", this);
58984 handleDragableRowClick : function(grid, rowIndex, e)
58986 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
58987 this.selectRow(rowIndex, false);
58988 grid.view.focusRow(rowIndex);
58989 this.fireEvent("afterselectionchange", this);
58994 * Selects multiple rows.
58995 * @param {Array} rows Array of the indexes of the row to select
58996 * @param {Boolean} keepExisting (optional) True to keep existing selections
58998 selectRows : function(rows, keepExisting){
59000 this.clearSelections();
59002 for(var i = 0, len = rows.length; i < len; i++){
59003 this.selectRow(rows[i], true);
59008 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59009 * @param {Number} startRow The index of the first row in the range
59010 * @param {Number} endRow The index of the last row in the range
59011 * @param {Boolean} keepExisting (optional) True to retain existing selections
59013 selectRange : function(startRow, endRow, keepExisting){
59018 this.clearSelections();
59020 if(startRow <= endRow){
59021 for(var i = startRow; i <= endRow; i++){
59022 this.selectRow(i, true);
59025 for(var i = startRow; i >= endRow; i--){
59026 this.selectRow(i, true);
59032 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59033 * @param {Number} startRow The index of the first row in the range
59034 * @param {Number} endRow The index of the last row in the range
59036 deselectRange : function(startRow, endRow, preventViewNotify){
59040 for(var i = startRow; i <= endRow; i++){
59041 this.deselectRow(i, preventViewNotify);
59047 * @param {Number} row The index of the row to select
59048 * @param {Boolean} keepExisting (optional) True to keep existing selections
59050 selectRow : function(index, keepExisting, preventViewNotify){
59051 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
59054 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59055 if(!keepExisting || this.singleSelect){
59056 this.clearSelections();
59058 var r = this.grid.dataSource.getAt(index);
59059 this.selections.add(r);
59060 this.last = this.lastActive = index;
59061 if(!preventViewNotify){
59062 this.grid.getView().onRowSelect(index);
59064 this.fireEvent("rowselect", this, index, r);
59065 this.fireEvent("selectionchange", this);
59071 * @param {Number} row The index of the row to deselect
59073 deselectRow : function(index, preventViewNotify){
59077 if(this.last == index){
59080 if(this.lastActive == index){
59081 this.lastActive = false;
59083 var r = this.grid.dataSource.getAt(index);
59084 this.selections.remove(r);
59085 if(!preventViewNotify){
59086 this.grid.getView().onRowDeselect(index);
59088 this.fireEvent("rowdeselect", this, index);
59089 this.fireEvent("selectionchange", this);
59093 restoreLast : function(){
59095 this.last = this._last;
59100 acceptsNav : function(row, col, cm){
59101 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59105 onEditorKey : function(field, e){
59106 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59111 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59113 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59115 }else if(k == e.ENTER && !e.ctrlKey){
59119 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59121 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59123 }else if(k == e.ESC){
59127 g.startEditing(newCell[0], newCell[1]);
59132 * Ext JS Library 1.1.1
59133 * Copyright(c) 2006-2007, Ext JS, LLC.
59135 * Originally Released Under LGPL - original licence link has changed is not relivant.
59138 * <script type="text/javascript">
59141 * @class Roo.grid.CellSelectionModel
59142 * @extends Roo.grid.AbstractSelectionModel
59143 * This class provides the basic implementation for cell selection in a grid.
59145 * @param {Object} config The object containing the configuration of this model.
59146 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59148 Roo.grid.CellSelectionModel = function(config){
59149 Roo.apply(this, config);
59151 this.selection = null;
59155 * @event beforerowselect
59156 * Fires before 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 "beforecellselect" : true,
59163 * @event cellselect
59164 * Fires when a cell is selected.
59165 * @param {SelectionModel} this
59166 * @param {Number} rowIndex The selected row index
59167 * @param {Number} colIndex The selected cell index
59169 "cellselect" : true,
59171 * @event selectionchange
59172 * Fires when the active selection changes.
59173 * @param {SelectionModel} this
59174 * @param {Object} selection null for no selection or an object (o) with two properties
59176 <li>o.record: the record object for the row the selection is in</li>
59177 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59180 "selectionchange" : true,
59183 * Fires when the tab (or enter) was pressed on the last editable cell
59184 * You can use this to trigger add new row.
59185 * @param {SelectionModel} this
59189 * @event beforeeditnext
59190 * Fires before the next editable sell is made active
59191 * You can use this to skip to another cell or fire the tabend
59192 * if you set cell to false
59193 * @param {Object} eventdata object : { cell : [ row, col ] }
59195 "beforeeditnext" : true
59197 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59200 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59202 enter_is_tab: false,
59205 initEvents : function(){
59206 this.grid.on("mousedown", this.handleMouseDown, this);
59207 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59208 var view = this.grid.view;
59209 view.on("refresh", this.onViewChange, this);
59210 view.on("rowupdated", this.onRowUpdated, this);
59211 view.on("beforerowremoved", this.clearSelections, this);
59212 view.on("beforerowsinserted", this.clearSelections, this);
59213 if(this.grid.isEditor){
59214 this.grid.on("beforeedit", this.beforeEdit, this);
59219 beforeEdit : function(e){
59220 this.select(e.row, e.column, false, true, e.record);
59224 onRowUpdated : function(v, index, r){
59225 if(this.selection && this.selection.record == r){
59226 v.onCellSelect(index, this.selection.cell[1]);
59231 onViewChange : function(){
59232 this.clearSelections(true);
59236 * Returns the currently selected cell,.
59237 * @return {Array} The selected cell (row, column) or null if none selected.
59239 getSelectedCell : function(){
59240 return this.selection ? this.selection.cell : null;
59244 * Clears all selections.
59245 * @param {Boolean} true to prevent the gridview from being notified about the change.
59247 clearSelections : function(preventNotify){
59248 var s = this.selection;
59250 if(preventNotify !== true){
59251 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59253 this.selection = null;
59254 this.fireEvent("selectionchange", this, null);
59259 * Returns true if there is a selection.
59260 * @return {Boolean}
59262 hasSelection : function(){
59263 return this.selection ? true : false;
59267 handleMouseDown : function(e, t){
59268 var v = this.grid.getView();
59269 if(this.isLocked()){
59272 var row = v.findRowIndex(t);
59273 var cell = v.findCellIndex(t);
59274 if(row !== false && cell !== false){
59275 this.select(row, cell);
59281 * @param {Number} rowIndex
59282 * @param {Number} collIndex
59284 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59285 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59286 this.clearSelections();
59287 r = r || this.grid.dataSource.getAt(rowIndex);
59290 cell : [rowIndex, colIndex]
59292 if(!preventViewNotify){
59293 var v = this.grid.getView();
59294 v.onCellSelect(rowIndex, colIndex);
59295 if(preventFocus !== true){
59296 v.focusCell(rowIndex, colIndex);
59299 this.fireEvent("cellselect", this, rowIndex, colIndex);
59300 this.fireEvent("selectionchange", this, this.selection);
59305 isSelectable : function(rowIndex, colIndex, cm){
59306 return !cm.isHidden(colIndex);
59310 handleKeyDown : function(e){
59311 //Roo.log('Cell Sel Model handleKeyDown');
59312 if(!e.isNavKeyPress()){
59315 var g = this.grid, s = this.selection;
59318 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59320 this.select(cell[0], cell[1]);
59325 var walk = function(row, col, step){
59326 return g.walkCells(row, col, step, sm.isSelectable, sm);
59328 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59335 // handled by onEditorKey
59336 if (g.isEditor && g.editing) {
59340 newCell = walk(r, c-1, -1);
59342 newCell = walk(r, c+1, 1);
59347 newCell = walk(r+1, c, 1);
59351 newCell = walk(r-1, c, -1);
59355 newCell = walk(r, c+1, 1);
59359 newCell = walk(r, c-1, -1);
59364 if(g.isEditor && !g.editing){
59365 g.startEditing(r, c);
59374 this.select(newCell[0], newCell[1]);
59380 acceptsNav : function(row, col, cm){
59381 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59385 * @param {Number} field (not used) - as it's normally used as a listener
59386 * @param {Number} e - event - fake it by using
59388 * var e = Roo.EventObjectImpl.prototype;
59389 * e.keyCode = e.TAB
59393 onEditorKey : function(field, e){
59395 var k = e.getKey(),
59398 ed = g.activeEditor,
59400 ///Roo.log('onEditorKey' + k);
59403 if (this.enter_is_tab && k == e.ENTER) {
59409 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59411 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59417 } else if(k == e.ENTER && !e.ctrlKey){
59420 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59422 } else if(k == e.ESC){
59427 var ecall = { cell : newCell, forward : forward };
59428 this.fireEvent('beforeeditnext', ecall );
59429 newCell = ecall.cell;
59430 forward = ecall.forward;
59434 //Roo.log('next cell after edit');
59435 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59436 } else if (forward) {
59437 // tabbed past last
59438 this.fireEvent.defer(100, this, ['tabend',this]);
59443 * Ext JS Library 1.1.1
59444 * Copyright(c) 2006-2007, Ext JS, LLC.
59446 * Originally Released Under LGPL - original licence link has changed is not relivant.
59449 * <script type="text/javascript">
59453 * @class Roo.grid.EditorGrid
59454 * @extends Roo.grid.Grid
59455 * Class for creating and editable grid.
59456 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59457 * The container MUST have some type of size defined for the grid to fill. The container will be
59458 * automatically set to position relative if it isn't already.
59459 * @param {Object} dataSource The data model to bind to
59460 * @param {Object} colModel The column model with info about this grid's columns
59462 Roo.grid.EditorGrid = function(container, config){
59463 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59464 this.getGridEl().addClass("xedit-grid");
59466 if(!this.selModel){
59467 this.selModel = new Roo.grid.CellSelectionModel();
59470 this.activeEditor = null;
59474 * @event beforeedit
59475 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59476 * <ul style="padding:5px;padding-left:16px;">
59477 * <li>grid - This grid</li>
59478 * <li>record - The record being edited</li>
59479 * <li>field - The field name being edited</li>
59480 * <li>value - The value for the field being edited.</li>
59481 * <li>row - The grid row index</li>
59482 * <li>column - The grid column index</li>
59483 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59485 * @param {Object} e An edit event (see above for description)
59487 "beforeedit" : true,
59490 * Fires after a cell is edited. <br />
59491 * <ul style="padding:5px;padding-left:16px;">
59492 * <li>grid - This grid</li>
59493 * <li>record - The record being edited</li>
59494 * <li>field - The field name being edited</li>
59495 * <li>value - The value being set</li>
59496 * <li>originalValue - The original value for the field, before the edit.</li>
59497 * <li>row - The grid row index</li>
59498 * <li>column - The grid column index</li>
59500 * @param {Object} e An edit event (see above for description)
59502 "afteredit" : true,
59504 * @event validateedit
59505 * Fires after a cell is edited, but before the value is set in the record.
59506 * You can use this to modify the value being set in the field, Return false
59507 * to cancel the change. The edit event object has the following properties <br />
59508 * <ul style="padding:5px;padding-left:16px;">
59509 * <li>editor - This editor</li>
59510 * <li>grid - This grid</li>
59511 * <li>record - The record being edited</li>
59512 * <li>field - The field name being edited</li>
59513 * <li>value - The value being set</li>
59514 * <li>originalValue - The original value for the field, before the edit.</li>
59515 * <li>row - The grid row index</li>
59516 * <li>column - The grid column index</li>
59517 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59519 * @param {Object} e An edit event (see above for description)
59521 "validateedit" : true
59523 this.on("bodyscroll", this.stopEditing, this);
59524 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59527 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59529 * @cfg {Number} clicksToEdit
59530 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59537 trackMouseOver: false, // causes very odd FF errors
59539 onCellDblClick : function(g, row, col){
59540 this.startEditing(row, col);
59543 onEditComplete : function(ed, value, startValue){
59544 this.editing = false;
59545 this.activeEditor = null;
59546 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59548 var field = this.colModel.getDataIndex(ed.col);
59553 originalValue: startValue,
59560 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59563 if(String(value) !== String(startValue)){
59565 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59566 r.set(field, e.value);
59567 // if we are dealing with a combo box..
59568 // then we also set the 'name' colum to be the displayField
59569 if (ed.field.displayField && ed.field.name) {
59570 r.set(ed.field.name, ed.field.el.dom.value);
59573 delete e.cancel; //?? why!!!
59574 this.fireEvent("afteredit", e);
59577 this.fireEvent("afteredit", e); // always fire it!
59579 this.view.focusCell(ed.row, ed.col);
59583 * Starts editing the specified for the specified row/column
59584 * @param {Number} rowIndex
59585 * @param {Number} colIndex
59587 startEditing : function(row, col){
59588 this.stopEditing();
59589 if(this.colModel.isCellEditable(col, row)){
59590 this.view.ensureVisible(row, col, true);
59592 var r = this.dataSource.getAt(row);
59593 var field = this.colModel.getDataIndex(col);
59594 var cell = Roo.get(this.view.getCell(row,col));
59599 value: r.data[field],
59604 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59605 this.editing = true;
59606 var ed = this.colModel.getCellEditor(col, row);
59612 ed.render(ed.parentEl || document.body);
59618 (function(){ // complex but required for focus issues in safari, ie and opera
59622 ed.on("complete", this.onEditComplete, this, {single: true});
59623 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
59624 this.activeEditor = ed;
59625 var v = r.data[field];
59626 ed.startEdit(this.view.getCell(row, col), v);
59627 // combo's with 'displayField and name set
59628 if (ed.field.displayField && ed.field.name) {
59629 ed.field.el.dom.value = r.data[ed.field.name];
59633 }).defer(50, this);
59639 * Stops any active editing
59641 stopEditing : function(){
59642 if(this.activeEditor){
59643 this.activeEditor.completeEdit();
59645 this.activeEditor = null;
59649 * Called to get grid's drag proxy text, by default returns this.ddText.
59652 getDragDropText : function(){
59653 var count = this.selModel.getSelectedCell() ? 1 : 0;
59654 return String.format(this.ddText, count, count == 1 ? '' : 's');
59659 * Ext JS Library 1.1.1
59660 * Copyright(c) 2006-2007, Ext JS, LLC.
59662 * Originally Released Under LGPL - original licence link has changed is not relivant.
59665 * <script type="text/javascript">
59668 // private - not really -- you end up using it !
59669 // This is a support class used internally by the Grid components
59672 * @class Roo.grid.GridEditor
59673 * @extends Roo.Editor
59674 * Class for creating and editable grid elements.
59675 * @param {Object} config any settings (must include field)
59677 Roo.grid.GridEditor = function(field, config){
59678 if (!config && field.field) {
59680 field = Roo.factory(config.field, Roo.form);
59682 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
59683 field.monitorTab = false;
59686 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
59689 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
59692 alignment: "tl-tl",
59695 cls: "x-small-editor x-grid-editor",
59700 * Ext JS Library 1.1.1
59701 * Copyright(c) 2006-2007, Ext JS, LLC.
59703 * Originally Released Under LGPL - original licence link has changed is not relivant.
59706 * <script type="text/javascript">
59711 Roo.grid.PropertyRecord = Roo.data.Record.create([
59712 {name:'name',type:'string'}, 'value'
59716 Roo.grid.PropertyStore = function(grid, source){
59718 this.store = new Roo.data.Store({
59719 recordType : Roo.grid.PropertyRecord
59721 this.store.on('update', this.onUpdate, this);
59723 this.setSource(source);
59725 Roo.grid.PropertyStore.superclass.constructor.call(this);
59730 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
59731 setSource : function(o){
59733 this.store.removeAll();
59736 if(this.isEditableValue(o[k])){
59737 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
59740 this.store.loadRecords({records: data}, {}, true);
59743 onUpdate : function(ds, record, type){
59744 if(type == Roo.data.Record.EDIT){
59745 var v = record.data['value'];
59746 var oldValue = record.modified['value'];
59747 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
59748 this.source[record.id] = v;
59750 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
59757 getProperty : function(row){
59758 return this.store.getAt(row);
59761 isEditableValue: function(val){
59762 if(val && val instanceof Date){
59764 }else if(typeof val == 'object' || typeof val == 'function'){
59770 setValue : function(prop, value){
59771 this.source[prop] = value;
59772 this.store.getById(prop).set('value', value);
59775 getSource : function(){
59776 return this.source;
59780 Roo.grid.PropertyColumnModel = function(grid, store){
59783 g.PropertyColumnModel.superclass.constructor.call(this, [
59784 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
59785 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
59787 this.store = store;
59788 this.bselect = Roo.DomHelper.append(document.body, {
59789 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
59790 {tag: 'option', value: 'true', html: 'true'},
59791 {tag: 'option', value: 'false', html: 'false'}
59794 Roo.id(this.bselect);
59797 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
59798 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
59799 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
59800 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
59801 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
59803 this.renderCellDelegate = this.renderCell.createDelegate(this);
59804 this.renderPropDelegate = this.renderProp.createDelegate(this);
59807 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
59811 valueText : 'Value',
59813 dateFormat : 'm/j/Y',
59816 renderDate : function(dateVal){
59817 return dateVal.dateFormat(this.dateFormat);
59820 renderBool : function(bVal){
59821 return bVal ? 'true' : 'false';
59824 isCellEditable : function(colIndex, rowIndex){
59825 return colIndex == 1;
59828 getRenderer : function(col){
59830 this.renderCellDelegate : this.renderPropDelegate;
59833 renderProp : function(v){
59834 return this.getPropertyName(v);
59837 renderCell : function(val){
59839 if(val instanceof Date){
59840 rv = this.renderDate(val);
59841 }else if(typeof val == 'boolean'){
59842 rv = this.renderBool(val);
59844 return Roo.util.Format.htmlEncode(rv);
59847 getPropertyName : function(name){
59848 var pn = this.grid.propertyNames;
59849 return pn && pn[name] ? pn[name] : name;
59852 getCellEditor : function(colIndex, rowIndex){
59853 var p = this.store.getProperty(rowIndex);
59854 var n = p.data['name'], val = p.data['value'];
59856 if(typeof(this.grid.customEditors[n]) == 'string'){
59857 return this.editors[this.grid.customEditors[n]];
59859 if(typeof(this.grid.customEditors[n]) != 'undefined'){
59860 return this.grid.customEditors[n];
59862 if(val instanceof Date){
59863 return this.editors['date'];
59864 }else if(typeof val == 'number'){
59865 return this.editors['number'];
59866 }else if(typeof val == 'boolean'){
59867 return this.editors['boolean'];
59869 return this.editors['string'];
59875 * @class Roo.grid.PropertyGrid
59876 * @extends Roo.grid.EditorGrid
59877 * This class represents the interface of a component based property grid control.
59878 * <br><br>Usage:<pre><code>
59879 var grid = new Roo.grid.PropertyGrid("my-container-id", {
59887 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59888 * The container MUST have some type of size defined for the grid to fill. The container will be
59889 * automatically set to position relative if it isn't already.
59890 * @param {Object} config A config object that sets properties on this grid.
59892 Roo.grid.PropertyGrid = function(container, config){
59893 config = config || {};
59894 var store = new Roo.grid.PropertyStore(this);
59895 this.store = store;
59896 var cm = new Roo.grid.PropertyColumnModel(this, store);
59897 store.store.sort('name', 'ASC');
59898 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
59901 enableColLock:false,
59902 enableColumnMove:false,
59904 trackMouseOver: false,
59907 this.getGridEl().addClass('x-props-grid');
59908 this.lastEditRow = null;
59909 this.on('columnresize', this.onColumnResize, this);
59912 * @event beforepropertychange
59913 * Fires before a property changes (return false to stop?)
59914 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
59915 * @param {String} id Record Id
59916 * @param {String} newval New Value
59917 * @param {String} oldval Old Value
59919 "beforepropertychange": true,
59921 * @event propertychange
59922 * Fires after a property changes
59923 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
59924 * @param {String} id Record Id
59925 * @param {String} newval New Value
59926 * @param {String} oldval Old Value
59928 "propertychange": true
59930 this.customEditors = this.customEditors || {};
59932 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
59935 * @cfg {Object} customEditors map of colnames=> custom editors.
59936 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
59937 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
59938 * false disables editing of the field.
59942 * @cfg {Object} propertyNames map of property Names to their displayed value
59945 render : function(){
59946 Roo.grid.PropertyGrid.superclass.render.call(this);
59947 this.autoSize.defer(100, this);
59950 autoSize : function(){
59951 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
59953 this.view.fitColumns();
59957 onColumnResize : function(){
59958 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
59962 * Sets the data for the Grid
59963 * accepts a Key => Value object of all the elements avaiable.
59964 * @param {Object} data to appear in grid.
59966 setSource : function(source){
59967 this.store.setSource(source);
59971 * Gets all the data from the grid.
59972 * @return {Object} data data stored in grid
59974 getSource : function(){
59975 return this.store.getSource();
59984 * @class Roo.grid.Calendar
59985 * @extends Roo.util.Grid
59986 * This class extends the Grid to provide a calendar widget
59987 * <br><br>Usage:<pre><code>
59988 var grid = new Roo.grid.Calendar("my-container-id", {
59991 selModel: mySelectionModel,
59992 autoSizeColumns: true,
59993 monitorWindowResize: false,
59994 trackMouseOver: true
59995 eventstore : real data store..
60001 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60002 * The container MUST have some type of size defined for the grid to fill. The container will be
60003 * automatically set to position relative if it isn't already.
60004 * @param {Object} config A config object that sets properties on this grid.
60006 Roo.grid.Calendar = function(container, config){
60007 // initialize the container
60008 this.container = Roo.get(container);
60009 this.container.update("");
60010 this.container.setStyle("overflow", "hidden");
60011 this.container.addClass('x-grid-container');
60013 this.id = this.container.id;
60015 Roo.apply(this, config);
60016 // check and correct shorthanded configs
60020 for (var r = 0;r < 6;r++) {
60023 for (var c =0;c < 7;c++) {
60027 if (this.eventStore) {
60028 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60029 this.eventStore.on('load',this.onLoad, this);
60030 this.eventStore.on('beforeload',this.clearEvents, this);
60034 this.dataSource = new Roo.data.Store({
60035 proxy: new Roo.data.MemoryProxy(rows),
60036 reader: new Roo.data.ArrayReader({}, [
60037 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60040 this.dataSource.load();
60041 this.ds = this.dataSource;
60042 this.ds.xmodule = this.xmodule || false;
60045 var cellRender = function(v,x,r)
60047 return String.format(
60048 '<div class="fc-day fc-widget-content"><div>' +
60049 '<div class="fc-event-container"></div>' +
60050 '<div class="fc-day-number">{0}</div>'+
60052 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60053 '</div></div>', v);
60058 this.colModel = new Roo.grid.ColumnModel( [
60060 xtype: 'ColumnModel',
60062 dataIndex : 'weekday0',
60064 renderer : cellRender
60067 xtype: 'ColumnModel',
60069 dataIndex : 'weekday1',
60071 renderer : cellRender
60074 xtype: 'ColumnModel',
60076 dataIndex : 'weekday2',
60077 header : 'Tuesday',
60078 renderer : cellRender
60081 xtype: 'ColumnModel',
60083 dataIndex : 'weekday3',
60084 header : 'Wednesday',
60085 renderer : cellRender
60088 xtype: 'ColumnModel',
60090 dataIndex : 'weekday4',
60091 header : 'Thursday',
60092 renderer : cellRender
60095 xtype: 'ColumnModel',
60097 dataIndex : 'weekday5',
60099 renderer : cellRender
60102 xtype: 'ColumnModel',
60104 dataIndex : 'weekday6',
60105 header : 'Saturday',
60106 renderer : cellRender
60109 this.cm = this.colModel;
60110 this.cm.xmodule = this.xmodule || false;
60114 //this.selModel = new Roo.grid.CellSelectionModel();
60115 //this.sm = this.selModel;
60116 //this.selModel.init(this);
60120 this.container.setWidth(this.width);
60124 this.container.setHeight(this.height);
60131 * The raw click event for the entire grid.
60132 * @param {Roo.EventObject} e
60137 * The raw dblclick event for the entire grid.
60138 * @param {Roo.EventObject} e
60142 * @event contextmenu
60143 * The raw contextmenu event for the entire grid.
60144 * @param {Roo.EventObject} e
60146 "contextmenu" : true,
60149 * The raw mousedown event for the entire grid.
60150 * @param {Roo.EventObject} e
60152 "mousedown" : true,
60155 * The raw mouseup event for the entire grid.
60156 * @param {Roo.EventObject} e
60161 * The raw mouseover event for the entire grid.
60162 * @param {Roo.EventObject} e
60164 "mouseover" : true,
60167 * The raw mouseout event for the entire grid.
60168 * @param {Roo.EventObject} e
60173 * The raw keypress event for the entire grid.
60174 * @param {Roo.EventObject} e
60179 * The raw keydown event for the entire grid.
60180 * @param {Roo.EventObject} e
60188 * Fires when a cell is clicked
60189 * @param {Grid} this
60190 * @param {Number} rowIndex
60191 * @param {Number} columnIndex
60192 * @param {Roo.EventObject} e
60194 "cellclick" : true,
60196 * @event celldblclick
60197 * Fires when a cell is double clicked
60198 * @param {Grid} this
60199 * @param {Number} rowIndex
60200 * @param {Number} columnIndex
60201 * @param {Roo.EventObject} e
60203 "celldblclick" : true,
60206 * Fires when a row is clicked
60207 * @param {Grid} this
60208 * @param {Number} rowIndex
60209 * @param {Roo.EventObject} e
60213 * @event rowdblclick
60214 * Fires when a row is double clicked
60215 * @param {Grid} this
60216 * @param {Number} rowIndex
60217 * @param {Roo.EventObject} e
60219 "rowdblclick" : true,
60221 * @event headerclick
60222 * Fires when a header is clicked
60223 * @param {Grid} this
60224 * @param {Number} columnIndex
60225 * @param {Roo.EventObject} e
60227 "headerclick" : true,
60229 * @event headerdblclick
60230 * Fires when a header cell is double clicked
60231 * @param {Grid} this
60232 * @param {Number} columnIndex
60233 * @param {Roo.EventObject} e
60235 "headerdblclick" : true,
60237 * @event rowcontextmenu
60238 * Fires when a row is right clicked
60239 * @param {Grid} this
60240 * @param {Number} rowIndex
60241 * @param {Roo.EventObject} e
60243 "rowcontextmenu" : true,
60245 * @event cellcontextmenu
60246 * Fires when a cell is right clicked
60247 * @param {Grid} this
60248 * @param {Number} rowIndex
60249 * @param {Number} cellIndex
60250 * @param {Roo.EventObject} e
60252 "cellcontextmenu" : true,
60254 * @event headercontextmenu
60255 * Fires when a header is right clicked
60256 * @param {Grid} this
60257 * @param {Number} columnIndex
60258 * @param {Roo.EventObject} e
60260 "headercontextmenu" : true,
60262 * @event bodyscroll
60263 * Fires when the body element is scrolled
60264 * @param {Number} scrollLeft
60265 * @param {Number} scrollTop
60267 "bodyscroll" : true,
60269 * @event columnresize
60270 * Fires when the user resizes a column
60271 * @param {Number} columnIndex
60272 * @param {Number} newSize
60274 "columnresize" : true,
60276 * @event columnmove
60277 * Fires when the user moves a column
60278 * @param {Number} oldIndex
60279 * @param {Number} newIndex
60281 "columnmove" : true,
60284 * Fires when row(s) start being dragged
60285 * @param {Grid} this
60286 * @param {Roo.GridDD} dd The drag drop object
60287 * @param {event} e The raw browser event
60289 "startdrag" : true,
60292 * Fires when a drag operation is complete
60293 * @param {Grid} this
60294 * @param {Roo.GridDD} dd The drag drop object
60295 * @param {event} e The raw browser event
60300 * Fires when dragged row(s) are dropped on a valid DD target
60301 * @param {Grid} this
60302 * @param {Roo.GridDD} dd The drag drop object
60303 * @param {String} targetId The target drag drop object
60304 * @param {event} e The raw browser event
60309 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60310 * @param {Grid} this
60311 * @param {Roo.GridDD} dd The drag drop object
60312 * @param {String} targetId The target drag drop object
60313 * @param {event} e The raw browser event
60318 * Fires when the dragged row(s) first cross another DD target while being dragged
60319 * @param {Grid} this
60320 * @param {Roo.GridDD} dd The drag drop object
60321 * @param {String} targetId The target drag drop object
60322 * @param {event} e The raw browser event
60324 "dragenter" : true,
60327 * Fires when the dragged row(s) leave another DD target while being dragged
60328 * @param {Grid} this
60329 * @param {Roo.GridDD} dd The drag drop object
60330 * @param {String} targetId The target drag drop object
60331 * @param {event} e The raw browser event
60336 * Fires when a row is rendered, so you can change add a style to it.
60337 * @param {GridView} gridview The grid view
60338 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60344 * Fires when the grid is rendered
60345 * @param {Grid} grid
60350 * Fires when a date is selected
60351 * @param {DatePicker} this
60352 * @param {Date} date The selected date
60356 * @event monthchange
60357 * Fires when the displayed month changes
60358 * @param {DatePicker} this
60359 * @param {Date} date The selected month
60361 'monthchange': true,
60363 * @event evententer
60364 * Fires when mouse over an event
60365 * @param {Calendar} this
60366 * @param {event} Event
60368 'evententer': true,
60370 * @event eventleave
60371 * Fires when the mouse leaves an
60372 * @param {Calendar} this
60375 'eventleave': true,
60377 * @event eventclick
60378 * Fires when the mouse click an
60379 * @param {Calendar} this
60382 'eventclick': true,
60384 * @event eventrender
60385 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60386 * @param {Calendar} this
60387 * @param {data} data to be modified
60389 'eventrender': true
60393 Roo.grid.Grid.superclass.constructor.call(this);
60394 this.on('render', function() {
60395 this.view.el.addClass('x-grid-cal');
60397 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60401 if (!Roo.grid.Calendar.style) {
60402 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60405 '.x-grid-cal .x-grid-col' : {
60406 height: 'auto !important',
60407 'vertical-align': 'top'
60409 '.x-grid-cal .fc-event-hori' : {
60420 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60422 * @cfg {Store} eventStore The store that loads events.
60427 activeDate : false,
60430 monitorWindowResize : false,
60433 resizeColumns : function() {
60434 var col = (this.view.el.getWidth() / 7) - 3;
60435 // loop through cols, and setWidth
60436 for(var i =0 ; i < 7 ; i++){
60437 this.cm.setColumnWidth(i, col);
60440 setDate :function(date) {
60442 Roo.log('setDate?');
60444 this.resizeColumns();
60445 var vd = this.activeDate;
60446 this.activeDate = date;
60447 // if(vd && this.el){
60448 // var t = date.getTime();
60449 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60450 // Roo.log('using add remove');
60452 // this.fireEvent('monthchange', this, date);
60454 // this.cells.removeClass("fc-state-highlight");
60455 // this.cells.each(function(c){
60456 // if(c.dateValue == t){
60457 // c.addClass("fc-state-highlight");
60458 // setTimeout(function(){
60459 // try{c.dom.firstChild.focus();}catch(e){}
60469 var days = date.getDaysInMonth();
60471 var firstOfMonth = date.getFirstDateOfMonth();
60472 var startingPos = firstOfMonth.getDay()-this.startDay;
60474 if(startingPos < this.startDay){
60478 var pm = date.add(Date.MONTH, -1);
60479 var prevStart = pm.getDaysInMonth()-startingPos;
60483 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60485 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60486 //this.cells.addClassOnOver('fc-state-hover');
60488 var cells = this.cells.elements;
60489 var textEls = this.textNodes;
60491 //Roo.each(cells, function(cell){
60492 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60495 days += startingPos;
60497 // convert everything to numbers so it's fast
60498 var day = 86400000;
60499 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60502 //Roo.log(prevStart);
60504 var today = new Date().clearTime().getTime();
60505 var sel = date.clearTime().getTime();
60506 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60507 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60508 var ddMatch = this.disabledDatesRE;
60509 var ddText = this.disabledDatesText;
60510 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60511 var ddaysText = this.disabledDaysText;
60512 var format = this.format;
60514 var setCellClass = function(cal, cell){
60516 //Roo.log('set Cell Class');
60518 var t = d.getTime();
60523 cell.dateValue = t;
60525 cell.className += " fc-today";
60526 cell.className += " fc-state-highlight";
60527 cell.title = cal.todayText;
60530 // disable highlight in other month..
60531 cell.className += " fc-state-highlight";
60536 //cell.className = " fc-state-disabled";
60537 cell.title = cal.minText;
60541 //cell.className = " fc-state-disabled";
60542 cell.title = cal.maxText;
60546 if(ddays.indexOf(d.getDay()) != -1){
60547 // cell.title = ddaysText;
60548 // cell.className = " fc-state-disabled";
60551 if(ddMatch && format){
60552 var fvalue = d.dateFormat(format);
60553 if(ddMatch.test(fvalue)){
60554 cell.title = ddText.replace("%0", fvalue);
60555 cell.className = " fc-state-disabled";
60559 if (!cell.initialClassName) {
60560 cell.initialClassName = cell.dom.className;
60563 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60568 for(; i < startingPos; i++) {
60569 cells[i].dayName = (++prevStart);
60570 Roo.log(textEls[i]);
60571 d.setDate(d.getDate()+1);
60573 //cells[i].className = "fc-past fc-other-month";
60574 setCellClass(this, cells[i]);
60579 for(; i < days; i++){
60580 intDay = i - startingPos + 1;
60581 cells[i].dayName = (intDay);
60582 d.setDate(d.getDate()+1);
60584 cells[i].className = ''; // "x-date-active";
60585 setCellClass(this, cells[i]);
60589 for(; i < 42; i++) {
60590 //textEls[i].innerHTML = (++extraDays);
60592 d.setDate(d.getDate()+1);
60593 cells[i].dayName = (++extraDays);
60594 cells[i].className = "fc-future fc-other-month";
60595 setCellClass(this, cells[i]);
60598 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60600 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60602 // this will cause all the cells to mis
60605 for (var r = 0;r < 6;r++) {
60606 for (var c =0;c < 7;c++) {
60607 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60611 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60612 for(i=0;i<cells.length;i++) {
60614 this.cells.elements[i].dayName = cells[i].dayName ;
60615 this.cells.elements[i].className = cells[i].className;
60616 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
60617 this.cells.elements[i].title = cells[i].title ;
60618 this.cells.elements[i].dateValue = cells[i].dateValue ;
60624 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
60625 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
60627 ////if(totalRows != 6){
60628 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
60629 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
60632 this.fireEvent('monthchange', this, date);
60637 * Returns the grid's SelectionModel.
60638 * @return {SelectionModel}
60640 getSelectionModel : function(){
60641 if(!this.selModel){
60642 this.selModel = new Roo.grid.CellSelectionModel();
60644 return this.selModel;
60648 this.eventStore.load()
60654 findCell : function(dt) {
60655 dt = dt.clearTime().getTime();
60657 this.cells.each(function(c){
60658 //Roo.log("check " +c.dateValue + '?=' + dt);
60659 if(c.dateValue == dt){
60669 findCells : function(rec) {
60670 var s = rec.data.start_dt.clone().clearTime().getTime();
60672 var e= rec.data.end_dt.clone().clearTime().getTime();
60675 this.cells.each(function(c){
60676 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
60678 if(c.dateValue > e){
60681 if(c.dateValue < s){
60690 findBestRow: function(cells)
60694 for (var i =0 ; i < cells.length;i++) {
60695 ret = Math.max(cells[i].rows || 0,ret);
60702 addItem : function(rec)
60704 // look for vertical location slot in
60705 var cells = this.findCells(rec);
60707 rec.row = this.findBestRow(cells);
60709 // work out the location.
60713 for(var i =0; i < cells.length; i++) {
60721 if (crow.start.getY() == cells[i].getY()) {
60723 crow.end = cells[i];
60739 for (var i = 0; i < cells.length;i++) {
60740 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
60747 clearEvents: function() {
60749 if (!this.eventStore.getCount()) {
60752 // reset number of rows in cells.
60753 Roo.each(this.cells.elements, function(c){
60757 this.eventStore.each(function(e) {
60758 this.clearEvent(e);
60763 clearEvent : function(ev)
60766 Roo.each(ev.els, function(el) {
60767 el.un('mouseenter' ,this.onEventEnter, this);
60768 el.un('mouseleave' ,this.onEventLeave, this);
60776 renderEvent : function(ev,ctr) {
60778 ctr = this.view.el.select('.fc-event-container',true).first();
60782 this.clearEvent(ev);
60788 var cells = ev.cells;
60789 var rows = ev.rows;
60790 this.fireEvent('eventrender', this, ev);
60792 for(var i =0; i < rows.length; i++) {
60796 cls += ' fc-event-start';
60798 if ((i+1) == rows.length) {
60799 cls += ' fc-event-end';
60802 //Roo.log(ev.data);
60803 // how many rows should it span..
60804 var cg = this.eventTmpl.append(ctr,Roo.apply({
60807 }, ev.data) , true);
60810 cg.on('mouseenter' ,this.onEventEnter, this, ev);
60811 cg.on('mouseleave' ,this.onEventLeave, this, ev);
60812 cg.on('click', this.onEventClick, this, ev);
60816 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
60817 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
60820 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
60821 cg.setWidth(ebox.right - sbox.x -2);
60825 renderEvents: function()
60827 // first make sure there is enough space..
60829 if (!this.eventTmpl) {
60830 this.eventTmpl = new Roo.Template(
60831 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
60832 '<div class="fc-event-inner">' +
60833 '<span class="fc-event-time">{time}</span>' +
60834 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
60836 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
60844 this.cells.each(function(c) {
60845 //Roo.log(c.select('.fc-day-content div',true).first());
60846 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
60849 var ctr = this.view.el.select('.fc-event-container',true).first();
60852 this.eventStore.each(function(ev){
60854 this.renderEvent(ev);
60858 this.view.layout();
60862 onEventEnter: function (e, el,event,d) {
60863 this.fireEvent('evententer', this, el, event);
60866 onEventLeave: function (e, el,event,d) {
60867 this.fireEvent('eventleave', this, el, event);
60870 onEventClick: function (e, el,event,d) {
60871 this.fireEvent('eventclick', this, el, event);
60874 onMonthChange: function () {
60878 onLoad: function () {
60880 //Roo.log('calendar onload');
60882 if(this.eventStore.getCount() > 0){
60886 this.eventStore.each(function(d){
60891 if (typeof(add.end_dt) == 'undefined') {
60892 Roo.log("Missing End time in calendar data: ");
60896 if (typeof(add.start_dt) == 'undefined') {
60897 Roo.log("Missing Start time in calendar data: ");
60901 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
60902 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
60903 add.id = add.id || d.id;
60904 add.title = add.title || '??';
60912 this.renderEvents();
60922 render : function ()
60926 if (!this.view.el.hasClass('course-timesheet')) {
60927 this.view.el.addClass('course-timesheet');
60929 if (this.tsStyle) {
60934 Roo.log(_this.grid.view.el.getWidth());
60937 this.tsStyle = Roo.util.CSS.createStyleSheet({
60938 '.course-timesheet .x-grid-row' : {
60941 '.x-grid-row td' : {
60942 'vertical-align' : 0
60944 '.course-edit-link' : {
60946 'text-overflow' : 'ellipsis',
60947 'overflow' : 'hidden',
60948 'white-space' : 'nowrap',
60949 'cursor' : 'pointer'
60954 '.de-act-sup-link' : {
60955 'color' : 'purple',
60956 'text-decoration' : 'line-through'
60960 'text-decoration' : 'line-through'
60962 '.course-timesheet .course-highlight' : {
60963 'border-top-style': 'dashed !important',
60964 'border-bottom-bottom': 'dashed !important'
60966 '.course-timesheet .course-item' : {
60967 'font-family' : 'tahoma, arial, helvetica',
60968 'font-size' : '11px',
60969 'overflow' : 'hidden',
60970 'padding-left' : '10px',
60971 'padding-right' : '10px',
60972 'padding-top' : '10px'
60980 monitorWindowResize : false,
60981 cellrenderer : function(v,x,r)
60986 xtype: 'CellSelectionModel',
60993 beforeload : function (_self, options)
60995 options.params = options.params || {};
60996 options.params._month = _this.monthField.getValue();
60997 options.params.limit = 9999;
60998 options.params['sort'] = 'when_dt';
60999 options.params['dir'] = 'ASC';
61000 this.proxy.loadResponse = this.loadResponse;
61002 //this.addColumns();
61004 load : function (_self, records, options)
61006 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
61007 // if you click on the translation.. you can edit it...
61008 var el = Roo.get(this);
61009 var id = el.dom.getAttribute('data-id');
61010 var d = el.dom.getAttribute('data-date');
61011 var t = el.dom.getAttribute('data-time');
61012 //var id = this.child('span').dom.textContent;
61015 Pman.Dialog.CourseCalendar.show({
61019 productitem_active : id ? 1 : 0
61021 _this.grid.ds.load({});
61026 _this.panel.fireEvent('resize', [ '', '' ]);
61029 loadResponse : function(o, success, response){
61030 // this is overridden on before load..
61032 Roo.log("our code?");
61033 //Roo.log(success);
61034 //Roo.log(response)
61035 delete this.activeRequest;
61037 this.fireEvent("loadexception", this, o, response);
61038 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61043 result = o.reader.read(response);
61045 Roo.log("load exception?");
61046 this.fireEvent("loadexception", this, o, response, e);
61047 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61050 Roo.log("ready...");
61051 // loop through result.records;
61052 // and set this.tdate[date] = [] << array of records..
61054 Roo.each(result.records, function(r){
61056 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61057 _this.tdata[r.data.when_dt.format('j')] = [];
61059 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61062 //Roo.log(_this.tdata);
61064 result.records = [];
61065 result.totalRecords = 6;
61067 // let's generate some duumy records for the rows.
61068 //var st = _this.dateField.getValue();
61070 // work out monday..
61071 //st = st.add(Date.DAY, -1 * st.format('w'));
61073 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61075 var firstOfMonth = date.getFirstDayOfMonth();
61076 var days = date.getDaysInMonth();
61078 var firstAdded = false;
61079 for (var i = 0; i < result.totalRecords ; i++) {
61080 //var d= st.add(Date.DAY, i);
61083 for(var w = 0 ; w < 7 ; w++){
61084 if(!firstAdded && firstOfMonth != w){
61091 var dd = (d > 0 && d < 10) ? "0"+d : d;
61092 row['weekday'+w] = String.format(
61093 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61094 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61096 date.format('Y-m-')+dd
61099 if(typeof(_this.tdata[d]) != 'undefined'){
61100 Roo.each(_this.tdata[d], function(r){
61104 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61105 if(r.parent_id*1>0){
61106 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61109 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61110 deactive = 'de-act-link';
61113 row['weekday'+w] += String.format(
61114 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61116 r.product_id_name, //1
61117 r.when_dt.format('h:ia'), //2
61127 // only do this if something added..
61129 result.records.push(_this.grid.dataSource.reader.newRow(row));
61133 // push it twice. (second one with an hour..
61137 this.fireEvent("load", this, o, o.request.arg);
61138 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61140 sortInfo : {field: 'when_dt', direction : 'ASC' },
61142 xtype: 'HttpProxy',
61145 url : baseURL + '/Roo/Shop_course.php'
61148 xtype: 'JsonReader',
61165 'name': 'parent_id',
61169 'name': 'product_id',
61173 'name': 'productitem_id',
61191 click : function (_self, e)
61193 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61194 sd.setMonth(sd.getMonth()-1);
61195 _this.monthField.setValue(sd.format('Y-m-d'));
61196 _this.grid.ds.load({});
61202 xtype: 'Separator',
61206 xtype: 'MonthField',
61209 render : function (_self)
61211 _this.monthField = _self;
61212 // _this.monthField.set today
61214 select : function (combo, date)
61216 _this.grid.ds.load({});
61219 value : (function() { return new Date(); })()
61222 xtype: 'Separator',
61228 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61238 click : function (_self, e)
61240 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61241 sd.setMonth(sd.getMonth()+1);
61242 _this.monthField.setValue(sd.format('Y-m-d'));
61243 _this.grid.ds.load({});
61256 * Ext JS Library 1.1.1
61257 * Copyright(c) 2006-2007, Ext JS, LLC.
61259 * Originally Released Under LGPL - original licence link has changed is not relivant.
61262 * <script type="text/javascript">
61266 * @class Roo.LoadMask
61267 * A simple utility class for generically masking elements while loading data. If the element being masked has
61268 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61269 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61270 * element's UpdateManager load indicator and will be destroyed after the initial load.
61272 * Create a new LoadMask
61273 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61274 * @param {Object} config The config object
61276 Roo.LoadMask = function(el, config){
61277 this.el = Roo.get(el);
61278 Roo.apply(this, config);
61280 this.store.on('beforeload', this.onBeforeLoad, this);
61281 this.store.on('load', this.onLoad, this);
61282 this.store.on('loadexception', this.onLoadException, this);
61283 this.removeMask = false;
61285 var um = this.el.getUpdateManager();
61286 um.showLoadIndicator = false; // disable the default indicator
61287 um.on('beforeupdate', this.onBeforeLoad, this);
61288 um.on('update', this.onLoad, this);
61289 um.on('failure', this.onLoad, this);
61290 this.removeMask = true;
61294 Roo.LoadMask.prototype = {
61296 * @cfg {Boolean} removeMask
61297 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61298 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61301 * @cfg {String} msg
61302 * The text to display in a centered loading message box (defaults to 'Loading...')
61304 msg : 'Loading...',
61306 * @cfg {String} msgCls
61307 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61309 msgCls : 'x-mask-loading',
61312 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61318 * Disables the mask to prevent it from being displayed
61320 disable : function(){
61321 this.disabled = true;
61325 * Enables the mask so that it can be displayed
61327 enable : function(){
61328 this.disabled = false;
61331 onLoadException : function()
61333 Roo.log(arguments);
61335 if (typeof(arguments[3]) != 'undefined') {
61336 Roo.MessageBox.alert("Error loading",arguments[3]);
61340 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61341 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61348 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61351 onLoad : function()
61353 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61357 onBeforeLoad : function(){
61358 if(!this.disabled){
61359 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61364 destroy : function(){
61366 this.store.un('beforeload', this.onBeforeLoad, this);
61367 this.store.un('load', this.onLoad, this);
61368 this.store.un('loadexception', this.onLoadException, this);
61370 var um = this.el.getUpdateManager();
61371 um.un('beforeupdate', this.onBeforeLoad, this);
61372 um.un('update', this.onLoad, this);
61373 um.un('failure', this.onLoad, this);
61378 * Ext JS Library 1.1.1
61379 * Copyright(c) 2006-2007, Ext JS, LLC.
61381 * Originally Released Under LGPL - original licence link has changed is not relivant.
61384 * <script type="text/javascript">
61389 * @class Roo.XTemplate
61390 * @extends Roo.Template
61391 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61393 var t = new Roo.XTemplate(
61394 '<select name="{name}">',
61395 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61399 // then append, applying the master template values
61402 * Supported features:
61407 {a_variable} - output encoded.
61408 {a_variable.format:("Y-m-d")} - call a method on the variable
61409 {a_variable:raw} - unencoded output
61410 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61411 {a_variable:this.method_on_template(...)} - call a method on the template object.
61416 <tpl for="a_variable or condition.."></tpl>
61417 <tpl if="a_variable or condition"></tpl>
61418 <tpl exec="some javascript"></tpl>
61419 <tpl name="named_template"></tpl> (experimental)
61421 <tpl for="."></tpl> - just iterate the property..
61422 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61426 Roo.XTemplate = function()
61428 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61435 Roo.extend(Roo.XTemplate, Roo.Template, {
61438 * The various sub templates
61443 * basic tag replacing syntax
61446 * // you can fake an object call by doing this
61450 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61453 * compile the template
61455 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61458 compile: function()
61462 s = ['<tpl>', s, '</tpl>'].join('');
61464 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61465 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61466 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61467 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61468 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61473 while(true == !!(m = s.match(re))){
61474 var forMatch = m[0].match(nameRe),
61475 ifMatch = m[0].match(ifRe),
61476 execMatch = m[0].match(execRe),
61477 namedMatch = m[0].match(namedRe),
61482 name = forMatch && forMatch[1] ? forMatch[1] : '';
61485 // if - puts fn into test..
61486 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61488 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61493 // exec - calls a function... returns empty if true is returned.
61494 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61496 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61504 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61505 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61506 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61509 var uid = namedMatch ? namedMatch[1] : id;
61513 id: namedMatch ? namedMatch[1] : id,
61520 s = s.replace(m[0], '');
61522 s = s.replace(m[0], '{xtpl'+ id + '}');
61527 for(var i = tpls.length-1; i >= 0; --i){
61528 this.compileTpl(tpls[i]);
61529 this.tpls[tpls[i].id] = tpls[i];
61531 this.master = tpls[tpls.length-1];
61535 * same as applyTemplate, except it's done to one of the subTemplates
61536 * when using named templates, you can do:
61538 * var str = pl.applySubTemplate('your-name', values);
61541 * @param {Number} id of the template
61542 * @param {Object} values to apply to template
61543 * @param {Object} parent (normaly the instance of this object)
61545 applySubTemplate : function(id, values, parent)
61549 var t = this.tpls[id];
61553 if(t.test && !t.test.call(this, values, parent)){
61557 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61558 Roo.log(e.toString());
61564 if(t.exec && t.exec.call(this, values, parent)){
61568 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61569 Roo.log(e.toString());
61574 var vs = t.target ? t.target.call(this, values, parent) : values;
61575 parent = t.target ? values : parent;
61576 if(t.target && vs instanceof Array){
61578 for(var i = 0, len = vs.length; i < len; i++){
61579 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61581 return buf.join('');
61583 return t.compiled.call(this, vs, parent);
61585 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61586 Roo.log(e.toString());
61587 Roo.log(t.compiled);
61592 compileTpl : function(tpl)
61594 var fm = Roo.util.Format;
61595 var useF = this.disableFormats !== true;
61596 var sep = Roo.isGecko ? "+" : ",";
61597 var undef = function(str) {
61598 Roo.log("Property not found :" + str);
61602 var fn = function(m, name, format, args)
61604 //Roo.log(arguments);
61605 args = args ? args.replace(/\\'/g,"'") : args;
61606 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61607 if (typeof(format) == 'undefined') {
61608 format= 'htmlEncode';
61610 if (format == 'raw' ) {
61614 if(name.substr(0, 4) == 'xtpl'){
61615 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
61618 // build an array of options to determine if value is undefined..
61620 // basically get 'xxxx.yyyy' then do
61621 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
61622 // (function () { Roo.log("Property not found"); return ''; })() :
61627 Roo.each(name.split('.'), function(st) {
61628 lookfor += (lookfor.length ? '.': '') + st;
61629 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
61632 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
61635 if(format && useF){
61637 args = args ? ',' + args : "";
61639 if(format.substr(0, 5) != "this."){
61640 format = "fm." + format + '(';
61642 format = 'this.call("'+ format.substr(5) + '", ';
61646 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
61650 // called with xxyx.yuu:(test,test)
61652 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
61654 // raw.. - :raw modifier..
61655 return "'"+ sep + udef_st + name + ")"+sep+"'";
61659 // branched to use + in gecko and [].join() in others
61661 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
61662 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
61665 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
61666 body.push(tpl.body.replace(/(\r\n|\n)/g,
61667 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
61668 body.push("'].join('');};};");
61669 body = body.join('');
61672 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
61674 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
61680 applyTemplate : function(values){
61681 return this.master.compiled.call(this, values, {});
61682 //var s = this.subs;
61685 apply : function(){
61686 return this.applyTemplate.apply(this, arguments);
61691 Roo.XTemplate.from = function(el){
61692 el = Roo.getDom(el);
61693 return new Roo.XTemplate(el.value || el.innerHTML);