4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
17 window["undefined"] = window["undefined"];
21 * Roo core utilities and functions.
26 * Copies all the properties of config to obj.
27 * @param {Object} obj The receiver of the properties
28 * @param {Object} config The source of the properties
29 * @param {Object} defaults A different object that will also be applied for default values
30 * @return {Object} returns obj
35 Roo.apply = function(o, c, defaults){
37 // no "this" reference for friendly out of scope calls
38 Roo.apply(o, defaults);
40 if(o && c && typeof c == 'object'){
51 var ua = navigator.userAgent.toLowerCase();
53 var isStrict = document.compatMode == "CSS1Compat",
54 isOpera = ua.indexOf("opera") > -1,
55 isSafari = (/webkit|khtml/).test(ua),
56 isFirefox = ua.indexOf("firefox") > -1,
57 isIE = ua.indexOf("msie") > -1,
58 isIE7 = ua.indexOf("msie 7") > -1,
59 isIE11 = /trident.*rv\:11\./.test(ua),
60 isEdge = ua.indexOf("edge") > -1,
61 isGecko = !isSafari && ua.indexOf("gecko") > -1,
62 isBorderBox = isIE && !isStrict,
63 isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
64 isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
65 isLinux = (ua.indexOf("linux") != -1),
66 isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
67 isIOS = /iphone|ipad/.test(ua),
68 isAndroid = /android/.test(ua),
69 isTouch = (function() {
71 if (ua.indexOf('chrome') != -1 && ua.indexOf('android') == -1) {
72 window.addEventListener('touchstart', function __set_has_touch__ () {
74 window.removeEventListener('touchstart', __set_has_touch__);
76 return false; // no touch on chrome!?
78 document.createEvent("TouchEvent");
85 // remove css image flicker
88 document.execCommand("BackgroundImageCache", false, true);
94 * True if the browser is in strict mode
99 * True if the page is running over SSL
104 * True when the document is fully initialized and ready for action
109 * Turn on debugging output (currently only the factory uses this)
116 * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
119 enableGarbageCollector : true,
122 * True to automatically purge event listeners after uncaching an element (defaults to false).
123 * Note: this only happens if enableGarbageCollector is true.
126 enableListenerCollection:false,
129 * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
130 * the IE insecure content warning (defaults to javascript:false).
133 SSL_SECURE_URL : "javascript:false",
136 * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
137 * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
140 BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
142 emptyFn : function(){},
145 * Copies all the properties of config to obj if they don't already exist.
146 * @param {Object} obj The receiver of the properties
147 * @param {Object} config The source of the properties
148 * @return {Object} returns obj
150 applyIf : function(o, c){
153 if(typeof o[p] == "undefined"){ o[p] = c[p]; }
160 * Applies event listeners to elements by selectors when the document is ready.
161 * The event name is specified with an @ suffix.
164 // add a listener for click on all anchors in element with id foo
165 '#foo a@click' : function(e, t){
169 // add the same listener to multiple selectors (separated by comma BEFORE the @)
170 '#foo a, #bar span.some-class@mouseover' : function(){
175 * @param {Object} obj The list of behaviors to apply
177 addBehaviors : function(o){
179 Roo.onReady(function(){
184 var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
186 var parts = b.split('@');
187 if(parts[1]){ // for Object prototype breakers
190 cache[s] = Roo.select(s);
192 cache[s].on(parts[1], o[b]);
199 * Generates unique ids. If the element already has an id, it is unchanged
200 * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
201 * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
202 * @return {String} The generated Id.
204 id : function(el, prefix){
205 prefix = prefix || "roo-gen";
207 var id = prefix + (++idSeed);
208 return el ? (el.id ? el.id : (el.id = id)) : id;
213 * Extends one class with another class and optionally overrides members with the passed literal. This class
214 * also adds the function "override()" to the class that can be used to override
215 * members on an instance.
216 * @param {Object} subclass The class inheriting the functionality
217 * @param {Object} superclass The class being extended
218 * @param {Object} overrides (optional) A literal with members
223 var io = function(o){
228 return function(sb, sp, overrides){
229 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
232 sb = function(){sp.apply(this, arguments);};
234 var F = function(){}, sbp, spp = sp.prototype;
236 sbp = sb.prototype = new F();
240 if(spp.constructor == Object.prototype.constructor){
245 sb.override = function(o){
249 Roo.override(sb, overrides);
255 * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
257 Roo.override(MyClass, {
258 newMethod1: function(){
261 newMethod2: function(foo){
266 * @param {Object} origclass The class to override
267 * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
268 * containing one or more methods.
271 override : function(origclass, overrides){
273 var p = origclass.prototype;
274 for(var method in overrides){
275 p[method] = overrides[method];
280 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
282 Roo.namespace('Company', 'Company.data');
283 Company.Widget = function() { ... }
284 Company.data.CustomStore = function(config) { ... }
286 * @param {String} namespace1
287 * @param {String} namespace2
288 * @param {String} etc
291 namespace : function(){
292 var a=arguments, o=null, i, j, d, rt;
293 for (i=0; i<a.length; ++i) {
297 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
298 for (j=1; j<d.length; ++j) {
299 o[d[j]]=o[d[j]] || {};
305 * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
307 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
308 Roo.factory(conf, Roo.data);
310 * @param {String} classname
311 * @param {String} namespace (optional)
315 factory : function(c, ns)
317 // no xtype, no ns or c.xns - or forced off by c.xns
318 if (!c.xtype || (!ns && !c.xns) || (c.xns === false)) { // not enough info...
321 ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
322 if (c.constructor == ns[c.xtype]) {// already created...
326 if (Roo.debug) { Roo.log("Roo.Factory(" + c.xtype + ")"); }
327 var ret = new ns[c.xtype](c);
331 c.xns = false; // prevent recursion..
335 * Logs to console if it can.
337 * @param {String|Object} string
342 if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
349 * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2". Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
353 urlEncode : function(o){
359 var ov = o[key], k = Roo.encodeURIComponent(key);
360 var type = typeof ov;
361 if(type == 'undefined'){
363 }else if(type != "function" && type != "object"){
364 buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
365 }else if(ov instanceof Array){
367 for(var i = 0, len = ov.length; i < len; i++) {
368 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
379 * Safe version of encodeURIComponent
380 * @param {String} data
384 encodeURIComponent : function (data)
387 return encodeURIComponent(data);
388 } catch(e) {} // should be an uri encode error.
390 if (data == '' || data == null){
393 // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
394 function nibble_to_hex(nibble){
395 var chars = '0123456789ABCDEF';
396 return chars.charAt(nibble);
398 data = data.toString();
400 for(var i=0; i<data.length; i++){
401 var c = data.charCodeAt(i);
402 var bs = new Array();
405 bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
406 bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
407 bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
408 bs[3] = 0x80 | (c & 0x3F);
409 }else if (c > 0x800){
411 bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
412 bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
413 bs[2] = 0x80 | (c & 0x3F);
416 bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
417 bs[1] = 0x80 | (c & 0x3F);
422 for(var j=0; j<bs.length; j++){
424 var hex = nibble_to_hex((b & 0xF0) >>> 4)
425 + nibble_to_hex(b &0x0F);
434 * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
435 * @param {String} string
436 * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
437 * @return {Object} A literal with members
439 urlDecode : function(string, overwrite){
440 if(!string || !string.length){
444 var pairs = string.split('&');
445 var pair, name, value;
446 for(var i = 0, len = pairs.length; i < len; i++){
447 pair = pairs[i].split('=');
448 name = decodeURIComponent(pair[0]);
449 value = decodeURIComponent(pair[1]);
450 if(overwrite !== true){
451 if(typeof obj[name] == "undefined"){
453 }else if(typeof obj[name] == "string"){
454 obj[name] = [obj[name]];
455 obj[name].push(value);
457 obj[name].push(value);
467 * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
468 * passed array is not really an array, your function is called once with it.
469 * The supplied function is called with (Object item, Number index, Array allItems).
470 * @param {Array/NodeList/Mixed} array
471 * @param {Function} fn
472 * @param {Object} scope
474 each : function(array, fn, scope){
475 if(typeof array.length == "undefined" || typeof array == "string"){
478 for(var i = 0, len = array.length; i < len; i++){
479 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
484 combine : function(){
485 var as = arguments, l = as.length, r = [];
486 for(var i = 0; i < l; i++){
488 if(a instanceof Array){
490 }else if(a.length !== undefined && !a.substr){
491 r = r.concat(Array.prototype.slice.call(a, 0));
500 * Escapes the passed string for use in a regular expression
501 * @param {String} str
504 escapeRe : function(s) {
505 return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
509 callback : function(cb, scope, args, delay){
510 if(typeof cb == "function"){
512 cb.defer(delay, scope, args || []);
514 cb.apply(scope, args || []);
520 * Return the dom node for the passed string (id), dom node, or Roo.Element
521 * @param {String/HTMLElement/Roo.Element} el
522 * @return HTMLElement
524 getDom : function(el){
528 return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
532 * Shorthand for {@link Roo.ComponentMgr#get}
534 * @return Roo.Component
536 getCmp : function(id){
537 return Roo.ComponentMgr.get(id);
540 num : function(v, defaultValue){
541 if(typeof v != 'number'){
547 destroy : function(){
548 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
552 as.removeAllListeners();
556 if(typeof as.purgeListeners == 'function'){
559 if(typeof as.destroy == 'function'){
566 // inpired by a similar function in mootools library
568 * Returns the type of object that is passed in. If the object passed in is null or undefined it
569 * return false otherwise it returns one of the following values:<ul>
570 * <li><b>string</b>: If the object passed is a string</li>
571 * <li><b>number</b>: If the object passed is a number</li>
572 * <li><b>boolean</b>: If the object passed is a boolean value</li>
573 * <li><b>function</b>: If the object passed is a function reference</li>
574 * <li><b>object</b>: If the object passed is an object</li>
575 * <li><b>array</b>: If the object passed is an array</li>
576 * <li><b>regexp</b>: If the object passed is a regular expression</li>
577 * <li><b>element</b>: If the object passed is a DOM Element</li>
578 * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
579 * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
580 * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
581 * @param {Mixed} object
585 if(o === undefined || o === null){
592 if(t == 'object' && o.nodeName) {
594 case 1: return 'element';
595 case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
598 if(t == 'object' || t == 'function') {
599 switch(o.constructor) {
600 case Array: return 'array';
601 case RegExp: return 'regexp';
603 if(typeof o.length == 'number' && typeof o.item == 'function') {
611 * Returns true if the passed value is null, undefined or an empty string (optional).
612 * @param {Mixed} value The value to test
613 * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
616 isEmpty : function(v, allowBlank){
617 return v === null || v === undefined || (!allowBlank ? v === '' : false);
625 isFirefox : isFirefox,
637 isBorderBox : isBorderBox,
639 isWindows : isWindows,
647 isAndroid : isAndroid,
652 * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
653 * you may want to set this to true.
656 useShims : ((isIE && !isIE7) || (isGecko && isMac)),
661 * Selects a single element as a Roo Element
662 * This is about as close as you can get to jQuery's $('do crazy stuff')
663 * @param {String} selector The selector/xpath query
664 * @param {Node} root (optional) The start of the query (defaults to document).
665 * @return {Roo.Element}
667 selectNode : function(selector, root)
669 var node = Roo.DomQuery.selectNode(selector,root);
670 return node ? Roo.get(node) : new Roo.Element(false);
678 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
679 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
682 "Roo.bootstrap.dash");
685 * Ext JS Library 1.1.1
686 * Copyright(c) 2006-2007, Ext JS, LLC.
688 * Originally Released Under LGPL - original licence link has changed is not relivant.
691 * <script type="text/javascript">
695 // wrappedn so fnCleanup is not in global scope...
697 function fnCleanUp() {
698 var p = Function.prototype;
699 delete p.createSequence;
701 delete p.createDelegate;
702 delete p.createCallback;
703 delete p.createInterceptor;
705 window.detachEvent("onunload", fnCleanUp);
707 window.attachEvent("onunload", fnCleanUp);
714 * These functions are available on every Function object (any JavaScript function).
716 Roo.apply(Function.prototype, {
718 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
719 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
720 * Will create a function that is bound to those 2 args.
721 * @return {Function} The new function
723 createCallback : function(/*args...*/){
724 // make args available, in function below
725 var args = arguments;
728 return method.apply(window, args);
733 * Creates a delegate (callback) that sets the scope to obj.
734 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
735 * Will create a function that is automatically scoped to this.
736 * @param {Object} obj (optional) The object for which the scope is set
737 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
738 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
739 * if a number the args are inserted at the specified position
740 * @return {Function} The new function
742 createDelegate : function(obj, args, appendArgs){
745 var callArgs = args || arguments;
746 if(appendArgs === true){
747 callArgs = Array.prototype.slice.call(arguments, 0);
748 callArgs = callArgs.concat(args);
749 }else if(typeof appendArgs == "number"){
750 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
751 var applyArgs = [appendArgs, 0].concat(args); // create method call params
752 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
754 return method.apply(obj || window, callArgs);
759 * Calls this function after the number of millseconds specified.
760 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
761 * @param {Object} obj (optional) The object for which the scope is set
762 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
763 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
764 * if a number the args are inserted at the specified position
765 * @return {Number} The timeout id that can be used with clearTimeout
767 defer : function(millis, obj, args, appendArgs){
768 var fn = this.createDelegate(obj, args, appendArgs);
770 return setTimeout(fn, millis);
776 * Create a combined function call sequence of the original function + the passed function.
777 * The resulting function returns the results of the original function.
778 * The passed fcn is called with the parameters of the original function
779 * @param {Function} fcn The function to sequence
780 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
781 * @return {Function} The new function
783 createSequence : function(fcn, scope){
784 if(typeof fcn != "function"){
789 var retval = method.apply(this || window, arguments);
790 fcn.apply(scope || this || window, arguments);
796 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
797 * The resulting function returns the results of the original function.
798 * The passed fcn is called with the parameters of the original function.
800 * @param {Function} fcn The function to call before the original
801 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
802 * @return {Function} The new function
804 createInterceptor : function(fcn, scope){
805 if(typeof fcn != "function"){
812 if(fcn.apply(scope || this || window, arguments) === false){
815 return method.apply(this || window, arguments);
821 * Ext JS Library 1.1.1
822 * Copyright(c) 2006-2007, Ext JS, LLC.
824 * Originally Released Under LGPL - original licence link has changed is not relivant.
827 * <script type="text/javascript">
830 Roo.applyIf(String, {
835 * Escapes the passed string for ' and \
836 * @param {String} string The string to escape
837 * @return {String} The escaped string
840 escape : function(string) {
841 return string.replace(/('|\\)/g, "\\$1");
845 * Pads the left side of a string with a specified character. This is especially useful
846 * for normalizing number and date strings. Example usage:
848 var s = String.leftPad('123', 5, '0');
849 // s now contains the string: '00123'
851 * @param {String} string The original string
852 * @param {Number} size The total length of the output string
853 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
854 * @return {String} The padded string
857 leftPad : function (val, size, ch) {
858 var result = new String(val);
859 if(ch === null || ch === undefined || ch === '') {
862 while (result.length < size) {
863 result = ch + result;
869 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
870 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
872 var cls = 'my-class', text = 'Some text';
873 var s = String.format('<div class="{0}">{1}</div>', cls, text);
874 // s now contains the string: '<div class="my-class">Some text</div>'
876 * @param {String} string The tokenized string to be formatted
877 * @param {String} value1 The value to replace token {0}
878 * @param {String} value2 Etc...
879 * @return {String} The formatted string
882 format : function(format){
883 var args = Array.prototype.slice.call(arguments, 1);
884 return format.replace(/\{(\d+)\}/g, function(m, i){
885 return Roo.util.Format.htmlEncode(args[i]);
893 * Utility function that allows you to easily switch a string between two alternating values. The passed value
894 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
895 * they are already different, the first value passed in is returned. Note that this method returns the new value
896 * but does not change the current string.
898 // alternate sort directions
899 sort = sort.toggle('ASC', 'DESC');
901 // instead of conditional logic:
902 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
904 * @param {String} value The value to compare to the current string
905 * @param {String} other The new value to use if the string already equals the first value passed in
906 * @return {String} The new value
909 String.prototype.toggle = function(value, other){
910 return this == value ? other : value;
915 * Remove invalid unicode characters from a string
917 * @return {String} The clean string
919 String.prototype.unicodeClean = function () {
920 return this.replace(/[\s\S]/g,
921 function(character) {
922 if (character.charCodeAt()< 256) {
926 encodeURIComponent(character);
937 * Ext JS Library 1.1.1
938 * Copyright(c) 2006-2007, Ext JS, LLC.
940 * Originally Released Under LGPL - original licence link has changed is not relivant.
943 * <script type="text/javascript">
949 Roo.applyIf(Number.prototype, {
951 * Checks whether or not the current number is within a desired range. If the number is already within the
952 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
953 * exceeded. Note that this method returns the constrained value but does not change the current number.
954 * @param {Number} min The minimum number in the range
955 * @param {Number} max The maximum number in the range
956 * @return {Number} The constrained value if outside the range, otherwise the current value
958 constrain : function(min, max){
959 return Math.min(Math.max(this, min), max);
963 * Ext JS Library 1.1.1
964 * Copyright(c) 2006-2007, Ext JS, LLC.
966 * Originally Released Under LGPL - original licence link has changed is not relivant.
969 * <script type="text/javascript">
974 Roo.applyIf(Array.prototype, {
977 * Checks whether or not the specified object exists in the array.
978 * @param {Object} o The object to check for
979 * @return {Number} The index of o in the array (or -1 if it is not found)
981 indexOf : function(o){
982 for (var i = 0, len = this.length; i < len; i++){
983 if(this[i] == o) { return i; }
989 * Removes the specified object from the array. If the object is not found nothing happens.
990 * @param {Object} o The object to remove
992 remove : function(o){
993 var index = this.indexOf(o);
995 this.splice(index, 1);
999 * Map (JS 1.6 compatibility)
1000 * @param {Function} function to call
1002 map : function(fun )
1004 var len = this.length >>> 0;
1005 if (typeof fun != "function") {
1006 throw new TypeError();
1008 var res = new Array(len);
1009 var thisp = arguments[1];
1010 for (var i = 0; i < len; i++)
1013 res[i] = fun.call(thisp, this[i], i, this);
1021 * @param {Array} o The array to compare to
1022 * @returns {Boolean} true if the same
1024 equals : function(b)
1026 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1033 if (this.length !== b.length) {
1037 // sort?? a.sort().equals(b.sort());
1039 for (var i = 0; i < this.length; ++i) {
1040 if (this[i] !== b[i]) {
1052 * Ext JS Library 1.1.1
1053 * Copyright(c) 2006-2007, Ext JS, LLC.
1055 * Originally Released Under LGPL - original licence link has changed is not relivant.
1058 * <script type="text/javascript">
1064 * The date parsing and format syntax is a subset of
1065 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1066 * supported will provide results equivalent to their PHP versions.
1068 * Following is the list of all currently supported formats:
1071 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1073 Format Output Description
1074 ------ ---------- --------------------------------------------------------------
1075 d 10 Day of the month, 2 digits with leading zeros
1076 D Wed A textual representation of a day, three letters
1077 j 10 Day of the month without leading zeros
1078 l Wednesday A full textual representation of the day of the week
1079 S th English ordinal day of month suffix, 2 chars (use with j)
1080 w 3 Numeric representation of the day of the week
1081 z 9 The julian date, or day of the year (0-365)
1082 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1083 F January A full textual representation of the month
1084 m 01 Numeric representation of a month, with leading zeros
1085 M Jan Month name abbreviation, three letters
1086 n 1 Numeric representation of a month, without leading zeros
1087 t 31 Number of days in the given month
1088 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1089 Y 2007 A full numeric representation of a year, 4 digits
1090 y 07 A two digit representation of a year
1091 a pm Lowercase Ante meridiem and Post meridiem
1092 A PM Uppercase Ante meridiem and Post meridiem
1093 g 3 12-hour format of an hour without leading zeros
1094 G 15 24-hour format of an hour without leading zeros
1095 h 03 12-hour format of an hour with leading zeros
1096 H 15 24-hour format of an hour with leading zeros
1097 i 05 Minutes with leading zeros
1098 s 01 Seconds, with leading zeros
1099 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1100 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1101 T CST Timezone setting of the machine running the code
1102 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1105 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1107 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1108 document.write(dt.format('Y-m-d')); //2007-01-10
1109 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1110 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A')); //Wednesday, the 10th of January 2007 03:05:01 PM
1113 * Here are some standard date/time patterns that you might find helpful. They
1114 * are not part of the source of Date.js, but to use them you can simply copy this
1115 * block of code into any script that is included after Date.js and they will also become
1116 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1119 ISO8601Long:"Y-m-d H:i:s",
1120 ISO8601Short:"Y-m-d",
1122 LongDate: "l, F d, Y",
1123 FullDateTime: "l, F d, Y g:i:s A",
1126 LongTime: "g:i:s A",
1127 SortableDateTime: "Y-m-d\\TH:i:s",
1128 UniversalSortableDateTime: "Y-m-d H:i:sO",
1135 var dt = new Date();
1136 document.write(dt.format(Date.patterns.ShortDate));
1141 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1142 * They generate precompiled functions from date formats instead of parsing and
1143 * processing the pattern every time you format a date. These functions are available
1144 * on every Date object (any javascript function).
1146 * The original article and download are here:
1147 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1154 Returns the number of milliseconds between this date and date
1155 @param {Date} date (optional) Defaults to now
1156 @return {Number} The diff in milliseconds
1157 @member Date getElapsed
1159 Date.prototype.getElapsed = function(date) {
1160 return Math.abs((date || new Date()).getTime()-this.getTime());
1162 // was in date file..
1166 Date.parseFunctions = {count:0};
1168 Date.parseRegexes = [];
1170 Date.formatFunctions = {count:0};
1173 Date.prototype.dateFormat = function(format) {
1174 if (Date.formatFunctions[format] == null) {
1175 Date.createNewFormat(format);
1177 var func = Date.formatFunctions[format];
1178 return this[func]();
1183 * Formats a date given the supplied format string
1184 * @param {String} format The format string
1185 * @return {String} The formatted date
1188 Date.prototype.format = Date.prototype.dateFormat;
1191 Date.createNewFormat = function(format) {
1192 var funcName = "format" + Date.formatFunctions.count++;
1193 Date.formatFunctions[format] = funcName;
1194 var code = "Date.prototype." + funcName + " = function(){return ";
1195 var special = false;
1197 for (var i = 0; i < format.length; ++i) {
1198 ch = format.charAt(i);
1199 if (!special && ch == "\\") {
1204 code += "'" + String.escape(ch) + "' + ";
1207 code += Date.getFormatCode(ch);
1210 /** eval:var:zzzzzzzzzzzzz */
1211 eval(code.substring(0, code.length - 3) + ";}");
1215 Date.getFormatCode = function(character) {
1216 switch (character) {
1218 return "String.leftPad(this.getDate(), 2, '0') + ";
1220 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1222 return "this.getDate() + ";
1224 return "Date.dayNames[this.getDay()] + ";
1226 return "this.getSuffix() + ";
1228 return "this.getDay() + ";
1230 return "this.getDayOfYear() + ";
1232 return "this.getWeekOfYear() + ";
1234 return "Date.monthNames[this.getMonth()] + ";
1236 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1238 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1240 return "(this.getMonth() + 1) + ";
1242 return "this.getDaysInMonth() + ";
1244 return "(this.isLeapYear() ? 1 : 0) + ";
1246 return "this.getFullYear() + ";
1248 return "('' + this.getFullYear()).substring(2, 4) + ";
1250 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1252 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1254 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1256 return "this.getHours() + ";
1258 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1260 return "String.leftPad(this.getHours(), 2, '0') + ";
1262 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1264 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1266 return "this.getGMTOffset() + ";
1268 return "this.getGMTColonOffset() + ";
1270 return "this.getTimezone() + ";
1272 return "(this.getTimezoneOffset() * -60) + ";
1274 return "'" + String.escape(character) + "' + ";
1279 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1280 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1281 * the date format that is not specified will default to the current date value for that part. Time parts can also
1282 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1283 * string or the parse operation will fail.
1286 //dt = Fri May 25 2007 (current date)
1287 var dt = new Date();
1289 //dt = Thu May 25 2006 (today's month/day in 2006)
1290 dt = Date.parseDate("2006", "Y");
1292 //dt = Sun Jan 15 2006 (all date parts specified)
1293 dt = Date.parseDate("2006-1-15", "Y-m-d");
1295 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1296 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1298 * @param {String} input The unparsed date as a string
1299 * @param {String} format The format the date is in
1300 * @return {Date} The parsed date
1303 Date.parseDate = function(input, format) {
1304 if (Date.parseFunctions[format] == null) {
1305 Date.createParser(format);
1307 var func = Date.parseFunctions[format];
1308 return Date[func](input);
1314 Date.createParser = function(format) {
1315 var funcName = "parse" + Date.parseFunctions.count++;
1316 var regexNum = Date.parseRegexes.length;
1317 var currentGroup = 1;
1318 Date.parseFunctions[format] = funcName;
1320 var code = "Date." + funcName + " = function(input){\n"
1321 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1322 + "var d = new Date();\n"
1323 + "y = d.getFullYear();\n"
1324 + "m = d.getMonth();\n"
1325 + "d = d.getDate();\n"
1326 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1327 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1328 + "if (results && results.length > 0) {";
1331 var special = false;
1333 for (var i = 0; i < format.length; ++i) {
1334 ch = format.charAt(i);
1335 if (!special && ch == "\\") {
1340 regex += String.escape(ch);
1343 var obj = Date.formatCodeToRegex(ch, currentGroup);
1344 currentGroup += obj.g;
1346 if (obj.g && obj.c) {
1352 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1353 + "{v = new Date(y, m, d, h, i, s);}\n"
1354 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1355 + "{v = new Date(y, m, d, h, i);}\n"
1356 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1357 + "{v = new Date(y, m, d, h);}\n"
1358 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1359 + "{v = new Date(y, m, d);}\n"
1360 + "else if (y >= 0 && m >= 0)\n"
1361 + "{v = new Date(y, m);}\n"
1362 + "else if (y >= 0)\n"
1363 + "{v = new Date(y);}\n"
1364 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1365 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1366 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1369 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1370 /** eval:var:zzzzzzzzzzzzz */
1375 Date.formatCodeToRegex = function(character, currentGroup) {
1376 switch (character) {
1380 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1383 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1384 s:"(\\d{1,2})"}; // day of month without leading zeroes
1387 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1388 s:"(\\d{2})"}; // day of month with leading zeroes
1392 s:"(?:" + Date.dayNames.join("|") + ")"};
1396 s:"(?:st|nd|rd|th)"};
1411 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1412 s:"(" + Date.monthNames.join("|") + ")"};
1415 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1416 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1419 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1420 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1423 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1424 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1435 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1439 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1440 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1444 c:"if (results[" + currentGroup + "] == 'am') {\n"
1445 + "if (h == 12) { h = 0; }\n"
1446 + "} else { if (h < 12) { h += 12; }}",
1450 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1451 + "if (h == 12) { h = 0; }\n"
1452 + "} else { if (h < 12) { h += 12; }}",
1457 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1458 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1462 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1463 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1466 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1470 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1475 "o = results[", currentGroup, "];\n",
1476 "var sn = o.substring(0,1);\n", // get + / - sign
1477 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1478 "var mn = o.substring(3,5) % 60;\n", // get minutes
1479 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1480 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1482 s:"([+\-]\\d{2,4})"};
1488 "o = results[", currentGroup, "];\n",
1489 "var sn = o.substring(0,1);\n",
1490 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1491 "var mn = o.substring(4,6) % 60;\n",
1492 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1493 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1499 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1502 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1503 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1504 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1508 s:String.escape(character)};
1513 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1514 * @return {String} The abbreviated timezone name (e.g. 'CST')
1516 Date.prototype.getTimezone = function() {
1517 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1521 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1522 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1524 Date.prototype.getGMTOffset = function() {
1525 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1526 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1527 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1531 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1532 * @return {String} 2-characters representing hours and 2-characters representing minutes
1533 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1535 Date.prototype.getGMTColonOffset = function() {
1536 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1537 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1539 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1543 * Get the numeric day number of the year, adjusted for leap year.
1544 * @return {Number} 0 through 364 (365 in leap years)
1546 Date.prototype.getDayOfYear = function() {
1548 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1549 for (var i = 0; i < this.getMonth(); ++i) {
1550 num += Date.daysInMonth[i];
1552 return num + this.getDate() - 1;
1556 * Get the string representation of the numeric week number of the year
1557 * (equivalent to the format specifier 'W').
1558 * @return {String} '00' through '52'
1560 Date.prototype.getWeekOfYear = function() {
1561 // Skip to Thursday of this week
1562 var now = this.getDayOfYear() + (4 - this.getDay());
1563 // Find the first Thursday of the year
1564 var jan1 = new Date(this.getFullYear(), 0, 1);
1565 var then = (7 - jan1.getDay() + 4);
1566 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1570 * Whether or not the current date is in a leap year.
1571 * @return {Boolean} True if the current date is in a leap year, else false
1573 Date.prototype.isLeapYear = function() {
1574 var year = this.getFullYear();
1575 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1579 * Get the first day of the current month, adjusted for leap year. The returned value
1580 * is the numeric day index within the week (0-6) which can be used in conjunction with
1581 * the {@link #monthNames} array to retrieve the textual day name.
1584 var dt = new Date('1/10/2007');
1585 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1587 * @return {Number} The day number (0-6)
1589 Date.prototype.getFirstDayOfMonth = function() {
1590 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1591 return (day < 0) ? (day + 7) : day;
1595 * Get the last day of the current month, adjusted for leap year. The returned value
1596 * is the numeric day index within the week (0-6) which can be used in conjunction with
1597 * the {@link #monthNames} array to retrieve the textual day name.
1600 var dt = new Date('1/10/2007');
1601 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1603 * @return {Number} The day number (0-6)
1605 Date.prototype.getLastDayOfMonth = function() {
1606 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1607 return (day < 0) ? (day + 7) : day;
1612 * Get the first date of this date's month
1615 Date.prototype.getFirstDateOfMonth = function() {
1616 return new Date(this.getFullYear(), this.getMonth(), 1);
1620 * Get the last date of this date's month
1623 Date.prototype.getLastDateOfMonth = function() {
1624 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1627 * Get the number of days in the current month, adjusted for leap year.
1628 * @return {Number} The number of days in the month
1630 Date.prototype.getDaysInMonth = function() {
1631 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1632 return Date.daysInMonth[this.getMonth()];
1636 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1637 * @return {String} 'st, 'nd', 'rd' or 'th'
1639 Date.prototype.getSuffix = function() {
1640 switch (this.getDate()) {
1657 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1660 * An array of textual month names.
1661 * Override these values for international dates, for example...
1662 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1681 * An array of textual day names.
1682 * Override these values for international dates, for example...
1683 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1699 Date.monthNumbers = {
1714 * Creates and returns a new Date instance with the exact same date value as the called instance.
1715 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1716 * variable will also be changed. When the intention is to create a new variable that will not
1717 * modify the original instance, you should create a clone.
1719 * Example of correctly cloning a date:
1722 var orig = new Date('10/1/2006');
1725 document.write(orig); //returns 'Thu Oct 05 2006'!
1728 var orig = new Date('10/1/2006');
1729 var copy = orig.clone();
1731 document.write(orig); //returns 'Thu Oct 01 2006'
1733 * @return {Date} The new Date instance
1735 Date.prototype.clone = function() {
1736 return new Date(this.getTime());
1740 * Clears any time information from this date
1741 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1742 @return {Date} this or the clone
1744 Date.prototype.clearTime = function(clone){
1746 return this.clone().clearTime();
1751 this.setMilliseconds(0);
1756 // safari setMonth is broken -- check that this is only donw once...
1757 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1758 Date.brokenSetMonth = Date.prototype.setMonth;
1759 Date.prototype.setMonth = function(num){
1761 var n = Math.ceil(-num);
1762 var back_year = Math.ceil(n/12);
1763 var month = (n % 12) ? 12 - n % 12 : 0 ;
1764 this.setFullYear(this.getFullYear() - back_year);
1765 return Date.brokenSetMonth.call(this, month);
1767 return Date.brokenSetMonth.apply(this, arguments);
1772 /** Date interval constant
1776 /** Date interval constant
1780 /** Date interval constant
1784 /** Date interval constant
1788 /** Date interval constant
1792 /** Date interval constant
1796 /** Date interval constant
1802 * Provides a convenient method of performing basic date arithmetic. This method
1803 * does not modify the Date instance being called - it creates and returns
1804 * a new Date instance containing the resulting date value.
1809 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1810 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1812 //Negative values will subtract correctly:
1813 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1814 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1816 //You can even chain several calls together in one line!
1817 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1818 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1821 * @param {String} interval A valid date interval enum value
1822 * @param {Number} value The amount to add to the current date
1823 * @return {Date} The new Date instance
1825 Date.prototype.add = function(interval, value){
1826 var d = this.clone();
1827 if (!interval || value === 0) { return d; }
1828 switch(interval.toLowerCase()){
1830 d.setMilliseconds(this.getMilliseconds() + value);
1833 d.setSeconds(this.getSeconds() + value);
1836 d.setMinutes(this.getMinutes() + value);
1839 d.setHours(this.getHours() + value);
1842 d.setDate(this.getDate() + value);
1845 var day = this.getDate();
1847 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1850 d.setMonth(this.getMonth() + value);
1853 d.setFullYear(this.getFullYear() + value);
1860 * Ext JS Library 1.1.1
1861 * Copyright(c) 2006-2007, Ext JS, LLC.
1863 * Originally Released Under LGPL - original licence link has changed is not relivant.
1866 * <script type="text/javascript">
1870 * @class Roo.lib.Dom
1873 * Dom utils (from YIU afaik)
1878 * Get the view width
1879 * @param {Boolean} full True will get the full document, otherwise it's the view width
1880 * @return {Number} The width
1883 getViewWidth : function(full) {
1884 return full ? this.getDocumentWidth() : this.getViewportWidth();
1887 * Get the view height
1888 * @param {Boolean} full True will get the full document, otherwise it's the view height
1889 * @return {Number} The height
1891 getViewHeight : function(full) {
1892 return full ? this.getDocumentHeight() : this.getViewportHeight();
1895 getDocumentHeight: function() {
1896 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1897 return Math.max(scrollHeight, this.getViewportHeight());
1900 getDocumentWidth: function() {
1901 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1902 return Math.max(scrollWidth, this.getViewportWidth());
1905 getViewportHeight: function() {
1906 var height = self.innerHeight;
1907 var mode = document.compatMode;
1909 if ((mode || Roo.isIE) && !Roo.isOpera) {
1910 height = (mode == "CSS1Compat") ?
1911 document.documentElement.clientHeight :
1912 document.body.clientHeight;
1918 getViewportWidth: function() {
1919 var width = self.innerWidth;
1920 var mode = document.compatMode;
1922 if (mode || Roo.isIE) {
1923 width = (mode == "CSS1Compat") ?
1924 document.documentElement.clientWidth :
1925 document.body.clientWidth;
1930 isAncestor : function(p, c) {
1937 if (p.contains && !Roo.isSafari) {
1938 return p.contains(c);
1939 } else if (p.compareDocumentPosition) {
1940 return !!(p.compareDocumentPosition(c) & 16);
1942 var parent = c.parentNode;
1947 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1950 parent = parent.parentNode;
1956 getRegion : function(el) {
1957 return Roo.lib.Region.getRegion(el);
1960 getY : function(el) {
1961 return this.getXY(el)[1];
1964 getX : function(el) {
1965 return this.getXY(el)[0];
1968 getXY : function(el) {
1969 var p, pe, b, scroll, bd = document.body;
1970 el = Roo.getDom(el);
1971 var fly = Roo.lib.AnimBase.fly;
1972 if (el.getBoundingClientRect) {
1973 b = el.getBoundingClientRect();
1974 scroll = fly(document).getScroll();
1975 return [b.left + scroll.left, b.top + scroll.top];
1981 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1988 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1995 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1996 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2003 if (p != el && pe.getStyle('overflow') != 'visible') {
2011 if (Roo.isSafari && hasAbsolute) {
2016 if (Roo.isGecko && !hasAbsolute) {
2018 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2019 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2023 while (p && p != bd) {
2024 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2036 setXY : function(el, xy) {
2037 el = Roo.fly(el, '_setXY');
2039 var pts = el.translatePoints(xy);
2040 if (xy[0] !== false) {
2041 el.dom.style.left = pts.left + "px";
2043 if (xy[1] !== false) {
2044 el.dom.style.top = pts.top + "px";
2048 setX : function(el, x) {
2049 this.setXY(el, [x, false]);
2052 setY : function(el, y) {
2053 this.setXY(el, [false, y]);
2057 * Portions of this file are based on pieces of Yahoo User Interface Library
2058 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2059 * YUI licensed under the BSD License:
2060 * http://developer.yahoo.net/yui/license.txt
2061 * <script type="text/javascript">
2065 Roo.lib.Event = function() {
2066 var loadComplete = false;
2068 var unloadListeners = [];
2070 var onAvailStack = [];
2072 var lastError = null;
2085 startInterval: function() {
2086 if (!this._interval) {
2088 var callback = function() {
2089 self._tryPreloadAttach();
2091 this._interval = setInterval(callback, this.POLL_INTERVAL);
2096 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2097 onAvailStack.push({ id: p_id,
2100 override: p_override,
2101 checkReady: false });
2103 retryCount = this.POLL_RETRYS;
2104 this.startInterval();
2108 addListener: function(el, eventName, fn) {
2109 el = Roo.getDom(el);
2114 if ("unload" == eventName) {
2115 unloadListeners[unloadListeners.length] =
2116 [el, eventName, fn];
2120 var wrappedFn = function(e) {
2121 return fn(Roo.lib.Event.getEvent(e));
2124 var li = [el, eventName, fn, wrappedFn];
2126 var index = listeners.length;
2127 listeners[index] = li;
2129 this.doAdd(el, eventName, wrappedFn, false);
2135 removeListener: function(el, eventName, fn) {
2138 el = Roo.getDom(el);
2141 return this.purgeElement(el, false, eventName);
2145 if ("unload" == eventName) {
2147 for (i = 0,len = unloadListeners.length; i < len; i++) {
2148 var li = unloadListeners[i];
2151 li[1] == eventName &&
2153 unloadListeners.splice(i, 1);
2161 var cacheItem = null;
2164 var index = arguments[3];
2166 if ("undefined" == typeof index) {
2167 index = this._getCacheIndex(el, eventName, fn);
2171 cacheItem = listeners[index];
2174 if (!el || !cacheItem) {
2178 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2180 delete listeners[index][this.WFN];
2181 delete listeners[index][this.FN];
2182 listeners.splice(index, 1);
2189 getTarget: function(ev, resolveTextNode) {
2190 ev = ev.browserEvent || ev;
2191 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2192 var t = ev.target || ev.srcElement;
2193 return this.resolveTextNode(t);
2197 resolveTextNode: function(node) {
2198 if (Roo.isSafari && node && 3 == node.nodeType) {
2199 return node.parentNode;
2206 getPageX: function(ev) {
2207 ev = ev.browserEvent || ev;
2208 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2210 if (!x && 0 !== x) {
2211 x = ev.clientX || 0;
2214 x += this.getScroll()[1];
2222 getPageY: function(ev) {
2223 ev = ev.browserEvent || ev;
2224 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2226 if (!y && 0 !== y) {
2227 y = ev.clientY || 0;
2230 y += this.getScroll()[0];
2239 getXY: function(ev) {
2240 ev = ev.browserEvent || ev;
2241 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2242 return [this.getPageX(ev), this.getPageY(ev)];
2246 getRelatedTarget: function(ev) {
2247 ev = ev.browserEvent || ev;
2248 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2249 var t = ev.relatedTarget;
2251 if (ev.type == "mouseout") {
2253 } else if (ev.type == "mouseover") {
2258 return this.resolveTextNode(t);
2262 getTime: function(ev) {
2263 ev = ev.browserEvent || ev;
2264 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2266 var t = new Date().getTime();
2270 this.lastError = ex;
2279 stopEvent: function(ev) {
2280 this.stopPropagation(ev);
2281 this.preventDefault(ev);
2285 stopPropagation: function(ev) {
2286 ev = ev.browserEvent || ev;
2287 if (ev.stopPropagation) {
2288 ev.stopPropagation();
2290 ev.cancelBubble = true;
2295 preventDefault: function(ev) {
2296 ev = ev.browserEvent || ev;
2297 if(ev.preventDefault) {
2298 ev.preventDefault();
2300 ev.returnValue = false;
2305 getEvent: function(e) {
2306 var ev = e || window.event;
2308 var c = this.getEvent.caller;
2310 ev = c.arguments[0];
2311 if (ev && Event == ev.constructor) {
2321 getCharCode: function(ev) {
2322 ev = ev.browserEvent || ev;
2323 return ev.charCode || ev.keyCode || 0;
2327 _getCacheIndex: function(el, eventName, fn) {
2328 for (var i = 0,len = listeners.length; i < len; ++i) {
2329 var li = listeners[i];
2331 li[this.FN] == fn &&
2332 li[this.EL] == el &&
2333 li[this.TYPE] == eventName) {
2345 getEl: function(id) {
2346 return document.getElementById(id);
2350 clearCache: function() {
2354 _load: function(e) {
2355 loadComplete = true;
2356 var EU = Roo.lib.Event;
2360 EU.doRemove(window, "load", EU._load);
2365 _tryPreloadAttach: function() {
2374 var tryAgain = !loadComplete;
2376 tryAgain = (retryCount > 0);
2381 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2382 var item = onAvailStack[i];
2384 var el = this.getEl(item.id);
2387 if (!item.checkReady ||
2390 (document && document.body)) {
2393 if (item.override) {
2394 if (item.override === true) {
2397 scope = item.override;
2400 item.fn.call(scope, item.obj);
2401 onAvailStack[i] = null;
2404 notAvail.push(item);
2409 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2413 this.startInterval();
2415 clearInterval(this._interval);
2416 this._interval = null;
2419 this.locked = false;
2426 purgeElement: function(el, recurse, eventName) {
2427 var elListeners = this.getListeners(el, eventName);
2429 for (var i = 0,len = elListeners.length; i < len; ++i) {
2430 var l = elListeners[i];
2431 this.removeListener(el, l.type, l.fn);
2435 if (recurse && el && el.childNodes) {
2436 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2437 this.purgeElement(el.childNodes[i], recurse, eventName);
2443 getListeners: function(el, eventName) {
2444 var results = [], searchLists;
2446 searchLists = [listeners, unloadListeners];
2447 } else if (eventName == "unload") {
2448 searchLists = [unloadListeners];
2450 searchLists = [listeners];
2453 for (var j = 0; j < searchLists.length; ++j) {
2454 var searchList = searchLists[j];
2455 if (searchList && searchList.length > 0) {
2456 for (var i = 0,len = searchList.length; i < len; ++i) {
2457 var l = searchList[i];
2458 if (l && l[this.EL] === el &&
2459 (!eventName || eventName === l[this.TYPE])) {
2464 adjust: l[this.ADJ_SCOPE],
2472 return (results.length) ? results : null;
2476 _unload: function(e) {
2478 var EU = Roo.lib.Event, i, j, l, len, index;
2480 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2481 l = unloadListeners[i];
2484 if (l[EU.ADJ_SCOPE]) {
2485 if (l[EU.ADJ_SCOPE] === true) {
2488 scope = l[EU.ADJ_SCOPE];
2491 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2492 unloadListeners[i] = null;
2498 unloadListeners = null;
2500 if (listeners && listeners.length > 0) {
2501 j = listeners.length;
2504 l = listeners[index];
2506 EU.removeListener(l[EU.EL], l[EU.TYPE],
2516 EU.doRemove(window, "unload", EU._unload);
2521 getScroll: function() {
2522 var dd = document.documentElement, db = document.body;
2523 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2524 return [dd.scrollTop, dd.scrollLeft];
2526 return [db.scrollTop, db.scrollLeft];
2533 doAdd: function () {
2534 if (window.addEventListener) {
2535 return function(el, eventName, fn, capture) {
2536 el.addEventListener(eventName, fn, (capture));
2538 } else if (window.attachEvent) {
2539 return function(el, eventName, fn, capture) {
2540 el.attachEvent("on" + eventName, fn);
2549 doRemove: function() {
2550 if (window.removeEventListener) {
2551 return function (el, eventName, fn, capture) {
2552 el.removeEventListener(eventName, fn, (capture));
2554 } else if (window.detachEvent) {
2555 return function (el, eventName, fn) {
2556 el.detachEvent("on" + eventName, fn);
2568 var E = Roo.lib.Event;
2569 E.on = E.addListener;
2570 E.un = E.removeListener;
2572 if (document && document.body) {
2575 E.doAdd(window, "load", E._load);
2577 E.doAdd(window, "unload", E._unload);
2578 E._tryPreloadAttach();
2582 * Portions of this file are based on pieces of Yahoo User Interface Library
2583 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2584 * YUI licensed under the BSD License:
2585 * http://developer.yahoo.net/yui/license.txt
2586 * <script type="text/javascript">
2592 * @class Roo.lib.Ajax
2599 request : function(method, uri, cb, data, options) {
2601 var hs = options.headers;
2604 if(hs.hasOwnProperty(h)){
2605 this.initHeader(h, hs[h], false);
2609 if(options.xmlData){
2610 this.initHeader('Content-Type', 'text/xml', false);
2612 data = options.xmlData;
2616 return this.asyncRequest(method, uri, cb, data);
2619 serializeForm : function(form) {
2620 if(typeof form == 'string') {
2621 form = (document.getElementById(form) || document.forms[form]);
2624 var el, name, val, disabled, data = '', hasSubmit = false;
2625 for (var i = 0; i < form.elements.length; i++) {
2626 el = form.elements[i];
2627 disabled = form.elements[i].disabled;
2628 name = form.elements[i].name;
2629 val = form.elements[i].value;
2631 if (!disabled && name){
2635 case 'select-multiple':
2636 for (var j = 0; j < el.options.length; j++) {
2637 if (el.options[j].selected) {
2639 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2642 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2650 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2663 if(hasSubmit == false) {
2664 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2669 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2674 data = data.substr(0, data.length - 1);
2682 useDefaultHeader:true,
2684 defaultPostHeader:'application/x-www-form-urlencoded',
2686 useDefaultXhrHeader:true,
2688 defaultXhrHeader:'XMLHttpRequest',
2690 hasDefaultHeaders:true,
2702 setProgId:function(id)
2704 this.activeX.unshift(id);
2707 setDefaultPostHeader:function(b)
2709 this.useDefaultHeader = b;
2712 setDefaultXhrHeader:function(b)
2714 this.useDefaultXhrHeader = b;
2717 setPollingInterval:function(i)
2719 if (typeof i == 'number' && isFinite(i)) {
2720 this.pollInterval = i;
2724 createXhrObject:function(transactionId)
2730 http = new XMLHttpRequest();
2732 obj = { conn:http, tId:transactionId };
2736 for (var i = 0; i < this.activeX.length; ++i) {
2740 http = new ActiveXObject(this.activeX[i]);
2742 obj = { conn:http, tId:transactionId };
2755 getConnectionObject:function()
2758 var tId = this.transactionId;
2762 o = this.createXhrObject(tId);
2764 this.transactionId++;
2775 asyncRequest:function(method, uri, callback, postData)
2777 var o = this.getConnectionObject();
2783 o.conn.open(method, uri, true);
2785 if (this.useDefaultXhrHeader) {
2786 if (!this.defaultHeaders['X-Requested-With']) {
2787 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2791 if(postData && this.useDefaultHeader){
2792 this.initHeader('Content-Type', this.defaultPostHeader);
2795 if (this.hasDefaultHeaders || this.hasHeaders) {
2799 this.handleReadyState(o, callback);
2800 o.conn.send(postData || null);
2806 handleReadyState:function(o, callback)
2810 if (callback && callback.timeout) {
2812 this.timeout[o.tId] = window.setTimeout(function() {
2813 oConn.abort(o, callback, true);
2814 }, callback.timeout);
2817 this.poll[o.tId] = window.setInterval(
2819 if (o.conn && o.conn.readyState == 4) {
2820 window.clearInterval(oConn.poll[o.tId]);
2821 delete oConn.poll[o.tId];
2823 if(callback && callback.timeout) {
2824 window.clearTimeout(oConn.timeout[o.tId]);
2825 delete oConn.timeout[o.tId];
2828 oConn.handleTransactionResponse(o, callback);
2831 , this.pollInterval);
2834 handleTransactionResponse:function(o, callback, isAbort)
2838 this.releaseObject(o);
2842 var httpStatus, responseObject;
2846 if (o.conn.status !== undefined && o.conn.status != 0) {
2847 httpStatus = o.conn.status;
2859 if (httpStatus >= 200 && httpStatus < 300) {
2860 responseObject = this.createResponseObject(o, callback.argument);
2861 if (callback.success) {
2862 if (!callback.scope) {
2863 callback.success(responseObject);
2868 callback.success.apply(callback.scope, [responseObject]);
2873 switch (httpStatus) {
2881 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2882 if (callback.failure) {
2883 if (!callback.scope) {
2884 callback.failure(responseObject);
2887 callback.failure.apply(callback.scope, [responseObject]);
2892 responseObject = this.createResponseObject(o, callback.argument);
2893 if (callback.failure) {
2894 if (!callback.scope) {
2895 callback.failure(responseObject);
2898 callback.failure.apply(callback.scope, [responseObject]);
2904 this.releaseObject(o);
2905 responseObject = null;
2908 createResponseObject:function(o, callbackArg)
2915 var headerStr = o.conn.getAllResponseHeaders();
2916 var header = headerStr.split('\n');
2917 for (var i = 0; i < header.length; i++) {
2918 var delimitPos = header[i].indexOf(':');
2919 if (delimitPos != -1) {
2920 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2928 obj.status = o.conn.status;
2929 obj.statusText = o.conn.statusText;
2930 obj.getResponseHeader = headerObj;
2931 obj.getAllResponseHeaders = headerStr;
2932 obj.responseText = o.conn.responseText;
2933 obj.responseXML = o.conn.responseXML;
2935 if (typeof callbackArg !== undefined) {
2936 obj.argument = callbackArg;
2942 createExceptionObject:function(tId, callbackArg, isAbort)
2945 var COMM_ERROR = 'communication failure';
2946 var ABORT_CODE = -1;
2947 var ABORT_ERROR = 'transaction aborted';
2953 obj.status = ABORT_CODE;
2954 obj.statusText = ABORT_ERROR;
2957 obj.status = COMM_CODE;
2958 obj.statusText = COMM_ERROR;
2962 obj.argument = callbackArg;
2968 initHeader:function(label, value, isDefault)
2970 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2972 if (headerObj[label] === undefined) {
2973 headerObj[label] = value;
2978 headerObj[label] = value + "," + headerObj[label];
2982 this.hasDefaultHeaders = true;
2985 this.hasHeaders = true;
2990 setHeader:function(o)
2992 if (this.hasDefaultHeaders) {
2993 for (var prop in this.defaultHeaders) {
2994 if (this.defaultHeaders.hasOwnProperty(prop)) {
2995 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3000 if (this.hasHeaders) {
3001 for (var prop in this.headers) {
3002 if (this.headers.hasOwnProperty(prop)) {
3003 o.conn.setRequestHeader(prop, this.headers[prop]);
3007 this.hasHeaders = false;
3011 resetDefaultHeaders:function() {
3012 delete this.defaultHeaders;
3013 this.defaultHeaders = {};
3014 this.hasDefaultHeaders = false;
3017 abort:function(o, callback, isTimeout)
3019 if(this.isCallInProgress(o)) {
3021 window.clearInterval(this.poll[o.tId]);
3022 delete this.poll[o.tId];
3024 delete this.timeout[o.tId];
3027 this.handleTransactionResponse(o, callback, true);
3037 isCallInProgress:function(o)
3040 return o.conn.readyState != 4 && o.conn.readyState != 0;
3049 releaseObject:function(o)
3058 'MSXML2.XMLHTTP.3.0',
3066 * Portions of this file are based on pieces of Yahoo User Interface Library
3067 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3068 * YUI licensed under the BSD License:
3069 * http://developer.yahoo.net/yui/license.txt
3070 * <script type="text/javascript">
3074 Roo.lib.Region = function(t, r, b, l) {
3084 Roo.lib.Region.prototype = {
3085 contains : function(region) {
3086 return ( region.left >= this.left &&
3087 region.right <= this.right &&
3088 region.top >= this.top &&
3089 region.bottom <= this.bottom );
3093 getArea : function() {
3094 return ( (this.bottom - this.top) * (this.right - this.left) );
3097 intersect : function(region) {
3098 var t = Math.max(this.top, region.top);
3099 var r = Math.min(this.right, region.right);
3100 var b = Math.min(this.bottom, region.bottom);
3101 var l = Math.max(this.left, region.left);
3103 if (b >= t && r >= l) {
3104 return new Roo.lib.Region(t, r, b, l);
3109 union : function(region) {
3110 var t = Math.min(this.top, region.top);
3111 var r = Math.max(this.right, region.right);
3112 var b = Math.max(this.bottom, region.bottom);
3113 var l = Math.min(this.left, region.left);
3115 return new Roo.lib.Region(t, r, b, l);
3118 adjust : function(t, l, b, r) {
3127 Roo.lib.Region.getRegion = function(el) {
3128 var p = Roo.lib.Dom.getXY(el);
3131 var r = p[0] + el.offsetWidth;
3132 var b = p[1] + el.offsetHeight;
3135 return new Roo.lib.Region(t, r, b, l);
3138 * Portions of this file are based on pieces of Yahoo User Interface Library
3139 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3140 * YUI licensed under the BSD License:
3141 * http://developer.yahoo.net/yui/license.txt
3142 * <script type="text/javascript">
3145 //@@dep Roo.lib.Region
3148 Roo.lib.Point = function(x, y) {
3149 if (x instanceof Array) {
3153 this.x = this.right = this.left = this[0] = x;
3154 this.y = this.top = this.bottom = this[1] = y;
3157 Roo.lib.Point.prototype = new Roo.lib.Region();
3159 * Portions of this file are based on pieces of Yahoo User Interface Library
3160 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3161 * YUI licensed under the BSD License:
3162 * http://developer.yahoo.net/yui/license.txt
3163 * <script type="text/javascript">
3170 scroll : function(el, args, duration, easing, cb, scope) {
3171 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3174 motion : function(el, args, duration, easing, cb, scope) {
3175 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3178 color : function(el, args, duration, easing, cb, scope) {
3179 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3182 run : function(el, args, duration, easing, cb, scope, type) {
3183 type = type || Roo.lib.AnimBase;
3184 if (typeof easing == "string") {
3185 easing = Roo.lib.Easing[easing];
3187 var anim = new type(el, args, duration, easing);
3188 anim.animateX(function() {
3189 Roo.callback(cb, scope);
3195 * Portions of this file are based on pieces of Yahoo User Interface Library
3196 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3197 * YUI licensed under the BSD License:
3198 * http://developer.yahoo.net/yui/license.txt
3199 * <script type="text/javascript">
3207 if (!libFlyweight) {
3208 libFlyweight = new Roo.Element.Flyweight();
3210 libFlyweight.dom = el;
3211 return libFlyweight;
3214 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3218 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3220 this.init(el, attributes, duration, method);
3224 Roo.lib.AnimBase.fly = fly;
3228 Roo.lib.AnimBase.prototype = {
3230 toString: function() {
3231 var el = this.getEl();
3232 var id = el.id || el.tagName;
3233 return ("Anim " + id);
3237 noNegatives: /width|height|opacity|padding/i,
3238 offsetAttribute: /^((width|height)|(top|left))$/,
3239 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3240 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3244 doMethod: function(attr, start, end) {
3245 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3249 setAttribute: function(attr, val, unit) {
3250 if (this.patterns.noNegatives.test(attr)) {
3251 val = (val > 0) ? val : 0;
3254 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3258 getAttribute: function(attr) {
3259 var el = this.getEl();
3260 var val = fly(el).getStyle(attr);
3262 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3263 return parseFloat(val);
3266 var a = this.patterns.offsetAttribute.exec(attr) || [];
3267 var pos = !!( a[3] );
3268 var box = !!( a[2] );
3271 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3272 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3281 getDefaultUnit: function(attr) {
3282 if (this.patterns.defaultUnit.test(attr)) {
3289 animateX : function(callback, scope) {
3290 var f = function() {
3291 this.onComplete.removeListener(f);
3292 if (typeof callback == "function") {
3293 callback.call(scope || this, this);
3296 this.onComplete.addListener(f, this);
3301 setRuntimeAttribute: function(attr) {
3304 var attributes = this.attributes;
3306 this.runtimeAttributes[attr] = {};
3308 var isset = function(prop) {
3309 return (typeof prop !== 'undefined');
3312 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3316 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3319 if (isset(attributes[attr]['to'])) {
3320 end = attributes[attr]['to'];
3321 } else if (isset(attributes[attr]['by'])) {
3322 if (start.constructor == Array) {
3324 for (var i = 0, len = start.length; i < len; ++i) {
3325 end[i] = start[i] + attributes[attr]['by'][i];
3328 end = start + attributes[attr]['by'];
3332 this.runtimeAttributes[attr].start = start;
3333 this.runtimeAttributes[attr].end = end;
3336 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3340 init: function(el, attributes, duration, method) {
3342 var isAnimated = false;
3345 var startTime = null;
3348 var actualFrames = 0;
3351 el = Roo.getDom(el);
3354 this.attributes = attributes || {};
3357 this.duration = duration || 1;
3360 this.method = method || Roo.lib.Easing.easeNone;
3363 this.useSeconds = true;
3366 this.currentFrame = 0;
3369 this.totalFrames = Roo.lib.AnimMgr.fps;
3372 this.getEl = function() {
3377 this.isAnimated = function() {
3382 this.getStartTime = function() {
3386 this.runtimeAttributes = {};
3389 this.animate = function() {
3390 if (this.isAnimated()) {
3394 this.currentFrame = 0;
3396 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3398 Roo.lib.AnimMgr.registerElement(this);
3402 this.stop = function(finish) {
3404 this.currentFrame = this.totalFrames;
3405 this._onTween.fire();
3407 Roo.lib.AnimMgr.stop(this);
3410 var onStart = function() {
3411 this.onStart.fire();
3413 this.runtimeAttributes = {};
3414 for (var attr in this.attributes) {
3415 this.setRuntimeAttribute(attr);
3420 startTime = new Date();
3424 var onTween = function() {
3426 duration: new Date() - this.getStartTime(),
3427 currentFrame: this.currentFrame
3430 data.toString = function() {
3432 'duration: ' + data.duration +
3433 ', currentFrame: ' + data.currentFrame
3437 this.onTween.fire(data);
3439 var runtimeAttributes = this.runtimeAttributes;
3441 for (var attr in runtimeAttributes) {
3442 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3448 var onComplete = function() {
3449 var actual_duration = (new Date() - startTime) / 1000 ;
3452 duration: actual_duration,
3453 frames: actualFrames,
3454 fps: actualFrames / actual_duration
3457 data.toString = function() {
3459 'duration: ' + data.duration +
3460 ', frames: ' + data.frames +
3461 ', fps: ' + data.fps
3467 this.onComplete.fire(data);
3471 this._onStart = new Roo.util.Event(this);
3472 this.onStart = new Roo.util.Event(this);
3473 this.onTween = new Roo.util.Event(this);
3474 this._onTween = new Roo.util.Event(this);
3475 this.onComplete = new Roo.util.Event(this);
3476 this._onComplete = new Roo.util.Event(this);
3477 this._onStart.addListener(onStart);
3478 this._onTween.addListener(onTween);
3479 this._onComplete.addListener(onComplete);
3484 * Portions of this file are based on pieces of Yahoo User Interface Library
3485 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3486 * YUI licensed under the BSD License:
3487 * http://developer.yahoo.net/yui/license.txt
3488 * <script type="text/javascript">
3492 Roo.lib.AnimMgr = new function() {
3509 this.registerElement = function(tween) {
3510 queue[queue.length] = tween;
3512 tween._onStart.fire();
3517 this.unRegister = function(tween, index) {
3518 tween._onComplete.fire();
3519 index = index || getIndex(tween);
3521 queue.splice(index, 1);
3525 if (tweenCount <= 0) {
3531 this.start = function() {
3532 if (thread === null) {
3533 thread = setInterval(this.run, this.delay);
3538 this.stop = function(tween) {
3540 clearInterval(thread);
3542 for (var i = 0, len = queue.length; i < len; ++i) {
3543 if (queue[0].isAnimated()) {
3544 this.unRegister(queue[0], 0);
3553 this.unRegister(tween);
3558 this.run = function() {
3559 for (var i = 0, len = queue.length; i < len; ++i) {
3560 var tween = queue[i];
3561 if (!tween || !tween.isAnimated()) {
3565 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3567 tween.currentFrame += 1;
3569 if (tween.useSeconds) {
3570 correctFrame(tween);
3572 tween._onTween.fire();
3575 Roo.lib.AnimMgr.stop(tween, i);
3580 var getIndex = function(anim) {
3581 for (var i = 0, len = queue.length; i < len; ++i) {
3582 if (queue[i] == anim) {
3590 var correctFrame = function(tween) {
3591 var frames = tween.totalFrames;
3592 var frame = tween.currentFrame;
3593 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3594 var elapsed = (new Date() - tween.getStartTime());
3597 if (elapsed < tween.duration * 1000) {
3598 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3600 tweak = frames - (frame + 1);
3602 if (tweak > 0 && isFinite(tweak)) {
3603 if (tween.currentFrame + tweak >= frames) {
3604 tweak = frames - (frame + 1);
3607 tween.currentFrame += tweak;
3613 * Portions of this file are based on pieces of Yahoo User Interface Library
3614 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3615 * YUI licensed under the BSD License:
3616 * http://developer.yahoo.net/yui/license.txt
3617 * <script type="text/javascript">
3620 Roo.lib.Bezier = new function() {
3622 this.getPosition = function(points, t) {
3623 var n = points.length;
3626 for (var i = 0; i < n; ++i) {
3627 tmp[i] = [points[i][0], points[i][1]];
3630 for (var j = 1; j < n; ++j) {
3631 for (i = 0; i < n - j; ++i) {
3632 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3633 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3637 return [ tmp[0][0], tmp[0][1] ];
3641 * Portions of this file are based on pieces of Yahoo User Interface Library
3642 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3643 * YUI licensed under the BSD License:
3644 * http://developer.yahoo.net/yui/license.txt
3645 * <script type="text/javascript">
3650 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3651 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3654 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3656 var fly = Roo.lib.AnimBase.fly;
3658 var superclass = Y.ColorAnim.superclass;
3659 var proto = Y.ColorAnim.prototype;
3661 proto.toString = function() {
3662 var el = this.getEl();
3663 var id = el.id || el.tagName;
3664 return ("ColorAnim " + id);
3667 proto.patterns.color = /color$/i;
3668 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3669 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3670 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3671 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3674 proto.parseColor = function(s) {
3675 if (s.length == 3) {
3679 var c = this.patterns.hex.exec(s);
3680 if (c && c.length == 4) {
3681 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3684 c = this.patterns.rgb.exec(s);
3685 if (c && c.length == 4) {
3686 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3689 c = this.patterns.hex3.exec(s);
3690 if (c && c.length == 4) {
3691 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3696 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3697 proto.getAttribute = function(attr) {
3698 var el = this.getEl();
3699 if (this.patterns.color.test(attr)) {
3700 var val = fly(el).getStyle(attr);
3702 if (this.patterns.transparent.test(val)) {
3703 var parent = el.parentNode;
3704 val = fly(parent).getStyle(attr);
3706 while (parent && this.patterns.transparent.test(val)) {
3707 parent = parent.parentNode;
3708 val = fly(parent).getStyle(attr);
3709 if (parent.tagName.toUpperCase() == 'HTML') {
3715 val = superclass.getAttribute.call(this, attr);
3720 proto.getAttribute = function(attr) {
3721 var el = this.getEl();
3722 if (this.patterns.color.test(attr)) {
3723 var val = fly(el).getStyle(attr);
3725 if (this.patterns.transparent.test(val)) {
3726 var parent = el.parentNode;
3727 val = fly(parent).getStyle(attr);
3729 while (parent && this.patterns.transparent.test(val)) {
3730 parent = parent.parentNode;
3731 val = fly(parent).getStyle(attr);
3732 if (parent.tagName.toUpperCase() == 'HTML') {
3738 val = superclass.getAttribute.call(this, attr);
3744 proto.doMethod = function(attr, start, end) {
3747 if (this.patterns.color.test(attr)) {
3749 for (var i = 0, len = start.length; i < len; ++i) {
3750 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3753 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3756 val = superclass.doMethod.call(this, attr, start, end);
3762 proto.setRuntimeAttribute = function(attr) {
3763 superclass.setRuntimeAttribute.call(this, attr);
3765 if (this.patterns.color.test(attr)) {
3766 var attributes = this.attributes;
3767 var start = this.parseColor(this.runtimeAttributes[attr].start);
3768 var end = this.parseColor(this.runtimeAttributes[attr].end);
3770 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3771 end = this.parseColor(attributes[attr].by);
3773 for (var i = 0, len = start.length; i < len; ++i) {
3774 end[i] = start[i] + end[i];
3778 this.runtimeAttributes[attr].start = start;
3779 this.runtimeAttributes[attr].end = end;
3785 * Portions of this file are based on pieces of Yahoo User Interface Library
3786 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3787 * YUI licensed under the BSD License:
3788 * http://developer.yahoo.net/yui/license.txt
3789 * <script type="text/javascript">
3795 easeNone: function (t, b, c, d) {
3796 return c * t / d + b;
3800 easeIn: function (t, b, c, d) {
3801 return c * (t /= d) * t + b;
3805 easeOut: function (t, b, c, d) {
3806 return -c * (t /= d) * (t - 2) + b;
3810 easeBoth: function (t, b, c, d) {
3811 if ((t /= d / 2) < 1) {
3812 return c / 2 * t * t + b;
3815 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3819 easeInStrong: function (t, b, c, d) {
3820 return c * (t /= d) * t * t * t + b;
3824 easeOutStrong: function (t, b, c, d) {
3825 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3829 easeBothStrong: function (t, b, c, d) {
3830 if ((t /= d / 2) < 1) {
3831 return c / 2 * t * t * t * t + b;
3834 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3839 elasticIn: function (t, b, c, d, a, p) {
3843 if ((t /= d) == 1) {
3850 if (!a || a < Math.abs(c)) {
3855 var s = p / (2 * Math.PI) * Math.asin(c / a);
3858 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3862 elasticOut: function (t, b, c, d, a, p) {
3866 if ((t /= d) == 1) {
3873 if (!a || a < Math.abs(c)) {
3878 var s = p / (2 * Math.PI) * Math.asin(c / a);
3881 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3885 elasticBoth: function (t, b, c, d, a, p) {
3890 if ((t /= d / 2) == 2) {
3898 if (!a || a < Math.abs(c)) {
3903 var s = p / (2 * Math.PI) * Math.asin(c / a);
3907 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3908 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3910 return a * Math.pow(2, -10 * (t -= 1)) *
3911 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3916 backIn: function (t, b, c, d, s) {
3917 if (typeof s == 'undefined') {
3920 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3924 backOut: function (t, b, c, d, s) {
3925 if (typeof s == 'undefined') {
3928 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3932 backBoth: function (t, b, c, d, s) {
3933 if (typeof s == 'undefined') {
3937 if ((t /= d / 2 ) < 1) {
3938 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3940 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3944 bounceIn: function (t, b, c, d) {
3945 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3949 bounceOut: function (t, b, c, d) {
3950 if ((t /= d) < (1 / 2.75)) {
3951 return c * (7.5625 * t * t) + b;
3952 } else if (t < (2 / 2.75)) {
3953 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3954 } else if (t < (2.5 / 2.75)) {
3955 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3957 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3961 bounceBoth: function (t, b, c, d) {
3963 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3965 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3968 * Portions of this file are based on pieces of Yahoo User Interface Library
3969 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3970 * YUI licensed under the BSD License:
3971 * http://developer.yahoo.net/yui/license.txt
3972 * <script type="text/javascript">
3976 Roo.lib.Motion = function(el, attributes, duration, method) {
3978 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3982 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3986 var superclass = Y.Motion.superclass;
3987 var proto = Y.Motion.prototype;
3989 proto.toString = function() {
3990 var el = this.getEl();
3991 var id = el.id || el.tagName;
3992 return ("Motion " + id);
3995 proto.patterns.points = /^points$/i;
3997 proto.setAttribute = function(attr, val, unit) {
3998 if (this.patterns.points.test(attr)) {
3999 unit = unit || 'px';
4000 superclass.setAttribute.call(this, 'left', val[0], unit);
4001 superclass.setAttribute.call(this, 'top', val[1], unit);
4003 superclass.setAttribute.call(this, attr, val, unit);
4007 proto.getAttribute = function(attr) {
4008 if (this.patterns.points.test(attr)) {
4010 superclass.getAttribute.call(this, 'left'),
4011 superclass.getAttribute.call(this, 'top')
4014 val = superclass.getAttribute.call(this, attr);
4020 proto.doMethod = function(attr, start, end) {
4023 if (this.patterns.points.test(attr)) {
4024 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4025 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4027 val = superclass.doMethod.call(this, attr, start, end);
4032 proto.setRuntimeAttribute = function(attr) {
4033 if (this.patterns.points.test(attr)) {
4034 var el = this.getEl();
4035 var attributes = this.attributes;
4037 var control = attributes['points']['control'] || [];
4041 if (control.length > 0 && !(control[0] instanceof Array)) {
4042 control = [control];
4045 for (i = 0,len = control.length; i < len; ++i) {
4046 tmp[i] = control[i];
4051 Roo.fly(el).position();
4053 if (isset(attributes['points']['from'])) {
4054 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4057 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4060 start = this.getAttribute('points');
4063 if (isset(attributes['points']['to'])) {
4064 end = translateValues.call(this, attributes['points']['to'], start);
4066 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4067 for (i = 0,len = control.length; i < len; ++i) {
4068 control[i] = translateValues.call(this, control[i], start);
4072 } else if (isset(attributes['points']['by'])) {
4073 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4075 for (i = 0,len = control.length; i < len; ++i) {
4076 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4080 this.runtimeAttributes[attr] = [start];
4082 if (control.length > 0) {
4083 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4086 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4089 superclass.setRuntimeAttribute.call(this, attr);
4093 var translateValues = function(val, start) {
4094 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4095 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4100 var isset = function(prop) {
4101 return (typeof prop !== 'undefined');
4105 * Portions of this file are based on pieces of Yahoo User Interface Library
4106 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4107 * YUI licensed under the BSD License:
4108 * http://developer.yahoo.net/yui/license.txt
4109 * <script type="text/javascript">
4113 Roo.lib.Scroll = function(el, attributes, duration, method) {
4115 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4119 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4123 var superclass = Y.Scroll.superclass;
4124 var proto = Y.Scroll.prototype;
4126 proto.toString = function() {
4127 var el = this.getEl();
4128 var id = el.id || el.tagName;
4129 return ("Scroll " + id);
4132 proto.doMethod = function(attr, start, end) {
4135 if (attr == 'scroll') {
4137 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4138 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4142 val = superclass.doMethod.call(this, attr, start, end);
4147 proto.getAttribute = function(attr) {
4149 var el = this.getEl();
4151 if (attr == 'scroll') {
4152 val = [ el.scrollLeft, el.scrollTop ];
4154 val = superclass.getAttribute.call(this, attr);
4160 proto.setAttribute = function(attr, val, unit) {
4161 var el = this.getEl();
4163 if (attr == 'scroll') {
4164 el.scrollLeft = val[0];
4165 el.scrollTop = val[1];
4167 superclass.setAttribute.call(this, attr, val, unit);
4173 * Ext JS Library 1.1.1
4174 * Copyright(c) 2006-2007, Ext JS, LLC.
4176 * Originally Released Under LGPL - original licence link has changed is not relivant.
4179 * <script type="text/javascript">
4183 // nasty IE9 hack - what a pile of crap that is..
4185 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4186 Range.prototype.createContextualFragment = function (html) {
4187 var doc = window.document;
4188 var container = doc.createElement("div");
4189 container.innerHTML = html;
4190 var frag = doc.createDocumentFragment(), n;
4191 while ((n = container.firstChild)) {
4192 frag.appendChild(n);
4199 * @class Roo.DomHelper
4200 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4201 * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4204 Roo.DomHelper = function(){
4205 var tempTableEl = null;
4206 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4207 var tableRe = /^table|tbody|tr|td$/i;
4209 // build as innerHTML where available
4211 var createHtml = function(o){
4212 if(typeof o == 'string'){
4221 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4222 if(attr == "style"){
4224 if(typeof s == "function"){
4227 if(typeof s == "string"){
4228 b += ' style="' + s + '"';
4229 }else if(typeof s == "object"){
4232 if(typeof s[key] != "function"){
4233 b += key + ":" + s[key] + ";";
4240 b += ' class="' + o["cls"] + '"';
4241 }else if(attr == "htmlFor"){
4242 b += ' for="' + o["htmlFor"] + '"';
4244 b += " " + attr + '="' + o[attr] + '"';
4248 if(emptyTags.test(o.tag)){
4252 var cn = o.children || o.cn;
4254 //http://bugs.kde.org/show_bug.cgi?id=71506
4255 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4256 for(var i = 0, len = cn.length; i < len; i++) {
4257 b += createHtml(cn[i], b);
4260 b += createHtml(cn, b);
4266 b += "</" + o.tag + ">";
4273 var createDom = function(o, parentNode){
4275 // defininition craeted..
4277 if (o.ns && o.ns != 'html') {
4279 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4280 xmlns[o.ns] = o.xmlns;
4283 if (typeof(xmlns[o.ns]) == 'undefined') {
4284 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4290 if (typeof(o) == 'string') {
4291 return parentNode.appendChild(document.createTextNode(o));
4293 o.tag = o.tag || div;
4294 if (o.ns && Roo.isIE) {
4296 o.tag = o.ns + ':' + o.tag;
4299 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4300 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4303 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4304 attr == "style" || typeof o[attr] == "function") { continue; }
4306 if(attr=="cls" && Roo.isIE){
4307 el.className = o["cls"];
4309 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4315 Roo.DomHelper.applyStyles(el, o.style);
4316 var cn = o.children || o.cn;
4318 //http://bugs.kde.org/show_bug.cgi?id=71506
4319 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4320 for(var i = 0, len = cn.length; i < len; i++) {
4321 createDom(cn[i], el);
4328 el.innerHTML = o.html;
4331 parentNode.appendChild(el);
4336 var ieTable = function(depth, s, h, e){
4337 tempTableEl.innerHTML = [s, h, e].join('');
4338 var i = -1, el = tempTableEl;
4345 // kill repeat to save bytes
4349 tbe = '</tbody>'+te,
4355 * Nasty code for IE's broken table implementation
4357 var insertIntoTable = function(tag, where, el, html){
4359 tempTableEl = document.createElement('div');
4364 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4367 if(where == 'beforebegin'){
4371 before = el.nextSibling;
4374 node = ieTable(4, trs, html, tre);
4376 else if(tag == 'tr'){
4377 if(where == 'beforebegin'){
4380 node = ieTable(3, tbs, html, tbe);
4381 } else if(where == 'afterend'){
4382 before = el.nextSibling;
4384 node = ieTable(3, tbs, html, tbe);
4385 } else{ // INTO a TR
4386 if(where == 'afterbegin'){
4387 before = el.firstChild;
4389 node = ieTable(4, trs, html, tre);
4391 } else if(tag == 'tbody'){
4392 if(where == 'beforebegin'){
4395 node = ieTable(2, ts, html, te);
4396 } else if(where == 'afterend'){
4397 before = el.nextSibling;
4399 node = ieTable(2, ts, html, te);
4401 if(where == 'afterbegin'){
4402 before = el.firstChild;
4404 node = ieTable(3, tbs, html, tbe);
4407 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4410 if(where == 'afterbegin'){
4411 before = el.firstChild;
4413 node = ieTable(2, ts, html, te);
4415 el.insertBefore(node, before);
4420 /** True to force the use of DOM instead of html fragments @type Boolean */
4424 * Returns the markup for the passed Element(s) config
4425 * @param {Object} o The Dom object spec (and children)
4428 markup : function(o){
4429 return createHtml(o);
4433 * Applies a style specification to an element
4434 * @param {String/HTMLElement} el The element to apply styles to
4435 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4436 * a function which returns such a specification.
4438 applyStyles : function(el, styles){
4441 if(typeof styles == "string"){
4442 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4444 while ((matches = re.exec(styles)) != null){
4445 el.setStyle(matches[1], matches[2]);
4447 }else if (typeof styles == "object"){
4448 for (var style in styles){
4449 el.setStyle(style, styles[style]);
4451 }else if (typeof styles == "function"){
4452 Roo.DomHelper.applyStyles(el, styles.call());
4458 * Inserts an HTML fragment into the Dom
4459 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4460 * @param {HTMLElement} el The context element
4461 * @param {String} html The HTML fragmenet
4462 * @return {HTMLElement} The new node
4464 insertHtml : function(where, el, html){
4465 where = where.toLowerCase();
4466 if(el.insertAdjacentHTML){
4467 if(tableRe.test(el.tagName)){
4469 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4475 el.insertAdjacentHTML('BeforeBegin', html);
4476 return el.previousSibling;
4478 el.insertAdjacentHTML('AfterBegin', html);
4479 return el.firstChild;
4481 el.insertAdjacentHTML('BeforeEnd', html);
4482 return el.lastChild;
4484 el.insertAdjacentHTML('AfterEnd', html);
4485 return el.nextSibling;
4487 throw 'Illegal insertion point -> "' + where + '"';
4489 var range = el.ownerDocument.createRange();
4493 range.setStartBefore(el);
4494 frag = range.createContextualFragment(html);
4495 el.parentNode.insertBefore(frag, el);
4496 return el.previousSibling;
4499 range.setStartBefore(el.firstChild);
4500 frag = range.createContextualFragment(html);
4501 el.insertBefore(frag, el.firstChild);
4502 return el.firstChild;
4504 el.innerHTML = html;
4505 return el.firstChild;
4509 range.setStartAfter(el.lastChild);
4510 frag = range.createContextualFragment(html);
4511 el.appendChild(frag);
4512 return el.lastChild;
4514 el.innerHTML = html;
4515 return el.lastChild;
4518 range.setStartAfter(el);
4519 frag = range.createContextualFragment(html);
4520 el.parentNode.insertBefore(frag, el.nextSibling);
4521 return el.nextSibling;
4523 throw 'Illegal insertion point -> "' + where + '"';
4527 * Creates new Dom element(s) and inserts them before el
4528 * @param {String/HTMLElement/Element} el The context element
4529 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531 * @return {HTMLElement/Roo.Element} The new node
4533 insertBefore : function(el, o, returnElement){
4534 return this.doInsert(el, o, returnElement, "beforeBegin");
4538 * Creates new Dom element(s) and inserts them after el
4539 * @param {String/HTMLElement/Element} el The context element
4540 * @param {Object} o The Dom object spec (and children)
4541 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4542 * @return {HTMLElement/Roo.Element} The new node
4544 insertAfter : function(el, o, returnElement){
4545 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4549 * Creates new Dom element(s) and inserts them as the first child of el
4550 * @param {String/HTMLElement/Element} el The context element
4551 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4552 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4553 * @return {HTMLElement/Roo.Element} The new node
4555 insertFirst : function(el, o, returnElement){
4556 return this.doInsert(el, o, returnElement, "afterBegin");
4560 doInsert : function(el, o, returnElement, pos, sibling){
4561 el = Roo.getDom(el);
4563 if(this.useDom || o.ns){
4564 newNode = createDom(o, null);
4565 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4567 var html = createHtml(o);
4568 newNode = this.insertHtml(pos, el, html);
4570 return returnElement ? Roo.get(newNode, true) : newNode;
4574 * Creates new Dom element(s) and appends them to el
4575 * @param {String/HTMLElement/Element} el The context element
4576 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4577 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4578 * @return {HTMLElement/Roo.Element} The new node
4580 append : function(el, o, returnElement){
4581 el = Roo.getDom(el);
4583 if(this.useDom || o.ns){
4584 newNode = createDom(o, null);
4585 el.appendChild(newNode);
4587 var html = createHtml(o);
4588 newNode = this.insertHtml("beforeEnd", el, html);
4590 return returnElement ? Roo.get(newNode, true) : newNode;
4594 * Creates new Dom element(s) and overwrites the contents of el with them
4595 * @param {String/HTMLElement/Element} el The context element
4596 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4597 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4598 * @return {HTMLElement/Roo.Element} The new node
4600 overwrite : function(el, o, returnElement){
4601 el = Roo.getDom(el);
4604 while (el.childNodes.length) {
4605 el.removeChild(el.firstChild);
4609 el.innerHTML = createHtml(o);
4612 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4616 * Creates a new Roo.DomHelper.Template from the Dom object spec
4617 * @param {Object} o The Dom object spec (and children)
4618 * @return {Roo.DomHelper.Template} The new template
4620 createTemplate : function(o){
4621 var html = createHtml(o);
4622 return new Roo.Template(html);
4628 * Ext JS Library 1.1.1
4629 * Copyright(c) 2006-2007, Ext JS, LLC.
4631 * Originally Released Under LGPL - original licence link has changed is not relivant.
4634 * <script type="text/javascript">
4638 * @class Roo.Template
4639 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4640 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4643 var t = new Roo.Template({
4644 html : '<div name="{id}">' +
4645 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4647 myformat: function (value, allValues) {
4648 return 'XX' + value;
4651 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4653 * For more information see this blog post with examples:
4654 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4655 - Create Elements using DOM, HTML fragments and Templates</a>.
4657 * @param {Object} cfg - Configuration object.
4659 Roo.Template = function(cfg){
4661 if(cfg instanceof Array){
4663 }else if(arguments.length > 1){
4664 cfg = Array.prototype.join.call(arguments, "");
4668 if (typeof(cfg) == 'object') {
4679 Roo.Template.prototype = {
4682 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
4688 * @cfg {String} url The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4689 * it should be fixed so that template is observable...
4693 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4701 * Returns an HTML fragment of this template with the specified values applied.
4702 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4703 * @return {String} The HTML fragment
4708 applyTemplate : function(values){
4709 //Roo.log(["applyTemplate", values]);
4713 return this.compiled(values);
4715 var useF = this.disableFormats !== true;
4716 var fm = Roo.util.Format, tpl = this;
4717 var fn = function(m, name, format, args){
4719 if(format.substr(0, 5) == "this."){
4720 return tpl.call(format.substr(5), values[name], values);
4723 // quoted values are required for strings in compiled templates,
4724 // but for non compiled we need to strip them
4725 // quoted reversed for jsmin
4726 var re = /^\s*['"](.*)["']\s*$/;
4727 args = args.split(',');
4728 for(var i = 0, len = args.length; i < len; i++){
4729 args[i] = args[i].replace(re, "$1");
4731 args = [values[name]].concat(args);
4733 args = [values[name]];
4735 return fm[format].apply(fm, args);
4738 return values[name] !== undefined ? values[name] : "";
4741 return this.html.replace(this.re, fn);
4759 this.loading = true;
4760 this.compiled = false;
4762 var cx = new Roo.data.Connection();
4766 success : function (response) {
4770 _t.set(response.responseText,true);
4776 failure : function(response) {
4777 Roo.log("Template failed to load from " + _t.url);
4784 * Sets the HTML used as the template and optionally compiles it.
4785 * @param {String} html
4786 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4787 * @return {Roo.Template} this
4789 set : function(html, compile){
4791 this.compiled = false;
4799 * True to disable format functions (defaults to false)
4802 disableFormats : false,
4805 * The regular expression used to match template variables
4809 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4812 * Compiles the template into an internal function, eliminating the RegEx overhead.
4813 * @return {Roo.Template} this
4815 compile : function(){
4816 var fm = Roo.util.Format;
4817 var useF = this.disableFormats !== true;
4818 var sep = Roo.isGecko ? "+" : ",";
4819 var fn = function(m, name, format, args){
4821 args = args ? ',' + args : "";
4822 if(format.substr(0, 5) != "this."){
4823 format = "fm." + format + '(';
4825 format = 'this.call("'+ format.substr(5) + '", ';
4829 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4831 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4834 // branched to use + in gecko and [].join() in others
4836 body = "this.compiled = function(values){ return '" +
4837 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4840 body = ["this.compiled = function(values){ return ['"];
4841 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4842 body.push("'].join('');};");
4843 body = body.join('');
4853 // private function used to call members
4854 call : function(fnName, value, allValues){
4855 return this[fnName](value, allValues);
4859 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4860 * @param {String/HTMLElement/Roo.Element} el The context element
4861 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4862 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4863 * @return {HTMLElement/Roo.Element} The new node or Element
4865 insertFirst: function(el, values, returnElement){
4866 return this.doInsert('afterBegin', el, values, returnElement);
4870 * Applies the supplied values to the template and inserts the new node(s) before el.
4871 * @param {String/HTMLElement/Roo.Element} el The context element
4872 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4873 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4874 * @return {HTMLElement/Roo.Element} The new node or Element
4876 insertBefore: function(el, values, returnElement){
4877 return this.doInsert('beforeBegin', el, values, returnElement);
4881 * Applies the supplied values to the template and inserts the new node(s) after el.
4882 * @param {String/HTMLElement/Roo.Element} el The context element
4883 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4884 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4885 * @return {HTMLElement/Roo.Element} The new node or Element
4887 insertAfter : function(el, values, returnElement){
4888 return this.doInsert('afterEnd', el, values, returnElement);
4892 * Applies the supplied values to the template and appends the new node(s) to el.
4893 * @param {String/HTMLElement/Roo.Element} el The context element
4894 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4895 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4896 * @return {HTMLElement/Roo.Element} The new node or Element
4898 append : function(el, values, returnElement){
4899 return this.doInsert('beforeEnd', el, values, returnElement);
4902 doInsert : function(where, el, values, returnEl){
4903 el = Roo.getDom(el);
4904 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4905 return returnEl ? Roo.get(newNode, true) : newNode;
4909 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4910 * @param {String/HTMLElement/Roo.Element} el The context element
4911 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4912 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4913 * @return {HTMLElement/Roo.Element} The new node or Element
4915 overwrite : function(el, values, returnElement){
4916 el = Roo.getDom(el);
4917 el.innerHTML = this.applyTemplate(values);
4918 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4922 * Alias for {@link #applyTemplate}
4925 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4928 Roo.DomHelper.Template = Roo.Template;
4931 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4932 * @param {String/HTMLElement} el A DOM element or its id
4933 * @returns {Roo.Template} The created template
4936 Roo.Template.from = function(el){
4937 el = Roo.getDom(el);
4938 return new Roo.Template(el.value || el.innerHTML);
4941 * Ext JS Library 1.1.1
4942 * Copyright(c) 2006-2007, Ext JS, LLC.
4944 * Originally Released Under LGPL - original licence link has changed is not relivant.
4947 * <script type="text/javascript">
4952 * This is code is also distributed under MIT license for use
4953 * with jQuery and prototype JavaScript libraries.
4956 * @class Roo.DomQuery
4957 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4959 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4962 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4964 <h4>Element Selectors:</h4>
4966 <li> <b>*</b> any element</li>
4967 <li> <b>E</b> an element with the tag E</li>
4968 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4969 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4970 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4971 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4973 <h4>Attribute Selectors:</h4>
4974 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4976 <li> <b>E[foo]</b> has an attribute "foo"</li>
4977 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4978 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4979 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4980 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4981 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4982 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4984 <h4>Pseudo Classes:</h4>
4986 <li> <b>E:first-child</b> E is the first child of its parent</li>
4987 <li> <b>E:last-child</b> E is the last child of its parent</li>
4988 <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4989 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4990 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4991 <li> <b>E:only-child</b> E is the only child of its parent</li>
4992 <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4993 <li> <b>E:first</b> the first E in the resultset</li>
4994 <li> <b>E:last</b> the last E in the resultset</li>
4995 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4996 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4997 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4998 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4999 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5000 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5001 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5002 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5003 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5005 <h4>CSS Value Selectors:</h4>
5007 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5008 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5009 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5010 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5011 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5012 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5016 Roo.DomQuery = function(){
5017 var cache = {}, simpleCache = {}, valueCache = {};
5018 var nonSpace = /\S/;
5019 var trimRe = /^\s+|\s+$/g;
5020 var tplRe = /\{(\d+)\}/g;
5021 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5022 var tagTokenRe = /^(#)?([\w-\*]+)/;
5023 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5025 function child(p, index){
5027 var n = p.firstChild;
5029 if(n.nodeType == 1){
5040 while((n = n.nextSibling) && n.nodeType != 1);
5045 while((n = n.previousSibling) && n.nodeType != 1);
5049 function children(d){
5050 var n = d.firstChild, ni = -1;
5052 var nx = n.nextSibling;
5053 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5063 function byClassName(c, a, v){
5067 var r = [], ri = -1, cn;
5068 for(var i = 0, ci; ci = c[i]; i++){
5069 if((' '+ci.className+' ').indexOf(v) != -1){
5076 function attrValue(n, attr){
5077 if(!n.tagName && typeof n.length != "undefined"){
5086 if(attr == "class" || attr == "className"){
5089 return n.getAttribute(attr) || n[attr];
5093 function getNodes(ns, mode, tagName){
5094 var result = [], ri = -1, cs;
5098 tagName = tagName || "*";
5099 if(typeof ns.getElementsByTagName != "undefined"){
5103 for(var i = 0, ni; ni = ns[i]; i++){
5104 cs = ni.getElementsByTagName(tagName);
5105 for(var j = 0, ci; ci = cs[j]; j++){
5109 }else if(mode == "/" || mode == ">"){
5110 var utag = tagName.toUpperCase();
5111 for(var i = 0, ni, cn; ni = ns[i]; i++){
5112 cn = ni.children || ni.childNodes;
5113 for(var j = 0, cj; cj = cn[j]; j++){
5114 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5119 }else if(mode == "+"){
5120 var utag = tagName.toUpperCase();
5121 for(var i = 0, n; n = ns[i]; i++){
5122 while((n = n.nextSibling) && n.nodeType != 1);
5123 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5127 }else if(mode == "~"){
5128 for(var i = 0, n; n = ns[i]; i++){
5129 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5138 function concat(a, b){
5142 for(var i = 0, l = b.length; i < l; i++){
5148 function byTag(cs, tagName){
5149 if(cs.tagName || cs == document){
5155 var r = [], ri = -1;
5156 tagName = tagName.toLowerCase();
5157 for(var i = 0, ci; ci = cs[i]; i++){
5158 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5165 function byId(cs, attr, id){
5166 if(cs.tagName || cs == document){
5172 var r = [], ri = -1;
5173 for(var i = 0,ci; ci = cs[i]; i++){
5174 if(ci && ci.id == id){
5182 function byAttribute(cs, attr, value, op, custom){
5183 var r = [], ri = -1, st = custom=="{";
5184 var f = Roo.DomQuery.operators[op];
5185 for(var i = 0, ci; ci = cs[i]; i++){
5188 a = Roo.DomQuery.getStyle(ci, attr);
5190 else if(attr == "class" || attr == "className"){
5192 }else if(attr == "for"){
5194 }else if(attr == "href"){
5195 a = ci.getAttribute("href", 2);
5197 a = ci.getAttribute(attr);
5199 if((f && f(a, value)) || (!f && a)){
5206 function byPseudo(cs, name, value){
5207 return Roo.DomQuery.pseudos[name](cs, value);
5210 // This is for IE MSXML which does not support expandos.
5211 // IE runs the same speed using setAttribute, however FF slows way down
5212 // and Safari completely fails so they need to continue to use expandos.
5213 var isIE = window.ActiveXObject ? true : false;
5215 // this eval is stop the compressor from
5216 // renaming the variable to something shorter
5218 /** eval:var:batch */
5223 function nodupIEXml(cs){
5225 cs[0].setAttribute("_nodup", d);
5227 for(var i = 1, len = cs.length; i < len; i++){
5229 if(!c.getAttribute("_nodup") != d){
5230 c.setAttribute("_nodup", d);
5234 for(var i = 0, len = cs.length; i < len; i++){
5235 cs[i].removeAttribute("_nodup");
5244 var len = cs.length, c, i, r = cs, cj, ri = -1;
5245 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5248 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5249 return nodupIEXml(cs);
5253 for(i = 1; c = cs[i]; i++){
5258 for(var j = 0; j < i; j++){
5261 for(j = i+1; cj = cs[j]; j++){
5273 function quickDiffIEXml(c1, c2){
5275 for(var i = 0, len = c1.length; i < len; i++){
5276 c1[i].setAttribute("_qdiff", d);
5279 for(var i = 0, len = c2.length; i < len; i++){
5280 if(c2[i].getAttribute("_qdiff") != d){
5281 r[r.length] = c2[i];
5284 for(var i = 0, len = c1.length; i < len; i++){
5285 c1[i].removeAttribute("_qdiff");
5290 function quickDiff(c1, c2){
5291 var len1 = c1.length;
5295 if(isIE && c1[0].selectSingleNode){
5296 return quickDiffIEXml(c1, c2);
5299 for(var i = 0; i < len1; i++){
5303 for(var i = 0, len = c2.length; i < len; i++){
5304 if(c2[i]._qdiff != d){
5305 r[r.length] = c2[i];
5311 function quickId(ns, mode, root, id){
5313 var d = root.ownerDocument || root;
5314 return d.getElementById(id);
5316 ns = getNodes(ns, mode, "*");
5317 return byId(ns, null, id);
5321 getStyle : function(el, name){
5322 return Roo.fly(el).getStyle(name);
5325 * Compiles a selector/xpath query into a reusable function. The returned function
5326 * takes one parameter "root" (optional), which is the context node from where the query should start.
5327 * @param {String} selector The selector/xpath query
5328 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5329 * @return {Function}
5331 compile : function(path, type){
5332 type = type || "select";
5334 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5335 var q = path, mode, lq;
5336 var tk = Roo.DomQuery.matchers;
5337 var tklen = tk.length;
5340 // accept leading mode switch
5341 var lmode = q.match(modeRe);
5342 if(lmode && lmode[1]){
5343 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5344 q = q.replace(lmode[1], "");
5346 // strip leading slashes
5347 while(path.substr(0, 1)=="/"){
5348 path = path.substr(1);
5351 while(q && lq != q){
5353 var tm = q.match(tagTokenRe);
5354 if(type == "select"){
5357 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5359 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5361 q = q.replace(tm[0], "");
5362 }else if(q.substr(0, 1) != '@'){
5363 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5368 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5370 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5372 q = q.replace(tm[0], "");
5375 while(!(mm = q.match(modeRe))){
5376 var matched = false;
5377 for(var j = 0; j < tklen; j++){
5379 var m = q.match(t.re);
5381 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5384 q = q.replace(m[0], "");
5389 // prevent infinite loop on bad selector
5391 throw 'Error parsing selector, parsing failed at "' + q + '"';
5395 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5396 q = q.replace(mm[1], "");
5399 fn[fn.length] = "return nodup(n);\n}";
5402 * list of variables that need from compression as they are used by eval.
5412 * eval:var:byClassName
5414 * eval:var:byAttribute
5415 * eval:var:attrValue
5423 * Selects a group of elements.
5424 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5425 * @param {Node} root (optional) The start of the query (defaults to document).
5428 select : function(path, root, type){
5429 if(!root || root == document){
5432 if(typeof root == "string"){
5433 root = document.getElementById(root);
5435 var paths = path.split(",");
5437 for(var i = 0, len = paths.length; i < len; i++){
5438 var p = paths[i].replace(trimRe, "");
5440 cache[p] = Roo.DomQuery.compile(p);
5442 throw p + " is not a valid selector";
5445 var result = cache[p](root);
5446 if(result && result != document){
5447 results = results.concat(result);
5450 if(paths.length > 1){
5451 return nodup(results);
5457 * Selects a single element.
5458 * @param {String} selector The selector/xpath query
5459 * @param {Node} root (optional) The start of the query (defaults to document).
5462 selectNode : function(path, root){
5463 return Roo.DomQuery.select(path, root)[0];
5467 * Selects the value of a node, optionally replacing null with the defaultValue.
5468 * @param {String} selector The selector/xpath query
5469 * @param {Node} root (optional) The start of the query (defaults to document).
5470 * @param {String} defaultValue
5472 selectValue : function(path, root, defaultValue){
5473 path = path.replace(trimRe, "");
5474 if(!valueCache[path]){
5475 valueCache[path] = Roo.DomQuery.compile(path, "select");
5477 var n = valueCache[path](root);
5478 n = n[0] ? n[0] : n;
5479 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5480 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5484 * Selects the value of a node, parsing integers and floats.
5485 * @param {String} selector The selector/xpath query
5486 * @param {Node} root (optional) The start of the query (defaults to document).
5487 * @param {Number} defaultValue
5490 selectNumber : function(path, root, defaultValue){
5491 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5492 return parseFloat(v);
5496 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5497 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5498 * @param {String} selector The simple selector to test
5501 is : function(el, ss){
5502 if(typeof el == "string"){
5503 el = document.getElementById(el);
5505 var isArray = (el instanceof Array);
5506 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5507 return isArray ? (result.length == el.length) : (result.length > 0);
5511 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5512 * @param {Array} el An array of elements to filter
5513 * @param {String} selector The simple selector to test
5514 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5515 * the selector instead of the ones that match
5518 filter : function(els, ss, nonMatches){
5519 ss = ss.replace(trimRe, "");
5520 if(!simpleCache[ss]){
5521 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5523 var result = simpleCache[ss](els);
5524 return nonMatches ? quickDiff(result, els) : result;
5528 * Collection of matching regular expressions and code snippets.
5532 select: 'n = byClassName(n, null, " {1} ");'
5534 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5535 select: 'n = byPseudo(n, "{1}", "{2}");'
5537 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5538 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5541 select: 'n = byId(n, null, "{1}");'
5544 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5549 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5550 * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, > <.
5553 "=" : function(a, v){
5556 "!=" : function(a, v){
5559 "^=" : function(a, v){
5560 return a && a.substr(0, v.length) == v;
5562 "$=" : function(a, v){
5563 return a && a.substr(a.length-v.length) == v;
5565 "*=" : function(a, v){
5566 return a && a.indexOf(v) !== -1;
5568 "%=" : function(a, v){
5569 return (a % v) == 0;
5571 "|=" : function(a, v){
5572 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5574 "~=" : function(a, v){
5575 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5580 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5581 * and the argument (if any) supplied in the selector.
5584 "first-child" : function(c){
5585 var r = [], ri = -1, n;
5586 for(var i = 0, ci; ci = n = c[i]; i++){
5587 while((n = n.previousSibling) && n.nodeType != 1);
5595 "last-child" : function(c){
5596 var r = [], ri = -1, n;
5597 for(var i = 0, ci; ci = n = c[i]; i++){
5598 while((n = n.nextSibling) && n.nodeType != 1);
5606 "nth-child" : function(c, a) {
5607 var r = [], ri = -1;
5608 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5609 var f = (m[1] || 1) - 0, l = m[2] - 0;
5610 for(var i = 0, n; n = c[i]; i++){
5611 var pn = n.parentNode;
5612 if (batch != pn._batch) {
5614 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5615 if(cn.nodeType == 1){
5622 if (l == 0 || n.nodeIndex == l){
5625 } else if ((n.nodeIndex + l) % f == 0){
5633 "only-child" : function(c){
5634 var r = [], ri = -1;;
5635 for(var i = 0, ci; ci = c[i]; i++){
5636 if(!prev(ci) && !next(ci)){
5643 "empty" : function(c){
5644 var r = [], ri = -1;
5645 for(var i = 0, ci; ci = c[i]; i++){
5646 var cns = ci.childNodes, j = 0, cn, empty = true;
5649 if(cn.nodeType == 1 || cn.nodeType == 3){
5661 "contains" : function(c, v){
5662 var r = [], ri = -1;
5663 for(var i = 0, ci; ci = c[i]; i++){
5664 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5671 "nodeValue" : function(c, v){
5672 var r = [], ri = -1;
5673 for(var i = 0, ci; ci = c[i]; i++){
5674 if(ci.firstChild && ci.firstChild.nodeValue == v){
5681 "checked" : function(c){
5682 var r = [], ri = -1;
5683 for(var i = 0, ci; ci = c[i]; i++){
5684 if(ci.checked == true){
5691 "not" : function(c, ss){
5692 return Roo.DomQuery.filter(c, ss, true);
5695 "odd" : function(c){
5696 return this["nth-child"](c, "odd");
5699 "even" : function(c){
5700 return this["nth-child"](c, "even");
5703 "nth" : function(c, a){
5704 return c[a-1] || [];
5707 "first" : function(c){
5711 "last" : function(c){
5712 return c[c.length-1] || [];
5715 "has" : function(c, ss){
5716 var s = Roo.DomQuery.select;
5717 var r = [], ri = -1;
5718 for(var i = 0, ci; ci = c[i]; i++){
5719 if(s(ss, ci).length > 0){
5726 "next" : function(c, ss){
5727 var is = Roo.DomQuery.is;
5728 var r = [], ri = -1;
5729 for(var i = 0, ci; ci = c[i]; i++){
5738 "prev" : function(c, ss){
5739 var is = Roo.DomQuery.is;
5740 var r = [], ri = -1;
5741 for(var i = 0, ci; ci = c[i]; i++){
5754 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5755 * @param {String} path The selector/xpath query
5756 * @param {Node} root (optional) The start of the query (defaults to document).
5761 Roo.query = Roo.DomQuery.select;
5764 * Ext JS Library 1.1.1
5765 * Copyright(c) 2006-2007, Ext JS, LLC.
5767 * Originally Released Under LGPL - original licence link has changed is not relivant.
5770 * <script type="text/javascript">
5774 * @class Roo.util.Observable
5775 * Base class that provides a common interface for publishing events. Subclasses are expected to
5776 * to have a property "events" with all the events defined.<br>
5779 Employee = function(name){
5786 Roo.extend(Employee, Roo.util.Observable);
5788 * @param {Object} config properties to use (incuding events / listeners)
5791 Roo.util.Observable = function(cfg){
5794 this.addEvents(cfg.events || {});
5796 delete cfg.events; // make sure
5799 Roo.apply(this, cfg);
5802 this.on(this.listeners);
5803 delete this.listeners;
5806 Roo.util.Observable.prototype = {
5808 * @cfg {Object} listeners list of events and functions to call for this object,
5812 'click' : function(e) {
5822 * Fires the specified event with the passed parameters (minus the event name).
5823 * @param {String} eventName
5824 * @param {Object...} args Variable number of parameters are passed to handlers
5825 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5827 fireEvent : function(){
5828 var ce = this.events[arguments[0].toLowerCase()];
5829 if(typeof ce == "object"){
5830 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5837 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5840 * Appends an event handler to this component
5841 * @param {String} eventName The type of event to listen for
5842 * @param {Function} handler The method the event invokes
5843 * @param {Object} scope (optional) The scope in which to execute the handler
5844 * function. The handler function's "this" context.
5845 * @param {Object} options (optional) An object containing handler configuration
5846 * properties. This may contain any of the following properties:<ul>
5847 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5848 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5849 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5850 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5851 * by the specified number of milliseconds. If the event fires again within that time, the original
5852 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5855 * <b>Combining Options</b><br>
5856 * Using the options argument, it is possible to combine different types of listeners:<br>
5858 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5860 el.on('click', this.onClick, this, {
5867 * <b>Attaching multiple handlers in 1 call</b><br>
5868 * The method also allows for a single argument to be passed which is a config object containing properties
5869 * which specify multiple handlers.
5878 fn: this.onMouseOver,
5882 fn: this.onMouseOut,
5888 * Or a shorthand syntax which passes the same scope object to all handlers:
5891 'click': this.onClick,
5892 'mouseover': this.onMouseOver,
5893 'mouseout': this.onMouseOut,
5898 addListener : function(eventName, fn, scope, o){
5899 if(typeof eventName == "object"){
5902 if(this.filterOptRe.test(e)){
5905 if(typeof o[e] == "function"){
5907 this.addListener(e, o[e], o.scope, o);
5909 // individual options
5910 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5915 o = (!o || typeof o == "boolean") ? {} : o;
5916 eventName = eventName.toLowerCase();
5917 var ce = this.events[eventName] || true;
5918 if(typeof ce == "boolean"){
5919 ce = new Roo.util.Event(this, eventName);
5920 this.events[eventName] = ce;
5922 ce.addListener(fn, scope, o);
5926 * Removes a listener
5927 * @param {String} eventName The type of event to listen for
5928 * @param {Function} handler The handler to remove
5929 * @param {Object} scope (optional) The scope (this object) for the handler
5931 removeListener : function(eventName, fn, scope){
5932 var ce = this.events[eventName.toLowerCase()];
5933 if(typeof ce == "object"){
5934 ce.removeListener(fn, scope);
5939 * Removes all listeners for this object
5941 purgeListeners : function(){
5942 for(var evt in this.events){
5943 if(typeof this.events[evt] == "object"){
5944 this.events[evt].clearListeners();
5949 relayEvents : function(o, events){
5950 var createHandler = function(ename){
5953 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5956 for(var i = 0, len = events.length; i < len; i++){
5957 var ename = events[i];
5958 if(!this.events[ename]){
5959 this.events[ename] = true;
5961 o.on(ename, createHandler(ename), this);
5966 * Used to define events on this Observable
5967 * @param {Object} object The object with the events defined
5969 addEvents : function(o){
5973 Roo.applyIf(this.events, o);
5977 * Checks to see if this object has any listeners for a specified event
5978 * @param {String} eventName The name of the event to check for
5979 * @return {Boolean} True if the event is being listened for, else false
5981 hasListener : function(eventName){
5982 var e = this.events[eventName];
5983 return typeof e == "object" && e.listeners.length > 0;
5987 * Appends an event handler to this element (shorthand for addListener)
5988 * @param {String} eventName The type of event to listen for
5989 * @param {Function} handler The method the event invokes
5990 * @param {Object} scope (optional) The scope in which to execute the handler
5991 * function. The handler function's "this" context.
5992 * @param {Object} options (optional)
5995 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5997 * Removes a listener (shorthand for removeListener)
5998 * @param {String} eventName The type of event to listen for
5999 * @param {Function} handler The handler to remove
6000 * @param {Object} scope (optional) The scope (this object) for the handler
6003 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6006 * Starts capture on the specified Observable. All events will be passed
6007 * to the supplied function with the event name + standard signature of the event
6008 * <b>before</b> the event is fired. If the supplied function returns false,
6009 * the event will not fire.
6010 * @param {Observable} o The Observable to capture
6011 * @param {Function} fn The function to call
6012 * @param {Object} scope (optional) The scope (this object) for the fn
6015 Roo.util.Observable.capture = function(o, fn, scope){
6016 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6020 * Removes <b>all</b> added captures from the Observable.
6021 * @param {Observable} o The Observable to release
6024 Roo.util.Observable.releaseCapture = function(o){
6025 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6030 var createBuffered = function(h, o, scope){
6031 var task = new Roo.util.DelayedTask();
6033 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6037 var createSingle = function(h, e, fn, scope){
6039 e.removeListener(fn, scope);
6040 return h.apply(scope, arguments);
6044 var createDelayed = function(h, o, scope){
6046 var args = Array.prototype.slice.call(arguments, 0);
6047 setTimeout(function(){
6048 h.apply(scope, args);
6053 Roo.util.Event = function(obj, name){
6056 this.listeners = [];
6059 Roo.util.Event.prototype = {
6060 addListener : function(fn, scope, options){
6061 var o = options || {};
6062 scope = scope || this.obj;
6063 if(!this.isListening(fn, scope)){
6064 var l = {fn: fn, scope: scope, options: o};
6067 h = createDelayed(h, o, scope);
6070 h = createSingle(h, this, fn, scope);
6073 h = createBuffered(h, o, scope);
6076 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6077 this.listeners.push(l);
6079 this.listeners = this.listeners.slice(0);
6080 this.listeners.push(l);
6085 findListener : function(fn, scope){
6086 scope = scope || this.obj;
6087 var ls = this.listeners;
6088 for(var i = 0, len = ls.length; i < len; i++){
6090 if(l.fn == fn && l.scope == scope){
6097 isListening : function(fn, scope){
6098 return this.findListener(fn, scope) != -1;
6101 removeListener : function(fn, scope){
6103 if((index = this.findListener(fn, scope)) != -1){
6105 this.listeners.splice(index, 1);
6107 this.listeners = this.listeners.slice(0);
6108 this.listeners.splice(index, 1);
6115 clearListeners : function(){
6116 this.listeners = [];
6120 var ls = this.listeners, scope, len = ls.length;
6123 var args = Array.prototype.slice.call(arguments, 0);
6124 for(var i = 0; i < len; i++){
6126 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6127 this.firing = false;
6131 this.firing = false;
6138 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6145 * @class Roo.Document
6146 * @extends Roo.util.Observable
6147 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6149 * @param {Object} config the methods and properties of the 'base' class for the application.
6151 * Generic Page handler - implement this to start your app..
6154 * MyProject = new Roo.Document({
6156 'load' : true // your events..
6159 'ready' : function() {
6160 // fired on Roo.onReady()
6165 Roo.Document = function(cfg) {
6170 Roo.util.Observable.call(this,cfg);
6174 Roo.onReady(function() {
6175 _this.fireEvent('ready');
6181 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6183 * Ext JS Library 1.1.1
6184 * Copyright(c) 2006-2007, Ext JS, LLC.
6186 * Originally Released Under LGPL - original licence link has changed is not relivant.
6189 * <script type="text/javascript">
6193 * @class Roo.EventManager
6194 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6195 * several useful events directly.
6196 * See {@link Roo.EventObject} for more details on normalized event objects.
6199 Roo.EventManager = function(){
6200 var docReadyEvent, docReadyProcId, docReadyState = false;
6201 var resizeEvent, resizeTask, textEvent, textSize;
6202 var E = Roo.lib.Event;
6203 var D = Roo.lib.Dom;
6208 var fireDocReady = function(){
6210 docReadyState = true;
6213 clearInterval(docReadyProcId);
6215 if(Roo.isGecko || Roo.isOpera) {
6216 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6219 var defer = document.getElementById("ie-deferred-loader");
6221 defer.onreadystatechange = null;
6222 defer.parentNode.removeChild(defer);
6226 docReadyEvent.fire();
6227 docReadyEvent.clearListeners();
6232 var initDocReady = function(){
6233 docReadyEvent = new Roo.util.Event();
6234 if(Roo.isGecko || Roo.isOpera) {
6235 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6237 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6238 var defer = document.getElementById("ie-deferred-loader");
6239 defer.onreadystatechange = function(){
6240 if(this.readyState == "complete"){
6244 }else if(Roo.isSafari){
6245 docReadyProcId = setInterval(function(){
6246 var rs = document.readyState;
6247 if(rs == "complete") {
6252 // no matter what, make sure it fires on load
6253 E.on(window, "load", fireDocReady);
6256 var createBuffered = function(h, o){
6257 var task = new Roo.util.DelayedTask(h);
6259 // create new event object impl so new events don't wipe out properties
6260 e = new Roo.EventObjectImpl(e);
6261 task.delay(o.buffer, h, null, [e]);
6265 var createSingle = function(h, el, ename, fn){
6267 Roo.EventManager.removeListener(el, ename, fn);
6272 var createDelayed = function(h, o){
6274 // create new event object impl so new events don't wipe out properties
6275 e = new Roo.EventObjectImpl(e);
6276 setTimeout(function(){
6281 var transitionEndVal = false;
6283 var transitionEnd = function()
6285 if (transitionEndVal) {
6286 return transitionEndVal;
6288 var el = document.createElement('div');
6290 var transEndEventNames = {
6291 WebkitTransition : 'webkitTransitionEnd',
6292 MozTransition : 'transitionend',
6293 OTransition : 'oTransitionEnd otransitionend',
6294 transition : 'transitionend'
6297 for (var name in transEndEventNames) {
6298 if (el.style[name] !== undefined) {
6299 transitionEndVal = transEndEventNames[name];
6300 return transitionEndVal ;
6307 var listen = function(element, ename, opt, fn, scope){
6308 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6309 fn = fn || o.fn; scope = scope || o.scope;
6310 var el = Roo.getDom(element);
6314 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6317 if (ename == 'transitionend') {
6318 ename = transitionEnd();
6320 var h = function(e){
6321 e = Roo.EventObject.setEvent(e);
6324 t = e.getTarget(o.delegate, el);
6331 if(o.stopEvent === true){
6334 if(o.preventDefault === true){
6337 if(o.stopPropagation === true){
6338 e.stopPropagation();
6341 if(o.normalized === false){
6345 fn.call(scope || el, e, t, o);
6348 h = createDelayed(h, o);
6351 h = createSingle(h, el, ename, fn);
6354 h = createBuffered(h, o);
6357 fn._handlers = fn._handlers || [];
6360 fn._handlers.push([Roo.id(el), ename, h]);
6365 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6366 el.addEventListener("DOMMouseScroll", h, false);
6367 E.on(window, 'unload', function(){
6368 el.removeEventListener("DOMMouseScroll", h, false);
6371 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6372 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6377 var stopListening = function(el, ename, fn){
6378 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6380 for(var i = 0, len = hds.length; i < len; i++){
6382 if(h[0] == id && h[1] == ename){
6389 E.un(el, ename, hd);
6390 el = Roo.getDom(el);
6391 if(ename == "mousewheel" && el.addEventListener){
6392 el.removeEventListener("DOMMouseScroll", hd, false);
6394 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6395 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6399 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6406 * @scope Roo.EventManager
6411 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6412 * object with a Roo.EventObject
6413 * @param {Function} fn The method the event invokes
6414 * @param {Object} scope An object that becomes the scope of the handler
6415 * @param {boolean} override If true, the obj passed in becomes
6416 * the execution scope of the listener
6417 * @return {Function} The wrapped function
6420 wrap : function(fn, scope, override){
6422 Roo.EventObject.setEvent(e);
6423 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6428 * Appends an event handler to an element (shorthand for addListener)
6429 * @param {String/HTMLElement} element The html element or id to assign the
6430 * @param {String} eventName The type of event to listen for
6431 * @param {Function} handler The method the event invokes
6432 * @param {Object} scope (optional) The scope in which to execute the handler
6433 * function. The handler function's "this" context.
6434 * @param {Object} options (optional) An object containing handler configuration
6435 * properties. This may contain any of the following properties:<ul>
6436 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6437 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6438 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6439 * <li>preventDefault {Boolean} True to prevent the default action</li>
6440 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6441 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6442 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6443 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6444 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6445 * by the specified number of milliseconds. If the event fires again within that time, the original
6446 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6449 * <b>Combining Options</b><br>
6450 * Using the options argument, it is possible to combine different types of listeners:<br>
6452 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6454 el.on('click', this.onClick, this, {
6461 * <b>Attaching multiple handlers in 1 call</b><br>
6462 * The method also allows for a single argument to be passed which is a config object containing properties
6463 * which specify multiple handlers.
6473 fn: this.onMouseOver
6482 * Or a shorthand syntax:<br>
6485 'click' : this.onClick,
6486 'mouseover' : this.onMouseOver,
6487 'mouseout' : this.onMouseOut
6491 addListener : function(element, eventName, fn, scope, options){
6492 if(typeof eventName == "object"){
6498 if(typeof o[e] == "function"){
6500 listen(element, e, o, o[e], o.scope);
6502 // individual options
6503 listen(element, e, o[e]);
6508 return listen(element, eventName, options, fn, scope);
6512 * Removes an event handler
6514 * @param {String/HTMLElement} element The id or html element to remove the
6516 * @param {String} eventName The type of event
6517 * @param {Function} fn
6518 * @return {Boolean} True if a listener was actually removed
6520 removeListener : function(element, eventName, fn){
6521 return stopListening(element, eventName, fn);
6525 * Fires when the document is ready (before onload and before images are loaded). Can be
6526 * accessed shorthanded Roo.onReady().
6527 * @param {Function} fn The method the event invokes
6528 * @param {Object} scope An object that becomes the scope of the handler
6529 * @param {boolean} options
6531 onDocumentReady : function(fn, scope, options){
6532 if(docReadyState){ // if it already fired
6533 docReadyEvent.addListener(fn, scope, options);
6534 docReadyEvent.fire();
6535 docReadyEvent.clearListeners();
6541 docReadyEvent.addListener(fn, scope, options);
6545 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6546 * @param {Function} fn The method the event invokes
6547 * @param {Object} scope An object that becomes the scope of the handler
6548 * @param {boolean} options
6550 onWindowResize : function(fn, scope, options){
6552 resizeEvent = new Roo.util.Event();
6553 resizeTask = new Roo.util.DelayedTask(function(){
6554 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6556 E.on(window, "resize", function(){
6558 resizeTask.delay(50);
6560 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6564 resizeEvent.addListener(fn, scope, options);
6568 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6569 * @param {Function} fn The method the event invokes
6570 * @param {Object} scope An object that becomes the scope of the handler
6571 * @param {boolean} options
6573 onTextResize : function(fn, scope, options){
6575 textEvent = new Roo.util.Event();
6576 var textEl = new Roo.Element(document.createElement('div'));
6577 textEl.dom.className = 'x-text-resize';
6578 textEl.dom.innerHTML = 'X';
6579 textEl.appendTo(document.body);
6580 textSize = textEl.dom.offsetHeight;
6581 setInterval(function(){
6582 if(textEl.dom.offsetHeight != textSize){
6583 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6585 }, this.textResizeInterval);
6587 textEvent.addListener(fn, scope, options);
6591 * Removes the passed window resize listener.
6592 * @param {Function} fn The method the event invokes
6593 * @param {Object} scope The scope of handler
6595 removeResizeListener : function(fn, scope){
6597 resizeEvent.removeListener(fn, scope);
6602 fireResize : function(){
6604 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6608 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6612 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6614 textResizeInterval : 50
6619 * @scopeAlias pub=Roo.EventManager
6623 * Appends an event handler to an element (shorthand for addListener)
6624 * @param {String/HTMLElement} element The html element or id to assign the
6625 * @param {String} eventName The type of event to listen for
6626 * @param {Function} handler The method the event invokes
6627 * @param {Object} scope (optional) The scope in which to execute the handler
6628 * function. The handler function's "this" context.
6629 * @param {Object} options (optional) An object containing handler configuration
6630 * properties. This may contain any of the following properties:<ul>
6631 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6632 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6633 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6634 * <li>preventDefault {Boolean} True to prevent the default action</li>
6635 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6636 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6637 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6638 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6639 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6640 * by the specified number of milliseconds. If the event fires again within that time, the original
6641 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6644 * <b>Combining Options</b><br>
6645 * Using the options argument, it is possible to combine different types of listeners:<br>
6647 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6649 el.on('click', this.onClick, this, {
6656 * <b>Attaching multiple handlers in 1 call</b><br>
6657 * The method also allows for a single argument to be passed which is a config object containing properties
6658 * which specify multiple handlers.
6668 fn: this.onMouseOver
6677 * Or a shorthand syntax:<br>
6680 'click' : this.onClick,
6681 'mouseover' : this.onMouseOver,
6682 'mouseout' : this.onMouseOut
6686 pub.on = pub.addListener;
6687 pub.un = pub.removeListener;
6689 pub.stoppedMouseDownEvent = new Roo.util.Event();
6693 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6694 * @param {Function} fn The method the event invokes
6695 * @param {Object} scope An object that becomes the scope of the handler
6696 * @param {boolean} override If true, the obj passed in becomes
6697 * the execution scope of the listener
6701 Roo.onReady = Roo.EventManager.onDocumentReady;
6703 Roo.onReady(function(){
6704 var bd = Roo.get(document.body);
6709 : Roo.isIE11 ? "roo-ie11"
6710 : Roo.isEdge ? "roo-edge"
6711 : Roo.isGecko ? "roo-gecko"
6712 : Roo.isOpera ? "roo-opera"
6713 : Roo.isSafari ? "roo-safari" : ""];
6716 cls.push("roo-mac");
6719 cls.push("roo-linux");
6722 cls.push("roo-ios");
6725 cls.push("roo-touch");
6727 if(Roo.isBorderBox){
6728 cls.push('roo-border-box');
6730 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6731 var p = bd.dom.parentNode;
6733 p.className += ' roo-strict';
6736 bd.addClass(cls.join(' '));
6740 * @class Roo.EventObject
6741 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6742 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6745 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6747 var target = e.getTarget();
6750 var myDiv = Roo.get("myDiv");
6751 myDiv.on("click", handleClick);
6753 Roo.EventManager.on("myDiv", 'click', handleClick);
6754 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6758 Roo.EventObject = function(){
6760 var E = Roo.lib.Event;
6762 // safari keypress events for special keys return bad keycodes
6765 63235 : 39, // right
6768 63276 : 33, // page up
6769 63277 : 34, // page down
6770 63272 : 46, // delete
6775 // normalize button clicks
6776 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6777 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6779 Roo.EventObjectImpl = function(e){
6781 this.setEvent(e.browserEvent || e);
6784 Roo.EventObjectImpl.prototype = {
6786 * Used to fix doc tools.
6787 * @scope Roo.EventObject.prototype
6793 /** The normal browser event */
6794 browserEvent : null,
6795 /** The button pressed in a mouse event */
6797 /** True if the shift key was down during the event */
6799 /** True if the control key was down during the event */
6801 /** True if the alt key was down during the event */
6860 setEvent : function(e){
6861 if(e == this || (e && e.browserEvent)){ // already wrapped
6864 this.browserEvent = e;
6866 // normalize buttons
6867 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6868 if(e.type == 'click' && this.button == -1){
6872 this.shiftKey = e.shiftKey;
6873 // mac metaKey behaves like ctrlKey
6874 this.ctrlKey = e.ctrlKey || e.metaKey;
6875 this.altKey = e.altKey;
6876 // in getKey these will be normalized for the mac
6877 this.keyCode = e.keyCode;
6878 // keyup warnings on firefox.
6879 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6880 // cache the target for the delayed and or buffered events
6881 this.target = E.getTarget(e);
6883 this.xy = E.getXY(e);
6886 this.shiftKey = false;
6887 this.ctrlKey = false;
6888 this.altKey = false;
6898 * Stop the event (preventDefault and stopPropagation)
6900 stopEvent : function(){
6901 if(this.browserEvent){
6902 if(this.browserEvent.type == 'mousedown'){
6903 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6905 E.stopEvent(this.browserEvent);
6910 * Prevents the browsers default handling of the event.
6912 preventDefault : function(){
6913 if(this.browserEvent){
6914 E.preventDefault(this.browserEvent);
6919 isNavKeyPress : function(){
6920 var k = this.keyCode;
6921 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6922 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6925 isSpecialKey : function(){
6926 var k = this.keyCode;
6927 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6928 (k == 16) || (k == 17) ||
6929 (k >= 18 && k <= 20) ||
6930 (k >= 33 && k <= 35) ||
6931 (k >= 36 && k <= 39) ||
6932 (k >= 44 && k <= 45);
6935 * Cancels bubbling of the event.
6937 stopPropagation : function(){
6938 if(this.browserEvent){
6939 if(this.type == 'mousedown'){
6940 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6942 E.stopPropagation(this.browserEvent);
6947 * Gets the key code for the event.
6950 getCharCode : function(){
6951 return this.charCode || this.keyCode;
6955 * Returns a normalized keyCode for the event.
6956 * @return {Number} The key code
6958 getKey : function(){
6959 var k = this.keyCode || this.charCode;
6960 return Roo.isSafari ? (safariKeys[k] || k) : k;
6964 * Gets the x coordinate of the event.
6967 getPageX : function(){
6972 * Gets the y coordinate of the event.
6975 getPageY : function(){
6980 * Gets the time of the event.
6983 getTime : function(){
6984 if(this.browserEvent){
6985 return E.getTime(this.browserEvent);
6991 * Gets the page coordinates of the event.
6992 * @return {Array} The xy values like [x, y]
6999 * Gets the target for the event.
7000 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7001 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7002 search as a number or element (defaults to 10 || document.body)
7003 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7004 * @return {HTMLelement}
7006 getTarget : function(selector, maxDepth, returnEl){
7007 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7010 * Gets the related target.
7011 * @return {HTMLElement}
7013 getRelatedTarget : function(){
7014 if(this.browserEvent){
7015 return E.getRelatedTarget(this.browserEvent);
7021 * Normalizes mouse wheel delta across browsers
7022 * @return {Number} The delta
7024 getWheelDelta : function(){
7025 var e = this.browserEvent;
7027 if(e.wheelDelta){ /* IE/Opera. */
7028 delta = e.wheelDelta/120;
7029 }else if(e.detail){ /* Mozilla case. */
7030 delta = -e.detail/3;
7036 * Returns true if the control, meta, shift or alt key was pressed during this event.
7039 hasModifier : function(){
7040 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7044 * Returns true if the target of this event equals el or is a child of el
7045 * @param {String/HTMLElement/Element} el
7046 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7049 within : function(el, related){
7050 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7051 return t && Roo.fly(el).contains(t);
7054 getPoint : function(){
7055 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7059 return new Roo.EventObjectImpl();
7064 * Ext JS Library 1.1.1
7065 * Copyright(c) 2006-2007, Ext JS, LLC.
7067 * Originally Released Under LGPL - original licence link has changed is not relivant.
7070 * <script type="text/javascript">
7074 // was in Composite Element!??!?!
7077 var D = Roo.lib.Dom;
7078 var E = Roo.lib.Event;
7079 var A = Roo.lib.Anim;
7081 // local style camelizing for speed
7083 var camelRe = /(-[a-z])/gi;
7084 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7085 var view = document.defaultView;
7088 * @class Roo.Element
7089 * Represents an Element in the DOM.<br><br>
7092 var el = Roo.get("my-div");
7095 var el = getEl("my-div");
7097 // or with a DOM element
7098 var el = Roo.get(myDivElement);
7100 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7101 * each call instead of constructing a new one.<br><br>
7102 * <b>Animations</b><br />
7103 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7104 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7106 Option Default Description
7107 --------- -------- ---------------------------------------------
7108 duration .35 The duration of the animation in seconds
7109 easing easeOut The YUI easing method
7110 callback none A function to execute when the anim completes
7111 scope this The scope (this) of the callback function
7113 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7114 * manipulate the animation. Here's an example:
7116 var el = Roo.get("my-div");
7121 // default animation
7122 el.setWidth(100, true);
7124 // animation with some options set
7131 // using the "anim" property to get the Anim object
7137 el.setWidth(100, opt);
7139 if(opt.anim.isAnimated()){
7143 * <b> Composite (Collections of) Elements</b><br />
7144 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7145 * @constructor Create a new Element directly.
7146 * @param {String/HTMLElement} element
7147 * @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).
7149 Roo.Element = function(element, forceNew){
7150 var dom = typeof element == "string" ?
7151 document.getElementById(element) : element;
7152 if(!dom){ // invalid id/element
7156 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7157 return Roo.Element.cache[id];
7167 * The DOM element ID
7170 this.id = id || Roo.id(dom);
7173 var El = Roo.Element;
7177 * The element's default display mode (defaults to "")
7180 originalDisplay : "",
7183 // note this is overridden in BS version..
7186 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7192 * Sets the element's visibility mode. When setVisible() is called it
7193 * will use this to determine whether to set the visibility or the display property.
7194 * @param visMode Element.VISIBILITY or Element.DISPLAY
7195 * @return {Roo.Element} this
7197 setVisibilityMode : function(visMode){
7198 this.visibilityMode = visMode;
7202 * Convenience method for setVisibilityMode(Element.DISPLAY)
7203 * @param {String} display (optional) What to set display to when visible
7204 * @return {Roo.Element} this
7206 enableDisplayMode : function(display){
7207 this.setVisibilityMode(El.DISPLAY);
7208 if(typeof display != "undefined") { this.originalDisplay = display; }
7213 * 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)
7214 * @param {String} selector The simple selector to test
7215 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7216 search as a number or element (defaults to 10 || document.body)
7217 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7218 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7220 findParent : function(simpleSelector, maxDepth, returnEl){
7221 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7222 maxDepth = maxDepth || 50;
7223 if(typeof maxDepth != "number"){
7224 stopEl = Roo.getDom(maxDepth);
7227 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7228 if(dq.is(p, simpleSelector)){
7229 return returnEl ? Roo.get(p) : p;
7239 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7240 * @param {String} selector The simple selector to test
7241 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7242 search as a number or element (defaults to 10 || document.body)
7243 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7244 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7246 findParentNode : function(simpleSelector, maxDepth, returnEl){
7247 var p = Roo.fly(this.dom.parentNode, '_internal');
7248 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7252 * Looks at the scrollable parent element
7254 findScrollableParent : function()
7256 var overflowRegex = /(auto|scroll)/;
7258 if(this.getStyle('position') === 'fixed'){
7259 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7262 var excludeStaticParent = this.getStyle('position') === "absolute";
7264 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7266 if (excludeStaticParent && parent.getStyle('position') === "static") {
7270 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7274 if(parent.dom.nodeName.toLowerCase() == 'body'){
7275 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7279 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7283 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7284 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7285 * @param {String} selector The simple selector to test
7286 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7287 search as a number or element (defaults to 10 || document.body)
7288 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7290 up : function(simpleSelector, maxDepth){
7291 return this.findParentNode(simpleSelector, maxDepth, true);
7297 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7298 * @param {String} selector The simple selector to test
7299 * @return {Boolean} True if this element matches the selector, else false
7301 is : function(simpleSelector){
7302 return Roo.DomQuery.is(this.dom, simpleSelector);
7306 * Perform animation on this element.
7307 * @param {Object} args The YUI animation control args
7308 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7309 * @param {Function} onComplete (optional) Function to call when animation completes
7310 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7311 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7312 * @return {Roo.Element} this
7314 animate : function(args, duration, onComplete, easing, animType){
7315 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7320 * @private Internal animation call
7322 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7323 animType = animType || 'run';
7325 var anim = Roo.lib.Anim[animType](
7327 (opt.duration || defaultDur) || .35,
7328 (opt.easing || defaultEase) || 'easeOut',
7330 Roo.callback(cb, this);
7331 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7339 // private legacy anim prep
7340 preanim : function(a, i){
7341 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7345 * Removes worthless text nodes
7346 * @param {Boolean} forceReclean (optional) By default the element
7347 * keeps track if it has been cleaned already so
7348 * you can call this over and over. However, if you update the element and
7349 * need to force a reclean, you can pass true.
7351 clean : function(forceReclean){
7352 if(this.isCleaned && forceReclean !== true){
7356 var d = this.dom, n = d.firstChild, ni = -1;
7358 var nx = n.nextSibling;
7359 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7366 this.isCleaned = true;
7371 calcOffsetsTo : function(el){
7374 var restorePos = false;
7375 if(el.getStyle('position') == 'static'){
7376 el.position('relative');
7381 while(op && op != d && op.tagName != 'HTML'){
7384 op = op.offsetParent;
7387 el.position('static');
7393 * Scrolls this element into view within the passed container.
7394 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7395 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7396 * @return {Roo.Element} this
7398 scrollIntoView : function(container, hscroll){
7399 var c = Roo.getDom(container) || document.body;
7402 var o = this.calcOffsetsTo(c),
7405 b = t+el.offsetHeight,
7406 r = l+el.offsetWidth;
7408 var ch = c.clientHeight;
7409 var ct = parseInt(c.scrollTop, 10);
7410 var cl = parseInt(c.scrollLeft, 10);
7412 var cr = cl + c.clientWidth;
7420 if(hscroll !== false){
7424 c.scrollLeft = r-c.clientWidth;
7431 scrollChildIntoView : function(child, hscroll){
7432 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7436 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7437 * the new height may not be available immediately.
7438 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7439 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7440 * @param {Function} onComplete (optional) Function to call when animation completes
7441 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7442 * @return {Roo.Element} this
7444 autoHeight : function(animate, duration, onComplete, easing){
7445 var oldHeight = this.getHeight();
7447 this.setHeight(1); // force clipping
7448 setTimeout(function(){
7449 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7451 this.setHeight(height);
7453 if(typeof onComplete == "function"){
7457 this.setHeight(oldHeight); // restore original height
7458 this.setHeight(height, animate, duration, function(){
7460 if(typeof onComplete == "function") { onComplete(); }
7461 }.createDelegate(this), easing);
7463 }.createDelegate(this), 0);
7468 * Returns true if this element is an ancestor of the passed element
7469 * @param {HTMLElement/String} el The element to check
7470 * @return {Boolean} True if this element is an ancestor of el, else false
7472 contains : function(el){
7473 if(!el){return false;}
7474 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7478 * Checks whether the element is currently visible using both visibility and display properties.
7479 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7480 * @return {Boolean} True if the element is currently visible, else false
7482 isVisible : function(deep) {
7483 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7484 if(deep !== true || !vis){
7487 var p = this.dom.parentNode;
7488 while(p && p.tagName.toLowerCase() != "body"){
7489 if(!Roo.fly(p, '_isVisible').isVisible()){
7498 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7499 * @param {String} selector The CSS selector
7500 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7501 * @return {CompositeElement/CompositeElementLite} The composite element
7503 select : function(selector, unique){
7504 return El.select(selector, unique, this.dom);
7508 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7509 * @param {String} selector The CSS selector
7510 * @return {Array} An array of the matched nodes
7512 query : function(selector, unique){
7513 return Roo.DomQuery.select(selector, this.dom);
7517 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7518 * @param {String} selector The CSS selector
7519 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7520 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7522 child : function(selector, returnDom){
7523 var n = Roo.DomQuery.selectNode(selector, this.dom);
7524 return returnDom ? n : Roo.get(n);
7528 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7529 * @param {String} selector The CSS selector
7530 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7531 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7533 down : function(selector, returnDom){
7534 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7535 return returnDom ? n : Roo.get(n);
7539 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7540 * @param {String} group The group the DD object is member of
7541 * @param {Object} config The DD config object
7542 * @param {Object} overrides An object containing methods to override/implement on the DD object
7543 * @return {Roo.dd.DD} The DD object
7545 initDD : function(group, config, overrides){
7546 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7547 return Roo.apply(dd, overrides);
7551 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7552 * @param {String} group The group the DDProxy object is member of
7553 * @param {Object} config The DDProxy config object
7554 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7555 * @return {Roo.dd.DDProxy} The DDProxy object
7557 initDDProxy : function(group, config, overrides){
7558 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7559 return Roo.apply(dd, overrides);
7563 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7564 * @param {String} group The group the DDTarget object is member of
7565 * @param {Object} config The DDTarget config object
7566 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7567 * @return {Roo.dd.DDTarget} The DDTarget object
7569 initDDTarget : function(group, config, overrides){
7570 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7571 return Roo.apply(dd, overrides);
7575 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7576 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7577 * @param {Boolean} visible Whether the element is visible
7578 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7579 * @return {Roo.Element} this
7581 setVisible : function(visible, animate){
7583 if(this.visibilityMode == El.DISPLAY){
7584 this.setDisplayed(visible);
7587 this.dom.style.visibility = visible ? "visible" : "hidden";
7590 // closure for composites
7592 var visMode = this.visibilityMode;
7594 this.setOpacity(.01);
7595 this.setVisible(true);
7597 this.anim({opacity: { to: (visible?1:0) }},
7598 this.preanim(arguments, 1),
7599 null, .35, 'easeIn', function(){
7601 if(visMode == El.DISPLAY){
7602 dom.style.display = "none";
7604 dom.style.visibility = "hidden";
7606 Roo.get(dom).setOpacity(1);
7614 * Returns true if display is not "none"
7617 isDisplayed : function() {
7618 return this.getStyle("display") != "none";
7622 * Toggles the element's visibility or display, depending on visibility mode.
7623 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7624 * @return {Roo.Element} this
7626 toggle : function(animate){
7627 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7632 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7633 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7634 * @return {Roo.Element} this
7636 setDisplayed : function(value) {
7637 if(typeof value == "boolean"){
7638 value = value ? this.originalDisplay : "none";
7640 this.setStyle("display", value);
7645 * Tries to focus the element. Any exceptions are caught and ignored.
7646 * @return {Roo.Element} this
7648 focus : function() {
7656 * Tries to blur the element. Any exceptions are caught and ignored.
7657 * @return {Roo.Element} this
7667 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7668 * @param {String/Array} className The CSS class to add, or an array of classes
7669 * @return {Roo.Element} this
7671 addClass : function(className){
7672 if(className instanceof Array){
7673 for(var i = 0, len = className.length; i < len; i++) {
7674 this.addClass(className[i]);
7677 if(className && !this.hasClass(className)){
7678 this.dom.className = this.dom.className + " " + className;
7685 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7686 * @param {String/Array} className The CSS class to add, or an array of classes
7687 * @return {Roo.Element} this
7689 radioClass : function(className){
7690 var siblings = this.dom.parentNode.childNodes;
7691 for(var i = 0; i < siblings.length; i++) {
7692 var s = siblings[i];
7693 if(s.nodeType == 1){
7694 Roo.get(s).removeClass(className);
7697 this.addClass(className);
7702 * Removes one or more CSS classes from the element.
7703 * @param {String/Array} className The CSS class to remove, or an array of classes
7704 * @return {Roo.Element} this
7706 removeClass : function(className){
7707 if(!className || !this.dom.className){
7710 if(className instanceof Array){
7711 for(var i = 0, len = className.length; i < len; i++) {
7712 this.removeClass(className[i]);
7715 if(this.hasClass(className)){
7716 var re = this.classReCache[className];
7718 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7719 this.classReCache[className] = re;
7721 this.dom.className =
7722 this.dom.className.replace(re, " ");
7732 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7733 * @param {String} className The CSS class to toggle
7734 * @return {Roo.Element} this
7736 toggleClass : function(className){
7737 if(this.hasClass(className)){
7738 this.removeClass(className);
7740 this.addClass(className);
7746 * Checks if the specified CSS class exists on this element's DOM node.
7747 * @param {String} className The CSS class to check for
7748 * @return {Boolean} True if the class exists, else false
7750 hasClass : function(className){
7751 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7755 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7756 * @param {String} oldClassName The CSS class to replace
7757 * @param {String} newClassName The replacement CSS class
7758 * @return {Roo.Element} this
7760 replaceClass : function(oldClassName, newClassName){
7761 this.removeClass(oldClassName);
7762 this.addClass(newClassName);
7767 * Returns an object with properties matching the styles requested.
7768 * For example, el.getStyles('color', 'font-size', 'width') might return
7769 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7770 * @param {String} style1 A style name
7771 * @param {String} style2 A style name
7772 * @param {String} etc.
7773 * @return {Object} The style object
7775 getStyles : function(){
7776 var a = arguments, len = a.length, r = {};
7777 for(var i = 0; i < len; i++){
7778 r[a[i]] = this.getStyle(a[i]);
7784 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7785 * @param {String} property The style property whose value is returned.
7786 * @return {String} The current value of the style property for this element.
7788 getStyle : function(){
7789 return view && view.getComputedStyle ?
7791 var el = this.dom, v, cs, camel;
7792 if(prop == 'float'){
7795 if(el.style && (v = el.style[prop])){
7798 if(cs = view.getComputedStyle(el, "")){
7799 if(!(camel = propCache[prop])){
7800 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7807 var el = this.dom, v, cs, camel;
7808 if(prop == 'opacity'){
7809 if(typeof el.style.filter == 'string'){
7810 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7812 var fv = parseFloat(m[1]);
7814 return fv ? fv / 100 : 0;
7819 }else if(prop == 'float'){
7820 prop = "styleFloat";
7822 if(!(camel = propCache[prop])){
7823 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7825 if(v = el.style[camel]){
7828 if(cs = el.currentStyle){
7836 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7837 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7838 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7839 * @return {Roo.Element} this
7841 setStyle : function(prop, value){
7842 if(typeof prop == "string"){
7844 if (prop == 'float') {
7845 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7850 if(!(camel = propCache[prop])){
7851 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7854 if(camel == 'opacity') {
7855 this.setOpacity(value);
7857 this.dom.style[camel] = value;
7860 for(var style in prop){
7861 if(typeof prop[style] != "function"){
7862 this.setStyle(style, prop[style]);
7870 * More flexible version of {@link #setStyle} for setting style properties.
7871 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7872 * a function which returns such a specification.
7873 * @return {Roo.Element} this
7875 applyStyles : function(style){
7876 Roo.DomHelper.applyStyles(this.dom, style);
7881 * 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).
7882 * @return {Number} The X position of the element
7885 return D.getX(this.dom);
7889 * 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).
7890 * @return {Number} The Y position of the element
7893 return D.getY(this.dom);
7897 * 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).
7898 * @return {Array} The XY position of the element
7901 return D.getXY(this.dom);
7905 * 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).
7906 * @param {Number} The X position of the element
7907 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7908 * @return {Roo.Element} this
7910 setX : function(x, animate){
7912 D.setX(this.dom, x);
7914 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7920 * 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).
7921 * @param {Number} The Y position of the element
7922 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7923 * @return {Roo.Element} this
7925 setY : function(y, animate){
7927 D.setY(this.dom, y);
7929 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7935 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7936 * @param {String} left The left CSS property value
7937 * @return {Roo.Element} this
7939 setLeft : function(left){
7940 this.setStyle("left", this.addUnits(left));
7945 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7946 * @param {String} top The top CSS property value
7947 * @return {Roo.Element} this
7949 setTop : function(top){
7950 this.setStyle("top", this.addUnits(top));
7955 * Sets the element's CSS right style.
7956 * @param {String} right The right CSS property value
7957 * @return {Roo.Element} this
7959 setRight : function(right){
7960 this.setStyle("right", this.addUnits(right));
7965 * Sets the element's CSS bottom style.
7966 * @param {String} bottom The bottom CSS property value
7967 * @return {Roo.Element} this
7969 setBottom : function(bottom){
7970 this.setStyle("bottom", this.addUnits(bottom));
7975 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7976 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7977 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7978 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7979 * @return {Roo.Element} this
7981 setXY : function(pos, animate){
7983 D.setXY(this.dom, pos);
7985 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7991 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7992 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7993 * @param {Number} x X value for new position (coordinates are page-based)
7994 * @param {Number} y Y value for new position (coordinates are page-based)
7995 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7996 * @return {Roo.Element} this
7998 setLocation : function(x, y, animate){
7999 this.setXY([x, y], this.preanim(arguments, 2));
8004 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8005 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8006 * @param {Number} x X value for new position (coordinates are page-based)
8007 * @param {Number} y Y value for new position (coordinates are page-based)
8008 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8009 * @return {Roo.Element} this
8011 moveTo : function(x, y, animate){
8012 this.setXY([x, y], this.preanim(arguments, 2));
8017 * Returns the region of the given element.
8018 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8019 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8021 getRegion : function(){
8022 return D.getRegion(this.dom);
8026 * Returns the offset height of the element
8027 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8028 * @return {Number} The element's height
8030 getHeight : function(contentHeight){
8031 var h = this.dom.offsetHeight || 0;
8032 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8036 * Returns the offset width of the element
8037 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8038 * @return {Number} The element's width
8040 getWidth : function(contentWidth){
8041 var w = this.dom.offsetWidth || 0;
8042 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8046 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8047 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8048 * if a height has not been set using CSS.
8051 getComputedHeight : function(){
8052 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8054 h = parseInt(this.getStyle('height'), 10) || 0;
8055 if(!this.isBorderBox()){
8056 h += this.getFrameWidth('tb');
8063 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8064 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8065 * if a width has not been set using CSS.
8068 getComputedWidth : function(){
8069 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8071 w = parseInt(this.getStyle('width'), 10) || 0;
8072 if(!this.isBorderBox()){
8073 w += this.getFrameWidth('lr');
8080 * Returns the size of the element.
8081 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8082 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8084 getSize : function(contentSize){
8085 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8089 * Returns the width and height of the viewport.
8090 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8092 getViewSize : function(){
8093 var d = this.dom, doc = document, aw = 0, ah = 0;
8094 if(d == doc || d == doc.body){
8095 return {width : D.getViewWidth(), height: D.getViewHeight()};
8098 width : d.clientWidth,
8099 height: d.clientHeight
8105 * Returns the value of the "value" attribute
8106 * @param {Boolean} asNumber true to parse the value as a number
8107 * @return {String/Number}
8109 getValue : function(asNumber){
8110 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8114 adjustWidth : function(width){
8115 if(typeof width == "number"){
8116 if(this.autoBoxAdjust && !this.isBorderBox()){
8117 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8127 adjustHeight : function(height){
8128 if(typeof height == "number"){
8129 if(this.autoBoxAdjust && !this.isBorderBox()){
8130 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8140 * Set the width of the element
8141 * @param {Number} width The new width
8142 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8143 * @return {Roo.Element} this
8145 setWidth : function(width, animate){
8146 width = this.adjustWidth(width);
8148 this.dom.style.width = this.addUnits(width);
8150 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8156 * Set the height of the element
8157 * @param {Number} height The new height
8158 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8159 * @return {Roo.Element} this
8161 setHeight : function(height, animate){
8162 height = this.adjustHeight(height);
8164 this.dom.style.height = this.addUnits(height);
8166 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8172 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8173 * @param {Number} width The new width
8174 * @param {Number} height The new height
8175 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8176 * @return {Roo.Element} this
8178 setSize : function(width, height, animate){
8179 if(typeof width == "object"){ // in case of object from getSize()
8180 height = width.height; width = width.width;
8182 width = this.adjustWidth(width); height = this.adjustHeight(height);
8184 this.dom.style.width = this.addUnits(width);
8185 this.dom.style.height = this.addUnits(height);
8187 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8193 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8194 * @param {Number} x X value for new position (coordinates are page-based)
8195 * @param {Number} y Y value for new position (coordinates are page-based)
8196 * @param {Number} width The new width
8197 * @param {Number} height The new height
8198 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8199 * @return {Roo.Element} this
8201 setBounds : function(x, y, width, height, animate){
8203 this.setSize(width, height);
8204 this.setLocation(x, y);
8206 width = this.adjustWidth(width); height = this.adjustHeight(height);
8207 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8208 this.preanim(arguments, 4), 'motion');
8214 * 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.
8215 * @param {Roo.lib.Region} region The region to fill
8216 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8217 * @return {Roo.Element} this
8219 setRegion : function(region, animate){
8220 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8225 * Appends an event handler
8227 * @param {String} eventName The type of event to append
8228 * @param {Function} fn The method the event invokes
8229 * @param {Object} scope (optional) The scope (this object) of the fn
8230 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8232 addListener : function(eventName, fn, scope, options){
8234 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8236 if (eventName == 'dblclick') {
8237 this.addListener('touchstart', this.onTapHandler, this);
8241 onTapHandler : function(event)
8243 if(!this.tapedTwice) {
8244 this.tapedTwice = true;
8246 setTimeout( function() {
8247 s.tapedTwice = false;
8251 event.preventDefault();
8252 var revent = new MouseEvent('dblclick', {
8258 this.dom.dispatchEvent(revent);
8259 //action on double tap goes below
8264 * Removes an event handler from this element
8265 * @param {String} eventName the type of event to remove
8266 * @param {Function} fn the method the event invokes
8267 * @return {Roo.Element} this
8269 removeListener : function(eventName, fn){
8270 Roo.EventManager.removeListener(this.dom, eventName, fn);
8275 * Removes all previous added listeners from this element
8276 * @return {Roo.Element} this
8278 removeAllListeners : function(){
8279 E.purgeElement(this.dom);
8283 relayEvent : function(eventName, observable){
8284 this.on(eventName, function(e){
8285 observable.fireEvent(eventName, e);
8290 * Set the opacity of the element
8291 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8292 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8293 * @return {Roo.Element} this
8295 setOpacity : function(opacity, animate){
8297 var s = this.dom.style;
8300 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8301 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8303 s.opacity = opacity;
8306 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8312 * Gets the left X coordinate
8313 * @param {Boolean} local True to get the local css position instead of page coordinate
8316 getLeft : function(local){
8320 return parseInt(this.getStyle("left"), 10) || 0;
8325 * Gets the right X coordinate of the element (element X position + element width)
8326 * @param {Boolean} local True to get the local css position instead of page coordinate
8329 getRight : function(local){
8331 return this.getX() + this.getWidth();
8333 return (this.getLeft(true) + this.getWidth()) || 0;
8338 * Gets the top Y coordinate
8339 * @param {Boolean} local True to get the local css position instead of page coordinate
8342 getTop : function(local) {
8346 return parseInt(this.getStyle("top"), 10) || 0;
8351 * Gets the bottom Y coordinate of the element (element Y position + element height)
8352 * @param {Boolean} local True to get the local css position instead of page coordinate
8355 getBottom : function(local){
8357 return this.getY() + this.getHeight();
8359 return (this.getTop(true) + this.getHeight()) || 0;
8364 * Initializes positioning on this element. If a desired position is not passed, it will make the
8365 * the element positioned relative IF it is not already positioned.
8366 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8367 * @param {Number} zIndex (optional) The zIndex to apply
8368 * @param {Number} x (optional) Set the page X position
8369 * @param {Number} y (optional) Set the page Y position
8371 position : function(pos, zIndex, x, y){
8373 if(this.getStyle('position') == 'static'){
8374 this.setStyle('position', 'relative');
8377 this.setStyle("position", pos);
8380 this.setStyle("z-index", zIndex);
8382 if(x !== undefined && y !== undefined){
8384 }else if(x !== undefined){
8386 }else if(y !== undefined){
8392 * Clear positioning back to the default when the document was loaded
8393 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8394 * @return {Roo.Element} this
8396 clearPositioning : function(value){
8404 "position" : "static"
8410 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8411 * snapshot before performing an update and then restoring the element.
8414 getPositioning : function(){
8415 var l = this.getStyle("left");
8416 var t = this.getStyle("top");
8418 "position" : this.getStyle("position"),
8420 "right" : l ? "" : this.getStyle("right"),
8422 "bottom" : t ? "" : this.getStyle("bottom"),
8423 "z-index" : this.getStyle("z-index")
8428 * Gets the width of the border(s) for the specified side(s)
8429 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8430 * passing lr would get the border (l)eft width + the border (r)ight width.
8431 * @return {Number} The width of the sides passed added together
8433 getBorderWidth : function(side){
8434 return this.addStyles(side, El.borders);
8438 * Gets the width of the padding(s) for the specified side(s)
8439 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8440 * passing lr would get the padding (l)eft + the padding (r)ight.
8441 * @return {Number} The padding of the sides passed added together
8443 getPadding : function(side){
8444 return this.addStyles(side, El.paddings);
8448 * Set positioning with an object returned by getPositioning().
8449 * @param {Object} posCfg
8450 * @return {Roo.Element} this
8452 setPositioning : function(pc){
8453 this.applyStyles(pc);
8454 if(pc.right == "auto"){
8455 this.dom.style.right = "";
8457 if(pc.bottom == "auto"){
8458 this.dom.style.bottom = "";
8464 fixDisplay : function(){
8465 if(this.getStyle("display") == "none"){
8466 this.setStyle("visibility", "hidden");
8467 this.setStyle("display", this.originalDisplay); // first try reverting to default
8468 if(this.getStyle("display") == "none"){ // if that fails, default to block
8469 this.setStyle("display", "block");
8475 * Quick set left and top adding default units
8476 * @param {String} left The left CSS property value
8477 * @param {String} top The top CSS property value
8478 * @return {Roo.Element} this
8480 setLeftTop : function(left, top){
8481 this.dom.style.left = this.addUnits(left);
8482 this.dom.style.top = this.addUnits(top);
8487 * Move this element relative to its current position.
8488 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8489 * @param {Number} distance How far to move the element in pixels
8490 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8491 * @return {Roo.Element} this
8493 move : function(direction, distance, animate){
8494 var xy = this.getXY();
8495 direction = direction.toLowerCase();
8499 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8503 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8508 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8513 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8520 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8521 * @return {Roo.Element} this
8524 if(!this.isClipped){
8525 this.isClipped = true;
8526 this.originalClip = {
8527 "o": this.getStyle("overflow"),
8528 "x": this.getStyle("overflow-x"),
8529 "y": this.getStyle("overflow-y")
8531 this.setStyle("overflow", "hidden");
8532 this.setStyle("overflow-x", "hidden");
8533 this.setStyle("overflow-y", "hidden");
8539 * Return clipping (overflow) to original clipping before clip() was called
8540 * @return {Roo.Element} this
8542 unclip : function(){
8544 this.isClipped = false;
8545 var o = this.originalClip;
8546 if(o.o){this.setStyle("overflow", o.o);}
8547 if(o.x){this.setStyle("overflow-x", o.x);}
8548 if(o.y){this.setStyle("overflow-y", o.y);}
8555 * Gets the x,y coordinates specified by the anchor position on the element.
8556 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8557 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8558 * {width: (target width), height: (target height)} (defaults to the element's current size)
8559 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8560 * @return {Array} [x, y] An array containing the element's x and y coordinates
8562 getAnchorXY : function(anchor, local, s){
8563 //Passing a different size is useful for pre-calculating anchors,
8564 //especially for anchored animations that change the el size.
8566 var w, h, vp = false;
8569 if(d == document.body || d == document){
8571 w = D.getViewWidth(); h = D.getViewHeight();
8573 w = this.getWidth(); h = this.getHeight();
8576 w = s.width; h = s.height;
8578 var x = 0, y = 0, r = Math.round;
8579 switch((anchor || "tl").toLowerCase()){
8621 var sc = this.getScroll();
8622 return [x + sc.left, y + sc.top];
8624 //Add the element's offset xy
8625 var o = this.getXY();
8626 return [x+o[0], y+o[1]];
8630 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8631 * supported position values.
8632 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8633 * @param {String} position The position to align to.
8634 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8635 * @return {Array} [x, y]
8637 getAlignToXY : function(el, p, o)
8642 throw "Element.alignTo with an element that doesn't exist";
8644 var c = false; //constrain to viewport
8645 var p1 = "", p2 = "";
8652 }else if(p.indexOf("-") == -1){
8655 p = p.toLowerCase();
8656 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8658 throw "Element.alignTo with an invalid alignment " + p;
8660 p1 = m[1]; p2 = m[2]; c = !!m[3];
8662 //Subtract the aligned el's internal xy from the target's offset xy
8663 //plus custom offset to get the aligned el's new offset xy
8664 var a1 = this.getAnchorXY(p1, true);
8665 var a2 = el.getAnchorXY(p2, false);
8666 var x = a2[0] - a1[0] + o[0];
8667 var y = a2[1] - a1[1] + o[1];
8669 //constrain the aligned el to viewport if necessary
8670 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8671 // 5px of margin for ie
8672 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8674 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8675 //perpendicular to the vp border, allow the aligned el to slide on that border,
8676 //otherwise swap the aligned el to the opposite border of the target.
8677 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8678 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8679 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8680 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8683 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8684 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8686 if((x+w) > dw + scrollX){
8687 x = swapX ? r.left-w : dw+scrollX-w;
8690 x = swapX ? r.right : scrollX;
8692 if((y+h) > dh + scrollY){
8693 y = swapY ? r.top-h : dh+scrollY-h;
8696 y = swapY ? r.bottom : scrollY;
8703 getConstrainToXY : function(){
8704 var os = {top:0, left:0, bottom:0, right: 0};
8706 return function(el, local, offsets, proposedXY){
8708 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8710 var vw, vh, vx = 0, vy = 0;
8711 if(el.dom == document.body || el.dom == document){
8712 vw = Roo.lib.Dom.getViewWidth();
8713 vh = Roo.lib.Dom.getViewHeight();
8715 vw = el.dom.clientWidth;
8716 vh = el.dom.clientHeight;
8718 var vxy = el.getXY();
8724 var s = el.getScroll();
8726 vx += offsets.left + s.left;
8727 vy += offsets.top + s.top;
8729 vw -= offsets.right;
8730 vh -= offsets.bottom;
8735 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8736 var x = xy[0], y = xy[1];
8737 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8739 // only move it if it needs it
8742 // first validate right/bottom
8751 // then make sure top/left isn't negative
8760 return moved ? [x, y] : false;
8765 adjustForConstraints : function(xy, parent, offsets){
8766 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8770 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8771 * document it aligns it to the viewport.
8772 * The position parameter is optional, and can be specified in any one of the following formats:
8774 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8775 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8776 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8777 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8778 * <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
8779 * element's anchor point, and the second value is used as the target's anchor point.</li>
8781 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8782 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8783 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8784 * that specified in order to enforce the viewport constraints.
8785 * Following are all of the supported anchor positions:
8788 ----- -----------------------------
8789 tl The top left corner (default)
8790 t The center of the top edge
8791 tr The top right corner
8792 l The center of the left edge
8793 c In the center of the element
8794 r The center of the right edge
8795 bl The bottom left corner
8796 b The center of the bottom edge
8797 br The bottom right corner
8801 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8802 el.alignTo("other-el");
8804 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8805 el.alignTo("other-el", "tr?");
8807 // align the bottom right corner of el with the center left edge of other-el
8808 el.alignTo("other-el", "br-l?");
8810 // align the center of el with the bottom left corner of other-el and
8811 // adjust the x position by -6 pixels (and the y position by 0)
8812 el.alignTo("other-el", "c-bl", [-6, 0]);
8814 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8815 * @param {String} position The position to align to.
8816 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8817 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8818 * @return {Roo.Element} this
8820 alignTo : function(element, position, offsets, animate){
8821 var xy = this.getAlignToXY(element, position, offsets);
8822 this.setXY(xy, this.preanim(arguments, 3));
8827 * Anchors an element to another element and realigns it when the window is resized.
8828 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8829 * @param {String} position The position to align to.
8830 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8831 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8832 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8833 * is a number, it is used as the buffer delay (defaults to 50ms).
8834 * @param {Function} callback The function to call after the animation finishes
8835 * @return {Roo.Element} this
8837 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8838 var action = function(){
8839 this.alignTo(el, alignment, offsets, animate);
8840 Roo.callback(callback, this);
8842 Roo.EventManager.onWindowResize(action, this);
8843 var tm = typeof monitorScroll;
8844 if(tm != 'undefined'){
8845 Roo.EventManager.on(window, 'scroll', action, this,
8846 {buffer: tm == 'number' ? monitorScroll : 50});
8848 action.call(this); // align immediately
8852 * Clears any opacity settings from this element. Required in some cases for IE.
8853 * @return {Roo.Element} this
8855 clearOpacity : function(){
8856 if (window.ActiveXObject) {
8857 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8858 this.dom.style.filter = "";
8861 this.dom.style.opacity = "";
8862 this.dom.style["-moz-opacity"] = "";
8863 this.dom.style["-khtml-opacity"] = "";
8869 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8870 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8871 * @return {Roo.Element} this
8873 hide : function(animate){
8874 this.setVisible(false, this.preanim(arguments, 0));
8879 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8880 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8881 * @return {Roo.Element} this
8883 show : function(animate){
8884 this.setVisible(true, this.preanim(arguments, 0));
8889 * @private Test if size has a unit, otherwise appends the default
8891 addUnits : function(size){
8892 return Roo.Element.addUnits(size, this.defaultUnit);
8896 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8897 * @return {Roo.Element} this
8899 beginMeasure : function(){
8901 if(el.offsetWidth || el.offsetHeight){
8902 return this; // offsets work already
8905 var p = this.dom, b = document.body; // start with this element
8906 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8907 var pe = Roo.get(p);
8908 if(pe.getStyle('display') == 'none'){
8909 changed.push({el: p, visibility: pe.getStyle("visibility")});
8910 p.style.visibility = "hidden";
8911 p.style.display = "block";
8915 this._measureChanged = changed;
8921 * Restores displays to before beginMeasure was called
8922 * @return {Roo.Element} this
8924 endMeasure : function(){
8925 var changed = this._measureChanged;
8927 for(var i = 0, len = changed.length; i < len; i++) {
8929 r.el.style.visibility = r.visibility;
8930 r.el.style.display = "none";
8932 this._measureChanged = null;
8938 * Update the innerHTML of this element, optionally searching for and processing scripts
8939 * @param {String} html The new HTML
8940 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8941 * @param {Function} callback For async script loading you can be noticed when the update completes
8942 * @return {Roo.Element} this
8944 update : function(html, loadScripts, callback){
8945 if(typeof html == "undefined"){
8948 if(loadScripts !== true){
8949 this.dom.innerHTML = html;
8950 if(typeof callback == "function"){
8958 html += '<span id="' + id + '"></span>';
8960 E.onAvailable(id, function(){
8961 var hd = document.getElementsByTagName("head")[0];
8962 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8963 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8964 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8967 while(match = re.exec(html)){
8968 var attrs = match[1];
8969 var srcMatch = attrs ? attrs.match(srcRe) : false;
8970 if(srcMatch && srcMatch[2]){
8971 var s = document.createElement("script");
8972 s.src = srcMatch[2];
8973 var typeMatch = attrs.match(typeRe);
8974 if(typeMatch && typeMatch[2]){
8975 s.type = typeMatch[2];
8978 }else if(match[2] && match[2].length > 0){
8979 if(window.execScript) {
8980 window.execScript(match[2]);
8988 window.eval(match[2]);
8992 var el = document.getElementById(id);
8993 if(el){el.parentNode.removeChild(el);}
8994 if(typeof callback == "function"){
8998 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9003 * Direct access to the UpdateManager update() method (takes the same parameters).
9004 * @param {String/Function} url The url for this request or a function to call to get the url
9005 * @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}
9006 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9007 * @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.
9008 * @return {Roo.Element} this
9011 var um = this.getUpdateManager();
9012 um.update.apply(um, arguments);
9017 * Gets this element's UpdateManager
9018 * @return {Roo.UpdateManager} The UpdateManager
9020 getUpdateManager : function(){
9021 if(!this.updateManager){
9022 this.updateManager = new Roo.UpdateManager(this);
9024 return this.updateManager;
9028 * Disables text selection for this element (normalized across browsers)
9029 * @return {Roo.Element} this
9031 unselectable : function(){
9032 this.dom.unselectable = "on";
9033 this.swallowEvent("selectstart", true);
9034 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9035 this.addClass("x-unselectable");
9040 * Calculates the x, y to center this element on the screen
9041 * @return {Array} The x, y values [x, y]
9043 getCenterXY : function(){
9044 return this.getAlignToXY(document, 'c-c');
9048 * Centers the Element in either the viewport, or another Element.
9049 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9051 center : function(centerIn){
9052 this.alignTo(centerIn || document, 'c-c');
9057 * Tests various css rules/browsers to determine if this element uses a border box
9060 isBorderBox : function(){
9061 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9065 * Return a box {x, y, width, height} that can be used to set another elements
9066 * size/location to match this element.
9067 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9068 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9069 * @return {Object} box An object in the format {x, y, width, height}
9071 getBox : function(contentBox, local){
9076 var left = parseInt(this.getStyle("left"), 10) || 0;
9077 var top = parseInt(this.getStyle("top"), 10) || 0;
9080 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9082 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9084 var l = this.getBorderWidth("l")+this.getPadding("l");
9085 var r = this.getBorderWidth("r")+this.getPadding("r");
9086 var t = this.getBorderWidth("t")+this.getPadding("t");
9087 var b = this.getBorderWidth("b")+this.getPadding("b");
9088 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)};
9090 bx.right = bx.x + bx.width;
9091 bx.bottom = bx.y + bx.height;
9096 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9097 for more information about the sides.
9098 * @param {String} sides
9101 getFrameWidth : function(sides, onlyContentBox){
9102 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9106 * 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.
9107 * @param {Object} box The box to fill {x, y, width, height}
9108 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9109 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9110 * @return {Roo.Element} this
9112 setBox : function(box, adjust, animate){
9113 var w = box.width, h = box.height;
9114 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9115 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9116 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9118 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9123 * Forces the browser to repaint this element
9124 * @return {Roo.Element} this
9126 repaint : function(){
9128 this.addClass("x-repaint");
9129 setTimeout(function(){
9130 Roo.get(dom).removeClass("x-repaint");
9136 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9137 * then it returns the calculated width of the sides (see getPadding)
9138 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9139 * @return {Object/Number}
9141 getMargins : function(side){
9144 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9145 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9146 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9147 right: parseInt(this.getStyle("margin-right"), 10) || 0
9150 return this.addStyles(side, El.margins);
9155 addStyles : function(sides, styles){
9157 for(var i = 0, len = sides.length; i < len; i++){
9158 v = this.getStyle(styles[sides.charAt(i)]);
9160 w = parseInt(v, 10);
9168 * Creates a proxy element of this element
9169 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9170 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9171 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9172 * @return {Roo.Element} The new proxy element
9174 createProxy : function(config, renderTo, matchBox){
9176 renderTo = Roo.getDom(renderTo);
9178 renderTo = document.body;
9180 config = typeof config == "object" ?
9181 config : {tag : "div", cls: config};
9182 var proxy = Roo.DomHelper.append(renderTo, config, true);
9184 proxy.setBox(this.getBox());
9190 * Puts a mask over this element to disable user interaction. Requires core.css.
9191 * This method can only be applied to elements which accept child nodes.
9192 * @param {String} msg (optional) A message to display in the mask
9193 * @param {String} msgCls (optional) A css class to apply to the msg element
9194 * @return {Element} The mask element
9196 mask : function(msg, msgCls)
9198 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9199 this.setStyle("position", "relative");
9202 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9205 this.addClass("x-masked");
9206 this._mask.setDisplayed(true);
9211 while (dom && dom.style) {
9212 if (!isNaN(parseInt(dom.style.zIndex))) {
9213 z = Math.max(z, parseInt(dom.style.zIndex));
9215 dom = dom.parentNode;
9217 // if we are masking the body - then it hides everything..
9218 if (this.dom == document.body) {
9220 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9221 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9224 if(typeof msg == 'string'){
9226 this._maskMsg = Roo.DomHelper.append(this.dom, {
9227 cls: "roo-el-mask-msg",
9231 cls: 'fa fa-spinner fa-spin'
9239 var mm = this._maskMsg;
9240 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9241 if (mm.dom.lastChild) { // weird IE issue?
9242 mm.dom.lastChild.innerHTML = msg;
9244 mm.setDisplayed(true);
9246 mm.setStyle('z-index', z + 102);
9248 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9249 this._mask.setHeight(this.getHeight());
9251 this._mask.setStyle('z-index', z + 100);
9257 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9258 * it is cached for reuse.
9260 unmask : function(removeEl){
9262 if(removeEl === true){
9263 this._mask.remove();
9266 this._maskMsg.remove();
9267 delete this._maskMsg;
9270 this._mask.setDisplayed(false);
9272 this._maskMsg.setDisplayed(false);
9276 this.removeClass("x-masked");
9280 * Returns true if this element is masked
9283 isMasked : function(){
9284 return this._mask && this._mask.isVisible();
9288 * Creates an iframe shim for this element to keep selects and other windowed objects from
9290 * @return {Roo.Element} The new shim element
9292 createShim : function(){
9293 var el = document.createElement('iframe');
9294 el.frameBorder = 'no';
9295 el.className = 'roo-shim';
9296 if(Roo.isIE && Roo.isSecure){
9297 el.src = Roo.SSL_SECURE_URL;
9299 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9300 shim.autoBoxAdjust = false;
9305 * Removes this element from the DOM and deletes it from the cache
9307 remove : function(){
9308 if(this.dom.parentNode){
9309 this.dom.parentNode.removeChild(this.dom);
9311 delete El.cache[this.dom.id];
9315 * Sets up event handlers to add and remove a css class when the mouse is over this element
9316 * @param {String} className
9317 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9318 * mouseout events for children elements
9319 * @return {Roo.Element} this
9321 addClassOnOver : function(className, preventFlicker){
9322 this.on("mouseover", function(){
9323 Roo.fly(this, '_internal').addClass(className);
9325 var removeFn = function(e){
9326 if(preventFlicker !== true || !e.within(this, true)){
9327 Roo.fly(this, '_internal').removeClass(className);
9330 this.on("mouseout", removeFn, this.dom);
9335 * Sets up event handlers to add and remove a css class when this element has the focus
9336 * @param {String} className
9337 * @return {Roo.Element} this
9339 addClassOnFocus : function(className){
9340 this.on("focus", function(){
9341 Roo.fly(this, '_internal').addClass(className);
9343 this.on("blur", function(){
9344 Roo.fly(this, '_internal').removeClass(className);
9349 * 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)
9350 * @param {String} className
9351 * @return {Roo.Element} this
9353 addClassOnClick : function(className){
9355 this.on("mousedown", function(){
9356 Roo.fly(dom, '_internal').addClass(className);
9357 var d = Roo.get(document);
9358 var fn = function(){
9359 Roo.fly(dom, '_internal').removeClass(className);
9360 d.removeListener("mouseup", fn);
9362 d.on("mouseup", fn);
9368 * Stops the specified event from bubbling and optionally prevents the default action
9369 * @param {String} eventName
9370 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9371 * @return {Roo.Element} this
9373 swallowEvent : function(eventName, preventDefault){
9374 var fn = function(e){
9375 e.stopPropagation();
9380 if(eventName instanceof Array){
9381 for(var i = 0, len = eventName.length; i < len; i++){
9382 this.on(eventName[i], fn);
9386 this.on(eventName, fn);
9393 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9396 * Sizes this element to its parent element's dimensions performing
9397 * neccessary box adjustments.
9398 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9399 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9400 * @return {Roo.Element} this
9402 fitToParent : function(monitorResize, targetParent) {
9403 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9404 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9405 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9408 var p = Roo.get(targetParent || this.dom.parentNode);
9409 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9410 if (monitorResize === true) {
9411 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9412 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9418 * Gets the next sibling, skipping text nodes
9419 * @return {HTMLElement} The next sibling or null
9421 getNextSibling : function(){
9422 var n = this.dom.nextSibling;
9423 while(n && n.nodeType != 1){
9430 * Gets the previous sibling, skipping text nodes
9431 * @return {HTMLElement} The previous sibling or null
9433 getPrevSibling : function(){
9434 var n = this.dom.previousSibling;
9435 while(n && n.nodeType != 1){
9436 n = n.previousSibling;
9443 * Appends the passed element(s) to this element
9444 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9445 * @return {Roo.Element} this
9447 appendChild: function(el){
9454 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9455 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9456 * automatically generated with the specified attributes.
9457 * @param {HTMLElement} insertBefore (optional) a child element of this element
9458 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9459 * @return {Roo.Element} The new child element
9461 createChild: function(config, insertBefore, returnDom){
9462 config = config || {tag:'div'};
9464 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9466 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9470 * Appends this element to the passed element
9471 * @param {String/HTMLElement/Element} el The new parent element
9472 * @return {Roo.Element} this
9474 appendTo: function(el){
9475 el = Roo.getDom(el);
9476 el.appendChild(this.dom);
9481 * Inserts this element before the passed element in the DOM
9482 * @param {String/HTMLElement/Element} el The element to insert before
9483 * @return {Roo.Element} this
9485 insertBefore: function(el){
9486 el = Roo.getDom(el);
9487 el.parentNode.insertBefore(this.dom, el);
9492 * Inserts this element after the passed element in the DOM
9493 * @param {String/HTMLElement/Element} el The element to insert after
9494 * @return {Roo.Element} this
9496 insertAfter: function(el){
9497 el = Roo.getDom(el);
9498 el.parentNode.insertBefore(this.dom, el.nextSibling);
9503 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9504 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9505 * @return {Roo.Element} The new child
9507 insertFirst: function(el, returnDom){
9509 if(typeof el == 'object' && !el.nodeType){ // dh config
9510 return this.createChild(el, this.dom.firstChild, returnDom);
9512 el = Roo.getDom(el);
9513 this.dom.insertBefore(el, this.dom.firstChild);
9514 return !returnDom ? Roo.get(el) : el;
9519 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9520 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9521 * @param {String} where (optional) 'before' or 'after' defaults to before
9522 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9523 * @return {Roo.Element} the inserted Element
9525 insertSibling: function(el, where, returnDom){
9526 where = where ? where.toLowerCase() : 'before';
9528 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9530 if(typeof el == 'object' && !el.nodeType){ // dh config
9531 if(where == 'after' && !this.dom.nextSibling){
9532 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9534 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9538 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9539 where == 'before' ? this.dom : this.dom.nextSibling);
9548 * Creates and wraps this element with another element
9549 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9550 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9551 * @return {HTMLElement/Element} The newly created wrapper element
9553 wrap: function(config, returnDom){
9555 config = {tag: "div"};
9557 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9558 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9563 * Replaces the passed element with this element
9564 * @param {String/HTMLElement/Element} el The element to replace
9565 * @return {Roo.Element} this
9567 replace: function(el){
9569 this.insertBefore(el);
9575 * Inserts an html fragment into this element
9576 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9577 * @param {String} html The HTML fragment
9578 * @param {Boolean} returnEl True to return an Roo.Element
9579 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9581 insertHtml : function(where, html, returnEl){
9582 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9583 return returnEl ? Roo.get(el) : el;
9587 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9588 * @param {Object} o The object with the attributes
9589 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9590 * @return {Roo.Element} this
9592 set : function(o, useSet){
9594 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9596 if(attr == "style" || typeof o[attr] == "function") { continue; }
9598 el.className = o["cls"];
9601 el.setAttribute(attr, o[attr]);
9608 Roo.DomHelper.applyStyles(el, o.style);
9614 * Convenience method for constructing a KeyMap
9615 * @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:
9616 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9617 * @param {Function} fn The function to call
9618 * @param {Object} scope (optional) The scope of the function
9619 * @return {Roo.KeyMap} The KeyMap created
9621 addKeyListener : function(key, fn, scope){
9623 if(typeof key != "object" || key instanceof Array){
9639 return new Roo.KeyMap(this, config);
9643 * Creates a KeyMap for this element
9644 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9645 * @return {Roo.KeyMap} The KeyMap created
9647 addKeyMap : function(config){
9648 return new Roo.KeyMap(this, config);
9652 * Returns true if this element is scrollable.
9655 isScrollable : function(){
9657 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9661 * 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().
9662 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9663 * @param {Number} value The new scroll value
9664 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9665 * @return {Element} this
9668 scrollTo : function(side, value, animate){
9669 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9671 this.dom[prop] = value;
9673 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9674 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9680 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9681 * within this element's scrollable range.
9682 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9683 * @param {Number} distance How far to scroll the element in pixels
9684 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9685 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9686 * was scrolled as far as it could go.
9688 scroll : function(direction, distance, animate){
9689 if(!this.isScrollable()){
9693 var l = el.scrollLeft, t = el.scrollTop;
9694 var w = el.scrollWidth, h = el.scrollHeight;
9695 var cw = el.clientWidth, ch = el.clientHeight;
9696 direction = direction.toLowerCase();
9697 var scrolled = false;
9698 var a = this.preanim(arguments, 2);
9703 var v = Math.min(l + distance, w-cw);
9704 this.scrollTo("left", v, a);
9711 var v = Math.max(l - distance, 0);
9712 this.scrollTo("left", v, a);
9720 var v = Math.max(t - distance, 0);
9721 this.scrollTo("top", v, a);
9729 var v = Math.min(t + distance, h-ch);
9730 this.scrollTo("top", v, a);
9739 * Translates the passed page coordinates into left/top css values for this element
9740 * @param {Number/Array} x The page x or an array containing [x, y]
9741 * @param {Number} y The page y
9742 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9744 translatePoints : function(x, y){
9745 if(typeof x == 'object' || x instanceof Array){
9748 var p = this.getStyle('position');
9749 var o = this.getXY();
9751 var l = parseInt(this.getStyle('left'), 10);
9752 var t = parseInt(this.getStyle('top'), 10);
9755 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9758 t = (p == "relative") ? 0 : this.dom.offsetTop;
9761 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9765 * Returns the current scroll position of the element.
9766 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9768 getScroll : function(){
9769 var d = this.dom, doc = document;
9770 if(d == doc || d == doc.body){
9771 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9772 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9773 return {left: l, top: t};
9775 return {left: d.scrollLeft, top: d.scrollTop};
9780 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9781 * are convert to standard 6 digit hex color.
9782 * @param {String} attr The css attribute
9783 * @param {String} defaultValue The default value to use when a valid color isn't found
9784 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9787 getColor : function(attr, defaultValue, prefix){
9788 var v = this.getStyle(attr);
9789 if(!v || v == "transparent" || v == "inherit") {
9790 return defaultValue;
9792 var color = typeof prefix == "undefined" ? "#" : prefix;
9793 if(v.substr(0, 4) == "rgb("){
9794 var rvs = v.slice(4, v.length -1).split(",");
9795 for(var i = 0; i < 3; i++){
9796 var h = parseInt(rvs[i]).toString(16);
9803 if(v.substr(0, 1) == "#"){
9805 for(var i = 1; i < 4; i++){
9806 var c = v.charAt(i);
9809 }else if(v.length == 7){
9810 color += v.substr(1);
9814 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9818 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9819 * gradient background, rounded corners and a 4-way shadow.
9820 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9821 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9822 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9823 * @return {Roo.Element} this
9825 boxWrap : function(cls){
9826 cls = cls || 'x-box';
9827 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9828 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9833 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9834 * @param {String} namespace The namespace in which to look for the attribute
9835 * @param {String} name The attribute name
9836 * @return {String} The attribute value
9838 getAttributeNS : Roo.isIE ? function(ns, name){
9840 var type = typeof d[ns+":"+name];
9841 if(type != 'undefined' && type != 'unknown'){
9842 return d[ns+":"+name];
9845 } : function(ns, name){
9847 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9852 * Sets or Returns the value the dom attribute value
9853 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9854 * @param {String} value (optional) The value to set the attribute to
9855 * @return {String} The attribute value
9857 attr : function(name){
9858 if (arguments.length > 1) {
9859 this.dom.setAttribute(name, arguments[1]);
9860 return arguments[1];
9862 if (typeof(name) == 'object') {
9863 for(var i in name) {
9864 this.attr(i, name[i]);
9870 if (!this.dom.hasAttribute(name)) {
9873 return this.dom.getAttribute(name);
9880 var ep = El.prototype;
9883 * Appends an event handler (Shorthand for addListener)
9884 * @param {String} eventName The type of event to append
9885 * @param {Function} fn The method the event invokes
9886 * @param {Object} scope (optional) The scope (this object) of the fn
9887 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9890 ep.on = ep.addListener;
9892 ep.mon = ep.addListener;
9895 * Removes an event handler from this element (shorthand for removeListener)
9896 * @param {String} eventName the type of event to remove
9897 * @param {Function} fn the method the event invokes
9898 * @return {Roo.Element} this
9901 ep.un = ep.removeListener;
9904 * true to automatically adjust width and height settings for box-model issues (default to true)
9906 ep.autoBoxAdjust = true;
9909 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9912 El.addUnits = function(v, defaultUnit){
9913 if(v === "" || v == "auto"){
9916 if(v === undefined){
9919 if(typeof v == "number" || !El.unitPattern.test(v)){
9920 return v + (defaultUnit || 'px');
9925 // special markup used throughout Roo when box wrapping elements
9926 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>';
9928 * Visibility mode constant - Use visibility to hide element
9934 * Visibility mode constant - Use display to hide element
9940 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9941 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9942 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9954 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9955 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9956 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9957 * @return {Element} The Element object
9960 El.get = function(el){
9962 if(!el){ return null; }
9963 if(typeof el == "string"){ // element id
9964 if(!(elm = document.getElementById(el))){
9967 if(ex = El.cache[el]){
9970 ex = El.cache[el] = new El(elm);
9973 }else if(el.tagName){ // dom element
9977 if(ex = El.cache[id]){
9980 ex = El.cache[id] = new El(el);
9983 }else if(el instanceof El){
9985 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9986 // catch case where it hasn't been appended
9987 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9990 }else if(el.isComposite){
9992 }else if(el instanceof Array){
9993 return El.select(el);
9994 }else if(el == document){
9995 // create a bogus element object representing the document object
9997 var f = function(){};
9998 f.prototype = El.prototype;
10000 docEl.dom = document;
10008 El.uncache = function(el){
10009 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10011 delete El.cache[a[i].id || a[i]];
10017 // Garbage collection - uncache elements/purge listeners on orphaned elements
10018 // so we don't hold a reference and cause the browser to retain them
10019 El.garbageCollect = function(){
10020 if(!Roo.enableGarbageCollector){
10021 clearInterval(El.collectorThread);
10024 for(var eid in El.cache){
10025 var el = El.cache[eid], d = el.dom;
10026 // -------------------------------------------------------
10027 // Determining what is garbage:
10028 // -------------------------------------------------------
10030 // dom node is null, definitely garbage
10031 // -------------------------------------------------------
10033 // no parentNode == direct orphan, definitely garbage
10034 // -------------------------------------------------------
10035 // !d.offsetParent && !document.getElementById(eid)
10036 // display none elements have no offsetParent so we will
10037 // also try to look it up by it's id. However, check
10038 // offsetParent first so we don't do unneeded lookups.
10039 // This enables collection of elements that are not orphans
10040 // directly, but somewhere up the line they have an orphan
10042 // -------------------------------------------------------
10043 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10044 delete El.cache[eid];
10045 if(d && Roo.enableListenerCollection){
10051 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10055 El.Flyweight = function(dom){
10058 El.Flyweight.prototype = El.prototype;
10060 El._flyweights = {};
10062 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10063 * the dom node can be overwritten by other code.
10064 * @param {String/HTMLElement} el The dom node or id
10065 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10066 * prevent conflicts (e.g. internally Roo uses "_internal")
10068 * @return {Element} The shared Element object
10070 El.fly = function(el, named){
10071 named = named || '_global';
10072 el = Roo.getDom(el);
10076 if(!El._flyweights[named]){
10077 El._flyweights[named] = new El.Flyweight();
10079 El._flyweights[named].dom = el;
10080 return El._flyweights[named];
10084 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10085 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10086 * Shorthand of {@link Roo.Element#get}
10087 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10088 * @return {Element} The Element object
10094 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10095 * the dom node can be overwritten by other code.
10096 * Shorthand of {@link Roo.Element#fly}
10097 * @param {String/HTMLElement} el The dom node or id
10098 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10099 * prevent conflicts (e.g. internally Roo uses "_internal")
10101 * @return {Element} The shared Element object
10107 // speedy lookup for elements never to box adjust
10108 var noBoxAdjust = Roo.isStrict ? {
10111 input:1, select:1, textarea:1
10113 if(Roo.isIE || Roo.isGecko){
10114 noBoxAdjust['button'] = 1;
10118 Roo.EventManager.on(window, 'unload', function(){
10120 delete El._flyweights;
10128 Roo.Element.selectorFunction = Roo.DomQuery.select;
10131 Roo.Element.select = function(selector, unique, root){
10133 if(typeof selector == "string"){
10134 els = Roo.Element.selectorFunction(selector, root);
10135 }else if(selector.length !== undefined){
10138 throw "Invalid selector";
10140 if(unique === true){
10141 return new Roo.CompositeElement(els);
10143 return new Roo.CompositeElementLite(els);
10147 * Selects elements based on the passed CSS selector to enable working on them as 1.
10148 * @param {String/Array} selector The CSS selector or an array of elements
10149 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10150 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10151 * @return {CompositeElementLite/CompositeElement}
10155 Roo.select = Roo.Element.select;
10172 * Ext JS Library 1.1.1
10173 * Copyright(c) 2006-2007, Ext JS, LLC.
10175 * Originally Released Under LGPL - original licence link has changed is not relivant.
10178 * <script type="text/javascript">
10183 //Notifies Element that fx methods are available
10184 Roo.enableFx = true;
10188 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10189 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10190 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10191 * Element effects to work.</p><br/>
10193 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10194 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10195 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10196 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10197 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10198 * expected results and should be done with care.</p><br/>
10200 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10201 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10204 ----- -----------------------------
10205 tl The top left corner
10206 t The center of the top edge
10207 tr The top right corner
10208 l The center of the left edge
10209 r The center of the right edge
10210 bl The bottom left corner
10211 b The center of the bottom edge
10212 br The bottom right corner
10214 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10215 * below are common options that can be passed to any Fx method.</b>
10216 * @cfg {Function} callback A function called when the effect is finished
10217 * @cfg {Object} scope The scope of the effect function
10218 * @cfg {String} easing A valid Easing value for the effect
10219 * @cfg {String} afterCls A css class to apply after the effect
10220 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10221 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10222 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10223 * effects that end with the element being visually hidden, ignored otherwise)
10224 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10225 * a function which returns such a specification that will be applied to the Element after the effect finishes
10226 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10227 * @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
10228 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10232 * Slides the element into view. An anchor point can be optionally passed to set the point of
10233 * origin for the slide effect. This function automatically handles wrapping the element with
10234 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10237 // default: slide the element in from the top
10240 // custom: slide the element in from the right with a 2-second duration
10241 el.slideIn('r', { duration: 2 });
10243 // common config options shown with default values
10249 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10250 * @param {Object} options (optional) Object literal with any of the Fx config options
10251 * @return {Roo.Element} The Element
10253 slideIn : function(anchor, o){
10254 var el = this.getFxEl();
10257 el.queueFx(o, function(){
10259 anchor = anchor || "t";
10261 // fix display to visibility
10264 // restore values after effect
10265 var r = this.getFxRestore();
10266 var b = this.getBox();
10267 // fixed size for slide
10271 var wrap = this.fxWrap(r.pos, o, "hidden");
10273 var st = this.dom.style;
10274 st.visibility = "visible";
10275 st.position = "absolute";
10277 // clear out temp styles after slide and unwrap
10278 var after = function(){
10279 el.fxUnwrap(wrap, r.pos, o);
10280 st.width = r.width;
10281 st.height = r.height;
10284 // time to calc the positions
10285 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10287 switch(anchor.toLowerCase()){
10289 wrap.setSize(b.width, 0);
10290 st.left = st.bottom = "0";
10294 wrap.setSize(0, b.height);
10295 st.right = st.top = "0";
10299 wrap.setSize(0, b.height);
10300 wrap.setX(b.right);
10301 st.left = st.top = "0";
10302 a = {width: bw, points: pt};
10305 wrap.setSize(b.width, 0);
10306 wrap.setY(b.bottom);
10307 st.left = st.top = "0";
10308 a = {height: bh, points: pt};
10311 wrap.setSize(0, 0);
10312 st.right = st.bottom = "0";
10313 a = {width: bw, height: bh};
10316 wrap.setSize(0, 0);
10317 wrap.setY(b.y+b.height);
10318 st.right = st.top = "0";
10319 a = {width: bw, height: bh, points: pt};
10322 wrap.setSize(0, 0);
10323 wrap.setXY([b.right, b.bottom]);
10324 st.left = st.top = "0";
10325 a = {width: bw, height: bh, points: pt};
10328 wrap.setSize(0, 0);
10329 wrap.setX(b.x+b.width);
10330 st.left = st.bottom = "0";
10331 a = {width: bw, height: bh, points: pt};
10334 this.dom.style.visibility = "visible";
10337 arguments.callee.anim = wrap.fxanim(a,
10347 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10348 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10349 * 'hidden') but block elements will still take up space in the document. The element must be removed
10350 * from the DOM using the 'remove' config option if desired. This function automatically handles
10351 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10354 // default: slide the element out to the top
10357 // custom: slide the element out to the right with a 2-second duration
10358 el.slideOut('r', { duration: 2 });
10360 // common config options shown with default values
10368 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10369 * @param {Object} options (optional) Object literal with any of the Fx config options
10370 * @return {Roo.Element} The Element
10372 slideOut : function(anchor, o){
10373 var el = this.getFxEl();
10376 el.queueFx(o, function(){
10378 anchor = anchor || "t";
10380 // restore values after effect
10381 var r = this.getFxRestore();
10383 var b = this.getBox();
10384 // fixed size for slide
10388 var wrap = this.fxWrap(r.pos, o, "visible");
10390 var st = this.dom.style;
10391 st.visibility = "visible";
10392 st.position = "absolute";
10396 var after = function(){
10398 el.setDisplayed(false);
10403 el.fxUnwrap(wrap, r.pos, o);
10405 st.width = r.width;
10406 st.height = r.height;
10411 var a, zero = {to: 0};
10412 switch(anchor.toLowerCase()){
10414 st.left = st.bottom = "0";
10415 a = {height: zero};
10418 st.right = st.top = "0";
10422 st.left = st.top = "0";
10423 a = {width: zero, points: {to:[b.right, b.y]}};
10426 st.left = st.top = "0";
10427 a = {height: zero, points: {to:[b.x, b.bottom]}};
10430 st.right = st.bottom = "0";
10431 a = {width: zero, height: zero};
10434 st.right = st.top = "0";
10435 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10438 st.left = st.top = "0";
10439 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10442 st.left = st.bottom = "0";
10443 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10447 arguments.callee.anim = wrap.fxanim(a,
10457 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10458 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10459 * The element must be removed from the DOM using the 'remove' config option if desired.
10465 // common config options shown with default values
10473 * @param {Object} options (optional) Object literal with any of the Fx config options
10474 * @return {Roo.Element} The Element
10476 puff : function(o){
10477 var el = this.getFxEl();
10480 el.queueFx(o, function(){
10481 this.clearOpacity();
10484 // restore values after effect
10485 var r = this.getFxRestore();
10486 var st = this.dom.style;
10488 var after = function(){
10490 el.setDisplayed(false);
10497 el.setPositioning(r.pos);
10498 st.width = r.width;
10499 st.height = r.height;
10504 var width = this.getWidth();
10505 var height = this.getHeight();
10507 arguments.callee.anim = this.fxanim({
10508 width : {to: this.adjustWidth(width * 2)},
10509 height : {to: this.adjustHeight(height * 2)},
10510 points : {by: [-(width * .5), -(height * .5)]},
10512 fontSize: {to:200, unit: "%"}
10523 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10524 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10525 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10531 // all config options shown with default values
10539 * @param {Object} options (optional) Object literal with any of the Fx config options
10540 * @return {Roo.Element} The Element
10542 switchOff : function(o){
10543 var el = this.getFxEl();
10546 el.queueFx(o, function(){
10547 this.clearOpacity();
10550 // restore values after effect
10551 var r = this.getFxRestore();
10552 var st = this.dom.style;
10554 var after = function(){
10556 el.setDisplayed(false);
10562 el.setPositioning(r.pos);
10563 st.width = r.width;
10564 st.height = r.height;
10569 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10570 this.clearOpacity();
10574 points:{by:[0, this.getHeight() * .5]}
10575 }, o, 'motion', 0.3, 'easeIn', after);
10576 }).defer(100, this);
10583 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10584 * changed using the "attr" config option) and then fading back to the original color. If no original
10585 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10588 // default: highlight background to yellow
10591 // custom: highlight foreground text to blue for 2 seconds
10592 el.highlight("0000ff", { attr: 'color', duration: 2 });
10594 // common config options shown with default values
10595 el.highlight("ffff9c", {
10596 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10597 endColor: (current color) or "ffffff",
10602 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10603 * @param {Object} options (optional) Object literal with any of the Fx config options
10604 * @return {Roo.Element} The Element
10606 highlight : function(color, o){
10607 var el = this.getFxEl();
10610 el.queueFx(o, function(){
10611 color = color || "ffff9c";
10612 attr = o.attr || "backgroundColor";
10614 this.clearOpacity();
10617 var origColor = this.getColor(attr);
10618 var restoreColor = this.dom.style[attr];
10619 endColor = (o.endColor || origColor) || "ffffff";
10621 var after = function(){
10622 el.dom.style[attr] = restoreColor;
10627 a[attr] = {from: color, to: endColor};
10628 arguments.callee.anim = this.fxanim(a,
10638 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10641 // default: a single light blue ripple
10644 // custom: 3 red ripples lasting 3 seconds total
10645 el.frame("ff0000", 3, { duration: 3 });
10647 // common config options shown with default values
10648 el.frame("C3DAF9", 1, {
10649 duration: 1 //duration of entire animation (not each individual ripple)
10650 // Note: Easing is not configurable and will be ignored if included
10653 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10654 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10655 * @param {Object} options (optional) Object literal with any of the Fx config options
10656 * @return {Roo.Element} The Element
10658 frame : function(color, count, o){
10659 var el = this.getFxEl();
10662 el.queueFx(o, function(){
10663 color = color || "#C3DAF9";
10664 if(color.length == 6){
10665 color = "#" + color;
10667 count = count || 1;
10668 duration = o.duration || 1;
10671 var b = this.getBox();
10672 var animFn = function(){
10673 var proxy = this.createProxy({
10676 visbility:"hidden",
10677 position:"absolute",
10678 "z-index":"35000", // yee haw
10679 border:"0px solid " + color
10682 var scale = Roo.isBorderBox ? 2 : 1;
10684 top:{from:b.y, to:b.y - 20},
10685 left:{from:b.x, to:b.x - 20},
10686 borderWidth:{from:0, to:10},
10687 opacity:{from:1, to:0},
10688 height:{from:b.height, to:(b.height + (20*scale))},
10689 width:{from:b.width, to:(b.width + (20*scale))}
10690 }, duration, function(){
10694 animFn.defer((duration/2)*1000, this);
10705 * Creates a pause before any subsequent queued effects begin. If there are
10706 * no effects queued after the pause it will have no effect.
10711 * @param {Number} seconds The length of time to pause (in seconds)
10712 * @return {Roo.Element} The Element
10714 pause : function(seconds){
10715 var el = this.getFxEl();
10718 el.queueFx(o, function(){
10719 setTimeout(function(){
10721 }, seconds * 1000);
10727 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10728 * using the "endOpacity" config option.
10731 // default: fade in from opacity 0 to 100%
10734 // custom: fade in from opacity 0 to 75% over 2 seconds
10735 el.fadeIn({ endOpacity: .75, duration: 2});
10737 // common config options shown with default values
10739 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10744 * @param {Object} options (optional) Object literal with any of the Fx config options
10745 * @return {Roo.Element} The Element
10747 fadeIn : function(o){
10748 var el = this.getFxEl();
10750 el.queueFx(o, function(){
10751 this.setOpacity(0);
10753 this.dom.style.visibility = 'visible';
10754 var to = o.endOpacity || 1;
10755 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10756 o, null, .5, "easeOut", function(){
10758 this.clearOpacity();
10767 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10768 * using the "endOpacity" config option.
10771 // default: fade out from the element's current opacity to 0
10774 // custom: fade out from the element's current opacity to 25% over 2 seconds
10775 el.fadeOut({ endOpacity: .25, duration: 2});
10777 // common config options shown with default values
10779 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10786 * @param {Object} options (optional) Object literal with any of the Fx config options
10787 * @return {Roo.Element} The Element
10789 fadeOut : function(o){
10790 var el = this.getFxEl();
10792 el.queueFx(o, function(){
10793 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10794 o, null, .5, "easeOut", function(){
10795 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10796 this.dom.style.display = "none";
10798 this.dom.style.visibility = "hidden";
10800 this.clearOpacity();
10808 * Animates the transition of an element's dimensions from a starting height/width
10809 * to an ending height/width.
10812 // change height and width to 100x100 pixels
10813 el.scale(100, 100);
10815 // common config options shown with default values. The height and width will default to
10816 // the element's existing values if passed as null.
10819 [element's height], {
10824 * @param {Number} width The new width (pass undefined to keep the original width)
10825 * @param {Number} height The new height (pass undefined to keep the original height)
10826 * @param {Object} options (optional) Object literal with any of the Fx config options
10827 * @return {Roo.Element} The Element
10829 scale : function(w, h, o){
10830 this.shift(Roo.apply({}, o, {
10838 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10839 * Any of these properties not specified in the config object will not be changed. This effect
10840 * requires that at least one new dimension, position or opacity setting must be passed in on
10841 * the config object in order for the function to have any effect.
10844 // slide the element horizontally to x position 200 while changing the height and opacity
10845 el.shift({ x: 200, height: 50, opacity: .8 });
10847 // common config options shown with default values.
10849 width: [element's width],
10850 height: [element's height],
10851 x: [element's x position],
10852 y: [element's y position],
10853 opacity: [element's opacity],
10858 * @param {Object} options Object literal with any of the Fx config options
10859 * @return {Roo.Element} The Element
10861 shift : function(o){
10862 var el = this.getFxEl();
10864 el.queueFx(o, function(){
10865 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10866 if(w !== undefined){
10867 a.width = {to: this.adjustWidth(w)};
10869 if(h !== undefined){
10870 a.height = {to: this.adjustHeight(h)};
10872 if(x !== undefined || y !== undefined){
10874 x !== undefined ? x : this.getX(),
10875 y !== undefined ? y : this.getY()
10878 if(op !== undefined){
10879 a.opacity = {to: op};
10881 if(o.xy !== undefined){
10882 a.points = {to: o.xy};
10884 arguments.callee.anim = this.fxanim(a,
10885 o, 'motion', .35, "easeOut", function(){
10893 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10894 * ending point of the effect.
10897 // default: slide the element downward while fading out
10900 // custom: slide the element out to the right with a 2-second duration
10901 el.ghost('r', { duration: 2 });
10903 // common config options shown with default values
10911 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10912 * @param {Object} options (optional) Object literal with any of the Fx config options
10913 * @return {Roo.Element} The Element
10915 ghost : function(anchor, o){
10916 var el = this.getFxEl();
10919 el.queueFx(o, function(){
10920 anchor = anchor || "b";
10922 // restore values after effect
10923 var r = this.getFxRestore();
10924 var w = this.getWidth(),
10925 h = this.getHeight();
10927 var st = this.dom.style;
10929 var after = function(){
10931 el.setDisplayed(false);
10937 el.setPositioning(r.pos);
10938 st.width = r.width;
10939 st.height = r.height;
10944 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10945 switch(anchor.toLowerCase()){
10972 arguments.callee.anim = this.fxanim(a,
10982 * Ensures that all effects queued after syncFx is called on the element are
10983 * run concurrently. This is the opposite of {@link #sequenceFx}.
10984 * @return {Roo.Element} The Element
10986 syncFx : function(){
10987 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10996 * Ensures that all effects queued after sequenceFx is called on the element are
10997 * run in sequence. This is the opposite of {@link #syncFx}.
10998 * @return {Roo.Element} The Element
11000 sequenceFx : function(){
11001 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11003 concurrent : false,
11010 nextFx : function(){
11011 var ef = this.fxQueue[0];
11018 * Returns true if the element has any effects actively running or queued, else returns false.
11019 * @return {Boolean} True if element has active effects, else false
11021 hasActiveFx : function(){
11022 return this.fxQueue && this.fxQueue[0];
11026 * Stops any running effects and clears the element's internal effects queue if it contains
11027 * any additional effects that haven't started yet.
11028 * @return {Roo.Element} The Element
11030 stopFx : function(){
11031 if(this.hasActiveFx()){
11032 var cur = this.fxQueue[0];
11033 if(cur && cur.anim && cur.anim.isAnimated()){
11034 this.fxQueue = [cur]; // clear out others
11035 cur.anim.stop(true);
11042 beforeFx : function(o){
11043 if(this.hasActiveFx() && !o.concurrent){
11054 * Returns true if the element is currently blocking so that no other effect can be queued
11055 * until this effect is finished, else returns false if blocking is not set. This is commonly
11056 * used to ensure that an effect initiated by a user action runs to completion prior to the
11057 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11058 * @return {Boolean} True if blocking, else false
11060 hasFxBlock : function(){
11061 var q = this.fxQueue;
11062 return q && q[0] && q[0].block;
11066 queueFx : function(o, fn){
11070 if(!this.hasFxBlock()){
11071 Roo.applyIf(o, this.fxDefaults);
11073 var run = this.beforeFx(o);
11074 fn.block = o.block;
11075 this.fxQueue.push(fn);
11087 fxWrap : function(pos, o, vis){
11089 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11092 wrapXY = this.getXY();
11094 var div = document.createElement("div");
11095 div.style.visibility = vis;
11096 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11097 wrap.setPositioning(pos);
11098 if(wrap.getStyle("position") == "static"){
11099 wrap.position("relative");
11101 this.clearPositioning('auto');
11103 wrap.dom.appendChild(this.dom);
11105 wrap.setXY(wrapXY);
11112 fxUnwrap : function(wrap, pos, o){
11113 this.clearPositioning();
11114 this.setPositioning(pos);
11116 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11122 getFxRestore : function(){
11123 var st = this.dom.style;
11124 return {pos: this.getPositioning(), width: st.width, height : st.height};
11128 afterFx : function(o){
11130 this.applyStyles(o.afterStyle);
11133 this.addClass(o.afterCls);
11135 if(o.remove === true){
11138 Roo.callback(o.callback, o.scope, [this]);
11140 this.fxQueue.shift();
11146 getFxEl : function(){ // support for composite element fx
11147 return Roo.get(this.dom);
11151 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11152 animType = animType || 'run';
11154 var anim = Roo.lib.Anim[animType](
11156 (opt.duration || defaultDur) || .35,
11157 (opt.easing || defaultEase) || 'easeOut',
11159 Roo.callback(cb, this);
11168 // backwords compat
11169 Roo.Fx.resize = Roo.Fx.scale;
11171 //When included, Roo.Fx is automatically applied to Element so that all basic
11172 //effects are available directly via the Element API
11173 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11175 * Ext JS Library 1.1.1
11176 * Copyright(c) 2006-2007, Ext JS, LLC.
11178 * Originally Released Under LGPL - original licence link has changed is not relivant.
11181 * <script type="text/javascript">
11186 * @class Roo.CompositeElement
11187 * Standard composite class. Creates a Roo.Element for every element in the collection.
11189 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11190 * actions will be performed on all the elements in this collection.</b>
11192 * All methods return <i>this</i> and can be chained.
11194 var els = Roo.select("#some-el div.some-class", true);
11195 // or select directly from an existing element
11196 var el = Roo.get('some-el');
11197 el.select('div.some-class', true);
11199 els.setWidth(100); // all elements become 100 width
11200 els.hide(true); // all elements fade out and hide
11202 els.setWidth(100).hide(true);
11205 Roo.CompositeElement = function(els){
11206 this.elements = [];
11207 this.addElements(els);
11209 Roo.CompositeElement.prototype = {
11211 addElements : function(els){
11215 if(typeof els == "string"){
11216 els = Roo.Element.selectorFunction(els);
11218 var yels = this.elements;
11219 var index = yels.length-1;
11220 for(var i = 0, len = els.length; i < len; i++) {
11221 yels[++index] = Roo.get(els[i]);
11227 * Clears this composite and adds the elements returned by the passed selector.
11228 * @param {String/Array} els A string CSS selector, an array of elements or an element
11229 * @return {CompositeElement} this
11231 fill : function(els){
11232 this.elements = [];
11238 * Filters this composite to only elements that match the passed selector.
11239 * @param {String} selector A string CSS selector
11240 * @param {Boolean} inverse return inverse filter (not matches)
11241 * @return {CompositeElement} this
11243 filter : function(selector, inverse){
11245 inverse = inverse || false;
11246 this.each(function(el){
11247 var match = inverse ? !el.is(selector) : el.is(selector);
11249 els[els.length] = el.dom;
11256 invoke : function(fn, args){
11257 var els = this.elements;
11258 for(var i = 0, len = els.length; i < len; i++) {
11259 Roo.Element.prototype[fn].apply(els[i], args);
11264 * Adds elements to this composite.
11265 * @param {String/Array} els A string CSS selector, an array of elements or an element
11266 * @return {CompositeElement} this
11268 add : function(els){
11269 if(typeof els == "string"){
11270 this.addElements(Roo.Element.selectorFunction(els));
11271 }else if(els.length !== undefined){
11272 this.addElements(els);
11274 this.addElements([els]);
11279 * Calls the passed function passing (el, this, index) for each element in this composite.
11280 * @param {Function} fn The function to call
11281 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11282 * @return {CompositeElement} this
11284 each : function(fn, scope){
11285 var els = this.elements;
11286 for(var i = 0, len = els.length; i < len; i++){
11287 if(fn.call(scope || els[i], els[i], this, i) === false) {
11295 * Returns the Element object at the specified index
11296 * @param {Number} index
11297 * @return {Roo.Element}
11299 item : function(index){
11300 return this.elements[index] || null;
11304 * Returns the first Element
11305 * @return {Roo.Element}
11307 first : function(){
11308 return this.item(0);
11312 * Returns the last Element
11313 * @return {Roo.Element}
11316 return this.item(this.elements.length-1);
11320 * Returns the number of elements in this composite
11323 getCount : function(){
11324 return this.elements.length;
11328 * Returns true if this composite contains the passed element
11331 contains : function(el){
11332 return this.indexOf(el) !== -1;
11336 * Returns true if this composite contains the passed element
11339 indexOf : function(el){
11340 return this.elements.indexOf(Roo.get(el));
11345 * Removes the specified element(s).
11346 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11347 * or an array of any of those.
11348 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11349 * @return {CompositeElement} this
11351 removeElement : function(el, removeDom){
11352 if(el instanceof Array){
11353 for(var i = 0, len = el.length; i < len; i++){
11354 this.removeElement(el[i]);
11358 var index = typeof el == 'number' ? el : this.indexOf(el);
11361 var d = this.elements[index];
11365 d.parentNode.removeChild(d);
11368 this.elements.splice(index, 1);
11374 * Replaces the specified element with the passed element.
11375 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11377 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11378 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11379 * @return {CompositeElement} this
11381 replaceElement : function(el, replacement, domReplace){
11382 var index = typeof el == 'number' ? el : this.indexOf(el);
11385 this.elements[index].replaceWith(replacement);
11387 this.elements.splice(index, 1, Roo.get(replacement))
11394 * Removes all elements.
11396 clear : function(){
11397 this.elements = [];
11401 Roo.CompositeElement.createCall = function(proto, fnName){
11402 if(!proto[fnName]){
11403 proto[fnName] = function(){
11404 return this.invoke(fnName, arguments);
11408 for(var fnName in Roo.Element.prototype){
11409 if(typeof Roo.Element.prototype[fnName] == "function"){
11410 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11416 * Ext JS Library 1.1.1
11417 * Copyright(c) 2006-2007, Ext JS, LLC.
11419 * Originally Released Under LGPL - original licence link has changed is not relivant.
11422 * <script type="text/javascript">
11426 * @class Roo.CompositeElementLite
11427 * @extends Roo.CompositeElement
11428 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11430 var els = Roo.select("#some-el div.some-class");
11431 // or select directly from an existing element
11432 var el = Roo.get('some-el');
11433 el.select('div.some-class');
11435 els.setWidth(100); // all elements become 100 width
11436 els.hide(true); // all elements fade out and hide
11438 els.setWidth(100).hide(true);
11439 </code></pre><br><br>
11440 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11441 * actions will be performed on all the elements in this collection.</b>
11443 Roo.CompositeElementLite = function(els){
11444 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11445 this.el = new Roo.Element.Flyweight();
11447 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11448 addElements : function(els){
11450 if(els instanceof Array){
11451 this.elements = this.elements.concat(els);
11453 var yels = this.elements;
11454 var index = yels.length-1;
11455 for(var i = 0, len = els.length; i < len; i++) {
11456 yels[++index] = els[i];
11462 invoke : function(fn, args){
11463 var els = this.elements;
11465 for(var i = 0, len = els.length; i < len; i++) {
11467 Roo.Element.prototype[fn].apply(el, args);
11472 * Returns a flyweight Element of the dom element object at the specified index
11473 * @param {Number} index
11474 * @return {Roo.Element}
11476 item : function(index){
11477 if(!this.elements[index]){
11480 this.el.dom = this.elements[index];
11484 // fixes scope with flyweight
11485 addListener : function(eventName, handler, scope, opt){
11486 var els = this.elements;
11487 for(var i = 0, len = els.length; i < len; i++) {
11488 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11494 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11495 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11496 * a reference to the dom node, use el.dom.</b>
11497 * @param {Function} fn The function to call
11498 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11499 * @return {CompositeElement} this
11501 each : function(fn, scope){
11502 var els = this.elements;
11504 for(var i = 0, len = els.length; i < len; i++){
11506 if(fn.call(scope || el, el, this, i) === false){
11513 indexOf : function(el){
11514 return this.elements.indexOf(Roo.getDom(el));
11517 replaceElement : function(el, replacement, domReplace){
11518 var index = typeof el == 'number' ? el : this.indexOf(el);
11520 replacement = Roo.getDom(replacement);
11522 var d = this.elements[index];
11523 d.parentNode.insertBefore(replacement, d);
11524 d.parentNode.removeChild(d);
11526 this.elements.splice(index, 1, replacement);
11531 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11535 * Ext JS Library 1.1.1
11536 * Copyright(c) 2006-2007, Ext JS, LLC.
11538 * Originally Released Under LGPL - original licence link has changed is not relivant.
11541 * <script type="text/javascript">
11547 * @class Roo.data.Connection
11548 * @extends Roo.util.Observable
11549 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11550 * either to a configured URL, or to a URL specified at request time.
11552 * Requests made by this class are asynchronous, and will return immediately. No data from
11553 * the server will be available to the statement immediately following the {@link #request} call.
11554 * To process returned data, use a callback in the request options object, or an event listener.
11556 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11557 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11558 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11559 * property and, if present, the IFRAME's XML document as the responseXML property.
11561 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11562 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11563 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11564 * standard DOM methods.
11566 * @param {Object} config a configuration object.
11568 Roo.data.Connection = function(config){
11569 Roo.apply(this, config);
11572 * @event beforerequest
11573 * Fires before a network request is made to retrieve a data object.
11574 * @param {Connection} conn This Connection object.
11575 * @param {Object} options The options config object passed to the {@link #request} method.
11577 "beforerequest" : true,
11579 * @event requestcomplete
11580 * Fires if the request was successfully completed.
11581 * @param {Connection} conn This Connection object.
11582 * @param {Object} response The XHR object containing the response data.
11583 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11584 * @param {Object} options The options config object passed to the {@link #request} method.
11586 "requestcomplete" : true,
11588 * @event requestexception
11589 * Fires if an error HTTP status was returned from the server.
11590 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11591 * @param {Connection} conn This Connection object.
11592 * @param {Object} response The XHR object containing the response data.
11593 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11594 * @param {Object} options The options config object passed to the {@link #request} method.
11596 "requestexception" : true
11598 Roo.data.Connection.superclass.constructor.call(this);
11601 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11603 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11606 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11607 * extra parameters to each request made by this object. (defaults to undefined)
11610 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11611 * to each request made by this object. (defaults to undefined)
11614 * @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)
11617 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11621 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11627 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11630 disableCaching: true,
11633 * Sends an HTTP request to a remote server.
11634 * @param {Object} options An object which may contain the following properties:<ul>
11635 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11636 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11637 * request, a url encoded string or a function to call to get either.</li>
11638 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11639 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11640 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11641 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11642 * <li>options {Object} The parameter to the request call.</li>
11643 * <li>success {Boolean} True if the request succeeded.</li>
11644 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11646 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11647 * The callback is passed the following parameters:<ul>
11648 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11649 * <li>options {Object} The parameter to the request call.</li>
11651 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11652 * The callback is passed the following parameters:<ul>
11653 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11654 * <li>options {Object} The parameter to the request call.</li>
11656 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11657 * for the callback function. Defaults to the browser window.</li>
11658 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11659 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11660 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11661 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11662 * params for the post data. Any params will be appended to the URL.</li>
11663 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11665 * @return {Number} transactionId
11667 request : function(o){
11668 if(this.fireEvent("beforerequest", this, o) !== false){
11671 if(typeof p == "function"){
11672 p = p.call(o.scope||window, o);
11674 if(typeof p == "object"){
11675 p = Roo.urlEncode(o.params);
11677 if(this.extraParams){
11678 var extras = Roo.urlEncode(this.extraParams);
11679 p = p ? (p + '&' + extras) : extras;
11682 var url = o.url || this.url;
11683 if(typeof url == 'function'){
11684 url = url.call(o.scope||window, o);
11688 var form = Roo.getDom(o.form);
11689 url = url || form.action;
11691 var enctype = form.getAttribute("enctype");
11694 return this.doFormDataUpload(o, url);
11697 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11698 return this.doFormUpload(o, p, url);
11700 var f = Roo.lib.Ajax.serializeForm(form);
11701 p = p ? (p + '&' + f) : f;
11704 if (!o.form && o.formData) {
11705 o.formData = o.formData === true ? new FormData() : o.formData;
11706 for (var k in o.params) {
11707 o.formData.append(k,o.params[k]);
11710 return this.doFormDataUpload(o, url);
11714 var hs = o.headers;
11715 if(this.defaultHeaders){
11716 hs = Roo.apply(hs || {}, this.defaultHeaders);
11723 success: this.handleResponse,
11724 failure: this.handleFailure,
11726 argument: {options: o},
11727 timeout : o.timeout || this.timeout
11730 var method = o.method||this.method||(p ? "POST" : "GET");
11732 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11733 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11736 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11740 }else if(this.autoAbort !== false){
11744 if((method == 'GET' && p) || o.xmlData){
11745 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11748 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11749 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11750 Roo.lib.Ajax.useDefaultHeader == true;
11751 return this.transId;
11753 Roo.callback(o.callback, o.scope, [o, null, null]);
11759 * Determine whether this object has a request outstanding.
11760 * @param {Number} transactionId (Optional) defaults to the last transaction
11761 * @return {Boolean} True if there is an outstanding request.
11763 isLoading : function(transId){
11765 return Roo.lib.Ajax.isCallInProgress(transId);
11767 return this.transId ? true : false;
11772 * Aborts any outstanding request.
11773 * @param {Number} transactionId (Optional) defaults to the last transaction
11775 abort : function(transId){
11776 if(transId || this.isLoading()){
11777 Roo.lib.Ajax.abort(transId || this.transId);
11782 handleResponse : function(response){
11783 this.transId = false;
11784 var options = response.argument.options;
11785 response.argument = options ? options.argument : null;
11786 this.fireEvent("requestcomplete", this, response, options);
11787 Roo.callback(options.success, options.scope, [response, options]);
11788 Roo.callback(options.callback, options.scope, [options, true, response]);
11792 handleFailure : function(response, e){
11793 this.transId = false;
11794 var options = response.argument.options;
11795 response.argument = options ? options.argument : null;
11796 this.fireEvent("requestexception", this, response, options, e);
11797 Roo.callback(options.failure, options.scope, [response, options]);
11798 Roo.callback(options.callback, options.scope, [options, false, response]);
11802 doFormUpload : function(o, ps, url){
11804 var frame = document.createElement('iframe');
11807 frame.className = 'x-hidden';
11809 frame.src = Roo.SSL_SECURE_URL;
11811 document.body.appendChild(frame);
11814 document.frames[id].name = id;
11817 var form = Roo.getDom(o.form);
11819 form.method = 'POST';
11820 form.enctype = form.encoding = 'multipart/form-data';
11826 if(ps){ // add dynamic params
11828 ps = Roo.urlDecode(ps, false);
11830 if(ps.hasOwnProperty(k)){
11831 hd = document.createElement('input');
11832 hd.type = 'hidden';
11835 form.appendChild(hd);
11842 var r = { // bogus response object
11847 r.argument = o ? o.argument : null;
11852 doc = frame.contentWindow.document;
11854 doc = (frame.contentDocument || window.frames[id].document);
11856 if(doc && doc.body){
11857 r.responseText = doc.body.innerHTML;
11859 if(doc && doc.XMLDocument){
11860 r.responseXML = doc.XMLDocument;
11862 r.responseXML = doc;
11869 Roo.EventManager.removeListener(frame, 'load', cb, this);
11871 this.fireEvent("requestcomplete", this, r, o);
11872 Roo.callback(o.success, o.scope, [r, o]);
11873 Roo.callback(o.callback, o.scope, [o, true, r]);
11875 setTimeout(function(){document.body.removeChild(frame);}, 100);
11878 Roo.EventManager.on(frame, 'load', cb, this);
11881 if(hiddens){ // remove dynamic params
11882 for(var i = 0, len = hiddens.length; i < len; i++){
11883 form.removeChild(hiddens[i]);
11887 // this is a 'formdata version???'
11890 doFormDataUpload : function(o, url)
11894 var form = Roo.getDom(o.form);
11895 form.enctype = form.encoding = 'multipart/form-data';
11896 formData = o.formData === true ? new FormData(form) : o.formData;
11898 formData = o.formData === true ? new FormData() : o.formData;
11903 success: this.handleResponse,
11904 failure: this.handleFailure,
11906 argument: {options: o},
11907 timeout : o.timeout || this.timeout
11910 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11914 }else if(this.autoAbort !== false){
11918 //Roo.lib.Ajax.defaultPostHeader = null;
11919 Roo.lib.Ajax.useDefaultHeader = false;
11920 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11921 Roo.lib.Ajax.useDefaultHeader = true;
11929 * Ext JS Library 1.1.1
11930 * Copyright(c) 2006-2007, Ext JS, LLC.
11932 * Originally Released Under LGPL - original licence link has changed is not relivant.
11935 * <script type="text/javascript">
11939 * Global Ajax request class.
11942 * @extends Roo.data.Connection
11945 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11946 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11947 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11948 * @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)
11949 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11950 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11951 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11953 Roo.Ajax = new Roo.data.Connection({
11962 * Serialize the passed form into a url encoded string
11964 * @param {String/HTMLElement} form
11967 serializeForm : function(form){
11968 return Roo.lib.Ajax.serializeForm(form);
11972 * Ext JS Library 1.1.1
11973 * Copyright(c) 2006-2007, Ext JS, LLC.
11975 * Originally Released Under LGPL - original licence link has changed is not relivant.
11978 * <script type="text/javascript">
11983 * @class Roo.UpdateManager
11984 * @extends Roo.util.Observable
11985 * Provides AJAX-style update for Element object.<br><br>
11988 * // Get it from a Roo.Element object
11989 * var el = Roo.get("foo");
11990 * var mgr = el.getUpdateManager();
11991 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11993 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11995 * // or directly (returns the same UpdateManager instance)
11996 * var mgr = new Roo.UpdateManager("myElementId");
11997 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11998 * mgr.on("update", myFcnNeedsToKnow);
12000 // short handed call directly from the element object
12001 Roo.get("foo").load({
12005 text: "Loading Foo..."
12009 * Create new UpdateManager directly.
12010 * @param {String/HTMLElement/Roo.Element} el The element to update
12011 * @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).
12013 Roo.UpdateManager = function(el, forceNew){
12015 if(!forceNew && el.updateManager){
12016 return el.updateManager;
12019 * The Element object
12020 * @type Roo.Element
12024 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12027 this.defaultUrl = null;
12031 * @event beforeupdate
12032 * Fired before an update is made, return false from your handler and the update is cancelled.
12033 * @param {Roo.Element} el
12034 * @param {String/Object/Function} url
12035 * @param {String/Object} params
12037 "beforeupdate": true,
12040 * Fired after successful update is made.
12041 * @param {Roo.Element} el
12042 * @param {Object} oResponseObject The response Object
12047 * Fired on update failure.
12048 * @param {Roo.Element} el
12049 * @param {Object} oResponseObject The response Object
12053 var d = Roo.UpdateManager.defaults;
12055 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12058 this.sslBlankUrl = d.sslBlankUrl;
12060 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12063 this.disableCaching = d.disableCaching;
12065 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12068 this.indicatorText = d.indicatorText;
12070 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12073 this.showLoadIndicator = d.showLoadIndicator;
12075 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12078 this.timeout = d.timeout;
12081 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12084 this.loadScripts = d.loadScripts;
12087 * Transaction object of current executing transaction
12089 this.transaction = null;
12094 this.autoRefreshProcId = null;
12096 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12099 this.refreshDelegate = this.refresh.createDelegate(this);
12101 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12104 this.updateDelegate = this.update.createDelegate(this);
12106 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12109 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12113 this.successDelegate = this.processSuccess.createDelegate(this);
12117 this.failureDelegate = this.processFailure.createDelegate(this);
12119 if(!this.renderer){
12121 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12123 this.renderer = new Roo.UpdateManager.BasicRenderer();
12126 Roo.UpdateManager.superclass.constructor.call(this);
12129 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12131 * Get the Element this UpdateManager is bound to
12132 * @return {Roo.Element} The element
12134 getEl : function(){
12138 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12139 * @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:
12142 url: "your-url.php",<br/>
12143 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12144 callback: yourFunction,<br/>
12145 scope: yourObject, //(optional scope) <br/>
12146 discardUrl: false, <br/>
12147 nocache: false,<br/>
12148 text: "Loading...",<br/>
12150 scripts: false<br/>
12153 * The only required property is url. The optional properties nocache, text and scripts
12154 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12155 * @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}
12156 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12157 * @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.
12159 update : function(url, params, callback, discardUrl){
12160 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12161 var method = this.method,
12163 if(typeof url == "object"){ // must be config object
12166 params = params || cfg.params;
12167 callback = callback || cfg.callback;
12168 discardUrl = discardUrl || cfg.discardUrl;
12169 if(callback && cfg.scope){
12170 callback = callback.createDelegate(cfg.scope);
12172 if(typeof cfg.method != "undefined"){method = cfg.method;};
12173 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12174 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12175 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12176 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12178 this.showLoading();
12180 this.defaultUrl = url;
12182 if(typeof url == "function"){
12183 url = url.call(this);
12186 method = method || (params ? "POST" : "GET");
12187 if(method == "GET"){
12188 url = this.prepareUrl(url);
12191 var o = Roo.apply(cfg ||{}, {
12194 success: this.successDelegate,
12195 failure: this.failureDelegate,
12196 callback: undefined,
12197 timeout: (this.timeout*1000),
12198 argument: {"url": url, "form": null, "callback": callback, "params": params}
12200 Roo.log("updated manager called with timeout of " + o.timeout);
12201 this.transaction = Roo.Ajax.request(o);
12206 * 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.
12207 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12208 * @param {String/HTMLElement} form The form Id or form element
12209 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12210 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12211 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12213 formUpdate : function(form, url, reset, callback){
12214 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12215 if(typeof url == "function"){
12216 url = url.call(this);
12218 form = Roo.getDom(form);
12219 this.transaction = Roo.Ajax.request({
12222 success: this.successDelegate,
12223 failure: this.failureDelegate,
12224 timeout: (this.timeout*1000),
12225 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12227 this.showLoading.defer(1, this);
12232 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12233 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12235 refresh : function(callback){
12236 if(this.defaultUrl == null){
12239 this.update(this.defaultUrl, null, callback, true);
12243 * Set this element to auto refresh.
12244 * @param {Number} interval How often to update (in seconds).
12245 * @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)
12246 * @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}
12247 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12248 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12250 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12252 this.update(url || this.defaultUrl, params, callback, true);
12254 if(this.autoRefreshProcId){
12255 clearInterval(this.autoRefreshProcId);
12257 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12261 * Stop auto refresh on this element.
12263 stopAutoRefresh : function(){
12264 if(this.autoRefreshProcId){
12265 clearInterval(this.autoRefreshProcId);
12266 delete this.autoRefreshProcId;
12270 isAutoRefreshing : function(){
12271 return this.autoRefreshProcId ? true : false;
12274 * Called to update the element to "Loading" state. Override to perform custom action.
12276 showLoading : function(){
12277 if(this.showLoadIndicator){
12278 this.el.update(this.indicatorText);
12283 * Adds unique parameter to query string if disableCaching = true
12286 prepareUrl : function(url){
12287 if(this.disableCaching){
12288 var append = "_dc=" + (new Date().getTime());
12289 if(url.indexOf("?") !== -1){
12290 url += "&" + append;
12292 url += "?" + append;
12301 processSuccess : function(response){
12302 this.transaction = null;
12303 if(response.argument.form && response.argument.reset){
12304 try{ // put in try/catch since some older FF releases had problems with this
12305 response.argument.form.reset();
12308 if(this.loadScripts){
12309 this.renderer.render(this.el, response, this,
12310 this.updateComplete.createDelegate(this, [response]));
12312 this.renderer.render(this.el, response, this);
12313 this.updateComplete(response);
12317 updateComplete : function(response){
12318 this.fireEvent("update", this.el, response);
12319 if(typeof response.argument.callback == "function"){
12320 response.argument.callback(this.el, true, response);
12327 processFailure : function(response){
12328 this.transaction = null;
12329 this.fireEvent("failure", this.el, response);
12330 if(typeof response.argument.callback == "function"){
12331 response.argument.callback(this.el, false, response);
12336 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12337 * @param {Object} renderer The object implementing the render() method
12339 setRenderer : function(renderer){
12340 this.renderer = renderer;
12343 getRenderer : function(){
12344 return this.renderer;
12348 * Set the defaultUrl used for updates
12349 * @param {String/Function} defaultUrl The url or a function to call to get the url
12351 setDefaultUrl : function(defaultUrl){
12352 this.defaultUrl = defaultUrl;
12356 * Aborts the executing transaction
12358 abort : function(){
12359 if(this.transaction){
12360 Roo.Ajax.abort(this.transaction);
12365 * Returns true if an update is in progress
12366 * @return {Boolean}
12368 isUpdating : function(){
12369 if(this.transaction){
12370 return Roo.Ajax.isLoading(this.transaction);
12377 * @class Roo.UpdateManager.defaults
12378 * @static (not really - but it helps the doc tool)
12379 * The defaults collection enables customizing the default properties of UpdateManager
12381 Roo.UpdateManager.defaults = {
12383 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12389 * True to process scripts by default (Defaults to false).
12392 loadScripts : false,
12395 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12398 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12400 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12403 disableCaching : false,
12405 * Whether to show indicatorText when loading (Defaults to true).
12408 showLoadIndicator : true,
12410 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12413 indicatorText : '<div class="loading-indicator">Loading...</div>'
12417 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12419 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12420 * @param {String/HTMLElement/Roo.Element} el The element to update
12421 * @param {String} url The url
12422 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12423 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12426 * @member Roo.UpdateManager
12428 Roo.UpdateManager.updateElement = function(el, url, params, options){
12429 var um = Roo.get(el, true).getUpdateManager();
12430 Roo.apply(um, options);
12431 um.update(url, params, options ? options.callback : null);
12433 // alias for backwards compat
12434 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12436 * @class Roo.UpdateManager.BasicRenderer
12437 * Default Content renderer. Updates the elements innerHTML with the responseText.
12439 Roo.UpdateManager.BasicRenderer = function(){};
12441 Roo.UpdateManager.BasicRenderer.prototype = {
12443 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12444 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12445 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12446 * @param {Roo.Element} el The element being rendered
12447 * @param {Object} response The YUI Connect response object
12448 * @param {UpdateManager} updateManager The calling update manager
12449 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12451 render : function(el, response, updateManager, callback){
12452 el.update(response.responseText, updateManager.loadScripts, callback);
12458 * (c)) Alan Knowles
12464 * @class Roo.DomTemplate
12465 * @extends Roo.Template
12466 * An effort at a dom based template engine..
12468 * Similar to XTemplate, except it uses dom parsing to create the template..
12470 * Supported features:
12475 {a_variable} - output encoded.
12476 {a_variable.format:("Y-m-d")} - call a method on the variable
12477 {a_variable:raw} - unencoded output
12478 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12479 {a_variable:this.method_on_template(...)} - call a method on the template object.
12484 <div roo-for="a_variable or condition.."></div>
12485 <div roo-if="a_variable or condition"></div>
12486 <div roo-exec="some javascript"></div>
12487 <div roo-name="named_template"></div>
12492 Roo.DomTemplate = function()
12494 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12501 Roo.extend(Roo.DomTemplate, Roo.Template, {
12503 * id counter for sub templates.
12507 * flag to indicate if dom parser is inside a pre,
12508 * it will strip whitespace if not.
12513 * The various sub templates
12521 * basic tag replacing syntax
12524 * // you can fake an object call by doing this
12528 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12529 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12531 iterChild : function (node, method) {
12533 var oldPre = this.inPre;
12534 if (node.tagName == 'PRE') {
12537 for( var i = 0; i < node.childNodes.length; i++) {
12538 method.call(this, node.childNodes[i]);
12540 this.inPre = oldPre;
12546 * compile the template
12548 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12551 compile: function()
12555 // covert the html into DOM...
12559 doc = document.implementation.createHTMLDocument("");
12560 doc.documentElement.innerHTML = this.html ;
12561 div = doc.documentElement;
12563 // old IE... - nasty -- it causes all sorts of issues.. with
12564 // images getting pulled from server..
12565 div = document.createElement('div');
12566 div.innerHTML = this.html;
12568 //doc.documentElement.innerHTML = htmlBody
12574 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12576 var tpls = this.tpls;
12578 // create a top level template from the snippet..
12580 //Roo.log(div.innerHTML);
12587 body : div.innerHTML,
12600 Roo.each(tpls, function(tp){
12601 this.compileTpl(tp);
12602 this.tpls[tp.id] = tp;
12605 this.master = tpls[0];
12611 compileNode : function(node, istop) {
12616 // skip anything not a tag..
12617 if (node.nodeType != 1) {
12618 if (node.nodeType == 3 && !this.inPre) {
12619 // reduce white space..
12620 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12643 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12644 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12645 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12646 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12652 // just itterate children..
12653 this.iterChild(node,this.compileNode);
12656 tpl.uid = this.id++;
12657 tpl.value = node.getAttribute('roo-' + tpl.attr);
12658 node.removeAttribute('roo-'+ tpl.attr);
12659 if (tpl.attr != 'name') {
12660 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12661 node.parentNode.replaceChild(placeholder, node);
12664 var placeholder = document.createElement('span');
12665 placeholder.className = 'roo-tpl-' + tpl.value;
12666 node.parentNode.replaceChild(placeholder, node);
12669 // parent now sees '{domtplXXXX}
12670 this.iterChild(node,this.compileNode);
12672 // we should now have node body...
12673 var div = document.createElement('div');
12674 div.appendChild(node);
12676 // this has the unfortunate side effect of converting tagged attributes
12677 // eg. href="{...}" into %7C...%7D
12678 // this has been fixed by searching for those combo's although it's a bit hacky..
12681 tpl.body = div.innerHTML;
12688 switch (tpl.value) {
12689 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12690 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12691 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12696 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12700 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12704 tpl.id = tpl.value; // replace non characters???
12710 this.tpls.push(tpl);
12720 * Compile a segment of the template into a 'sub-template'
12726 compileTpl : function(tpl)
12728 var fm = Roo.util.Format;
12729 var useF = this.disableFormats !== true;
12731 var sep = Roo.isGecko ? "+\n" : ",\n";
12733 var undef = function(str) {
12734 Roo.debug && Roo.log("Property not found :" + str);
12738 //Roo.log(tpl.body);
12742 var fn = function(m, lbrace, name, format, args)
12745 //Roo.log(arguments);
12746 args = args ? args.replace(/\\'/g,"'") : args;
12747 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12748 if (typeof(format) == 'undefined') {
12749 format = 'htmlEncode';
12751 if (format == 'raw' ) {
12755 if(name.substr(0, 6) == 'domtpl'){
12756 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12759 // build an array of options to determine if value is undefined..
12761 // basically get 'xxxx.yyyy' then do
12762 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12763 // (function () { Roo.log("Property not found"); return ''; })() :
12768 Roo.each(name.split('.'), function(st) {
12769 lookfor += (lookfor.length ? '.': '') + st;
12770 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12773 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12776 if(format && useF){
12778 args = args ? ',' + args : "";
12780 if(format.substr(0, 5) != "this."){
12781 format = "fm." + format + '(';
12783 format = 'this.call("'+ format.substr(5) + '", ';
12787 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12790 if (args && args.length) {
12791 // called with xxyx.yuu:(test,test)
12793 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12795 // raw.. - :raw modifier..
12796 return "'"+ sep + udef_st + name + ")"+sep+"'";
12800 // branched to use + in gecko and [].join() in others
12802 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12803 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12806 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12807 body.push(tpl.body.replace(/(\r\n|\n)/g,
12808 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12809 body.push("'].join('');};};");
12810 body = body.join('');
12813 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12815 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12822 * same as applyTemplate, except it's done to one of the subTemplates
12823 * when using named templates, you can do:
12825 * var str = pl.applySubTemplate('your-name', values);
12828 * @param {Number} id of the template
12829 * @param {Object} values to apply to template
12830 * @param {Object} parent (normaly the instance of this object)
12832 applySubTemplate : function(id, values, parent)
12836 var t = this.tpls[id];
12840 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12841 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12845 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12852 if(t.execCall && t.execCall.call(this, values, parent)){
12856 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12862 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12863 parent = t.target ? values : parent;
12864 if(t.forCall && vs instanceof Array){
12866 for(var i = 0, len = vs.length; i < len; i++){
12868 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12870 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12872 //Roo.log(t.compiled);
12876 return buf.join('');
12879 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12884 return t.compiled.call(this, vs, parent);
12886 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12888 //Roo.log(t.compiled);
12896 applyTemplate : function(values){
12897 return this.master.compiled.call(this, values, {});
12898 //var s = this.subs;
12901 apply : function(){
12902 return this.applyTemplate.apply(this, arguments);
12907 Roo.DomTemplate.from = function(el){
12908 el = Roo.getDom(el);
12909 return new Roo.Domtemplate(el.value || el.innerHTML);
12912 * Ext JS Library 1.1.1
12913 * Copyright(c) 2006-2007, Ext JS, LLC.
12915 * Originally Released Under LGPL - original licence link has changed is not relivant.
12918 * <script type="text/javascript">
12922 * @class Roo.util.DelayedTask
12923 * Provides a convenient method of performing setTimeout where a new
12924 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12925 * You can use this class to buffer
12926 * the keypress events for a certain number of milliseconds, and perform only if they stop
12927 * for that amount of time.
12928 * @constructor The parameters to this constructor serve as defaults and are not required.
12929 * @param {Function} fn (optional) The default function to timeout
12930 * @param {Object} scope (optional) The default scope of that timeout
12931 * @param {Array} args (optional) The default Array of arguments
12933 Roo.util.DelayedTask = function(fn, scope, args){
12934 var id = null, d, t;
12936 var call = function(){
12937 var now = new Date().getTime();
12941 fn.apply(scope, args || []);
12945 * Cancels any pending timeout and queues a new one
12946 * @param {Number} delay The milliseconds to delay
12947 * @param {Function} newFn (optional) Overrides function passed to constructor
12948 * @param {Object} newScope (optional) Overrides scope passed to constructor
12949 * @param {Array} newArgs (optional) Overrides args passed to constructor
12951 this.delay = function(delay, newFn, newScope, newArgs){
12952 if(id && delay != d){
12956 t = new Date().getTime();
12958 scope = newScope || scope;
12959 args = newArgs || args;
12961 id = setInterval(call, d);
12966 * Cancel the last queued timeout
12968 this.cancel = function(){
12976 * Ext JS Library 1.1.1
12977 * Copyright(c) 2006-2007, Ext JS, LLC.
12979 * Originally Released Under LGPL - original licence link has changed is not relivant.
12982 * <script type="text/javascript">
12986 Roo.util.TaskRunner = function(interval){
12987 interval = interval || 10;
12988 var tasks = [], removeQueue = [];
12990 var running = false;
12992 var stopThread = function(){
12998 var startThread = function(){
13001 id = setInterval(runTasks, interval);
13005 var removeTask = function(task){
13006 removeQueue.push(task);
13012 var runTasks = function(){
13013 if(removeQueue.length > 0){
13014 for(var i = 0, len = removeQueue.length; i < len; i++){
13015 tasks.remove(removeQueue[i]);
13018 if(tasks.length < 1){
13023 var now = new Date().getTime();
13024 for(var i = 0, len = tasks.length; i < len; ++i){
13026 var itime = now - t.taskRunTime;
13027 if(t.interval <= itime){
13028 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13029 t.taskRunTime = now;
13030 if(rt === false || t.taskRunCount === t.repeat){
13035 if(t.duration && t.duration <= (now - t.taskStartTime)){
13042 * Queues a new task.
13043 * @param {Object} task
13045 this.start = function(task){
13047 task.taskStartTime = new Date().getTime();
13048 task.taskRunTime = 0;
13049 task.taskRunCount = 0;
13054 this.stop = function(task){
13059 this.stopAll = function(){
13061 for(var i = 0, len = tasks.length; i < len; i++){
13062 if(tasks[i].onStop){
13071 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13073 * Ext JS Library 1.1.1
13074 * Copyright(c) 2006-2007, Ext JS, LLC.
13076 * Originally Released Under LGPL - original licence link has changed is not relivant.
13079 * <script type="text/javascript">
13084 * @class Roo.util.MixedCollection
13085 * @extends Roo.util.Observable
13086 * A Collection class that maintains both numeric indexes and keys and exposes events.
13088 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13089 * collection (defaults to false)
13090 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13091 * and return the key value for that item. This is used when available to look up the key on items that
13092 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13093 * equivalent to providing an implementation for the {@link #getKey} method.
13095 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13103 * Fires when the collection is cleared.
13108 * Fires when an item is added to the collection.
13109 * @param {Number} index The index at which the item was added.
13110 * @param {Object} o The item added.
13111 * @param {String} key The key associated with the added item.
13116 * Fires when an item is replaced in the collection.
13117 * @param {String} key he key associated with the new added.
13118 * @param {Object} old The item being replaced.
13119 * @param {Object} new The new item.
13124 * Fires when an item is removed from the collection.
13125 * @param {Object} o The item being removed.
13126 * @param {String} key (optional) The key associated with the removed item.
13131 this.allowFunctions = allowFunctions === true;
13133 this.getKey = keyFn;
13135 Roo.util.MixedCollection.superclass.constructor.call(this);
13138 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13139 allowFunctions : false,
13142 * Adds an item to the collection.
13143 * @param {String} key The key to associate with the item
13144 * @param {Object} o The item to add.
13145 * @return {Object} The item added.
13147 add : function(key, o){
13148 if(arguments.length == 1){
13150 key = this.getKey(o);
13152 if(typeof key == "undefined" || key === null){
13154 this.items.push(o);
13155 this.keys.push(null);
13157 var old = this.map[key];
13159 return this.replace(key, o);
13162 this.items.push(o);
13164 this.keys.push(key);
13166 this.fireEvent("add", this.length-1, o, key);
13171 * MixedCollection has a generic way to fetch keys if you implement getKey.
13174 var mc = new Roo.util.MixedCollection();
13175 mc.add(someEl.dom.id, someEl);
13176 mc.add(otherEl.dom.id, otherEl);
13180 var mc = new Roo.util.MixedCollection();
13181 mc.getKey = function(el){
13187 // or via the constructor
13188 var mc = new Roo.util.MixedCollection(false, function(el){
13194 * @param o {Object} The item for which to find the key.
13195 * @return {Object} The key for the passed item.
13197 getKey : function(o){
13202 * Replaces an item in the collection.
13203 * @param {String} key The key associated with the item to replace, or the item to replace.
13204 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13205 * @return {Object} The new item.
13207 replace : function(key, o){
13208 if(arguments.length == 1){
13210 key = this.getKey(o);
13212 var old = this.item(key);
13213 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13214 return this.add(key, o);
13216 var index = this.indexOfKey(key);
13217 this.items[index] = o;
13219 this.fireEvent("replace", key, old, o);
13224 * Adds all elements of an Array or an Object to the collection.
13225 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13226 * an Array of values, each of which are added to the collection.
13228 addAll : function(objs){
13229 if(arguments.length > 1 || objs instanceof Array){
13230 var args = arguments.length > 1 ? arguments : objs;
13231 for(var i = 0, len = args.length; i < len; i++){
13235 for(var key in objs){
13236 if(this.allowFunctions || typeof objs[key] != "function"){
13237 this.add(key, objs[key]);
13244 * Executes the specified function once for every item in the collection, passing each
13245 * item as the first and only parameter. returning false from the function will stop the iteration.
13246 * @param {Function} fn The function to execute for each item.
13247 * @param {Object} scope (optional) The scope in which to execute the function.
13249 each : function(fn, scope){
13250 var items = [].concat(this.items); // each safe for removal
13251 for(var i = 0, len = items.length; i < len; i++){
13252 if(fn.call(scope || items[i], items[i], i, len) === false){
13259 * Executes the specified function once for every key in the collection, passing each
13260 * key, and its associated item as the first two parameters.
13261 * @param {Function} fn The function to execute for each item.
13262 * @param {Object} scope (optional) The scope in which to execute the function.
13264 eachKey : function(fn, scope){
13265 for(var i = 0, len = this.keys.length; i < len; i++){
13266 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13271 * Returns the first item in the collection which elicits a true return value from the
13272 * passed selection function.
13273 * @param {Function} fn The selection function to execute for each item.
13274 * @param {Object} scope (optional) The scope in which to execute the function.
13275 * @return {Object} The first item in the collection which returned true from the selection function.
13277 find : function(fn, scope){
13278 for(var i = 0, len = this.items.length; i < len; i++){
13279 if(fn.call(scope || window, this.items[i], this.keys[i])){
13280 return this.items[i];
13287 * Inserts an item at the specified index in the collection.
13288 * @param {Number} index The index to insert the item at.
13289 * @param {String} key The key to associate with the new item, or the item itself.
13290 * @param {Object} o (optional) If the second parameter was a key, the new item.
13291 * @return {Object} The item inserted.
13293 insert : function(index, key, o){
13294 if(arguments.length == 2){
13296 key = this.getKey(o);
13298 if(index >= this.length){
13299 return this.add(key, o);
13302 this.items.splice(index, 0, o);
13303 if(typeof key != "undefined" && key != null){
13306 this.keys.splice(index, 0, key);
13307 this.fireEvent("add", index, o, key);
13312 * Removed an item from the collection.
13313 * @param {Object} o The item to remove.
13314 * @return {Object} The item removed.
13316 remove : function(o){
13317 return this.removeAt(this.indexOf(o));
13321 * Remove an item from a specified index in the collection.
13322 * @param {Number} index The index within the collection of the item to remove.
13324 removeAt : function(index){
13325 if(index < this.length && index >= 0){
13327 var o = this.items[index];
13328 this.items.splice(index, 1);
13329 var key = this.keys[index];
13330 if(typeof key != "undefined"){
13331 delete this.map[key];
13333 this.keys.splice(index, 1);
13334 this.fireEvent("remove", o, key);
13339 * Removed an item associated with the passed key fom the collection.
13340 * @param {String} key The key of the item to remove.
13342 removeKey : function(key){
13343 return this.removeAt(this.indexOfKey(key));
13347 * Returns the number of items in the collection.
13348 * @return {Number} the number of items in the collection.
13350 getCount : function(){
13351 return this.length;
13355 * Returns index within the collection of the passed Object.
13356 * @param {Object} o The item to find the index of.
13357 * @return {Number} index of the item.
13359 indexOf : function(o){
13360 if(!this.items.indexOf){
13361 for(var i = 0, len = this.items.length; i < len; i++){
13362 if(this.items[i] == o) {
13368 return this.items.indexOf(o);
13373 * Returns index within the collection of the passed key.
13374 * @param {String} key The key to find the index of.
13375 * @return {Number} index of the key.
13377 indexOfKey : function(key){
13378 if(!this.keys.indexOf){
13379 for(var i = 0, len = this.keys.length; i < len; i++){
13380 if(this.keys[i] == key) {
13386 return this.keys.indexOf(key);
13391 * Returns the item associated with the passed key OR index. Key has priority over index.
13392 * @param {String/Number} key The key or index of the item.
13393 * @return {Object} The item associated with the passed key.
13395 item : function(key){
13396 if (key === 'length') {
13399 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13400 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13404 * Returns the item at the specified index.
13405 * @param {Number} index The index of the item.
13408 itemAt : function(index){
13409 return this.items[index];
13413 * Returns the item associated with the passed key.
13414 * @param {String/Number} key The key of the item.
13415 * @return {Object} The item associated with the passed key.
13417 key : function(key){
13418 return this.map[key];
13422 * Returns true if the collection contains the passed Object as an item.
13423 * @param {Object} o The Object to look for in the collection.
13424 * @return {Boolean} True if the collection contains the Object as an item.
13426 contains : function(o){
13427 return this.indexOf(o) != -1;
13431 * Returns true if the collection contains the passed Object as a key.
13432 * @param {String} key The key to look for in the collection.
13433 * @return {Boolean} True if the collection contains the Object as a key.
13435 containsKey : function(key){
13436 return typeof this.map[key] != "undefined";
13440 * Removes all items from the collection.
13442 clear : function(){
13447 this.fireEvent("clear");
13451 * Returns the first item in the collection.
13452 * @return {Object} the first item in the collection..
13454 first : function(){
13455 return this.items[0];
13459 * Returns the last item in the collection.
13460 * @return {Object} the last item in the collection..
13463 return this.items[this.length-1];
13466 _sort : function(property, dir, fn){
13467 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13468 fn = fn || function(a, b){
13471 var c = [], k = this.keys, items = this.items;
13472 for(var i = 0, len = items.length; i < len; i++){
13473 c[c.length] = {key: k[i], value: items[i], index: i};
13475 c.sort(function(a, b){
13476 var v = fn(a[property], b[property]) * dsc;
13478 v = (a.index < b.index ? -1 : 1);
13482 for(var i = 0, len = c.length; i < len; i++){
13483 items[i] = c[i].value;
13486 this.fireEvent("sort", this);
13490 * Sorts this collection with the passed comparison function
13491 * @param {String} direction (optional) "ASC" or "DESC"
13492 * @param {Function} fn (optional) comparison function
13494 sort : function(dir, fn){
13495 this._sort("value", dir, fn);
13499 * Sorts this collection by keys
13500 * @param {String} direction (optional) "ASC" or "DESC"
13501 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13503 keySort : function(dir, fn){
13504 this._sort("key", dir, fn || function(a, b){
13505 return String(a).toUpperCase()-String(b).toUpperCase();
13510 * Returns a range of items in this collection
13511 * @param {Number} startIndex (optional) defaults to 0
13512 * @param {Number} endIndex (optional) default to the last item
13513 * @return {Array} An array of items
13515 getRange : function(start, end){
13516 var items = this.items;
13517 if(items.length < 1){
13520 start = start || 0;
13521 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13524 for(var i = start; i <= end; i++) {
13525 r[r.length] = items[i];
13528 for(var i = start; i >= end; i--) {
13529 r[r.length] = items[i];
13536 * Filter the <i>objects</i> in this collection by a specific property.
13537 * Returns a new collection that has been filtered.
13538 * @param {String} property A property on your objects
13539 * @param {String/RegExp} value Either string that the property values
13540 * should start with or a RegExp to test against the property
13541 * @return {MixedCollection} The new filtered collection
13543 filter : function(property, value){
13544 if(!value.exec){ // not a regex
13545 value = String(value);
13546 if(value.length == 0){
13547 return this.clone();
13549 value = new RegExp("^" + Roo.escapeRe(value), "i");
13551 return this.filterBy(function(o){
13552 return o && value.test(o[property]);
13557 * Filter by a function. * Returns a new collection that has been filtered.
13558 * The passed function will be called with each
13559 * object in the collection. If the function returns true, the value is included
13560 * otherwise it is filtered.
13561 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13562 * @param {Object} scope (optional) The scope of the function (defaults to this)
13563 * @return {MixedCollection} The new filtered collection
13565 filterBy : function(fn, scope){
13566 var r = new Roo.util.MixedCollection();
13567 r.getKey = this.getKey;
13568 var k = this.keys, it = this.items;
13569 for(var i = 0, len = it.length; i < len; i++){
13570 if(fn.call(scope||this, it[i], k[i])){
13571 r.add(k[i], it[i]);
13578 * Creates a duplicate of this collection
13579 * @return {MixedCollection}
13581 clone : function(){
13582 var r = new Roo.util.MixedCollection();
13583 var k = this.keys, it = this.items;
13584 for(var i = 0, len = it.length; i < len; i++){
13585 r.add(k[i], it[i]);
13587 r.getKey = this.getKey;
13592 * Returns the item associated with the passed key or index.
13594 * @param {String/Number} key The key or index of the item.
13595 * @return {Object} The item associated with the passed key.
13597 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13599 * Ext JS Library 1.1.1
13600 * Copyright(c) 2006-2007, Ext JS, LLC.
13602 * Originally Released Under LGPL - original licence link has changed is not relivant.
13605 * <script type="text/javascript">
13608 * @class Roo.util.JSON
13609 * Modified version of Douglas Crockford"s json.js that doesn"t
13610 * mess with the Object prototype
13611 * http://www.json.org/js.html
13614 Roo.util.JSON = new (function(){
13615 var useHasOwn = {}.hasOwnProperty ? true : false;
13617 // crashes Safari in some instances
13618 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13620 var pad = function(n) {
13621 return n < 10 ? "0" + n : n;
13634 var encodeString = function(s){
13635 if (/["\\\x00-\x1f]/.test(s)) {
13636 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13641 c = b.charCodeAt();
13643 Math.floor(c / 16).toString(16) +
13644 (c % 16).toString(16);
13647 return '"' + s + '"';
13650 var encodeArray = function(o){
13651 var a = ["["], b, i, l = o.length, v;
13652 for (i = 0; i < l; i += 1) {
13654 switch (typeof v) {
13663 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13671 var encodeDate = function(o){
13672 return '"' + o.getFullYear() + "-" +
13673 pad(o.getMonth() + 1) + "-" +
13674 pad(o.getDate()) + "T" +
13675 pad(o.getHours()) + ":" +
13676 pad(o.getMinutes()) + ":" +
13677 pad(o.getSeconds()) + '"';
13681 * Encodes an Object, Array or other value
13682 * @param {Mixed} o The variable to encode
13683 * @return {String} The JSON string
13685 this.encode = function(o)
13687 // should this be extended to fully wrap stringify..
13689 if(typeof o == "undefined" || o === null){
13691 }else if(o instanceof Array){
13692 return encodeArray(o);
13693 }else if(o instanceof Date){
13694 return encodeDate(o);
13695 }else if(typeof o == "string"){
13696 return encodeString(o);
13697 }else if(typeof o == "number"){
13698 return isFinite(o) ? String(o) : "null";
13699 }else if(typeof o == "boolean"){
13702 var a = ["{"], b, i, v;
13704 if(!useHasOwn || o.hasOwnProperty(i)) {
13706 switch (typeof v) {
13715 a.push(this.encode(i), ":",
13716 v === null ? "null" : this.encode(v));
13727 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13728 * @param {String} json The JSON string
13729 * @return {Object} The resulting object
13731 this.decode = function(json){
13733 return /** eval:var:json */ eval("(" + json + ')');
13737 * Shorthand for {@link Roo.util.JSON#encode}
13738 * @member Roo encode
13740 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13742 * Shorthand for {@link Roo.util.JSON#decode}
13743 * @member Roo decode
13745 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13748 * Ext JS Library 1.1.1
13749 * Copyright(c) 2006-2007, Ext JS, LLC.
13751 * Originally Released Under LGPL - original licence link has changed is not relivant.
13754 * <script type="text/javascript">
13758 * @class Roo.util.Format
13759 * Reusable data formatting functions
13762 Roo.util.Format = function(){
13763 var trimRe = /^\s+|\s+$/g;
13766 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13767 * @param {String} value The string to truncate
13768 * @param {Number} length The maximum length to allow before truncating
13769 * @return {String} The converted text
13771 ellipsis : function(value, len){
13772 if(value && value.length > len){
13773 return value.substr(0, len-3)+"...";
13779 * Checks a reference and converts it to empty string if it is undefined
13780 * @param {Mixed} value Reference to check
13781 * @return {Mixed} Empty string if converted, otherwise the original value
13783 undef : function(value){
13784 return typeof value != "undefined" ? value : "";
13788 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13789 * @param {String} value The string to encode
13790 * @return {String} The encoded text
13792 htmlEncode : function(value){
13793 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13797 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13798 * @param {String} value The string to decode
13799 * @return {String} The decoded text
13801 htmlDecode : function(value){
13802 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13806 * Trims any whitespace from either side of a string
13807 * @param {String} value The text to trim
13808 * @return {String} The trimmed text
13810 trim : function(value){
13811 return String(value).replace(trimRe, "");
13815 * Returns a substring from within an original string
13816 * @param {String} value The original text
13817 * @param {Number} start The start index of the substring
13818 * @param {Number} length The length of the substring
13819 * @return {String} The substring
13821 substr : function(value, start, length){
13822 return String(value).substr(start, length);
13826 * Converts a string to all lower case letters
13827 * @param {String} value The text to convert
13828 * @return {String} The converted text
13830 lowercase : function(value){
13831 return String(value).toLowerCase();
13835 * Converts a string to all upper case letters
13836 * @param {String} value The text to convert
13837 * @return {String} The converted text
13839 uppercase : function(value){
13840 return String(value).toUpperCase();
13844 * Converts the first character only of a string to upper case
13845 * @param {String} value The text to convert
13846 * @return {String} The converted text
13848 capitalize : function(value){
13849 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13853 call : function(value, fn){
13854 if(arguments.length > 2){
13855 var args = Array.prototype.slice.call(arguments, 2);
13856 args.unshift(value);
13858 return /** eval:var:value */ eval(fn).apply(window, args);
13860 /** eval:var:value */
13861 return /** eval:var:value */ eval(fn).call(window, value);
13867 * safer version of Math.toFixed..??/
13868 * @param {Number/String} value The numeric value to format
13869 * @param {Number/String} value Decimal places
13870 * @return {String} The formatted currency string
13872 toFixed : function(v, n)
13874 // why not use to fixed - precision is buggered???
13876 return Math.round(v-0);
13878 var fact = Math.pow(10,n+1);
13879 v = (Math.round((v-0)*fact))/fact;
13880 var z = (''+fact).substring(2);
13881 if (v == Math.floor(v)) {
13882 return Math.floor(v) + '.' + z;
13885 // now just padd decimals..
13886 var ps = String(v).split('.');
13887 var fd = (ps[1] + z);
13888 var r = fd.substring(0,n);
13889 var rm = fd.substring(n);
13891 return ps[0] + '.' + r;
13893 r*=1; // turn it into a number;
13895 if (String(r).length != n) {
13898 r = String(r).substring(1); // chop the end off.
13901 return ps[0] + '.' + r;
13906 * Format a number as US currency
13907 * @param {Number/String} value The numeric value to format
13908 * @return {String} The formatted currency string
13910 usMoney : function(v){
13911 return '$' + Roo.util.Format.number(v);
13916 * eventually this should probably emulate php's number_format
13917 * @param {Number/String} value The numeric value to format
13918 * @param {Number} decimals number of decimal places
13919 * @param {String} delimiter for thousands (default comma)
13920 * @return {String} The formatted currency string
13922 number : function(v, decimals, thousandsDelimiter)
13924 // multiply and round.
13925 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13926 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13928 var mul = Math.pow(10, decimals);
13929 var zero = String(mul).substring(1);
13930 v = (Math.round((v-0)*mul))/mul;
13932 // if it's '0' number.. then
13934 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13936 var ps = v.split('.');
13939 var r = /(\d+)(\d{3})/;
13942 if(thousandsDelimiter.length != 0) {
13943 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13948 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13949 // does not have decimals
13950 (decimals ? ('.' + zero) : '');
13953 return whole + sub ;
13957 * Parse a value into a formatted date using the specified format pattern.
13958 * @param {Mixed} value The value to format
13959 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13960 * @return {String} The formatted date string
13962 date : function(v, format){
13966 if(!(v instanceof Date)){
13967 v = new Date(Date.parse(v));
13969 return v.dateFormat(format || Roo.util.Format.defaults.date);
13973 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13974 * @param {String} format Any valid date format string
13975 * @return {Function} The date formatting function
13977 dateRenderer : function(format){
13978 return function(v){
13979 return Roo.util.Format.date(v, format);
13984 stripTagsRE : /<\/?[^>]+>/gi,
13987 * Strips all HTML tags
13988 * @param {Mixed} value The text from which to strip tags
13989 * @return {String} The stripped text
13991 stripTags : function(v){
13992 return !v ? v : String(v).replace(this.stripTagsRE, "");
13995 * Size in Mb,Gb etc.
13996 * @param {Number} value The number to be formated
13997 * @param {number} decimals how many decimal places
13998 * @return {String} the formated string
14000 size : function(value, decimals)
14002 var sizes = ['b', 'k', 'M', 'G', 'T'];
14006 var i = parseInt(Math.floor(Math.log(v) / Math.log(1024)));
14007 return this.number(v / Math.pow(1024, i) ,decimals) + ' ' + sizes[i];
14014 Roo.util.Format.defaults = {
14018 * Ext JS Library 1.1.1
14019 * Copyright(c) 2006-2007, Ext JS, LLC.
14021 * Originally Released Under LGPL - original licence link has changed is not relivant.
14024 * <script type="text/javascript">
14031 * @class Roo.MasterTemplate
14032 * @extends Roo.Template
14033 * Provides a template that can have child templates. The syntax is:
14035 var t = new Roo.MasterTemplate(
14036 '<select name="{name}">',
14037 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14040 t.add('options', {value: 'foo', text: 'bar'});
14041 // or you can add multiple child elements in one shot
14042 t.addAll('options', [
14043 {value: 'foo', text: 'bar'},
14044 {value: 'foo2', text: 'bar2'},
14045 {value: 'foo3', text: 'bar3'}
14047 // then append, applying the master template values
14048 t.append('my-form', {name: 'my-select'});
14050 * A name attribute for the child template is not required if you have only one child
14051 * template or you want to refer to them by index.
14053 Roo.MasterTemplate = function(){
14054 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14055 this.originalHtml = this.html;
14057 var m, re = this.subTemplateRe;
14060 while(m = re.exec(this.html)){
14061 var name = m[1], content = m[2];
14066 tpl : new Roo.Template(content)
14069 st[name] = st[subIndex];
14071 st[subIndex].tpl.compile();
14072 st[subIndex].tpl.call = this.call.createDelegate(this);
14075 this.subCount = subIndex;
14078 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14080 * The regular expression used to match sub templates
14084 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14087 * Applies the passed values to a child template.
14088 * @param {String/Number} name (optional) The name or index of the child template
14089 * @param {Array/Object} values The values to be applied to the template
14090 * @return {MasterTemplate} this
14092 add : function(name, values){
14093 if(arguments.length == 1){
14094 values = arguments[0];
14097 var s = this.subs[name];
14098 s.buffer[s.buffer.length] = s.tpl.apply(values);
14103 * Applies all the passed values to a child template.
14104 * @param {String/Number} name (optional) The name or index of the child template
14105 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14106 * @param {Boolean} reset (optional) True to reset the template first
14107 * @return {MasterTemplate} this
14109 fill : function(name, values, reset){
14111 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14119 for(var i = 0, len = values.length; i < len; i++){
14120 this.add(name, values[i]);
14126 * Resets the template for reuse
14127 * @return {MasterTemplate} this
14129 reset : function(){
14131 for(var i = 0; i < this.subCount; i++){
14137 applyTemplate : function(values){
14139 var replaceIndex = -1;
14140 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14141 return s[++replaceIndex].buffer.join("");
14143 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14146 apply : function(){
14147 return this.applyTemplate.apply(this, arguments);
14150 compile : function(){return this;}
14154 * Alias for fill().
14157 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14159 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14160 * var tpl = Roo.MasterTemplate.from('element-id');
14161 * @param {String/HTMLElement} el
14162 * @param {Object} config
14165 Roo.MasterTemplate.from = function(el, config){
14166 el = Roo.getDom(el);
14167 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14170 * Ext JS Library 1.1.1
14171 * Copyright(c) 2006-2007, Ext JS, LLC.
14173 * Originally Released Under LGPL - original licence link has changed is not relivant.
14176 * <script type="text/javascript">
14181 * @class Roo.util.CSS
14182 * Utility class for manipulating CSS rules
14185 Roo.util.CSS = function(){
14187 var doc = document;
14189 var camelRe = /(-[a-z])/gi;
14190 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14194 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14195 * tag and appended to the HEAD of the document.
14196 * @param {String|Object} cssText The text containing the css rules
14197 * @param {String} id An id to add to the stylesheet for later removal
14198 * @return {StyleSheet}
14200 createStyleSheet : function(cssText, id){
14202 var head = doc.getElementsByTagName("head")[0];
14203 var nrules = doc.createElement("style");
14204 nrules.setAttribute("type", "text/css");
14206 nrules.setAttribute("id", id);
14208 if (typeof(cssText) != 'string') {
14209 // support object maps..
14210 // not sure if this a good idea..
14211 // perhaps it should be merged with the general css handling
14212 // and handle js style props.
14213 var cssTextNew = [];
14214 for(var n in cssText) {
14216 for(var k in cssText[n]) {
14217 citems.push( k + ' : ' +cssText[n][k] + ';' );
14219 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14222 cssText = cssTextNew.join("\n");
14228 head.appendChild(nrules);
14229 ss = nrules.styleSheet;
14230 ss.cssText = cssText;
14233 nrules.appendChild(doc.createTextNode(cssText));
14235 nrules.cssText = cssText;
14237 head.appendChild(nrules);
14238 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14240 this.cacheStyleSheet(ss);
14245 * Removes a style or link tag by id
14246 * @param {String} id The id of the tag
14248 removeStyleSheet : function(id){
14249 var existing = doc.getElementById(id);
14251 existing.parentNode.removeChild(existing);
14256 * Dynamically swaps an existing stylesheet reference for a new one
14257 * @param {String} id The id of an existing link tag to remove
14258 * @param {String} url The href of the new stylesheet to include
14260 swapStyleSheet : function(id, url){
14261 this.removeStyleSheet(id);
14262 var ss = doc.createElement("link");
14263 ss.setAttribute("rel", "stylesheet");
14264 ss.setAttribute("type", "text/css");
14265 ss.setAttribute("id", id);
14266 ss.setAttribute("href", url);
14267 doc.getElementsByTagName("head")[0].appendChild(ss);
14271 * Refresh the rule cache if you have dynamically added stylesheets
14272 * @return {Object} An object (hash) of rules indexed by selector
14274 refreshCache : function(){
14275 return this.getRules(true);
14279 cacheStyleSheet : function(stylesheet){
14283 try{// try catch for cross domain access issue
14284 var ssRules = stylesheet.cssRules || stylesheet.rules;
14285 for(var j = ssRules.length-1; j >= 0; --j){
14286 rules[ssRules[j].selectorText] = ssRules[j];
14292 * Gets all css rules for the document
14293 * @param {Boolean} refreshCache true to refresh the internal cache
14294 * @return {Object} An object (hash) of rules indexed by selector
14296 getRules : function(refreshCache){
14297 if(rules == null || refreshCache){
14299 var ds = doc.styleSheets;
14300 for(var i =0, len = ds.length; i < len; i++){
14302 this.cacheStyleSheet(ds[i]);
14310 * Gets an an individual CSS rule by selector(s)
14311 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14312 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14313 * @return {CSSRule} The CSS rule or null if one is not found
14315 getRule : function(selector, refreshCache){
14316 var rs = this.getRules(refreshCache);
14317 if(!(selector instanceof Array)){
14318 return rs[selector];
14320 for(var i = 0; i < selector.length; i++){
14321 if(rs[selector[i]]){
14322 return rs[selector[i]];
14330 * Updates a rule property
14331 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14332 * @param {String} property The css property
14333 * @param {String} value The new value for the property
14334 * @return {Boolean} true If a rule was found and updated
14336 updateRule : function(selector, property, value){
14337 if(!(selector instanceof Array)){
14338 var rule = this.getRule(selector);
14340 rule.style[property.replace(camelRe, camelFn)] = value;
14344 for(var i = 0; i < selector.length; i++){
14345 if(this.updateRule(selector[i], property, value)){
14355 * Ext JS Library 1.1.1
14356 * Copyright(c) 2006-2007, Ext JS, LLC.
14358 * Originally Released Under LGPL - original licence link has changed is not relivant.
14361 * <script type="text/javascript">
14367 * @class Roo.util.ClickRepeater
14368 * @extends Roo.util.Observable
14370 * A wrapper class which can be applied to any element. Fires a "click" event while the
14371 * mouse is pressed. The interval between firings may be specified in the config but
14372 * defaults to 10 milliseconds.
14374 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14376 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14377 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14378 * Similar to an autorepeat key delay.
14379 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14380 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14381 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14382 * "interval" and "delay" are ignored. "immediate" is honored.
14383 * @cfg {Boolean} preventDefault True to prevent the default click event
14384 * @cfg {Boolean} stopDefault True to stop the default click event
14387 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14388 * 2007-02-02 jvs Renamed to ClickRepeater
14389 * 2007-02-03 jvs Modifications for FF Mac and Safari
14392 * @param {String/HTMLElement/Element} el The element to listen on
14393 * @param {Object} config
14395 Roo.util.ClickRepeater = function(el, config)
14397 this.el = Roo.get(el);
14398 this.el.unselectable();
14400 Roo.apply(this, config);
14405 * Fires when the mouse button is depressed.
14406 * @param {Roo.util.ClickRepeater} this
14408 "mousedown" : true,
14411 * Fires on a specified interval during the time the element is pressed.
14412 * @param {Roo.util.ClickRepeater} this
14417 * Fires when the mouse key is released.
14418 * @param {Roo.util.ClickRepeater} this
14423 this.el.on("mousedown", this.handleMouseDown, this);
14424 if(this.preventDefault || this.stopDefault){
14425 this.el.on("click", function(e){
14426 if(this.preventDefault){
14427 e.preventDefault();
14429 if(this.stopDefault){
14435 // allow inline handler
14437 this.on("click", this.handler, this.scope || this);
14440 Roo.util.ClickRepeater.superclass.constructor.call(this);
14443 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14446 preventDefault : true,
14447 stopDefault : false,
14451 handleMouseDown : function(){
14452 clearTimeout(this.timer);
14454 if(this.pressClass){
14455 this.el.addClass(this.pressClass);
14457 this.mousedownTime = new Date();
14459 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14460 this.el.on("mouseout", this.handleMouseOut, this);
14462 this.fireEvent("mousedown", this);
14463 this.fireEvent("click", this);
14465 this.timer = this.click.defer(this.delay || this.interval, this);
14469 click : function(){
14470 this.fireEvent("click", this);
14471 this.timer = this.click.defer(this.getInterval(), this);
14475 getInterval: function(){
14476 if(!this.accelerate){
14477 return this.interval;
14479 var pressTime = this.mousedownTime.getElapsed();
14480 if(pressTime < 500){
14482 }else if(pressTime < 1700){
14484 }else if(pressTime < 2600){
14486 }else if(pressTime < 3500){
14488 }else if(pressTime < 4400){
14490 }else if(pressTime < 5300){
14492 }else if(pressTime < 6200){
14500 handleMouseOut : function(){
14501 clearTimeout(this.timer);
14502 if(this.pressClass){
14503 this.el.removeClass(this.pressClass);
14505 this.el.on("mouseover", this.handleMouseReturn, this);
14509 handleMouseReturn : function(){
14510 this.el.un("mouseover", this.handleMouseReturn);
14511 if(this.pressClass){
14512 this.el.addClass(this.pressClass);
14518 handleMouseUp : function(){
14519 clearTimeout(this.timer);
14520 this.el.un("mouseover", this.handleMouseReturn);
14521 this.el.un("mouseout", this.handleMouseOut);
14522 Roo.get(document).un("mouseup", this.handleMouseUp);
14523 this.el.removeClass(this.pressClass);
14524 this.fireEvent("mouseup", this);
14527 * @class Roo.util.Clipboard
14533 Roo.util.Clipboard = {
14535 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
14536 * @param {String} text to copy to clipboard
14538 write : function(text) {
14539 // navigator clipboard api needs a secure context (https)
14540 if (navigator.clipboard && window.isSecureContext) {
14541 // navigator clipboard api method'
14542 navigator.clipboard.writeText(text);
14545 // text area method
14546 var ta = document.createElement("textarea");
14548 // make the textarea out of viewport
14549 ta.style.position = "fixed";
14550 ta.style.left = "-999999px";
14551 ta.style.top = "-999999px";
14552 document.body.appendChild(ta);
14555 document.execCommand('copy');
14565 * Ext JS Library 1.1.1
14566 * Copyright(c) 2006-2007, Ext JS, LLC.
14568 * Originally Released Under LGPL - original licence link has changed is not relivant.
14571 * <script type="text/javascript">
14576 * @class Roo.KeyNav
14577 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14578 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14579 * way to implement custom navigation schemes for any UI component.</p>
14580 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14581 * pageUp, pageDown, del, home, end. Usage:</p>
14583 var nav = new Roo.KeyNav("my-element", {
14584 "left" : function(e){
14585 this.moveLeft(e.ctrlKey);
14587 "right" : function(e){
14588 this.moveRight(e.ctrlKey);
14590 "enter" : function(e){
14597 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14598 * @param {Object} config The config
14600 Roo.KeyNav = function(el, config){
14601 this.el = Roo.get(el);
14602 Roo.apply(this, config);
14603 if(!this.disabled){
14604 this.disabled = true;
14609 Roo.KeyNav.prototype = {
14611 * @cfg {Boolean} disabled
14612 * True to disable this KeyNav instance (defaults to false)
14616 * @cfg {String} defaultEventAction
14617 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14618 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14619 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14621 defaultEventAction: "stopEvent",
14623 * @cfg {Boolean} forceKeyDown
14624 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14625 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14626 * handle keydown instead of keypress.
14628 forceKeyDown : false,
14631 prepareEvent : function(e){
14632 var k = e.getKey();
14633 var h = this.keyToHandler[k];
14634 //if(h && this[h]){
14635 // e.stopPropagation();
14637 if(Roo.isSafari && h && k >= 37 && k <= 40){
14643 relay : function(e){
14644 var k = e.getKey();
14645 var h = this.keyToHandler[k];
14647 if(this.doRelay(e, this[h], h) !== true){
14648 e[this.defaultEventAction]();
14654 doRelay : function(e, h, hname){
14655 return h.call(this.scope || this, e);
14658 // possible handlers
14672 // quick lookup hash
14689 * Enable this KeyNav
14691 enable: function(){
14693 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14694 // the EventObject will normalize Safari automatically
14695 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14696 this.el.on("keydown", this.relay, this);
14698 this.el.on("keydown", this.prepareEvent, this);
14699 this.el.on("keypress", this.relay, this);
14701 this.disabled = false;
14706 * Disable this KeyNav
14708 disable: function(){
14709 if(!this.disabled){
14710 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14711 this.el.un("keydown", this.relay);
14713 this.el.un("keydown", this.prepareEvent);
14714 this.el.un("keypress", this.relay);
14716 this.disabled = true;
14721 * Ext JS Library 1.1.1
14722 * Copyright(c) 2006-2007, Ext JS, LLC.
14724 * Originally Released Under LGPL - original licence link has changed is not relivant.
14727 * <script type="text/javascript">
14732 * @class Roo.KeyMap
14733 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14734 * The constructor accepts the same config object as defined by {@link #addBinding}.
14735 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14736 * combination it will call the function with this signature (if the match is a multi-key
14737 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14738 * A KeyMap can also handle a string representation of keys.<br />
14741 // map one key by key code
14742 var map = new Roo.KeyMap("my-element", {
14743 key: 13, // or Roo.EventObject.ENTER
14748 // map multiple keys to one action by string
14749 var map = new Roo.KeyMap("my-element", {
14755 // map multiple keys to multiple actions by strings and array of codes
14756 var map = new Roo.KeyMap("my-element", [
14759 fn: function(){ alert("Return was pressed"); }
14762 fn: function(){ alert('a, b or c was pressed'); }
14767 fn: function(){ alert('Control + shift + tab was pressed.'); }
14771 * <b>Note: A KeyMap starts enabled</b>
14773 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14774 * @param {Object} config The config (see {@link #addBinding})
14775 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14777 Roo.KeyMap = function(el, config, eventName){
14778 this.el = Roo.get(el);
14779 this.eventName = eventName || "keydown";
14780 this.bindings = [];
14782 this.addBinding(config);
14787 Roo.KeyMap.prototype = {
14789 * True to stop the event from bubbling and prevent the default browser action if the
14790 * key was handled by the KeyMap (defaults to false)
14796 * Add a new binding to this KeyMap. The following config object properties are supported:
14798 Property Type Description
14799 ---------- --------------- ----------------------------------------------------------------------
14800 key String/Array A single keycode or an array of keycodes to handle
14801 shift Boolean True to handle key only when shift is pressed (defaults to false)
14802 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14803 alt Boolean True to handle key only when alt is pressed (defaults to false)
14804 fn Function The function to call when KeyMap finds the expected key combination
14805 scope Object The scope of the callback function
14811 var map = new Roo.KeyMap(document, {
14812 key: Roo.EventObject.ENTER,
14817 //Add a new binding to the existing KeyMap later
14825 * @param {Object/Array} config A single KeyMap config or an array of configs
14827 addBinding : function(config){
14828 if(config instanceof Array){
14829 for(var i = 0, len = config.length; i < len; i++){
14830 this.addBinding(config[i]);
14834 var keyCode = config.key,
14835 shift = config.shift,
14836 ctrl = config.ctrl,
14839 scope = config.scope;
14840 if(typeof keyCode == "string"){
14842 var keyString = keyCode.toUpperCase();
14843 for(var j = 0, len = keyString.length; j < len; j++){
14844 ks.push(keyString.charCodeAt(j));
14848 var keyArray = keyCode instanceof Array;
14849 var handler = function(e){
14850 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14851 var k = e.getKey();
14853 for(var i = 0, len = keyCode.length; i < len; i++){
14854 if(keyCode[i] == k){
14855 if(this.stopEvent){
14858 fn.call(scope || window, k, e);
14864 if(this.stopEvent){
14867 fn.call(scope || window, k, e);
14872 this.bindings.push(handler);
14876 * Shorthand for adding a single key listener
14877 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14878 * following options:
14879 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14880 * @param {Function} fn The function to call
14881 * @param {Object} scope (optional) The scope of the function
14883 on : function(key, fn, scope){
14884 var keyCode, shift, ctrl, alt;
14885 if(typeof key == "object" && !(key instanceof Array)){
14904 handleKeyDown : function(e){
14905 if(this.enabled){ //just in case
14906 var b = this.bindings;
14907 for(var i = 0, len = b.length; i < len; i++){
14908 b[i].call(this, e);
14914 * Returns true if this KeyMap is enabled
14915 * @return {Boolean}
14917 isEnabled : function(){
14918 return this.enabled;
14922 * Enables this KeyMap
14924 enable: function(){
14926 this.el.on(this.eventName, this.handleKeyDown, this);
14927 this.enabled = true;
14932 * Disable this KeyMap
14934 disable: function(){
14936 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14937 this.enabled = false;
14942 * Ext JS Library 1.1.1
14943 * Copyright(c) 2006-2007, Ext JS, LLC.
14945 * Originally Released Under LGPL - original licence link has changed is not relivant.
14948 * <script type="text/javascript">
14953 * @class Roo.util.TextMetrics
14954 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14955 * wide, in pixels, a given block of text will be.
14958 Roo.util.TextMetrics = function(){
14962 * Measures the size of the specified text
14963 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14964 * that can affect the size of the rendered text
14965 * @param {String} text The text to measure
14966 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14967 * in order to accurately measure the text height
14968 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14970 measure : function(el, text, fixedWidth){
14972 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14975 shared.setFixedWidth(fixedWidth || 'auto');
14976 return shared.getSize(text);
14980 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14981 * the overhead of multiple calls to initialize the style properties on each measurement.
14982 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14983 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14984 * in order to accurately measure the text height
14985 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14987 createInstance : function(el, fixedWidth){
14988 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14995 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14996 var ml = new Roo.Element(document.createElement('div'));
14997 document.body.appendChild(ml.dom);
14998 ml.position('absolute');
14999 ml.setLeftTop(-1000, -1000);
15003 ml.setWidth(fixedWidth);
15008 * Returns the size of the specified text based on the internal element's style and width properties
15009 * @memberOf Roo.util.TextMetrics.Instance#
15010 * @param {String} text The text to measure
15011 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15013 getSize : function(text){
15015 var s = ml.getSize();
15021 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15022 * that can affect the size of the rendered text
15023 * @memberOf Roo.util.TextMetrics.Instance#
15024 * @param {String/HTMLElement} el The element, dom node or id
15026 bind : function(el){
15028 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15033 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15034 * to set a fixed width in order to accurately measure the text height.
15035 * @memberOf Roo.util.TextMetrics.Instance#
15036 * @param {Number} width The width to set on the element
15038 setFixedWidth : function(width){
15039 ml.setWidth(width);
15043 * Returns the measured width of the specified text
15044 * @memberOf Roo.util.TextMetrics.Instance#
15045 * @param {String} text The text to measure
15046 * @return {Number} width The width in pixels
15048 getWidth : function(text){
15049 ml.dom.style.width = 'auto';
15050 return this.getSize(text).width;
15054 * Returns the measured height of the specified text. For multiline text, be sure to call
15055 * {@link #setFixedWidth} if necessary.
15056 * @memberOf Roo.util.TextMetrics.Instance#
15057 * @param {String} text The text to measure
15058 * @return {Number} height The height in pixels
15060 getHeight : function(text){
15061 return this.getSize(text).height;
15065 instance.bind(bindTo);
15070 // backwards compat
15071 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15073 * Ext JS Library 1.1.1
15074 * Copyright(c) 2006-2007, Ext JS, LLC.
15076 * Originally Released Under LGPL - original licence link has changed is not relivant.
15079 * <script type="text/javascript">
15083 * @class Roo.state.Provider
15084 * Abstract base class for state provider implementations. This class provides methods
15085 * for encoding and decoding <b>typed</b> variables including dates and defines the
15086 * Provider interface.
15088 Roo.state.Provider = function(){
15090 * @event statechange
15091 * Fires when a state change occurs.
15092 * @param {Provider} this This state provider
15093 * @param {String} key The state key which was changed
15094 * @param {String} value The encoded value for the state
15097 "statechange": true
15100 Roo.state.Provider.superclass.constructor.call(this);
15102 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15104 * Returns the current value for a key
15105 * @param {String} name The key name
15106 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15107 * @return {Mixed} The state data
15109 get : function(name, defaultValue){
15110 return typeof this.state[name] == "undefined" ?
15111 defaultValue : this.state[name];
15115 * Clears a value from the state
15116 * @param {String} name The key name
15118 clear : function(name){
15119 delete this.state[name];
15120 this.fireEvent("statechange", this, name, null);
15124 * Sets the value for a key
15125 * @param {String} name The key name
15126 * @param {Mixed} value The value to set
15128 set : function(name, value){
15129 this.state[name] = value;
15130 this.fireEvent("statechange", this, name, value);
15134 * Decodes a string previously encoded with {@link #encodeValue}.
15135 * @param {String} value The value to decode
15136 * @return {Mixed} The decoded value
15138 decodeValue : function(cookie){
15139 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15140 var matches = re.exec(unescape(cookie));
15141 if(!matches || !matches[1]) {
15142 return; // non state cookie
15144 var type = matches[1];
15145 var v = matches[2];
15148 return parseFloat(v);
15150 return new Date(Date.parse(v));
15155 var values = v.split("^");
15156 for(var i = 0, len = values.length; i < len; i++){
15157 all.push(this.decodeValue(values[i]));
15162 var values = v.split("^");
15163 for(var i = 0, len = values.length; i < len; i++){
15164 var kv = values[i].split("=");
15165 all[kv[0]] = this.decodeValue(kv[1]);
15174 * Encodes a value including type information. Decode with {@link #decodeValue}.
15175 * @param {Mixed} value The value to encode
15176 * @return {String} The encoded value
15178 encodeValue : function(v){
15180 if(typeof v == "number"){
15182 }else if(typeof v == "boolean"){
15183 enc = "b:" + (v ? "1" : "0");
15184 }else if(v instanceof Date){
15185 enc = "d:" + v.toGMTString();
15186 }else if(v instanceof Array){
15188 for(var i = 0, len = v.length; i < len; i++){
15189 flat += this.encodeValue(v[i]);
15195 }else if(typeof v == "object"){
15198 if(typeof v[key] != "function"){
15199 flat += key + "=" + this.encodeValue(v[key]) + "^";
15202 enc = "o:" + flat.substring(0, flat.length-1);
15206 return escape(enc);
15212 * Ext JS Library 1.1.1
15213 * Copyright(c) 2006-2007, Ext JS, LLC.
15215 * Originally Released Under LGPL - original licence link has changed is not relivant.
15218 * <script type="text/javascript">
15221 * @class Roo.state.Manager
15222 * This is the global state manager. By default all components that are "state aware" check this class
15223 * for state information if you don't pass them a custom state provider. In order for this class
15224 * to be useful, it must be initialized with a provider when your application initializes.
15226 // in your initialization function
15228 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15230 // supposed you have a {@link Roo.BorderLayout}
15231 var layout = new Roo.BorderLayout(...);
15232 layout.restoreState();
15233 // or a {Roo.BasicDialog}
15234 var dialog = new Roo.BasicDialog(...);
15235 dialog.restoreState();
15239 Roo.state.Manager = function(){
15240 var provider = new Roo.state.Provider();
15244 * Configures the default state provider for your application
15245 * @param {Provider} stateProvider The state provider to set
15247 setProvider : function(stateProvider){
15248 provider = stateProvider;
15252 * Returns the current value for a key
15253 * @param {String} name The key name
15254 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15255 * @return {Mixed} The state data
15257 get : function(key, defaultValue){
15258 return provider.get(key, defaultValue);
15262 * Sets the value for a key
15263 * @param {String} name The key name
15264 * @param {Mixed} value The state data
15266 set : function(key, value){
15267 provider.set(key, value);
15271 * Clears a value from the state
15272 * @param {String} name The key name
15274 clear : function(key){
15275 provider.clear(key);
15279 * Gets the currently configured state provider
15280 * @return {Provider} The state provider
15282 getProvider : function(){
15289 * Ext JS Library 1.1.1
15290 * Copyright(c) 2006-2007, Ext JS, LLC.
15292 * Originally Released Under LGPL - original licence link has changed is not relivant.
15295 * <script type="text/javascript">
15298 * @class Roo.state.CookieProvider
15299 * @extends Roo.state.Provider
15300 * The default Provider implementation which saves state via cookies.
15303 var cp = new Roo.state.CookieProvider({
15305 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15306 domain: "roojs.com"
15308 Roo.state.Manager.setProvider(cp);
15310 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15311 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15312 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15313 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15314 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15315 * domain the page is running on including the 'www' like 'www.roojs.com')
15316 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15318 * Create a new CookieProvider
15319 * @param {Object} config The configuration object
15321 Roo.state.CookieProvider = function(config){
15322 Roo.state.CookieProvider.superclass.constructor.call(this);
15324 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15325 this.domain = null;
15326 this.secure = false;
15327 Roo.apply(this, config);
15328 this.state = this.readCookies();
15331 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15333 set : function(name, value){
15334 if(typeof value == "undefined" || value === null){
15338 this.setCookie(name, value);
15339 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15343 clear : function(name){
15344 this.clearCookie(name);
15345 Roo.state.CookieProvider.superclass.clear.call(this, name);
15349 readCookies : function(){
15351 var c = document.cookie + ";";
15352 var re = /\s?(.*?)=(.*?);/g;
15354 while((matches = re.exec(c)) != null){
15355 var name = matches[1];
15356 var value = matches[2];
15357 if(name && name.substring(0,3) == "ys-"){
15358 cookies[name.substr(3)] = this.decodeValue(value);
15365 setCookie : function(name, value){
15366 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15367 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15368 ((this.path == null) ? "" : ("; path=" + this.path)) +
15369 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15370 ((this.secure == true) ? "; secure" : "");
15374 clearCookie : function(name){
15375 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15376 ((this.path == null) ? "" : ("; path=" + this.path)) +
15377 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15378 ((this.secure == true) ? "; secure" : "");
15382 * Ext JS Library 1.1.1
15383 * Copyright(c) 2006-2007, Ext JS, LLC.
15385 * Originally Released Under LGPL - original licence link has changed is not relivant.
15388 * <script type="text/javascript">
15393 * @class Roo.ComponentMgr
15394 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15397 Roo.ComponentMgr = function(){
15398 var all = new Roo.util.MixedCollection();
15402 * Registers a component.
15403 * @param {Roo.Component} c The component
15405 register : function(c){
15410 * Unregisters a component.
15411 * @param {Roo.Component} c The component
15413 unregister : function(c){
15418 * Returns a component by id
15419 * @param {String} id The component id
15421 get : function(id){
15422 return all.get(id);
15426 * Registers a function that will be called when a specified component is added to ComponentMgr
15427 * @param {String} id The component id
15428 * @param {Funtction} fn The callback function
15429 * @param {Object} scope The scope of the callback
15431 onAvailable : function(id, fn, scope){
15432 all.on("add", function(index, o){
15434 fn.call(scope || o, o);
15435 all.un("add", fn, scope);
15442 * Ext JS Library 1.1.1
15443 * Copyright(c) 2006-2007, Ext JS, LLC.
15445 * Originally Released Under LGPL - original licence link has changed is not relivant.
15448 * <script type="text/javascript">
15452 * @class Roo.Component
15453 * @extends Roo.util.Observable
15454 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15455 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15456 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15457 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15458 * All visual components (widgets) that require rendering into a layout should subclass Component.
15460 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15461 * 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
15462 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15464 Roo.Component = function(config){
15465 config = config || {};
15466 if(config.tagName || config.dom || typeof config == "string"){ // element object
15467 config = {el: config, id: config.id || config};
15469 this.initialConfig = config;
15471 Roo.apply(this, config);
15475 * Fires after the component is disabled.
15476 * @param {Roo.Component} this
15481 * Fires after the component is enabled.
15482 * @param {Roo.Component} this
15486 * @event beforeshow
15487 * Fires before the component is shown. Return false to stop the show.
15488 * @param {Roo.Component} this
15493 * Fires after the component is shown.
15494 * @param {Roo.Component} this
15498 * @event beforehide
15499 * Fires before the component is hidden. Return false to stop the hide.
15500 * @param {Roo.Component} this
15505 * Fires after the component is hidden.
15506 * @param {Roo.Component} this
15510 * @event beforerender
15511 * Fires before the component is rendered. Return false to stop the render.
15512 * @param {Roo.Component} this
15514 beforerender : true,
15517 * Fires after the component is rendered.
15518 * @param {Roo.Component} this
15522 * @event beforedestroy
15523 * Fires before the component is destroyed. Return false to stop the destroy.
15524 * @param {Roo.Component} this
15526 beforedestroy : true,
15529 * Fires after the component is destroyed.
15530 * @param {Roo.Component} this
15535 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15537 Roo.ComponentMgr.register(this);
15538 Roo.Component.superclass.constructor.call(this);
15539 this.initComponent();
15540 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15541 this.render(this.renderTo);
15542 delete this.renderTo;
15547 Roo.Component.AUTO_ID = 1000;
15549 Roo.extend(Roo.Component, Roo.util.Observable, {
15551 * @scope Roo.Component.prototype
15553 * true if this component is hidden. Read-only.
15558 * true if this component is disabled. Read-only.
15563 * true if this component has been rendered. Read-only.
15567 /** @cfg {String} disableClass
15568 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15570 disabledClass : "x-item-disabled",
15571 /** @cfg {Boolean} allowDomMove
15572 * Whether the component can move the Dom node when rendering (defaults to true).
15574 allowDomMove : true,
15575 /** @cfg {String} hideMode (display|visibility)
15576 * How this component should hidden. Supported values are
15577 * "visibility" (css visibility), "offsets" (negative offset position) and
15578 * "display" (css display) - defaults to "display".
15580 hideMode: 'display',
15583 ctype : "Roo.Component",
15586 * @cfg {String} actionMode
15587 * which property holds the element that used for hide() / show() / disable() / enable()
15588 * default is 'el' for forms you probably want to set this to fieldEl
15593 getActionEl : function(){
15594 return this[this.actionMode];
15597 initComponent : Roo.emptyFn,
15599 * If this is a lazy rendering component, render it to its container element.
15600 * @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.
15602 render : function(container, position){
15608 if(this.fireEvent("beforerender", this) === false){
15612 if(!container && this.el){
15613 this.el = Roo.get(this.el);
15614 container = this.el.dom.parentNode;
15615 this.allowDomMove = false;
15617 this.container = Roo.get(container);
15618 this.rendered = true;
15619 if(position !== undefined){
15620 if(typeof position == 'number'){
15621 position = this.container.dom.childNodes[position];
15623 position = Roo.getDom(position);
15626 this.onRender(this.container, position || null);
15628 this.el.addClass(this.cls);
15632 this.el.applyStyles(this.style);
15635 this.fireEvent("render", this);
15636 this.afterRender(this.container);
15649 // default function is not really useful
15650 onRender : function(ct, position){
15652 this.el = Roo.get(this.el);
15653 if(this.allowDomMove !== false){
15654 ct.dom.insertBefore(this.el.dom, position);
15660 getAutoCreate : function(){
15661 var cfg = typeof this.autoCreate == "object" ?
15662 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15663 if(this.id && !cfg.id){
15670 afterRender : Roo.emptyFn,
15673 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15674 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15676 destroy : function(){
15677 if(this.fireEvent("beforedestroy", this) !== false){
15678 this.purgeListeners();
15679 this.beforeDestroy();
15681 this.el.removeAllListeners();
15683 if(this.actionMode == "container"){
15684 this.container.remove();
15688 Roo.ComponentMgr.unregister(this);
15689 this.fireEvent("destroy", this);
15694 beforeDestroy : function(){
15699 onDestroy : function(){
15704 * Returns the underlying {@link Roo.Element}.
15705 * @return {Roo.Element} The element
15707 getEl : function(){
15712 * Returns the id of this component.
15715 getId : function(){
15720 * Try to focus this component.
15721 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15722 * @return {Roo.Component} this
15724 focus : function(selectText){
15727 if(selectText === true){
15728 this.el.dom.select();
15743 * Disable this component.
15744 * @return {Roo.Component} this
15746 disable : function(){
15750 this.disabled = true;
15751 this.fireEvent("disable", this);
15756 onDisable : function(){
15757 this.getActionEl().addClass(this.disabledClass);
15758 this.el.dom.disabled = true;
15762 * Enable this component.
15763 * @return {Roo.Component} this
15765 enable : function(){
15769 this.disabled = false;
15770 this.fireEvent("enable", this);
15775 onEnable : function(){
15776 this.getActionEl().removeClass(this.disabledClass);
15777 this.el.dom.disabled = false;
15781 * Convenience function for setting disabled/enabled by boolean.
15782 * @param {Boolean} disabled
15784 setDisabled : function(disabled){
15785 this[disabled ? "disable" : "enable"]();
15789 * Show this component.
15790 * @return {Roo.Component} this
15793 if(this.fireEvent("beforeshow", this) !== false){
15794 this.hidden = false;
15798 this.fireEvent("show", this);
15804 onShow : function(){
15805 var ae = this.getActionEl();
15806 if(this.hideMode == 'visibility'){
15807 ae.dom.style.visibility = "visible";
15808 }else if(this.hideMode == 'offsets'){
15809 ae.removeClass('x-hidden');
15811 ae.dom.style.display = "";
15816 * Hide this component.
15817 * @return {Roo.Component} this
15820 if(this.fireEvent("beforehide", this) !== false){
15821 this.hidden = true;
15825 this.fireEvent("hide", this);
15831 onHide : function(){
15832 var ae = this.getActionEl();
15833 if(this.hideMode == 'visibility'){
15834 ae.dom.style.visibility = "hidden";
15835 }else if(this.hideMode == 'offsets'){
15836 ae.addClass('x-hidden');
15838 ae.dom.style.display = "none";
15843 * Convenience function to hide or show this component by boolean.
15844 * @param {Boolean} visible True to show, false to hide
15845 * @return {Roo.Component} this
15847 setVisible: function(visible){
15857 * Returns true if this component is visible.
15859 isVisible : function(){
15860 return this.getActionEl().isVisible();
15863 cloneConfig : function(overrides){
15864 overrides = overrides || {};
15865 var id = overrides.id || Roo.id();
15866 var cfg = Roo.applyIf(overrides, this.initialConfig);
15867 cfg.id = id; // prevent dup id
15868 return new this.constructor(cfg);
15872 * Ext JS Library 1.1.1
15873 * Copyright(c) 2006-2007, Ext JS, LLC.
15875 * Originally Released Under LGPL - original licence link has changed is not relivant.
15878 * <script type="text/javascript">
15882 * @class Roo.BoxComponent
15883 * @extends Roo.Component
15884 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15885 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15886 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15887 * layout containers.
15889 * @param {Roo.Element/String/Object} config The configuration options.
15891 Roo.BoxComponent = function(config){
15892 Roo.Component.call(this, config);
15896 * Fires after the component is resized.
15897 * @param {Roo.Component} this
15898 * @param {Number} adjWidth The box-adjusted width that was set
15899 * @param {Number} adjHeight The box-adjusted height that was set
15900 * @param {Number} rawWidth The width that was originally specified
15901 * @param {Number} rawHeight The height that was originally specified
15906 * Fires after the component is moved.
15907 * @param {Roo.Component} this
15908 * @param {Number} x The new x position
15909 * @param {Number} y The new y position
15915 Roo.extend(Roo.BoxComponent, Roo.Component, {
15916 // private, set in afterRender to signify that the component has been rendered
15918 // private, used to defer height settings to subclasses
15919 deferHeight: false,
15920 /** @cfg {Number} width
15921 * width (optional) size of component
15923 /** @cfg {Number} height
15924 * height (optional) size of component
15928 * Sets the width and height of the component. This method fires the resize event. This method can accept
15929 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15930 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15931 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15932 * @return {Roo.BoxComponent} this
15934 setSize : function(w, h){
15935 // support for standard size objects
15936 if(typeof w == 'object'){
15941 if(!this.boxReady){
15947 // prevent recalcs when not needed
15948 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15951 this.lastSize = {width: w, height: h};
15953 var adj = this.adjustSize(w, h);
15954 var aw = adj.width, ah = adj.height;
15955 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15956 var rz = this.getResizeEl();
15957 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15958 rz.setSize(aw, ah);
15959 }else if(!this.deferHeight && ah !== undefined){
15961 }else if(aw !== undefined){
15964 this.onResize(aw, ah, w, h);
15965 this.fireEvent('resize', this, aw, ah, w, h);
15971 * Gets the current size of the component's underlying element.
15972 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15974 getSize : function(){
15975 return this.el.getSize();
15979 * Gets the current XY position of the component's underlying element.
15980 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15981 * @return {Array} The XY position of the element (e.g., [100, 200])
15983 getPosition : function(local){
15984 if(local === true){
15985 return [this.el.getLeft(true), this.el.getTop(true)];
15987 return this.xy || this.el.getXY();
15991 * Gets the current box measurements of the component's underlying element.
15992 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15993 * @returns {Object} box An object in the format {x, y, width, height}
15995 getBox : function(local){
15996 var s = this.el.getSize();
15998 s.x = this.el.getLeft(true);
15999 s.y = this.el.getTop(true);
16001 var xy = this.xy || this.el.getXY();
16009 * Sets the current box measurements of the component's underlying element.
16010 * @param {Object} box An object in the format {x, y, width, height}
16011 * @returns {Roo.BoxComponent} this
16013 updateBox : function(box){
16014 this.setSize(box.width, box.height);
16015 this.setPagePosition(box.x, box.y);
16020 getResizeEl : function(){
16021 return this.resizeEl || this.el;
16025 getPositionEl : function(){
16026 return this.positionEl || this.el;
16030 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16031 * This method fires the move event.
16032 * @param {Number} left The new left
16033 * @param {Number} top The new top
16034 * @returns {Roo.BoxComponent} this
16036 setPosition : function(x, y){
16039 if(!this.boxReady){
16042 var adj = this.adjustPosition(x, y);
16043 var ax = adj.x, ay = adj.y;
16045 var el = this.getPositionEl();
16046 if(ax !== undefined || ay !== undefined){
16047 if(ax !== undefined && ay !== undefined){
16048 el.setLeftTop(ax, ay);
16049 }else if(ax !== undefined){
16051 }else if(ay !== undefined){
16054 this.onPosition(ax, ay);
16055 this.fireEvent('move', this, ax, ay);
16061 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16062 * This method fires the move event.
16063 * @param {Number} x The new x position
16064 * @param {Number} y The new y position
16065 * @returns {Roo.BoxComponent} this
16067 setPagePosition : function(x, y){
16070 if(!this.boxReady){
16073 if(x === undefined || y === undefined){ // cannot translate undefined points
16076 var p = this.el.translatePoints(x, y);
16077 this.setPosition(p.left, p.top);
16082 onRender : function(ct, position){
16083 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16085 this.resizeEl = Roo.get(this.resizeEl);
16087 if(this.positionEl){
16088 this.positionEl = Roo.get(this.positionEl);
16093 afterRender : function(){
16094 Roo.BoxComponent.superclass.afterRender.call(this);
16095 this.boxReady = true;
16096 this.setSize(this.width, this.height);
16097 if(this.x || this.y){
16098 this.setPosition(this.x, this.y);
16100 if(this.pageX || this.pageY){
16101 this.setPagePosition(this.pageX, this.pageY);
16106 * Force the component's size to recalculate based on the underlying element's current height and width.
16107 * @returns {Roo.BoxComponent} this
16109 syncSize : function(){
16110 delete this.lastSize;
16111 this.setSize(this.el.getWidth(), this.el.getHeight());
16116 * Called after the component is resized, this method is empty by default but can be implemented by any
16117 * subclass that needs to perform custom logic after a resize occurs.
16118 * @param {Number} adjWidth The box-adjusted width that was set
16119 * @param {Number} adjHeight The box-adjusted height that was set
16120 * @param {Number} rawWidth The width that was originally specified
16121 * @param {Number} rawHeight The height that was originally specified
16123 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16128 * Called after the component is moved, this method is empty by default but can be implemented by any
16129 * subclass that needs to perform custom logic after a move occurs.
16130 * @param {Number} x The new x position
16131 * @param {Number} y The new y position
16133 onPosition : function(x, y){
16138 adjustSize : function(w, h){
16139 if(this.autoWidth){
16142 if(this.autoHeight){
16145 return {width : w, height: h};
16149 adjustPosition : function(x, y){
16150 return {x : x, y: y};
16154 * Ext JS Library 1.1.1
16155 * Copyright(c) 2006-2007, Ext JS, LLC.
16157 * Originally Released Under LGPL - original licence link has changed is not relivant.
16160 * <script type="text/javascript">
16165 * @extends Roo.Element
16166 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16167 * automatic maintaining of shadow/shim positions.
16168 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16169 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16170 * you can pass a string with a CSS class name. False turns off the shadow.
16171 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16172 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16173 * @cfg {String} cls CSS class to add to the element
16174 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16175 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16177 * @param {Object} config An object with config options.
16178 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16181 Roo.Layer = function(config, existingEl){
16182 config = config || {};
16183 var dh = Roo.DomHelper;
16184 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16186 this.dom = Roo.getDom(existingEl);
16189 var o = config.dh || {tag: "div", cls: "x-layer"};
16190 this.dom = dh.append(pel, o);
16193 this.addClass(config.cls);
16195 this.constrain = config.constrain !== false;
16196 this.visibilityMode = Roo.Element.VISIBILITY;
16198 this.id = this.dom.id = config.id;
16200 this.id = Roo.id(this.dom);
16202 this.zindex = config.zindex || this.getZIndex();
16203 this.position("absolute", this.zindex);
16205 this.shadowOffset = config.shadowOffset || 4;
16206 this.shadow = new Roo.Shadow({
16207 offset : this.shadowOffset,
16208 mode : config.shadow
16211 this.shadowOffset = 0;
16213 this.useShim = config.shim !== false && Roo.useShims;
16214 this.useDisplay = config.useDisplay;
16218 var supr = Roo.Element.prototype;
16220 // shims are shared among layer to keep from having 100 iframes
16223 Roo.extend(Roo.Layer, Roo.Element, {
16225 getZIndex : function(){
16226 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16229 getShim : function(){
16236 var shim = shims.shift();
16238 shim = this.createShim();
16239 shim.enableDisplayMode('block');
16240 shim.dom.style.display = 'none';
16241 shim.dom.style.visibility = 'visible';
16243 var pn = this.dom.parentNode;
16244 if(shim.dom.parentNode != pn){
16245 pn.insertBefore(shim.dom, this.dom);
16247 shim.setStyle('z-index', this.getZIndex()-2);
16252 hideShim : function(){
16254 this.shim.setDisplayed(false);
16255 shims.push(this.shim);
16260 disableShadow : function(){
16262 this.shadowDisabled = true;
16263 this.shadow.hide();
16264 this.lastShadowOffset = this.shadowOffset;
16265 this.shadowOffset = 0;
16269 enableShadow : function(show){
16271 this.shadowDisabled = false;
16272 this.shadowOffset = this.lastShadowOffset;
16273 delete this.lastShadowOffset;
16281 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16282 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16283 sync : function(doShow){
16284 var sw = this.shadow;
16285 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16286 var sh = this.getShim();
16288 var w = this.getWidth(),
16289 h = this.getHeight();
16291 var l = this.getLeft(true),
16292 t = this.getTop(true);
16294 if(sw && !this.shadowDisabled){
16295 if(doShow && !sw.isVisible()){
16298 sw.realign(l, t, w, h);
16304 // fit the shim behind the shadow, so it is shimmed too
16305 var a = sw.adjusts, s = sh.dom.style;
16306 s.left = (Math.min(l, l+a.l))+"px";
16307 s.top = (Math.min(t, t+a.t))+"px";
16308 s.width = (w+a.w)+"px";
16309 s.height = (h+a.h)+"px";
16316 sh.setLeftTop(l, t);
16323 destroy : function(){
16326 this.shadow.hide();
16328 this.removeAllListeners();
16329 var pn = this.dom.parentNode;
16331 pn.removeChild(this.dom);
16333 Roo.Element.uncache(this.id);
16336 remove : function(){
16341 beginUpdate : function(){
16342 this.updating = true;
16346 endUpdate : function(){
16347 this.updating = false;
16352 hideUnders : function(negOffset){
16354 this.shadow.hide();
16360 constrainXY : function(){
16361 if(this.constrain){
16362 var vw = Roo.lib.Dom.getViewWidth(),
16363 vh = Roo.lib.Dom.getViewHeight();
16364 var s = Roo.get(document).getScroll();
16366 var xy = this.getXY();
16367 var x = xy[0], y = xy[1];
16368 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16369 // only move it if it needs it
16371 // first validate right/bottom
16372 if((x + w) > vw+s.left){
16373 x = vw - w - this.shadowOffset;
16376 if((y + h) > vh+s.top){
16377 y = vh - h - this.shadowOffset;
16380 // then make sure top/left isn't negative
16391 var ay = this.avoidY;
16392 if(y <= ay && (y+h) >= ay){
16398 supr.setXY.call(this, xy);
16404 isVisible : function(){
16405 return this.visible;
16409 showAction : function(){
16410 this.visible = true; // track visibility to prevent getStyle calls
16411 if(this.useDisplay === true){
16412 this.setDisplayed("");
16413 }else if(this.lastXY){
16414 supr.setXY.call(this, this.lastXY);
16415 }else if(this.lastLT){
16416 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16421 hideAction : function(){
16422 this.visible = false;
16423 if(this.useDisplay === true){
16424 this.setDisplayed(false);
16426 this.setLeftTop(-10000,-10000);
16430 // overridden Element method
16431 setVisible : function(v, a, d, c, e){
16436 var cb = function(){
16441 }.createDelegate(this);
16442 supr.setVisible.call(this, true, true, d, cb, e);
16445 this.hideUnders(true);
16454 }.createDelegate(this);
16456 supr.setVisible.call(this, v, a, d, cb, e);
16465 storeXY : function(xy){
16466 delete this.lastLT;
16470 storeLeftTop : function(left, top){
16471 delete this.lastXY;
16472 this.lastLT = [left, top];
16476 beforeFx : function(){
16477 this.beforeAction();
16478 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16482 afterFx : function(){
16483 Roo.Layer.superclass.afterFx.apply(this, arguments);
16484 this.sync(this.isVisible());
16488 beforeAction : function(){
16489 if(!this.updating && this.shadow){
16490 this.shadow.hide();
16494 // overridden Element method
16495 setLeft : function(left){
16496 this.storeLeftTop(left, this.getTop(true));
16497 supr.setLeft.apply(this, arguments);
16501 setTop : function(top){
16502 this.storeLeftTop(this.getLeft(true), top);
16503 supr.setTop.apply(this, arguments);
16507 setLeftTop : function(left, top){
16508 this.storeLeftTop(left, top);
16509 supr.setLeftTop.apply(this, arguments);
16513 setXY : function(xy, a, d, c, e){
16515 this.beforeAction();
16517 var cb = this.createCB(c);
16518 supr.setXY.call(this, xy, a, d, cb, e);
16525 createCB : function(c){
16536 // overridden Element method
16537 setX : function(x, a, d, c, e){
16538 this.setXY([x, this.getY()], a, d, c, e);
16541 // overridden Element method
16542 setY : function(y, a, d, c, e){
16543 this.setXY([this.getX(), y], a, d, c, e);
16546 // overridden Element method
16547 setSize : function(w, h, a, d, c, e){
16548 this.beforeAction();
16549 var cb = this.createCB(c);
16550 supr.setSize.call(this, w, h, a, d, cb, e);
16556 // overridden Element method
16557 setWidth : function(w, a, d, c, e){
16558 this.beforeAction();
16559 var cb = this.createCB(c);
16560 supr.setWidth.call(this, w, a, d, cb, e);
16566 // overridden Element method
16567 setHeight : function(h, a, d, c, e){
16568 this.beforeAction();
16569 var cb = this.createCB(c);
16570 supr.setHeight.call(this, h, a, d, cb, e);
16576 // overridden Element method
16577 setBounds : function(x, y, w, h, a, d, c, e){
16578 this.beforeAction();
16579 var cb = this.createCB(c);
16581 this.storeXY([x, y]);
16582 supr.setXY.call(this, [x, y]);
16583 supr.setSize.call(this, w, h, a, d, cb, e);
16586 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16592 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16593 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16594 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16595 * @param {Number} zindex The new z-index to set
16596 * @return {this} The Layer
16598 setZIndex : function(zindex){
16599 this.zindex = zindex;
16600 this.setStyle("z-index", zindex + 2);
16602 this.shadow.setZIndex(zindex + 1);
16605 this.shim.setStyle("z-index", zindex);
16610 * Original code for Roojs - LGPL
16611 * <script type="text/javascript">
16615 * @class Roo.XComponent
16616 * A delayed Element creator...
16617 * Or a way to group chunks of interface together.
16618 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16619 * used in conjunction with XComponent.build() it will create an instance of each element,
16620 * then call addxtype() to build the User interface.
16622 * Mypart.xyx = new Roo.XComponent({
16624 parent : 'Mypart.xyz', // empty == document.element.!!
16628 disabled : function() {}
16630 tree : function() { // return an tree of xtype declared components
16634 xtype : 'NestedLayoutPanel',
16641 * It can be used to build a big heiracy, with parent etc.
16642 * or you can just use this to render a single compoent to a dom element
16643 * MYPART.render(Roo.Element | String(id) | dom_element )
16650 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16651 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16653 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16655 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16656 * - if mulitple topModules exist, the last one is defined as the top module.
16660 * When the top level or multiple modules are to embedded into a existing HTML page,
16661 * the parent element can container '#id' of the element where the module will be drawn.
16665 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16666 * it relies more on a include mechanism, where sub modules are included into an outer page.
16667 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16669 * Bootstrap Roo Included elements
16671 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16672 * hence confusing the component builder as it thinks there are multiple top level elements.
16674 * String Over-ride & Translations
16676 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16677 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16678 * are needed. @see Roo.XComponent.overlayString
16682 * @extends Roo.util.Observable
16684 * @param cfg {Object} configuration of component
16687 Roo.XComponent = function(cfg) {
16688 Roo.apply(this, cfg);
16692 * Fires when this the componnt is built
16693 * @param {Roo.XComponent} c the component
16698 this.region = this.region || 'center'; // default..
16699 Roo.XComponent.register(this);
16700 this.modules = false;
16701 this.el = false; // where the layout goes..
16705 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16708 * The created element (with Roo.factory())
16709 * @type {Roo.Layout}
16715 * for BC - use el in new code
16716 * @type {Roo.Layout}
16722 * for BC - use el in new code
16723 * @type {Roo.Layout}
16728 * @cfg {Function|boolean} disabled
16729 * If this module is disabled by some rule, return true from the funtion
16734 * @cfg {String} parent
16735 * Name of parent element which it get xtype added to..
16740 * @cfg {String} order
16741 * Used to set the order in which elements are created (usefull for multiple tabs)
16746 * @cfg {String} name
16747 * String to display while loading.
16751 * @cfg {String} region
16752 * Region to render component to (defaults to center)
16757 * @cfg {Array} items
16758 * A single item array - the first element is the root of the tree..
16759 * It's done this way to stay compatible with the Xtype system...
16765 * The method that retuns the tree of parts that make up this compoennt
16772 * render element to dom or tree
16773 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16776 render : function(el)
16780 var hp = this.parent ? 1 : 0;
16781 Roo.debug && Roo.log(this);
16783 var tree = this._tree ? this._tree() : this.tree();
16786 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16787 // if parent is a '#.....' string, then let's use that..
16788 var ename = this.parent.substr(1);
16789 this.parent = false;
16790 Roo.debug && Roo.log(ename);
16792 case 'bootstrap-body':
16793 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16794 // this is the BorderLayout standard?
16795 this.parent = { el : true };
16798 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16799 // need to insert stuff...
16801 el : new Roo.bootstrap.layout.Border({
16802 el : document.body,
16808 tabPosition: 'top',
16809 //resizeTabs: true,
16810 alwaysShowTabs: true,
16820 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16821 this.parent = { el : new Roo.bootstrap.Body() };
16822 Roo.debug && Roo.log("setting el to doc body");
16825 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16829 this.parent = { el : true};
16832 el = Roo.get(ename);
16833 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16834 this.parent = { el : true};
16841 if (!el && !this.parent) {
16842 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16847 Roo.debug && Roo.log("EL:");
16848 Roo.debug && Roo.log(el);
16849 Roo.debug && Roo.log("this.parent.el:");
16850 Roo.debug && Roo.log(this.parent.el);
16853 // altertive root elements ??? - we need a better way to indicate these.
16854 var is_alt = Roo.XComponent.is_alt ||
16855 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16856 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16857 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16861 if (!this.parent && is_alt) {
16862 //el = Roo.get(document.body);
16863 this.parent = { el : true };
16868 if (!this.parent) {
16870 Roo.debug && Roo.log("no parent - creating one");
16872 el = el ? Roo.get(el) : false;
16874 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16877 el : new Roo.bootstrap.layout.Border({
16878 el: el || document.body,
16884 tabPosition: 'top',
16885 //resizeTabs: true,
16886 alwaysShowTabs: false,
16889 overflow: 'visible'
16895 // it's a top level one..
16897 el : new Roo.BorderLayout(el || document.body, {
16902 tabPosition: 'top',
16903 //resizeTabs: true,
16904 alwaysShowTabs: el && hp? false : true,
16905 hideTabs: el || !hp ? true : false,
16913 if (!this.parent.el) {
16914 // probably an old style ctor, which has been disabled.
16918 // The 'tree' method is '_tree now'
16920 tree.region = tree.region || this.region;
16921 var is_body = false;
16922 if (this.parent.el === true) {
16923 // bootstrap... - body..
16927 this.parent.el = Roo.factory(tree);
16931 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16932 this.fireEvent('built', this);
16934 this.panel = this.el;
16935 this.layout = this.panel.layout;
16936 this.parentLayout = this.parent.layout || false;
16942 Roo.apply(Roo.XComponent, {
16944 * @property hideProgress
16945 * true to disable the building progress bar.. usefull on single page renders.
16948 hideProgress : false,
16950 * @property buildCompleted
16951 * True when the builder has completed building the interface.
16954 buildCompleted : false,
16957 * @property topModule
16958 * the upper most module - uses document.element as it's constructor.
16965 * @property modules
16966 * array of modules to be created by registration system.
16967 * @type {Array} of Roo.XComponent
16972 * @property elmodules
16973 * array of modules to be created by which use #ID
16974 * @type {Array} of Roo.XComponent
16981 * Is an alternative Root - normally used by bootstrap or other systems,
16982 * where the top element in the tree can wrap 'body'
16983 * @type {boolean} (default false)
16988 * @property build_from_html
16989 * Build elements from html - used by bootstrap HTML stuff
16990 * - this is cleared after build is completed
16991 * @type {boolean} (default false)
16994 build_from_html : false,
16996 * Register components to be built later.
16998 * This solves the following issues
16999 * - Building is not done on page load, but after an authentication process has occured.
17000 * - Interface elements are registered on page load
17001 * - Parent Interface elements may not be loaded before child, so this handles that..
17008 module : 'Pman.Tab.projectMgr',
17010 parent : 'Pman.layout',
17011 disabled : false, // or use a function..
17014 * * @param {Object} details about module
17016 register : function(obj) {
17018 Roo.XComponent.event.fireEvent('register', obj);
17019 switch(typeof(obj.disabled) ) {
17025 if ( obj.disabled() ) {
17031 if (obj.disabled || obj.region == '#disabled') {
17037 this.modules.push(obj);
17041 * convert a string to an object..
17042 * eg. 'AAA.BBB' -> finds AAA.BBB
17046 toObject : function(str)
17048 if (!str || typeof(str) == 'object') {
17051 if (str.substring(0,1) == '#') {
17055 var ar = str.split('.');
17060 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17062 throw "Module not found : " + str;
17066 throw "Module not found : " + str;
17068 Roo.each(ar, function(e) {
17069 if (typeof(o[e]) == 'undefined') {
17070 throw "Module not found : " + str;
17081 * move modules into their correct place in the tree..
17084 preBuild : function ()
17087 Roo.each(this.modules , function (obj)
17089 Roo.XComponent.event.fireEvent('beforebuild', obj);
17091 var opar = obj.parent;
17093 obj.parent = this.toObject(opar);
17095 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17100 Roo.debug && Roo.log("GOT top level module");
17101 Roo.debug && Roo.log(obj);
17102 obj.modules = new Roo.util.MixedCollection(false,
17103 function(o) { return o.order + '' }
17105 this.topModule = obj;
17108 // parent is a string (usually a dom element name..)
17109 if (typeof(obj.parent) == 'string') {
17110 this.elmodules.push(obj);
17113 if (obj.parent.constructor != Roo.XComponent) {
17114 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17116 if (!obj.parent.modules) {
17117 obj.parent.modules = new Roo.util.MixedCollection(false,
17118 function(o) { return o.order + '' }
17121 if (obj.parent.disabled) {
17122 obj.disabled = true;
17124 obj.parent.modules.add(obj);
17129 * make a list of modules to build.
17130 * @return {Array} list of modules.
17133 buildOrder : function()
17136 var cmp = function(a,b) {
17137 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17139 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17140 throw "No top level modules to build";
17143 // make a flat list in order of modules to build.
17144 var mods = this.topModule ? [ this.topModule ] : [];
17147 // elmodules (is a list of DOM based modules )
17148 Roo.each(this.elmodules, function(e) {
17150 if (!this.topModule &&
17151 typeof(e.parent) == 'string' &&
17152 e.parent.substring(0,1) == '#' &&
17153 Roo.get(e.parent.substr(1))
17156 _this.topModule = e;
17162 // add modules to their parents..
17163 var addMod = function(m) {
17164 Roo.debug && Roo.log("build Order: add: " + m.name);
17167 if (m.modules && !m.disabled) {
17168 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17169 m.modules.keySort('ASC', cmp );
17170 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17172 m.modules.each(addMod);
17174 Roo.debug && Roo.log("build Order: no child modules");
17176 // not sure if this is used any more..
17178 m.finalize.name = m.name + " (clean up) ";
17179 mods.push(m.finalize);
17183 if (this.topModule && this.topModule.modules) {
17184 this.topModule.modules.keySort('ASC', cmp );
17185 this.topModule.modules.each(addMod);
17191 * Build the registered modules.
17192 * @param {Object} parent element.
17193 * @param {Function} optional method to call after module has been added.
17197 build : function(opts)
17200 if (typeof(opts) != 'undefined') {
17201 Roo.apply(this,opts);
17205 var mods = this.buildOrder();
17207 //this.allmods = mods;
17208 //Roo.debug && Roo.log(mods);
17210 if (!mods.length) { // should not happen
17211 throw "NO modules!!!";
17215 var msg = "Building Interface...";
17216 // flash it up as modal - so we store the mask!?
17217 if (!this.hideProgress && Roo.MessageBox) {
17218 Roo.MessageBox.show({ title: 'loading' });
17219 Roo.MessageBox.show({
17220 title: "Please wait...",
17230 var total = mods.length;
17233 var progressRun = function() {
17234 if (!mods.length) {
17235 Roo.debug && Roo.log('hide?');
17236 if (!this.hideProgress && Roo.MessageBox) {
17237 Roo.MessageBox.hide();
17239 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17241 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17247 var m = mods.shift();
17250 Roo.debug && Roo.log(m);
17251 // not sure if this is supported any more.. - modules that are are just function
17252 if (typeof(m) == 'function') {
17254 return progressRun.defer(10, _this);
17258 msg = "Building Interface " + (total - mods.length) +
17260 (m.name ? (' - ' + m.name) : '');
17261 Roo.debug && Roo.log(msg);
17262 if (!_this.hideProgress && Roo.MessageBox) {
17263 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17267 // is the module disabled?
17268 var disabled = (typeof(m.disabled) == 'function') ?
17269 m.disabled.call(m.module.disabled) : m.disabled;
17273 return progressRun(); // we do not update the display!
17281 // it's 10 on top level, and 1 on others??? why...
17282 return progressRun.defer(10, _this);
17285 progressRun.defer(1, _this);
17291 * Overlay a set of modified strings onto a component
17292 * This is dependant on our builder exporting the strings and 'named strings' elements.
17294 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17295 * @param {Object} associative array of 'named' string and it's new value.
17298 overlayStrings : function( component, strings )
17300 if (typeof(component['_named_strings']) == 'undefined') {
17301 throw "ERROR: component does not have _named_strings";
17303 for ( var k in strings ) {
17304 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17305 if (md !== false) {
17306 component['_strings'][md] = strings[k];
17308 Roo.log('could not find named string: ' + k + ' in');
17309 Roo.log(component);
17324 * wrapper for event.on - aliased later..
17325 * Typically use to register a event handler for register:
17327 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17336 Roo.XComponent.event = new Roo.util.Observable({
17340 * Fires when an Component is registered,
17341 * set the disable property on the Component to stop registration.
17342 * @param {Roo.XComponent} c the component being registerd.
17347 * @event beforebuild
17348 * Fires before each Component is built
17349 * can be used to apply permissions.
17350 * @param {Roo.XComponent} c the component being registerd.
17353 'beforebuild' : true,
17355 * @event buildcomplete
17356 * Fires on the top level element when all elements have been built
17357 * @param {Roo.XComponent} the top level component.
17359 'buildcomplete' : true
17364 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17367 * marked - a markdown parser
17368 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17369 * https://github.com/chjj/marked
17375 * Roo.Markdown - is a very crude wrapper around marked..
17379 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17381 * Note: move the sample code to the bottom of this
17382 * file before uncommenting it.
17387 Roo.Markdown.toHtml = function(text) {
17389 var c = new Roo.Markdown.marked.setOptions({
17390 renderer: new Roo.Markdown.marked.Renderer(),
17401 text = text.replace(/\\\n/g,' ');
17402 return Roo.Markdown.marked(text);
17407 // Wraps all "globals" so that the only thing
17408 // exposed is makeHtml().
17414 * eval:var:unescape
17422 var escape = function (html, encode) {
17424 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17425 .replace(/</g, '<')
17426 .replace(/>/g, '>')
17427 .replace(/"/g, '"')
17428 .replace(/'/g, ''');
17431 var unescape = function (html) {
17432 // explicitly match decimal, hex, and named HTML entities
17433 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17434 n = n.toLowerCase();
17435 if (n === 'colon') { return ':'; }
17436 if (n.charAt(0) === '#') {
17437 return n.charAt(1) === 'x'
17438 ? String.fromCharCode(parseInt(n.substring(2), 16))
17439 : String.fromCharCode(+n.substring(1));
17445 var replace = function (regex, opt) {
17446 regex = regex.source;
17448 return function self(name, val) {
17449 if (!name) { return new RegExp(regex, opt); }
17450 val = val.source || val;
17451 val = val.replace(/(^|[^\[])\^/g, '$1');
17452 regex = regex.replace(name, val);
17461 var noop = function () {}
17467 var merge = function (obj) {
17472 for (; i < arguments.length; i++) {
17473 target = arguments[i];
17474 for (key in target) {
17475 if (Object.prototype.hasOwnProperty.call(target, key)) {
17476 obj[key] = target[key];
17486 * Block-Level Grammar
17494 code: /^( {4}[^\n]+\n*)+/,
17496 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17497 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17499 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17500 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17501 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17502 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17503 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17505 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17509 block.bullet = /(?:[*+-]|\d+\.)/;
17510 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17511 block.item = replace(block.item, 'gm')
17512 (/bull/g, block.bullet)
17515 block.list = replace(block.list)
17516 (/bull/g, block.bullet)
17517 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17518 ('def', '\\n+(?=' + block.def.source + ')')
17521 block.blockquote = replace(block.blockquote)
17525 block._tag = '(?!(?:'
17526 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17527 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17528 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17530 block.html = replace(block.html)
17531 ('comment', /<!--[\s\S]*?-->/)
17532 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17533 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17534 (/tag/g, block._tag)
17537 block.paragraph = replace(block.paragraph)
17539 ('heading', block.heading)
17540 ('lheading', block.lheading)
17541 ('blockquote', block.blockquote)
17542 ('tag', '<' + block._tag)
17547 * Normal Block Grammar
17550 block.normal = merge({}, block);
17553 * GFM Block Grammar
17556 block.gfm = merge({}, block.normal, {
17557 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17559 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17562 block.gfm.paragraph = replace(block.paragraph)
17564 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17565 + block.list.source.replace('\\1', '\\3') + '|')
17569 * GFM + Tables Block Grammar
17572 block.tables = merge({}, block.gfm, {
17573 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17574 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17581 var Lexer = function (options) {
17583 this.tokens.links = {};
17584 this.options = options || marked.defaults;
17585 this.rules = block.normal;
17587 if (this.options.gfm) {
17588 if (this.options.tables) {
17589 this.rules = block.tables;
17591 this.rules = block.gfm;
17597 * Expose Block Rules
17600 Lexer.rules = block;
17603 * Static Lex Method
17606 Lexer.lex = function(src, options) {
17607 var lexer = new Lexer(options);
17608 return lexer.lex(src);
17615 Lexer.prototype.lex = function(src) {
17617 .replace(/\r\n|\r/g, '\n')
17618 .replace(/\t/g, ' ')
17619 .replace(/\u00a0/g, ' ')
17620 .replace(/\u2424/g, '\n');
17622 return this.token(src, true);
17629 Lexer.prototype.token = function(src, top, bq) {
17630 var src = src.replace(/^ +$/gm, '')
17643 if (cap = this.rules.newline.exec(src)) {
17644 src = src.substring(cap[0].length);
17645 if (cap[0].length > 1) {
17653 if (cap = this.rules.code.exec(src)) {
17654 src = src.substring(cap[0].length);
17655 cap = cap[0].replace(/^ {4}/gm, '');
17658 text: !this.options.pedantic
17659 ? cap.replace(/\n+$/, '')
17666 if (cap = this.rules.fences.exec(src)) {
17667 src = src.substring(cap[0].length);
17677 if (cap = this.rules.heading.exec(src)) {
17678 src = src.substring(cap[0].length);
17681 depth: cap[1].length,
17687 // table no leading pipe (gfm)
17688 if (top && (cap = this.rules.nptable.exec(src))) {
17689 src = src.substring(cap[0].length);
17693 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17694 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17695 cells: cap[3].replace(/\n$/, '').split('\n')
17698 for (i = 0; i < item.align.length; i++) {
17699 if (/^ *-+: *$/.test(item.align[i])) {
17700 item.align[i] = 'right';
17701 } else if (/^ *:-+: *$/.test(item.align[i])) {
17702 item.align[i] = 'center';
17703 } else if (/^ *:-+ *$/.test(item.align[i])) {
17704 item.align[i] = 'left';
17706 item.align[i] = null;
17710 for (i = 0; i < item.cells.length; i++) {
17711 item.cells[i] = item.cells[i].split(/ *\| */);
17714 this.tokens.push(item);
17720 if (cap = this.rules.lheading.exec(src)) {
17721 src = src.substring(cap[0].length);
17724 depth: cap[2] === '=' ? 1 : 2,
17731 if (cap = this.rules.hr.exec(src)) {
17732 src = src.substring(cap[0].length);
17740 if (cap = this.rules.blockquote.exec(src)) {
17741 src = src.substring(cap[0].length);
17744 type: 'blockquote_start'
17747 cap = cap[0].replace(/^ *> ?/gm, '');
17749 // Pass `top` to keep the current
17750 // "toplevel" state. This is exactly
17751 // how markdown.pl works.
17752 this.token(cap, top, true);
17755 type: 'blockquote_end'
17762 if (cap = this.rules.list.exec(src)) {
17763 src = src.substring(cap[0].length);
17767 type: 'list_start',
17768 ordered: bull.length > 1
17771 // Get each top-level item.
17772 cap = cap[0].match(this.rules.item);
17778 for (; i < l; i++) {
17781 // Remove the list item's bullet
17782 // so it is seen as the next token.
17783 space = item.length;
17784 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17786 // Outdent whatever the
17787 // list item contains. Hacky.
17788 if (~item.indexOf('\n ')) {
17789 space -= item.length;
17790 item = !this.options.pedantic
17791 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17792 : item.replace(/^ {1,4}/gm, '');
17795 // Determine whether the next list item belongs here.
17796 // Backpedal if it does not belong in this list.
17797 if (this.options.smartLists && i !== l - 1) {
17798 b = block.bullet.exec(cap[i + 1])[0];
17799 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17800 src = cap.slice(i + 1).join('\n') + src;
17805 // Determine whether item is loose or not.
17806 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17807 // for discount behavior.
17808 loose = next || /\n\n(?!\s*$)/.test(item);
17810 next = item.charAt(item.length - 1) === '\n';
17811 if (!loose) { loose = next; }
17816 ? 'loose_item_start'
17817 : 'list_item_start'
17821 this.token(item, false, bq);
17824 type: 'list_item_end'
17836 if (cap = this.rules.html.exec(src)) {
17837 src = src.substring(cap[0].length);
17839 type: this.options.sanitize
17842 pre: !this.options.sanitizer
17843 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17850 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17851 src = src.substring(cap[0].length);
17852 this.tokens.links[cap[1].toLowerCase()] = {
17860 if (top && (cap = this.rules.table.exec(src))) {
17861 src = src.substring(cap[0].length);
17865 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17866 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17867 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17870 for (i = 0; i < item.align.length; i++) {
17871 if (/^ *-+: *$/.test(item.align[i])) {
17872 item.align[i] = 'right';
17873 } else if (/^ *:-+: *$/.test(item.align[i])) {
17874 item.align[i] = 'center';
17875 } else if (/^ *:-+ *$/.test(item.align[i])) {
17876 item.align[i] = 'left';
17878 item.align[i] = null;
17882 for (i = 0; i < item.cells.length; i++) {
17883 item.cells[i] = item.cells[i]
17884 .replace(/^ *\| *| *\| *$/g, '')
17888 this.tokens.push(item);
17893 // top-level paragraph
17894 if (top && (cap = this.rules.paragraph.exec(src))) {
17895 src = src.substring(cap[0].length);
17898 text: cap[1].charAt(cap[1].length - 1) === '\n'
17899 ? cap[1].slice(0, -1)
17906 if (cap = this.rules.text.exec(src)) {
17907 // Top-level should never reach here.
17908 src = src.substring(cap[0].length);
17918 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17922 return this.tokens;
17926 * Inline-Level Grammar
17930 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17931 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17933 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17934 link: /^!?\[(inside)\]\(href\)/,
17935 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17936 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17937 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17938 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17939 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17940 br: /^ {2,}\n(?!\s*$)/,
17942 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17945 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17946 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17948 inline.link = replace(inline.link)
17949 ('inside', inline._inside)
17950 ('href', inline._href)
17953 inline.reflink = replace(inline.reflink)
17954 ('inside', inline._inside)
17958 * Normal Inline Grammar
17961 inline.normal = merge({}, inline);
17964 * Pedantic Inline Grammar
17967 inline.pedantic = merge({}, inline.normal, {
17968 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17969 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17973 * GFM Inline Grammar
17976 inline.gfm = merge({}, inline.normal, {
17977 escape: replace(inline.escape)('])', '~|])')(),
17978 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17979 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17980 text: replace(inline.text)
17982 ('|', '|https?://|')
17987 * GFM + Line Breaks Inline Grammar
17990 inline.breaks = merge({}, inline.gfm, {
17991 br: replace(inline.br)('{2,}', '*')(),
17992 text: replace(inline.gfm.text)('{2,}', '*')()
17996 * Inline Lexer & Compiler
17999 var InlineLexer = function (links, options) {
18000 this.options = options || marked.defaults;
18001 this.links = links;
18002 this.rules = inline.normal;
18003 this.renderer = this.options.renderer || new Renderer;
18004 this.renderer.options = this.options;
18008 Error('Tokens array requires a `links` property.');
18011 if (this.options.gfm) {
18012 if (this.options.breaks) {
18013 this.rules = inline.breaks;
18015 this.rules = inline.gfm;
18017 } else if (this.options.pedantic) {
18018 this.rules = inline.pedantic;
18023 * Expose Inline Rules
18026 InlineLexer.rules = inline;
18029 * Static Lexing/Compiling Method
18032 InlineLexer.output = function(src, links, options) {
18033 var inline = new InlineLexer(links, options);
18034 return inline.output(src);
18041 InlineLexer.prototype.output = function(src) {
18050 if (cap = this.rules.escape.exec(src)) {
18051 src = src.substring(cap[0].length);
18057 if (cap = this.rules.autolink.exec(src)) {
18058 src = src.substring(cap[0].length);
18059 if (cap[2] === '@') {
18060 text = cap[1].charAt(6) === ':'
18061 ? this.mangle(cap[1].substring(7))
18062 : this.mangle(cap[1]);
18063 href = this.mangle('mailto:') + text;
18065 text = escape(cap[1]);
18068 out += this.renderer.link(href, null, text);
18073 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18074 src = src.substring(cap[0].length);
18075 text = escape(cap[1]);
18077 out += this.renderer.link(href, null, text);
18082 if (cap = this.rules.tag.exec(src)) {
18083 if (!this.inLink && /^<a /i.test(cap[0])) {
18084 this.inLink = true;
18085 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18086 this.inLink = false;
18088 src = src.substring(cap[0].length);
18089 out += this.options.sanitize
18090 ? this.options.sanitizer
18091 ? this.options.sanitizer(cap[0])
18098 if (cap = this.rules.link.exec(src)) {
18099 src = src.substring(cap[0].length);
18100 this.inLink = true;
18101 out += this.outputLink(cap, {
18105 this.inLink = false;
18110 if ((cap = this.rules.reflink.exec(src))
18111 || (cap = this.rules.nolink.exec(src))) {
18112 src = src.substring(cap[0].length);
18113 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18114 link = this.links[link.toLowerCase()];
18115 if (!link || !link.href) {
18116 out += cap[0].charAt(0);
18117 src = cap[0].substring(1) + src;
18120 this.inLink = true;
18121 out += this.outputLink(cap, link);
18122 this.inLink = false;
18127 if (cap = this.rules.strong.exec(src)) {
18128 src = src.substring(cap[0].length);
18129 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18134 if (cap = this.rules.em.exec(src)) {
18135 src = src.substring(cap[0].length);
18136 out += this.renderer.em(this.output(cap[2] || cap[1]));
18141 if (cap = this.rules.code.exec(src)) {
18142 src = src.substring(cap[0].length);
18143 out += this.renderer.codespan(escape(cap[2], true));
18148 if (cap = this.rules.br.exec(src)) {
18149 src = src.substring(cap[0].length);
18150 out += this.renderer.br();
18155 if (cap = this.rules.del.exec(src)) {
18156 src = src.substring(cap[0].length);
18157 out += this.renderer.del(this.output(cap[1]));
18162 if (cap = this.rules.text.exec(src)) {
18163 src = src.substring(cap[0].length);
18164 out += this.renderer.text(escape(this.smartypants(cap[0])));
18170 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18181 InlineLexer.prototype.outputLink = function(cap, link) {
18182 var href = escape(link.href)
18183 , title = link.title ? escape(link.title) : null;
18185 return cap[0].charAt(0) !== '!'
18186 ? this.renderer.link(href, title, this.output(cap[1]))
18187 : this.renderer.image(href, title, escape(cap[1]));
18191 * Smartypants Transformations
18194 InlineLexer.prototype.smartypants = function(text) {
18195 if (!this.options.smartypants) { return text; }
18198 .replace(/---/g, '\u2014')
18200 .replace(/--/g, '\u2013')
18202 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18203 // closing singles & apostrophes
18204 .replace(/'/g, '\u2019')
18206 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18208 .replace(/"/g, '\u201d')
18210 .replace(/\.{3}/g, '\u2026');
18217 InlineLexer.prototype.mangle = function(text) {
18218 if (!this.options.mangle) { return text; }
18224 for (; i < l; i++) {
18225 ch = text.charCodeAt(i);
18226 if (Math.random() > 0.5) {
18227 ch = 'x' + ch.toString(16);
18229 out += '&#' + ch + ';';
18240 * eval:var:Renderer
18243 var Renderer = function (options) {
18244 this.options = options || {};
18247 Renderer.prototype.code = function(code, lang, escaped) {
18248 if (this.options.highlight) {
18249 var out = this.options.highlight(code, lang);
18250 if (out != null && out !== code) {
18255 // hack!!! - it's already escapeD?
18260 return '<pre><code>'
18261 + (escaped ? code : escape(code, true))
18262 + '\n</code></pre>';
18265 return '<pre><code class="'
18266 + this.options.langPrefix
18267 + escape(lang, true)
18269 + (escaped ? code : escape(code, true))
18270 + '\n</code></pre>\n';
18273 Renderer.prototype.blockquote = function(quote) {
18274 return '<blockquote>\n' + quote + '</blockquote>\n';
18277 Renderer.prototype.html = function(html) {
18281 Renderer.prototype.heading = function(text, level, raw) {
18285 + this.options.headerPrefix
18286 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18294 Renderer.prototype.hr = function() {
18295 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18298 Renderer.prototype.list = function(body, ordered) {
18299 var type = ordered ? 'ol' : 'ul';
18300 return '<' + type + '>\n' + body + '</' + type + '>\n';
18303 Renderer.prototype.listitem = function(text) {
18304 return '<li>' + text + '</li>\n';
18307 Renderer.prototype.paragraph = function(text) {
18308 return '<p>' + text + '</p>\n';
18311 Renderer.prototype.table = function(header, body) {
18312 return '<table class="table table-striped">\n'
18322 Renderer.prototype.tablerow = function(content) {
18323 return '<tr>\n' + content + '</tr>\n';
18326 Renderer.prototype.tablecell = function(content, flags) {
18327 var type = flags.header ? 'th' : 'td';
18328 var tag = flags.align
18329 ? '<' + type + ' style="text-align:' + flags.align + '">'
18330 : '<' + type + '>';
18331 return tag + content + '</' + type + '>\n';
18334 // span level renderer
18335 Renderer.prototype.strong = function(text) {
18336 return '<strong>' + text + '</strong>';
18339 Renderer.prototype.em = function(text) {
18340 return '<em>' + text + '</em>';
18343 Renderer.prototype.codespan = function(text) {
18344 return '<code>' + text + '</code>';
18347 Renderer.prototype.br = function() {
18348 return this.options.xhtml ? '<br/>' : '<br>';
18351 Renderer.prototype.del = function(text) {
18352 return '<del>' + text + '</del>';
18355 Renderer.prototype.link = function(href, title, text) {
18356 if (this.options.sanitize) {
18358 var prot = decodeURIComponent(unescape(href))
18359 .replace(/[^\w:]/g, '')
18364 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18368 var out = '<a href="' + href + '"';
18370 out += ' title="' + title + '"';
18372 out += '>' + text + '</a>';
18376 Renderer.prototype.image = function(href, title, text) {
18377 var out = '<img src="' + href + '" alt="' + text + '"';
18379 out += ' title="' + title + '"';
18381 out += this.options.xhtml ? '/>' : '>';
18385 Renderer.prototype.text = function(text) {
18390 * Parsing & Compiling
18396 var Parser= function (options) {
18399 this.options = options || marked.defaults;
18400 this.options.renderer = this.options.renderer || new Renderer;
18401 this.renderer = this.options.renderer;
18402 this.renderer.options = this.options;
18406 * Static Parse Method
18409 Parser.parse = function(src, options, renderer) {
18410 var parser = new Parser(options, renderer);
18411 return parser.parse(src);
18418 Parser.prototype.parse = function(src) {
18419 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18420 this.tokens = src.reverse();
18423 while (this.next()) {
18434 Parser.prototype.next = function() {
18435 return this.token = this.tokens.pop();
18439 * Preview Next Token
18442 Parser.prototype.peek = function() {
18443 return this.tokens[this.tokens.length - 1] || 0;
18447 * Parse Text Tokens
18450 Parser.prototype.parseText = function() {
18451 var body = this.token.text;
18453 while (this.peek().type === 'text') {
18454 body += '\n' + this.next().text;
18457 return this.inline.output(body);
18461 * Parse Current Token
18464 Parser.prototype.tok = function() {
18465 switch (this.token.type) {
18470 return this.renderer.hr();
18473 return this.renderer.heading(
18474 this.inline.output(this.token.text),
18479 return this.renderer.code(this.token.text,
18481 this.token.escaped);
18494 for (i = 0; i < this.token.header.length; i++) {
18495 flags = { header: true, align: this.token.align[i] };
18496 cell += this.renderer.tablecell(
18497 this.inline.output(this.token.header[i]),
18498 { header: true, align: this.token.align[i] }
18501 header += this.renderer.tablerow(cell);
18503 for (i = 0; i < this.token.cells.length; i++) {
18504 row = this.token.cells[i];
18507 for (j = 0; j < row.length; j++) {
18508 cell += this.renderer.tablecell(
18509 this.inline.output(row[j]),
18510 { header: false, align: this.token.align[j] }
18514 body += this.renderer.tablerow(cell);
18516 return this.renderer.table(header, body);
18518 case 'blockquote_start': {
18521 while (this.next().type !== 'blockquote_end') {
18522 body += this.tok();
18525 return this.renderer.blockquote(body);
18527 case 'list_start': {
18529 , ordered = this.token.ordered;
18531 while (this.next().type !== 'list_end') {
18532 body += this.tok();
18535 return this.renderer.list(body, ordered);
18537 case 'list_item_start': {
18540 while (this.next().type !== 'list_item_end') {
18541 body += this.token.type === 'text'
18546 return this.renderer.listitem(body);
18548 case 'loose_item_start': {
18551 while (this.next().type !== 'list_item_end') {
18552 body += this.tok();
18555 return this.renderer.listitem(body);
18558 var html = !this.token.pre && !this.options.pedantic
18559 ? this.inline.output(this.token.text)
18561 return this.renderer.html(html);
18563 case 'paragraph': {
18564 return this.renderer.paragraph(this.inline.output(this.token.text));
18567 return this.renderer.paragraph(this.parseText());
18579 var marked = function (src, opt, callback) {
18580 if (callback || typeof opt === 'function') {
18586 opt = merge({}, marked.defaults, opt || {});
18588 var highlight = opt.highlight
18594 tokens = Lexer.lex(src, opt)
18596 return callback(e);
18599 pending = tokens.length;
18603 var done = function(err) {
18605 opt.highlight = highlight;
18606 return callback(err);
18612 out = Parser.parse(tokens, opt);
18617 opt.highlight = highlight;
18621 : callback(null, out);
18624 if (!highlight || highlight.length < 3) {
18628 delete opt.highlight;
18630 if (!pending) { return done(); }
18632 for (; i < tokens.length; i++) {
18634 if (token.type !== 'code') {
18635 return --pending || done();
18637 return highlight(token.text, token.lang, function(err, code) {
18638 if (err) { return done(err); }
18639 if (code == null || code === token.text) {
18640 return --pending || done();
18643 token.escaped = true;
18644 --pending || done();
18652 if (opt) { opt = merge({}, marked.defaults, opt); }
18653 return Parser.parse(Lexer.lex(src, opt), opt);
18655 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18656 if ((opt || marked.defaults).silent) {
18657 return '<p>An error occured:</p><pre>'
18658 + escape(e.message + '', true)
18670 marked.setOptions = function(opt) {
18671 merge(marked.defaults, opt);
18675 marked.defaults = {
18686 langPrefix: 'lang-',
18687 smartypants: false,
18689 renderer: new Renderer,
18697 marked.Parser = Parser;
18698 marked.parser = Parser.parse;
18700 marked.Renderer = Renderer;
18702 marked.Lexer = Lexer;
18703 marked.lexer = Lexer.lex;
18705 marked.InlineLexer = InlineLexer;
18706 marked.inlineLexer = InlineLexer.output;
18708 marked.parse = marked;
18710 Roo.Markdown.marked = marked;
18714 * Ext JS Library 1.1.1
18715 * Copyright(c) 2006-2007, Ext JS, LLC.
18717 * Originally Released Under LGPL - original licence link has changed is not relivant.
18720 * <script type="text/javascript">
18726 * These classes are derivatives of the similarly named classes in the YUI Library.
18727 * The original license:
18728 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18729 * Code licensed under the BSD License:
18730 * http://developer.yahoo.net/yui/license.txt
18735 var Event=Roo.EventManager;
18736 var Dom=Roo.lib.Dom;
18739 * @class Roo.dd.DragDrop
18740 * @extends Roo.util.Observable
18741 * Defines the interface and base operation of items that that can be
18742 * dragged or can be drop targets. It was designed to be extended, overriding
18743 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18744 * Up to three html elements can be associated with a DragDrop instance:
18746 * <li>linked element: the element that is passed into the constructor.
18747 * This is the element which defines the boundaries for interaction with
18748 * other DragDrop objects.</li>
18749 * <li>handle element(s): The drag operation only occurs if the element that
18750 * was clicked matches a handle element. By default this is the linked
18751 * element, but there are times that you will want only a portion of the
18752 * linked element to initiate the drag operation, and the setHandleElId()
18753 * method provides a way to define this.</li>
18754 * <li>drag element: this represents the element that would be moved along
18755 * with the cursor during a drag operation. By default, this is the linked
18756 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18757 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18760 * This class should not be instantiated until the onload event to ensure that
18761 * the associated elements are available.
18762 * The following would define a DragDrop obj that would interact with any
18763 * other DragDrop obj in the "group1" group:
18765 * dd = new Roo.dd.DragDrop("div1", "group1");
18767 * Since none of the event handlers have been implemented, nothing would
18768 * actually happen if you were to run the code above. Normally you would
18769 * override this class or one of the default implementations, but you can
18770 * also override the methods you want on an instance of the class...
18772 * dd.onDragDrop = function(e, id) {
18773 * alert("dd was dropped on " + id);
18777 * @param {String} id of the element that is linked to this instance
18778 * @param {String} sGroup the group of related DragDrop objects
18779 * @param {object} config an object containing configurable attributes
18780 * Valid properties for DragDrop:
18781 * padding, isTarget, maintainOffset, primaryButtonOnly
18783 Roo.dd.DragDrop = function(id, sGroup, config) {
18785 this.init(id, sGroup, config);
18790 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18793 * The id of the element associated with this object. This is what we
18794 * refer to as the "linked element" because the size and position of
18795 * this element is used to determine when the drag and drop objects have
18803 * Configuration attributes passed into the constructor
18810 * The id of the element that will be dragged. By default this is same
18811 * as the linked element , but could be changed to another element. Ex:
18813 * @property dragElId
18820 * the id of the element that initiates the drag operation. By default
18821 * this is the linked element, but could be changed to be a child of this
18822 * element. This lets us do things like only starting the drag when the
18823 * header element within the linked html element is clicked.
18824 * @property handleElId
18831 * An associative array of HTML tags that will be ignored if clicked.
18832 * @property invalidHandleTypes
18833 * @type {string: string}
18835 invalidHandleTypes: null,
18838 * An associative array of ids for elements that will be ignored if clicked
18839 * @property invalidHandleIds
18840 * @type {string: string}
18842 invalidHandleIds: null,
18845 * An indexted array of css class names for elements that will be ignored
18847 * @property invalidHandleClasses
18850 invalidHandleClasses: null,
18853 * The linked element's absolute X position at the time the drag was
18855 * @property startPageX
18862 * The linked element's absolute X position at the time the drag was
18864 * @property startPageY
18871 * The group defines a logical collection of DragDrop objects that are
18872 * related. Instances only get events when interacting with other
18873 * DragDrop object in the same group. This lets us define multiple
18874 * groups using a single DragDrop subclass if we want.
18876 * @type {string: string}
18881 * Individual drag/drop instances can be locked. This will prevent
18882 * onmousedown start drag.
18890 * Lock this instance
18893 lock: function() { this.locked = true; },
18896 * Unlock this instace
18899 unlock: function() { this.locked = false; },
18902 * By default, all insances can be a drop target. This can be disabled by
18903 * setting isTarget to false.
18910 * The padding configured for this drag and drop object for calculating
18911 * the drop zone intersection with this object.
18918 * Cached reference to the linked element
18919 * @property _domRef
18925 * Internal typeof flag
18926 * @property __ygDragDrop
18929 __ygDragDrop: true,
18932 * Set to true when horizontal contraints are applied
18933 * @property constrainX
18940 * Set to true when vertical contraints are applied
18941 * @property constrainY
18948 * The left constraint
18956 * The right constraint
18964 * The up constraint
18973 * The down constraint
18981 * Maintain offsets when we resetconstraints. Set to true when you want
18982 * the position of the element relative to its parent to stay the same
18983 * when the page changes
18985 * @property maintainOffset
18988 maintainOffset: false,
18991 * Array of pixel locations the element will snap to if we specified a
18992 * horizontal graduation/interval. This array is generated automatically
18993 * when you define a tick interval.
19000 * Array of pixel locations the element will snap to if we specified a
19001 * vertical graduation/interval. This array is generated automatically
19002 * when you define a tick interval.
19009 * By default the drag and drop instance will only respond to the primary
19010 * button click (left button for a right-handed mouse). Set to true to
19011 * allow drag and drop to start with any mouse click that is propogated
19013 * @property primaryButtonOnly
19016 primaryButtonOnly: true,
19019 * The availabe property is false until the linked dom element is accessible.
19020 * @property available
19026 * By default, drags can only be initiated if the mousedown occurs in the
19027 * region the linked element is. This is done in part to work around a
19028 * bug in some browsers that mis-report the mousedown if the previous
19029 * mouseup happened outside of the window. This property is set to true
19030 * if outer handles are defined.
19032 * @property hasOuterHandles
19036 hasOuterHandles: false,
19039 * Code that executes immediately before the startDrag event
19040 * @method b4StartDrag
19043 b4StartDrag: function(x, y) { },
19046 * Abstract method called after a drag/drop object is clicked
19047 * and the drag or mousedown time thresholds have beeen met.
19048 * @method startDrag
19049 * @param {int} X click location
19050 * @param {int} Y click location
19052 startDrag: function(x, y) { /* override this */ },
19055 * Code that executes immediately before the onDrag event
19059 b4Drag: function(e) { },
19062 * Abstract method called during the onMouseMove event while dragging an
19065 * @param {Event} e the mousemove event
19067 onDrag: function(e) { /* override this */ },
19070 * Abstract method called when this element fist begins hovering over
19071 * another DragDrop obj
19072 * @method onDragEnter
19073 * @param {Event} e the mousemove event
19074 * @param {String|DragDrop[]} id In POINT mode, the element
19075 * id this is hovering over. In INTERSECT mode, an array of one or more
19076 * dragdrop items being hovered over.
19078 onDragEnter: function(e, id) { /* override this */ },
19081 * Code that executes immediately before the onDragOver event
19082 * @method b4DragOver
19085 b4DragOver: function(e) { },
19088 * Abstract method called when this element is hovering over another
19090 * @method onDragOver
19091 * @param {Event} e the mousemove event
19092 * @param {String|DragDrop[]} id In POINT mode, the element
19093 * id this is hovering over. In INTERSECT mode, an array of dd items
19094 * being hovered over.
19096 onDragOver: function(e, id) { /* override this */ },
19099 * Code that executes immediately before the onDragOut event
19100 * @method b4DragOut
19103 b4DragOut: function(e) { },
19106 * Abstract method called when we are no longer hovering over an element
19107 * @method onDragOut
19108 * @param {Event} e the mousemove event
19109 * @param {String|DragDrop[]} id In POINT mode, the element
19110 * id this was hovering over. In INTERSECT mode, an array of dd items
19111 * that the mouse is no longer over.
19113 onDragOut: function(e, id) { /* override this */ },
19116 * Code that executes immediately before the onDragDrop event
19117 * @method b4DragDrop
19120 b4DragDrop: function(e) { },
19123 * Abstract method called when this item is dropped on another DragDrop
19125 * @method onDragDrop
19126 * @param {Event} e the mouseup event
19127 * @param {String|DragDrop[]} id In POINT mode, the element
19128 * id this was dropped on. In INTERSECT mode, an array of dd items this
19131 onDragDrop: function(e, id) { /* override this */ },
19134 * Abstract method called when this item is dropped on an area with no
19136 * @method onInvalidDrop
19137 * @param {Event} e the mouseup event
19139 onInvalidDrop: function(e) { /* override this */ },
19142 * Code that executes immediately before the endDrag event
19143 * @method b4EndDrag
19146 b4EndDrag: function(e) { },
19149 * Fired when we are done dragging the object
19151 * @param {Event} e the mouseup event
19153 endDrag: function(e) { /* override this */ },
19156 * Code executed immediately before the onMouseDown event
19157 * @method b4MouseDown
19158 * @param {Event} e the mousedown event
19161 b4MouseDown: function(e) { },
19164 * Event handler that fires when a drag/drop obj gets a mousedown
19165 * @method onMouseDown
19166 * @param {Event} e the mousedown event
19168 onMouseDown: function(e) { /* override this */ },
19171 * Event handler that fires when a drag/drop obj gets a mouseup
19172 * @method onMouseUp
19173 * @param {Event} e the mouseup event
19175 onMouseUp: function(e) { /* override this */ },
19178 * Override the onAvailable method to do what is needed after the initial
19179 * position was determined.
19180 * @method onAvailable
19182 onAvailable: function () {
19186 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19189 defaultPadding : {left:0, right:0, top:0, bottom:0},
19192 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19196 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19197 { dragElId: "existingProxyDiv" });
19198 dd.startDrag = function(){
19199 this.constrainTo("parent-id");
19202 * Or you can initalize it using the {@link Roo.Element} object:
19204 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19205 startDrag : function(){
19206 this.constrainTo("parent-id");
19210 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19211 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19212 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19213 * an object containing the sides to pad. For example: {right:10, bottom:10}
19214 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19216 constrainTo : function(constrainTo, pad, inContent){
19217 if(typeof pad == "number"){
19218 pad = {left: pad, right:pad, top:pad, bottom:pad};
19220 pad = pad || this.defaultPadding;
19221 var b = Roo.get(this.getEl()).getBox();
19222 var ce = Roo.get(constrainTo);
19223 var s = ce.getScroll();
19224 var c, cd = ce.dom;
19225 if(cd == document.body){
19226 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19229 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19233 var topSpace = b.y - c.y;
19234 var leftSpace = b.x - c.x;
19236 this.resetConstraints();
19237 this.setXConstraint(leftSpace - (pad.left||0), // left
19238 c.width - leftSpace - b.width - (pad.right||0) //right
19240 this.setYConstraint(topSpace - (pad.top||0), //top
19241 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19246 * Returns a reference to the linked element
19248 * @return {HTMLElement} the html element
19250 getEl: function() {
19251 if (!this._domRef) {
19252 this._domRef = Roo.getDom(this.id);
19255 return this._domRef;
19259 * Returns a reference to the actual element to drag. By default this is
19260 * the same as the html element, but it can be assigned to another
19261 * element. An example of this can be found in Roo.dd.DDProxy
19262 * @method getDragEl
19263 * @return {HTMLElement} the html element
19265 getDragEl: function() {
19266 return Roo.getDom(this.dragElId);
19270 * Sets up the DragDrop object. Must be called in the constructor of any
19271 * Roo.dd.DragDrop subclass
19273 * @param id the id of the linked element
19274 * @param {String} sGroup the group of related items
19275 * @param {object} config configuration attributes
19277 init: function(id, sGroup, config) {
19278 this.initTarget(id, sGroup, config);
19279 if (!Roo.isTouch) {
19280 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19282 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19283 // Event.on(this.id, "selectstart", Event.preventDefault);
19287 * Initializes Targeting functionality only... the object does not
19288 * get a mousedown handler.
19289 * @method initTarget
19290 * @param id the id of the linked element
19291 * @param {String} sGroup the group of related items
19292 * @param {object} config configuration attributes
19294 initTarget: function(id, sGroup, config) {
19296 // configuration attributes
19297 this.config = config || {};
19299 // create a local reference to the drag and drop manager
19300 this.DDM = Roo.dd.DDM;
19301 // initialize the groups array
19304 // assume that we have an element reference instead of an id if the
19305 // parameter is not a string
19306 if (typeof id !== "string") {
19313 // add to an interaction group
19314 this.addToGroup((sGroup) ? sGroup : "default");
19316 // We don't want to register this as the handle with the manager
19317 // so we just set the id rather than calling the setter.
19318 this.handleElId = id;
19320 // the linked element is the element that gets dragged by default
19321 this.setDragElId(id);
19323 // by default, clicked anchors will not start drag operations.
19324 this.invalidHandleTypes = { A: "A" };
19325 this.invalidHandleIds = {};
19326 this.invalidHandleClasses = [];
19328 this.applyConfig();
19330 this.handleOnAvailable();
19334 * Applies the configuration parameters that were passed into the constructor.
19335 * This is supposed to happen at each level through the inheritance chain. So
19336 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19337 * DragDrop in order to get all of the parameters that are available in
19339 * @method applyConfig
19341 applyConfig: function() {
19343 // configurable properties:
19344 // padding, isTarget, maintainOffset, primaryButtonOnly
19345 this.padding = this.config.padding || [0, 0, 0, 0];
19346 this.isTarget = (this.config.isTarget !== false);
19347 this.maintainOffset = (this.config.maintainOffset);
19348 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19353 * Executed when the linked element is available
19354 * @method handleOnAvailable
19357 handleOnAvailable: function() {
19358 this.available = true;
19359 this.resetConstraints();
19360 this.onAvailable();
19364 * Configures the padding for the target zone in px. Effectively expands
19365 * (or reduces) the virtual object size for targeting calculations.
19366 * Supports css-style shorthand; if only one parameter is passed, all sides
19367 * will have that padding, and if only two are passed, the top and bottom
19368 * will have the first param, the left and right the second.
19369 * @method setPadding
19370 * @param {int} iTop Top pad
19371 * @param {int} iRight Right pad
19372 * @param {int} iBot Bot pad
19373 * @param {int} iLeft Left pad
19375 setPadding: function(iTop, iRight, iBot, iLeft) {
19376 // this.padding = [iLeft, iRight, iTop, iBot];
19377 if (!iRight && 0 !== iRight) {
19378 this.padding = [iTop, iTop, iTop, iTop];
19379 } else if (!iBot && 0 !== iBot) {
19380 this.padding = [iTop, iRight, iTop, iRight];
19382 this.padding = [iTop, iRight, iBot, iLeft];
19387 * Stores the initial placement of the linked element.
19388 * @method setInitialPosition
19389 * @param {int} diffX the X offset, default 0
19390 * @param {int} diffY the Y offset, default 0
19392 setInitPosition: function(diffX, diffY) {
19393 var el = this.getEl();
19395 if (!this.DDM.verifyEl(el)) {
19399 var dx = diffX || 0;
19400 var dy = diffY || 0;
19402 var p = Dom.getXY( el );
19404 this.initPageX = p[0] - dx;
19405 this.initPageY = p[1] - dy;
19407 this.lastPageX = p[0];
19408 this.lastPageY = p[1];
19411 this.setStartPosition(p);
19415 * Sets the start position of the element. This is set when the obj
19416 * is initialized, the reset when a drag is started.
19417 * @method setStartPosition
19418 * @param pos current position (from previous lookup)
19421 setStartPosition: function(pos) {
19422 var p = pos || Dom.getXY( this.getEl() );
19423 this.deltaSetXY = null;
19425 this.startPageX = p[0];
19426 this.startPageY = p[1];
19430 * Add this instance to a group of related drag/drop objects. All
19431 * instances belong to at least one group, and can belong to as many
19432 * groups as needed.
19433 * @method addToGroup
19434 * @param sGroup {string} the name of the group
19436 addToGroup: function(sGroup) {
19437 this.groups[sGroup] = true;
19438 this.DDM.regDragDrop(this, sGroup);
19442 * Remove's this instance from the supplied interaction group
19443 * @method removeFromGroup
19444 * @param {string} sGroup The group to drop
19446 removeFromGroup: function(sGroup) {
19447 if (this.groups[sGroup]) {
19448 delete this.groups[sGroup];
19451 this.DDM.removeDDFromGroup(this, sGroup);
19455 * Allows you to specify that an element other than the linked element
19456 * will be moved with the cursor during a drag
19457 * @method setDragElId
19458 * @param id {string} the id of the element that will be used to initiate the drag
19460 setDragElId: function(id) {
19461 this.dragElId = id;
19465 * Allows you to specify a child of the linked element that should be
19466 * used to initiate the drag operation. An example of this would be if
19467 * you have a content div with text and links. Clicking anywhere in the
19468 * content area would normally start the drag operation. Use this method
19469 * to specify that an element inside of the content div is the element
19470 * that starts the drag operation.
19471 * @method setHandleElId
19472 * @param id {string} the id of the element that will be used to
19473 * initiate the drag.
19475 setHandleElId: function(id) {
19476 if (typeof id !== "string") {
19479 this.handleElId = id;
19480 this.DDM.regHandle(this.id, id);
19484 * Allows you to set an element outside of the linked element as a drag
19486 * @method setOuterHandleElId
19487 * @param id the id of the element that will be used to initiate the drag
19489 setOuterHandleElId: function(id) {
19490 if (typeof id !== "string") {
19493 Event.on(id, "mousedown",
19494 this.handleMouseDown, this);
19495 this.setHandleElId(id);
19497 this.hasOuterHandles = true;
19501 * Remove all drag and drop hooks for this element
19504 unreg: function() {
19505 Event.un(this.id, "mousedown",
19506 this.handleMouseDown);
19507 Event.un(this.id, "touchstart",
19508 this.handleMouseDown);
19509 this._domRef = null;
19510 this.DDM._remove(this);
19513 destroy : function(){
19518 * Returns true if this instance is locked, or the drag drop mgr is locked
19519 * (meaning that all drag/drop is disabled on the page.)
19521 * @return {boolean} true if this obj or all drag/drop is locked, else
19524 isLocked: function() {
19525 return (this.DDM.isLocked() || this.locked);
19529 * Fired when this object is clicked
19530 * @method handleMouseDown
19532 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19535 handleMouseDown: function(e, oDD){
19537 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19538 //Roo.log('not touch/ button !=0');
19541 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19542 return; // double touch..
19546 if (this.isLocked()) {
19547 //Roo.log('locked');
19551 this.DDM.refreshCache(this.groups);
19552 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19553 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19554 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19555 //Roo.log('no outer handes or not over target');
19558 // Roo.log('check validator');
19559 if (this.clickValidator(e)) {
19560 // Roo.log('validate success');
19561 // set the initial element position
19562 this.setStartPosition();
19565 this.b4MouseDown(e);
19566 this.onMouseDown(e);
19568 this.DDM.handleMouseDown(e, this);
19570 this.DDM.stopEvent(e);
19578 clickValidator: function(e) {
19579 var target = e.getTarget();
19580 return ( this.isValidHandleChild(target) &&
19581 (this.id == this.handleElId ||
19582 this.DDM.handleWasClicked(target, this.id)) );
19586 * Allows you to specify a tag name that should not start a drag operation
19587 * when clicked. This is designed to facilitate embedding links within a
19588 * drag handle that do something other than start the drag.
19589 * @method addInvalidHandleType
19590 * @param {string} tagName the type of element to exclude
19592 addInvalidHandleType: function(tagName) {
19593 var type = tagName.toUpperCase();
19594 this.invalidHandleTypes[type] = type;
19598 * Lets you to specify an element id for a child of a drag handle
19599 * that should not initiate a drag
19600 * @method addInvalidHandleId
19601 * @param {string} id the element id of the element you wish to ignore
19603 addInvalidHandleId: function(id) {
19604 if (typeof id !== "string") {
19607 this.invalidHandleIds[id] = id;
19611 * Lets you specify a css class of elements that will not initiate a drag
19612 * @method addInvalidHandleClass
19613 * @param {string} cssClass the class of the elements you wish to ignore
19615 addInvalidHandleClass: function(cssClass) {
19616 this.invalidHandleClasses.push(cssClass);
19620 * Unsets an excluded tag name set by addInvalidHandleType
19621 * @method removeInvalidHandleType
19622 * @param {string} tagName the type of element to unexclude
19624 removeInvalidHandleType: function(tagName) {
19625 var type = tagName.toUpperCase();
19626 // this.invalidHandleTypes[type] = null;
19627 delete this.invalidHandleTypes[type];
19631 * Unsets an invalid handle id
19632 * @method removeInvalidHandleId
19633 * @param {string} id the id of the element to re-enable
19635 removeInvalidHandleId: function(id) {
19636 if (typeof id !== "string") {
19639 delete this.invalidHandleIds[id];
19643 * Unsets an invalid css class
19644 * @method removeInvalidHandleClass
19645 * @param {string} cssClass the class of the element(s) you wish to
19648 removeInvalidHandleClass: function(cssClass) {
19649 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19650 if (this.invalidHandleClasses[i] == cssClass) {
19651 delete this.invalidHandleClasses[i];
19657 * Checks the tag exclusion list to see if this click should be ignored
19658 * @method isValidHandleChild
19659 * @param {HTMLElement} node the HTMLElement to evaluate
19660 * @return {boolean} true if this is a valid tag type, false if not
19662 isValidHandleChild: function(node) {
19665 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19668 nodeName = node.nodeName.toUpperCase();
19670 nodeName = node.nodeName;
19672 valid = valid && !this.invalidHandleTypes[nodeName];
19673 valid = valid && !this.invalidHandleIds[node.id];
19675 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19676 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19685 * Create the array of horizontal tick marks if an interval was specified
19686 * in setXConstraint().
19687 * @method setXTicks
19690 setXTicks: function(iStartX, iTickSize) {
19692 this.xTickSize = iTickSize;
19696 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19698 this.xTicks[this.xTicks.length] = i;
19703 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19705 this.xTicks[this.xTicks.length] = i;
19710 this.xTicks.sort(this.DDM.numericSort) ;
19714 * Create the array of vertical tick marks if an interval was specified in
19715 * setYConstraint().
19716 * @method setYTicks
19719 setYTicks: function(iStartY, iTickSize) {
19721 this.yTickSize = iTickSize;
19725 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19727 this.yTicks[this.yTicks.length] = i;
19732 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19734 this.yTicks[this.yTicks.length] = i;
19739 this.yTicks.sort(this.DDM.numericSort) ;
19743 * By default, the element can be dragged any place on the screen. Use
19744 * this method to limit the horizontal travel of the element. Pass in
19745 * 0,0 for the parameters if you want to lock the drag to the y axis.
19746 * @method setXConstraint
19747 * @param {int} iLeft the number of pixels the element can move to the left
19748 * @param {int} iRight the number of pixels the element can move to the
19750 * @param {int} iTickSize optional parameter for specifying that the
19752 * should move iTickSize pixels at a time.
19754 setXConstraint: function(iLeft, iRight, iTickSize) {
19755 this.leftConstraint = iLeft;
19756 this.rightConstraint = iRight;
19758 this.minX = this.initPageX - iLeft;
19759 this.maxX = this.initPageX + iRight;
19760 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19762 this.constrainX = true;
19766 * Clears any constraints applied to this instance. Also clears ticks
19767 * since they can't exist independent of a constraint at this time.
19768 * @method clearConstraints
19770 clearConstraints: function() {
19771 this.constrainX = false;
19772 this.constrainY = false;
19777 * Clears any tick interval defined for this instance
19778 * @method clearTicks
19780 clearTicks: function() {
19781 this.xTicks = null;
19782 this.yTicks = null;
19783 this.xTickSize = 0;
19784 this.yTickSize = 0;
19788 * By default, the element can be dragged any place on the screen. Set
19789 * this to limit the vertical travel of the element. Pass in 0,0 for the
19790 * parameters if you want to lock the drag to the x axis.
19791 * @method setYConstraint
19792 * @param {int} iUp the number of pixels the element can move up
19793 * @param {int} iDown the number of pixels the element can move down
19794 * @param {int} iTickSize optional parameter for specifying that the
19795 * element should move iTickSize pixels at a time.
19797 setYConstraint: function(iUp, iDown, iTickSize) {
19798 this.topConstraint = iUp;
19799 this.bottomConstraint = iDown;
19801 this.minY = this.initPageY - iUp;
19802 this.maxY = this.initPageY + iDown;
19803 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19805 this.constrainY = true;
19810 * resetConstraints must be called if you manually reposition a dd element.
19811 * @method resetConstraints
19812 * @param {boolean} maintainOffset
19814 resetConstraints: function() {
19817 // Maintain offsets if necessary
19818 if (this.initPageX || this.initPageX === 0) {
19819 // figure out how much this thing has moved
19820 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19821 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19823 this.setInitPosition(dx, dy);
19825 // This is the first time we have detected the element's position
19827 this.setInitPosition();
19830 if (this.constrainX) {
19831 this.setXConstraint( this.leftConstraint,
19832 this.rightConstraint,
19836 if (this.constrainY) {
19837 this.setYConstraint( this.topConstraint,
19838 this.bottomConstraint,
19844 * Normally the drag element is moved pixel by pixel, but we can specify
19845 * that it move a number of pixels at a time. This method resolves the
19846 * location when we have it set up like this.
19848 * @param {int} val where we want to place the object
19849 * @param {int[]} tickArray sorted array of valid points
19850 * @return {int} the closest tick
19853 getTick: function(val, tickArray) {
19856 // If tick interval is not defined, it is effectively 1 pixel,
19857 // so we return the value passed to us.
19859 } else if (tickArray[0] >= val) {
19860 // The value is lower than the first tick, so we return the first
19862 return tickArray[0];
19864 for (var i=0, len=tickArray.length; i<len; ++i) {
19866 if (tickArray[next] && tickArray[next] >= val) {
19867 var diff1 = val - tickArray[i];
19868 var diff2 = tickArray[next] - val;
19869 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19873 // The value is larger than the last tick, so we return the last
19875 return tickArray[tickArray.length - 1];
19882 * @return {string} string representation of the dd obj
19884 toString: function() {
19885 return ("DragDrop " + this.id);
19893 * Ext JS Library 1.1.1
19894 * Copyright(c) 2006-2007, Ext JS, LLC.
19896 * Originally Released Under LGPL - original licence link has changed is not relivant.
19899 * <script type="text/javascript">
19904 * The drag and drop utility provides a framework for building drag and drop
19905 * applications. In addition to enabling drag and drop for specific elements,
19906 * the drag and drop elements are tracked by the manager class, and the
19907 * interactions between the various elements are tracked during the drag and
19908 * the implementing code is notified about these important moments.
19911 // Only load the library once. Rewriting the manager class would orphan
19912 // existing drag and drop instances.
19913 if (!Roo.dd.DragDropMgr) {
19916 * @class Roo.dd.DragDropMgr
19917 * DragDropMgr is a singleton that tracks the element interaction for
19918 * all DragDrop items in the window. Generally, you will not call
19919 * this class directly, but it does have helper methods that could
19920 * be useful in your DragDrop implementations.
19923 Roo.dd.DragDropMgr = function() {
19925 var Event = Roo.EventManager;
19930 * Two dimensional Array of registered DragDrop objects. The first
19931 * dimension is the DragDrop item group, the second the DragDrop
19934 * @type {string: string}
19941 * Array of element ids defined as drag handles. Used to determine
19942 * if the element that generated the mousedown event is actually the
19943 * handle and not the html element itself.
19944 * @property handleIds
19945 * @type {string: string}
19952 * the DragDrop object that is currently being dragged
19953 * @property dragCurrent
19961 * the DragDrop object(s) that are being hovered over
19962 * @property dragOvers
19970 * the X distance between the cursor and the object being dragged
19979 * the Y distance between the cursor and the object being dragged
19988 * Flag to determine if we should prevent the default behavior of the
19989 * events we define. By default this is true, but this can be set to
19990 * false if you need the default behavior (not recommended)
19991 * @property preventDefault
19995 preventDefault: true,
19998 * Flag to determine if we should stop the propagation of the events
19999 * we generate. This is true by default but you may want to set it to
20000 * false if the html element contains other features that require the
20002 * @property stopPropagation
20006 stopPropagation: true,
20009 * Internal flag that is set to true when drag and drop has been
20011 * @property initialized
20018 * All drag and drop can be disabled.
20026 * Called the first time an element is registered.
20032 this.initialized = true;
20036 * In point mode, drag and drop interaction is defined by the
20037 * location of the cursor during the drag/drop
20045 * In intersect mode, drag and drop interactio nis defined by the
20046 * overlap of two or more drag and drop objects.
20047 * @property INTERSECT
20054 * The current drag and drop mode. Default: POINT
20062 * Runs method on all drag and drop objects
20063 * @method _execOnAll
20067 _execOnAll: function(sMethod, args) {
20068 for (var i in this.ids) {
20069 for (var j in this.ids[i]) {
20070 var oDD = this.ids[i][j];
20071 if (! this.isTypeOfDD(oDD)) {
20074 oDD[sMethod].apply(oDD, args);
20080 * Drag and drop initialization. Sets up the global event handlers
20085 _onLoad: function() {
20089 if (!Roo.isTouch) {
20090 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20091 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20093 Event.on(document, "touchend", this.handleMouseUp, this, true);
20094 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20096 Event.on(window, "unload", this._onUnload, this, true);
20097 Event.on(window, "resize", this._onResize, this, true);
20098 // Event.on(window, "mouseout", this._test);
20103 * Reset constraints on all drag and drop objs
20104 * @method _onResize
20108 _onResize: function(e) {
20109 this._execOnAll("resetConstraints", []);
20113 * Lock all drag and drop functionality
20117 lock: function() { this.locked = true; },
20120 * Unlock all drag and drop functionality
20124 unlock: function() { this.locked = false; },
20127 * Is drag and drop locked?
20129 * @return {boolean} True if drag and drop is locked, false otherwise.
20132 isLocked: function() { return this.locked; },
20135 * Location cache that is set for all drag drop objects when a drag is
20136 * initiated, cleared when the drag is finished.
20137 * @property locationCache
20144 * Set useCache to false if you want to force object the lookup of each
20145 * drag and drop linked element constantly during a drag.
20146 * @property useCache
20153 * The number of pixels that the mouse needs to move after the
20154 * mousedown before the drag is initiated. Default=3;
20155 * @property clickPixelThresh
20159 clickPixelThresh: 3,
20162 * The number of milliseconds after the mousedown event to initiate the
20163 * drag if we don't get a mouseup event. Default=1000
20164 * @property clickTimeThresh
20168 clickTimeThresh: 350,
20171 * Flag that indicates that either the drag pixel threshold or the
20172 * mousdown time threshold has been met
20173 * @property dragThreshMet
20178 dragThreshMet: false,
20181 * Timeout used for the click time threshold
20182 * @property clickTimeout
20187 clickTimeout: null,
20190 * The X position of the mousedown event stored for later use when a
20191 * drag threshold is met.
20200 * The Y position of the mousedown event stored for later use when a
20201 * drag threshold is met.
20210 * Each DragDrop instance must be registered with the DragDropMgr.
20211 * This is executed in DragDrop.init()
20212 * @method regDragDrop
20213 * @param {DragDrop} oDD the DragDrop object to register
20214 * @param {String} sGroup the name of the group this element belongs to
20217 regDragDrop: function(oDD, sGroup) {
20218 if (!this.initialized) { this.init(); }
20220 if (!this.ids[sGroup]) {
20221 this.ids[sGroup] = {};
20223 this.ids[sGroup][oDD.id] = oDD;
20227 * Removes the supplied dd instance from the supplied group. Executed
20228 * by DragDrop.removeFromGroup, so don't call this function directly.
20229 * @method removeDDFromGroup
20233 removeDDFromGroup: function(oDD, sGroup) {
20234 if (!this.ids[sGroup]) {
20235 this.ids[sGroup] = {};
20238 var obj = this.ids[sGroup];
20239 if (obj && obj[oDD.id]) {
20240 delete obj[oDD.id];
20245 * Unregisters a drag and drop item. This is executed in
20246 * DragDrop.unreg, use that method instead of calling this directly.
20251 _remove: function(oDD) {
20252 for (var g in oDD.groups) {
20253 if (g && this.ids[g][oDD.id]) {
20254 delete this.ids[g][oDD.id];
20257 delete this.handleIds[oDD.id];
20261 * Each DragDrop handle element must be registered. This is done
20262 * automatically when executing DragDrop.setHandleElId()
20263 * @method regHandle
20264 * @param {String} sDDId the DragDrop id this element is a handle for
20265 * @param {String} sHandleId the id of the element that is the drag
20269 regHandle: function(sDDId, sHandleId) {
20270 if (!this.handleIds[sDDId]) {
20271 this.handleIds[sDDId] = {};
20273 this.handleIds[sDDId][sHandleId] = sHandleId;
20277 * Utility function to determine if a given element has been
20278 * registered as a drag drop item.
20279 * @method isDragDrop
20280 * @param {String} id the element id to check
20281 * @return {boolean} true if this element is a DragDrop item,
20285 isDragDrop: function(id) {
20286 return ( this.getDDById(id) ) ? true : false;
20290 * Returns the drag and drop instances that are in all groups the
20291 * passed in instance belongs to.
20292 * @method getRelated
20293 * @param {DragDrop} p_oDD the obj to get related data for
20294 * @param {boolean} bTargetsOnly if true, only return targetable objs
20295 * @return {DragDrop[]} the related instances
20298 getRelated: function(p_oDD, bTargetsOnly) {
20300 for (var i in p_oDD.groups) {
20301 for (j in this.ids[i]) {
20302 var dd = this.ids[i][j];
20303 if (! this.isTypeOfDD(dd)) {
20306 if (!bTargetsOnly || dd.isTarget) {
20307 oDDs[oDDs.length] = dd;
20316 * Returns true if the specified dd target is a legal target for
20317 * the specifice drag obj
20318 * @method isLegalTarget
20319 * @param {DragDrop} the drag obj
20320 * @param {DragDrop} the target
20321 * @return {boolean} true if the target is a legal target for the
20325 isLegalTarget: function (oDD, oTargetDD) {
20326 var targets = this.getRelated(oDD, true);
20327 for (var i=0, len=targets.length;i<len;++i) {
20328 if (targets[i].id == oTargetDD.id) {
20337 * My goal is to be able to transparently determine if an object is
20338 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20339 * returns "object", oDD.constructor.toString() always returns
20340 * "DragDrop" and not the name of the subclass. So for now it just
20341 * evaluates a well-known variable in DragDrop.
20342 * @method isTypeOfDD
20343 * @param {Object} the object to evaluate
20344 * @return {boolean} true if typeof oDD = DragDrop
20347 isTypeOfDD: function (oDD) {
20348 return (oDD && oDD.__ygDragDrop);
20352 * Utility function to determine if a given element has been
20353 * registered as a drag drop handle for the given Drag Drop object.
20355 * @param {String} id the element id to check
20356 * @return {boolean} true if this element is a DragDrop handle, false
20360 isHandle: function(sDDId, sHandleId) {
20361 return ( this.handleIds[sDDId] &&
20362 this.handleIds[sDDId][sHandleId] );
20366 * Returns the DragDrop instance for a given id
20367 * @method getDDById
20368 * @param {String} id the id of the DragDrop object
20369 * @return {DragDrop} the drag drop object, null if it is not found
20372 getDDById: function(id) {
20373 for (var i in this.ids) {
20374 if (this.ids[i][id]) {
20375 return this.ids[i][id];
20382 * Fired after a registered DragDrop object gets the mousedown event.
20383 * Sets up the events required to track the object being dragged
20384 * @method handleMouseDown
20385 * @param {Event} e the event
20386 * @param oDD the DragDrop object being dragged
20390 handleMouseDown: function(e, oDD) {
20392 Roo.QuickTips.disable();
20394 this.currentTarget = e.getTarget();
20396 this.dragCurrent = oDD;
20398 var el = oDD.getEl();
20400 // track start position
20401 this.startX = e.getPageX();
20402 this.startY = e.getPageY();
20404 this.deltaX = this.startX - el.offsetLeft;
20405 this.deltaY = this.startY - el.offsetTop;
20407 this.dragThreshMet = false;
20409 this.clickTimeout = setTimeout(
20411 var DDM = Roo.dd.DDM;
20412 DDM.startDrag(DDM.startX, DDM.startY);
20414 this.clickTimeThresh );
20418 * Fired when either the drag pixel threshol or the mousedown hold
20419 * time threshold has been met.
20420 * @method startDrag
20421 * @param x {int} the X position of the original mousedown
20422 * @param y {int} the Y position of the original mousedown
20425 startDrag: function(x, y) {
20426 clearTimeout(this.clickTimeout);
20427 if (this.dragCurrent) {
20428 this.dragCurrent.b4StartDrag(x, y);
20429 this.dragCurrent.startDrag(x, y);
20431 this.dragThreshMet = true;
20435 * Internal function to handle the mouseup event. Will be invoked
20436 * from the context of the document.
20437 * @method handleMouseUp
20438 * @param {Event} e the event
20442 handleMouseUp: function(e) {
20445 Roo.QuickTips.enable();
20447 if (! this.dragCurrent) {
20451 clearTimeout(this.clickTimeout);
20453 if (this.dragThreshMet) {
20454 this.fireEvents(e, true);
20464 * Utility to stop event propagation and event default, if these
20465 * features are turned on.
20466 * @method stopEvent
20467 * @param {Event} e the event as returned by this.getEvent()
20470 stopEvent: function(e){
20471 if(this.stopPropagation) {
20472 e.stopPropagation();
20475 if (this.preventDefault) {
20476 e.preventDefault();
20481 * Internal function to clean up event handlers after the drag
20482 * operation is complete
20484 * @param {Event} e the event
20488 stopDrag: function(e) {
20489 // Fire the drag end event for the item that was dragged
20490 if (this.dragCurrent) {
20491 if (this.dragThreshMet) {
20492 this.dragCurrent.b4EndDrag(e);
20493 this.dragCurrent.endDrag(e);
20496 this.dragCurrent.onMouseUp(e);
20499 this.dragCurrent = null;
20500 this.dragOvers = {};
20504 * Internal function to handle the mousemove event. Will be invoked
20505 * from the context of the html element.
20507 * @TODO figure out what we can do about mouse events lost when the
20508 * user drags objects beyond the window boundary. Currently we can
20509 * detect this in internet explorer by verifying that the mouse is
20510 * down during the mousemove event. Firefox doesn't give us the
20511 * button state on the mousemove event.
20512 * @method handleMouseMove
20513 * @param {Event} e the event
20517 handleMouseMove: function(e) {
20518 if (! this.dragCurrent) {
20522 // var button = e.which || e.button;
20524 // check for IE mouseup outside of page boundary
20525 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20527 return this.handleMouseUp(e);
20530 if (!this.dragThreshMet) {
20531 var diffX = Math.abs(this.startX - e.getPageX());
20532 var diffY = Math.abs(this.startY - e.getPageY());
20533 if (diffX > this.clickPixelThresh ||
20534 diffY > this.clickPixelThresh) {
20535 this.startDrag(this.startX, this.startY);
20539 if (this.dragThreshMet) {
20540 this.dragCurrent.b4Drag(e);
20541 this.dragCurrent.onDrag(e);
20542 if(!this.dragCurrent.moveOnly){
20543 this.fireEvents(e, false);
20553 * Iterates over all of the DragDrop elements to find ones we are
20554 * hovering over or dropping on
20555 * @method fireEvents
20556 * @param {Event} e the event
20557 * @param {boolean} isDrop is this a drop op or a mouseover op?
20561 fireEvents: function(e, isDrop) {
20562 var dc = this.dragCurrent;
20564 // If the user did the mouse up outside of the window, we could
20565 // get here even though we have ended the drag.
20566 if (!dc || dc.isLocked()) {
20570 var pt = e.getPoint();
20572 // cache the previous dragOver array
20578 var enterEvts = [];
20580 // Check to see if the object(s) we were hovering over is no longer
20581 // being hovered over so we can fire the onDragOut event
20582 for (var i in this.dragOvers) {
20584 var ddo = this.dragOvers[i];
20586 if (! this.isTypeOfDD(ddo)) {
20590 if (! this.isOverTarget(pt, ddo, this.mode)) {
20591 outEvts.push( ddo );
20594 oldOvers[i] = true;
20595 delete this.dragOvers[i];
20598 for (var sGroup in dc.groups) {
20600 if ("string" != typeof sGroup) {
20604 for (i in this.ids[sGroup]) {
20605 var oDD = this.ids[sGroup][i];
20606 if (! this.isTypeOfDD(oDD)) {
20610 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20611 if (this.isOverTarget(pt, oDD, this.mode)) {
20612 // look for drop interactions
20614 dropEvts.push( oDD );
20615 // look for drag enter and drag over interactions
20618 // initial drag over: dragEnter fires
20619 if (!oldOvers[oDD.id]) {
20620 enterEvts.push( oDD );
20621 // subsequent drag overs: dragOver fires
20623 overEvts.push( oDD );
20626 this.dragOvers[oDD.id] = oDD;
20634 if (outEvts.length) {
20635 dc.b4DragOut(e, outEvts);
20636 dc.onDragOut(e, outEvts);
20639 if (enterEvts.length) {
20640 dc.onDragEnter(e, enterEvts);
20643 if (overEvts.length) {
20644 dc.b4DragOver(e, overEvts);
20645 dc.onDragOver(e, overEvts);
20648 if (dropEvts.length) {
20649 dc.b4DragDrop(e, dropEvts);
20650 dc.onDragDrop(e, dropEvts);
20654 // fire dragout events
20656 for (i=0, len=outEvts.length; i<len; ++i) {
20657 dc.b4DragOut(e, outEvts[i].id);
20658 dc.onDragOut(e, outEvts[i].id);
20661 // fire enter events
20662 for (i=0,len=enterEvts.length; i<len; ++i) {
20663 // dc.b4DragEnter(e, oDD.id);
20664 dc.onDragEnter(e, enterEvts[i].id);
20667 // fire over events
20668 for (i=0,len=overEvts.length; i<len; ++i) {
20669 dc.b4DragOver(e, overEvts[i].id);
20670 dc.onDragOver(e, overEvts[i].id);
20673 // fire drop events
20674 for (i=0, len=dropEvts.length; i<len; ++i) {
20675 dc.b4DragDrop(e, dropEvts[i].id);
20676 dc.onDragDrop(e, dropEvts[i].id);
20681 // notify about a drop that did not find a target
20682 if (isDrop && !dropEvts.length) {
20683 dc.onInvalidDrop(e);
20689 * Helper function for getting the best match from the list of drag
20690 * and drop objects returned by the drag and drop events when we are
20691 * in INTERSECT mode. It returns either the first object that the
20692 * cursor is over, or the object that has the greatest overlap with
20693 * the dragged element.
20694 * @method getBestMatch
20695 * @param {DragDrop[]} dds The array of drag and drop objects
20697 * @return {DragDrop} The best single match
20700 getBestMatch: function(dds) {
20702 // Return null if the input is not what we expect
20703 //if (!dds || !dds.length || dds.length == 0) {
20705 // If there is only one item, it wins
20706 //} else if (dds.length == 1) {
20708 var len = dds.length;
20713 // Loop through the targeted items
20714 for (var i=0; i<len; ++i) {
20716 // If the cursor is over the object, it wins. If the
20717 // cursor is over multiple matches, the first one we come
20719 if (dd.cursorIsOver) {
20722 // Otherwise the object with the most overlap wins
20725 winner.overlap.getArea() < dd.overlap.getArea()) {
20736 * Refreshes the cache of the top-left and bottom-right points of the
20737 * drag and drop objects in the specified group(s). This is in the
20738 * format that is stored in the drag and drop instance, so typical
20741 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20745 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20747 * @TODO this really should be an indexed array. Alternatively this
20748 * method could accept both.
20749 * @method refreshCache
20750 * @param {Object} groups an associative array of groups to refresh
20753 refreshCache: function(groups) {
20754 for (var sGroup in groups) {
20755 if ("string" != typeof sGroup) {
20758 for (var i in this.ids[sGroup]) {
20759 var oDD = this.ids[sGroup][i];
20761 if (this.isTypeOfDD(oDD)) {
20762 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20763 var loc = this.getLocation(oDD);
20765 this.locationCache[oDD.id] = loc;
20767 delete this.locationCache[oDD.id];
20768 // this will unregister the drag and drop object if
20769 // the element is not in a usable state
20778 * This checks to make sure an element exists and is in the DOM. The
20779 * main purpose is to handle cases where innerHTML is used to remove
20780 * drag and drop objects from the DOM. IE provides an 'unspecified
20781 * error' when trying to access the offsetParent of such an element
20783 * @param {HTMLElement} el the element to check
20784 * @return {boolean} true if the element looks usable
20787 verifyEl: function(el) {
20792 parent = el.offsetParent;
20795 parent = el.offsetParent;
20806 * Returns a Region object containing the drag and drop element's position
20807 * and size, including the padding configured for it
20808 * @method getLocation
20809 * @param {DragDrop} oDD the drag and drop object to get the
20811 * @return {Roo.lib.Region} a Region object representing the total area
20812 * the element occupies, including any padding
20813 * the instance is configured for.
20816 getLocation: function(oDD) {
20817 if (! this.isTypeOfDD(oDD)) {
20821 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20824 pos= Roo.lib.Dom.getXY(el);
20832 x2 = x1 + el.offsetWidth;
20834 y2 = y1 + el.offsetHeight;
20836 t = y1 - oDD.padding[0];
20837 r = x2 + oDD.padding[1];
20838 b = y2 + oDD.padding[2];
20839 l = x1 - oDD.padding[3];
20841 return new Roo.lib.Region( t, r, b, l );
20845 * Checks the cursor location to see if it over the target
20846 * @method isOverTarget
20847 * @param {Roo.lib.Point} pt The point to evaluate
20848 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20849 * @return {boolean} true if the mouse is over the target
20853 isOverTarget: function(pt, oTarget, intersect) {
20854 // use cache if available
20855 var loc = this.locationCache[oTarget.id];
20856 if (!loc || !this.useCache) {
20857 loc = this.getLocation(oTarget);
20858 this.locationCache[oTarget.id] = loc;
20866 oTarget.cursorIsOver = loc.contains( pt );
20868 // DragDrop is using this as a sanity check for the initial mousedown
20869 // in this case we are done. In POINT mode, if the drag obj has no
20870 // contraints, we are also done. Otherwise we need to evaluate the
20871 // location of the target as related to the actual location of the
20872 // dragged element.
20873 var dc = this.dragCurrent;
20874 if (!dc || !dc.getTargetCoord ||
20875 (!intersect && !dc.constrainX && !dc.constrainY)) {
20876 return oTarget.cursorIsOver;
20879 oTarget.overlap = null;
20881 // Get the current location of the drag element, this is the
20882 // location of the mouse event less the delta that represents
20883 // where the original mousedown happened on the element. We
20884 // need to consider constraints and ticks as well.
20885 var pos = dc.getTargetCoord(pt.x, pt.y);
20887 var el = dc.getDragEl();
20888 var curRegion = new Roo.lib.Region( pos.y,
20889 pos.x + el.offsetWidth,
20890 pos.y + el.offsetHeight,
20893 var overlap = curRegion.intersect(loc);
20896 oTarget.overlap = overlap;
20897 return (intersect) ? true : oTarget.cursorIsOver;
20904 * unload event handler
20905 * @method _onUnload
20909 _onUnload: function(e, me) {
20910 Roo.dd.DragDropMgr.unregAll();
20914 * Cleans up the drag and drop events and objects.
20919 unregAll: function() {
20921 if (this.dragCurrent) {
20923 this.dragCurrent = null;
20926 this._execOnAll("unreg", []);
20928 for (i in this.elementCache) {
20929 delete this.elementCache[i];
20932 this.elementCache = {};
20937 * A cache of DOM elements
20938 * @property elementCache
20945 * Get the wrapper for the DOM element specified
20946 * @method getElWrapper
20947 * @param {String} id the id of the element to get
20948 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20950 * @deprecated This wrapper isn't that useful
20953 getElWrapper: function(id) {
20954 var oWrapper = this.elementCache[id];
20955 if (!oWrapper || !oWrapper.el) {
20956 oWrapper = this.elementCache[id] =
20957 new this.ElementWrapper(Roo.getDom(id));
20963 * Returns the actual DOM element
20964 * @method getElement
20965 * @param {String} id the id of the elment to get
20966 * @return {Object} The element
20967 * @deprecated use Roo.getDom instead
20970 getElement: function(id) {
20971 return Roo.getDom(id);
20975 * Returns the style property for the DOM element (i.e.,
20976 * document.getElById(id).style)
20978 * @param {String} id the id of the elment to get
20979 * @return {Object} The style property of the element
20980 * @deprecated use Roo.getDom instead
20983 getCss: function(id) {
20984 var el = Roo.getDom(id);
20985 return (el) ? el.style : null;
20989 * Inner class for cached elements
20990 * @class DragDropMgr.ElementWrapper
20995 ElementWrapper: function(el) {
21000 this.el = el || null;
21005 this.id = this.el && el.id;
21007 * A reference to the style property
21010 this.css = this.el && el.style;
21014 * Returns the X position of an html element
21016 * @param el the element for which to get the position
21017 * @return {int} the X coordinate
21019 * @deprecated use Roo.lib.Dom.getX instead
21022 getPosX: function(el) {
21023 return Roo.lib.Dom.getX(el);
21027 * Returns the Y position of an html element
21029 * @param el the element for which to get the position
21030 * @return {int} the Y coordinate
21031 * @deprecated use Roo.lib.Dom.getY instead
21034 getPosY: function(el) {
21035 return Roo.lib.Dom.getY(el);
21039 * Swap two nodes. In IE, we use the native method, for others we
21040 * emulate the IE behavior
21042 * @param n1 the first node to swap
21043 * @param n2 the other node to swap
21046 swapNode: function(n1, n2) {
21050 var p = n2.parentNode;
21051 var s = n2.nextSibling;
21054 p.insertBefore(n1, n2);
21055 } else if (n2 == n1.nextSibling) {
21056 p.insertBefore(n2, n1);
21058 n1.parentNode.replaceChild(n2, n1);
21059 p.insertBefore(n1, s);
21065 * Returns the current scroll position
21066 * @method getScroll
21070 getScroll: function () {
21071 var t, l, dde=document.documentElement, db=document.body;
21072 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21074 l = dde.scrollLeft;
21081 return { top: t, left: l };
21085 * Returns the specified element style property
21087 * @param {HTMLElement} el the element
21088 * @param {string} styleProp the style property
21089 * @return {string} The value of the style property
21090 * @deprecated use Roo.lib.Dom.getStyle
21093 getStyle: function(el, styleProp) {
21094 return Roo.fly(el).getStyle(styleProp);
21098 * Gets the scrollTop
21099 * @method getScrollTop
21100 * @return {int} the document's scrollTop
21103 getScrollTop: function () { return this.getScroll().top; },
21106 * Gets the scrollLeft
21107 * @method getScrollLeft
21108 * @return {int} the document's scrollTop
21111 getScrollLeft: function () { return this.getScroll().left; },
21114 * Sets the x/y position of an element to the location of the
21117 * @param {HTMLElement} moveEl The element to move
21118 * @param {HTMLElement} targetEl The position reference element
21121 moveToEl: function (moveEl, targetEl) {
21122 var aCoord = Roo.lib.Dom.getXY(targetEl);
21123 Roo.lib.Dom.setXY(moveEl, aCoord);
21127 * Numeric array sort function
21128 * @method numericSort
21131 numericSort: function(a, b) { return (a - b); },
21135 * @property _timeoutCount
21142 * Trying to make the load order less important. Without this we get
21143 * an error if this file is loaded before the Event Utility.
21144 * @method _addListeners
21148 _addListeners: function() {
21149 var DDM = Roo.dd.DDM;
21150 if ( Roo.lib.Event && document ) {
21153 if (DDM._timeoutCount > 2000) {
21155 setTimeout(DDM._addListeners, 10);
21156 if (document && document.body) {
21157 DDM._timeoutCount += 1;
21164 * Recursively searches the immediate parent and all child nodes for
21165 * the handle element in order to determine wheter or not it was
21167 * @method handleWasClicked
21168 * @param node the html element to inspect
21171 handleWasClicked: function(node, id) {
21172 if (this.isHandle(id, node.id)) {
21175 // check to see if this is a text node child of the one we want
21176 var p = node.parentNode;
21179 if (this.isHandle(id, p.id)) {
21194 // shorter alias, save a few bytes
21195 Roo.dd.DDM = Roo.dd.DragDropMgr;
21196 Roo.dd.DDM._addListeners();
21200 * Ext JS Library 1.1.1
21201 * Copyright(c) 2006-2007, Ext JS, LLC.
21203 * Originally Released Under LGPL - original licence link has changed is not relivant.
21206 * <script type="text/javascript">
21211 * A DragDrop implementation where the linked element follows the
21212 * mouse cursor during a drag.
21213 * @extends Roo.dd.DragDrop
21215 * @param {String} id the id of the linked element
21216 * @param {String} sGroup the group of related DragDrop items
21217 * @param {object} config an object containing configurable attributes
21218 * Valid properties for DD:
21221 Roo.dd.DD = function(id, sGroup, config) {
21223 this.init(id, sGroup, config);
21227 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21230 * When set to true, the utility automatically tries to scroll the browser
21231 * window wehn a drag and drop element is dragged near the viewport boundary.
21232 * Defaults to true.
21239 * Sets the pointer offset to the distance between the linked element's top
21240 * left corner and the location the element was clicked
21241 * @method autoOffset
21242 * @param {int} iPageX the X coordinate of the click
21243 * @param {int} iPageY the Y coordinate of the click
21245 autoOffset: function(iPageX, iPageY) {
21246 var x = iPageX - this.startPageX;
21247 var y = iPageY - this.startPageY;
21248 this.setDelta(x, y);
21252 * Sets the pointer offset. You can call this directly to force the
21253 * offset to be in a particular location (e.g., pass in 0,0 to set it
21254 * to the center of the object)
21256 * @param {int} iDeltaX the distance from the left
21257 * @param {int} iDeltaY the distance from the top
21259 setDelta: function(iDeltaX, iDeltaY) {
21260 this.deltaX = iDeltaX;
21261 this.deltaY = iDeltaY;
21265 * Sets the drag element to the location of the mousedown or click event,
21266 * maintaining the cursor location relative to the location on the element
21267 * that was clicked. Override this if you want to place the element in a
21268 * location other than where the cursor is.
21269 * @method setDragElPos
21270 * @param {int} iPageX the X coordinate of the mousedown or drag event
21271 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21273 setDragElPos: function(iPageX, iPageY) {
21274 // the first time we do this, we are going to check to make sure
21275 // the element has css positioning
21277 var el = this.getDragEl();
21278 this.alignElWithMouse(el, iPageX, iPageY);
21282 * Sets the element to the location of the mousedown or click event,
21283 * maintaining the cursor location relative to the location on the element
21284 * that was clicked. Override this if you want to place the element in a
21285 * location other than where the cursor is.
21286 * @method alignElWithMouse
21287 * @param {HTMLElement} el the element to move
21288 * @param {int} iPageX the X coordinate of the mousedown or drag event
21289 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21291 alignElWithMouse: function(el, iPageX, iPageY) {
21292 var oCoord = this.getTargetCoord(iPageX, iPageY);
21293 var fly = el.dom ? el : Roo.fly(el);
21294 if (!this.deltaSetXY) {
21295 var aCoord = [oCoord.x, oCoord.y];
21297 var newLeft = fly.getLeft(true);
21298 var newTop = fly.getTop(true);
21299 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21301 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21304 this.cachePosition(oCoord.x, oCoord.y);
21305 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21310 * Saves the most recent position so that we can reset the constraints and
21311 * tick marks on-demand. We need to know this so that we can calculate the
21312 * number of pixels the element is offset from its original position.
21313 * @method cachePosition
21314 * @param iPageX the current x position (optional, this just makes it so we
21315 * don't have to look it up again)
21316 * @param iPageY the current y position (optional, this just makes it so we
21317 * don't have to look it up again)
21319 cachePosition: function(iPageX, iPageY) {
21321 this.lastPageX = iPageX;
21322 this.lastPageY = iPageY;
21324 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21325 this.lastPageX = aCoord[0];
21326 this.lastPageY = aCoord[1];
21331 * Auto-scroll the window if the dragged object has been moved beyond the
21332 * visible window boundary.
21333 * @method autoScroll
21334 * @param {int} x the drag element's x position
21335 * @param {int} y the drag element's y position
21336 * @param {int} h the height of the drag element
21337 * @param {int} w the width of the drag element
21340 autoScroll: function(x, y, h, w) {
21343 // The client height
21344 var clientH = Roo.lib.Dom.getViewWidth();
21346 // The client width
21347 var clientW = Roo.lib.Dom.getViewHeight();
21349 // The amt scrolled down
21350 var st = this.DDM.getScrollTop();
21352 // The amt scrolled right
21353 var sl = this.DDM.getScrollLeft();
21355 // Location of the bottom of the element
21358 // Location of the right of the element
21361 // The distance from the cursor to the bottom of the visible area,
21362 // adjusted so that we don't scroll if the cursor is beyond the
21363 // element drag constraints
21364 var toBot = (clientH + st - y - this.deltaY);
21366 // The distance from the cursor to the right of the visible area
21367 var toRight = (clientW + sl - x - this.deltaX);
21370 // How close to the edge the cursor must be before we scroll
21371 // var thresh = (document.all) ? 100 : 40;
21374 // How many pixels to scroll per autoscroll op. This helps to reduce
21375 // clunky scrolling. IE is more sensitive about this ... it needs this
21376 // value to be higher.
21377 var scrAmt = (document.all) ? 80 : 30;
21379 // Scroll down if we are near the bottom of the visible page and the
21380 // obj extends below the crease
21381 if ( bot > clientH && toBot < thresh ) {
21382 window.scrollTo(sl, st + scrAmt);
21385 // Scroll up if the window is scrolled down and the top of the object
21386 // goes above the top border
21387 if ( y < st && st > 0 && y - st < thresh ) {
21388 window.scrollTo(sl, st - scrAmt);
21391 // Scroll right if the obj is beyond the right border and the cursor is
21392 // near the border.
21393 if ( right > clientW && toRight < thresh ) {
21394 window.scrollTo(sl + scrAmt, st);
21397 // Scroll left if the window has been scrolled to the right and the obj
21398 // extends past the left border
21399 if ( x < sl && sl > 0 && x - sl < thresh ) {
21400 window.scrollTo(sl - scrAmt, st);
21406 * Finds the location the element should be placed if we want to move
21407 * it to where the mouse location less the click offset would place us.
21408 * @method getTargetCoord
21409 * @param {int} iPageX the X coordinate of the click
21410 * @param {int} iPageY the Y coordinate of the click
21411 * @return an object that contains the coordinates (Object.x and Object.y)
21414 getTargetCoord: function(iPageX, iPageY) {
21417 var x = iPageX - this.deltaX;
21418 var y = iPageY - this.deltaY;
21420 if (this.constrainX) {
21421 if (x < this.minX) { x = this.minX; }
21422 if (x > this.maxX) { x = this.maxX; }
21425 if (this.constrainY) {
21426 if (y < this.minY) { y = this.minY; }
21427 if (y > this.maxY) { y = this.maxY; }
21430 x = this.getTick(x, this.xTicks);
21431 y = this.getTick(y, this.yTicks);
21438 * Sets up config options specific to this class. Overrides
21439 * Roo.dd.DragDrop, but all versions of this method through the
21440 * inheritance chain are called
21442 applyConfig: function() {
21443 Roo.dd.DD.superclass.applyConfig.call(this);
21444 this.scroll = (this.config.scroll !== false);
21448 * Event that fires prior to the onMouseDown event. Overrides
21451 b4MouseDown: function(e) {
21452 // this.resetConstraints();
21453 this.autoOffset(e.getPageX(),
21458 * Event that fires prior to the onDrag event. Overrides
21461 b4Drag: function(e) {
21462 this.setDragElPos(e.getPageX(),
21466 toString: function() {
21467 return ("DD " + this.id);
21470 //////////////////////////////////////////////////////////////////////////
21471 // Debugging ygDragDrop events that can be overridden
21472 //////////////////////////////////////////////////////////////////////////
21474 startDrag: function(x, y) {
21477 onDrag: function(e) {
21480 onDragEnter: function(e, id) {
21483 onDragOver: function(e, id) {
21486 onDragOut: function(e, id) {
21489 onDragDrop: function(e, id) {
21492 endDrag: function(e) {
21499 * Ext JS Library 1.1.1
21500 * Copyright(c) 2006-2007, Ext JS, LLC.
21502 * Originally Released Under LGPL - original licence link has changed is not relivant.
21505 * <script type="text/javascript">
21509 * @class Roo.dd.DDProxy
21510 * A DragDrop implementation that inserts an empty, bordered div into
21511 * the document that follows the cursor during drag operations. At the time of
21512 * the click, the frame div is resized to the dimensions of the linked html
21513 * element, and moved to the exact location of the linked element.
21515 * References to the "frame" element refer to the single proxy element that
21516 * was created to be dragged in place of all DDProxy elements on the
21519 * @extends Roo.dd.DD
21521 * @param {String} id the id of the linked html element
21522 * @param {String} sGroup the group of related DragDrop objects
21523 * @param {object} config an object containing configurable attributes
21524 * Valid properties for DDProxy in addition to those in DragDrop:
21525 * resizeFrame, centerFrame, dragElId
21527 Roo.dd.DDProxy = function(id, sGroup, config) {
21529 this.init(id, sGroup, config);
21535 * The default drag frame div id
21536 * @property Roo.dd.DDProxy.dragElId
21540 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21542 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21545 * By default we resize the drag frame to be the same size as the element
21546 * we want to drag (this is to get the frame effect). We can turn it off
21547 * if we want a different behavior.
21548 * @property resizeFrame
21554 * By default the frame is positioned exactly where the drag element is, so
21555 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21556 * you do not have constraints on the obj is to have the drag frame centered
21557 * around the cursor. Set centerFrame to true for this effect.
21558 * @property centerFrame
21561 centerFrame: false,
21564 * Creates the proxy element if it does not yet exist
21565 * @method createFrame
21567 createFrame: function() {
21569 var body = document.body;
21571 if (!body || !body.firstChild) {
21572 setTimeout( function() { self.createFrame(); }, 50 );
21576 var div = this.getDragEl();
21579 div = document.createElement("div");
21580 div.id = this.dragElId;
21583 s.position = "absolute";
21584 s.visibility = "hidden";
21586 s.border = "2px solid #aaa";
21589 // appendChild can blow up IE if invoked prior to the window load event
21590 // while rendering a table. It is possible there are other scenarios
21591 // that would cause this to happen as well.
21592 body.insertBefore(div, body.firstChild);
21597 * Initialization for the drag frame element. Must be called in the
21598 * constructor of all subclasses
21599 * @method initFrame
21601 initFrame: function() {
21602 this.createFrame();
21605 applyConfig: function() {
21606 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21608 this.resizeFrame = (this.config.resizeFrame !== false);
21609 this.centerFrame = (this.config.centerFrame);
21610 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21614 * Resizes the drag frame to the dimensions of the clicked object, positions
21615 * it over the object, and finally displays it
21616 * @method showFrame
21617 * @param {int} iPageX X click position
21618 * @param {int} iPageY Y click position
21621 showFrame: function(iPageX, iPageY) {
21622 var el = this.getEl();
21623 var dragEl = this.getDragEl();
21624 var s = dragEl.style;
21626 this._resizeProxy();
21628 if (this.centerFrame) {
21629 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21630 Math.round(parseInt(s.height, 10)/2) );
21633 this.setDragElPos(iPageX, iPageY);
21635 Roo.fly(dragEl).show();
21639 * The proxy is automatically resized to the dimensions of the linked
21640 * element when a drag is initiated, unless resizeFrame is set to false
21641 * @method _resizeProxy
21644 _resizeProxy: function() {
21645 if (this.resizeFrame) {
21646 var el = this.getEl();
21647 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21651 // overrides Roo.dd.DragDrop
21652 b4MouseDown: function(e) {
21653 var x = e.getPageX();
21654 var y = e.getPageY();
21655 this.autoOffset(x, y);
21656 this.setDragElPos(x, y);
21659 // overrides Roo.dd.DragDrop
21660 b4StartDrag: function(x, y) {
21661 // show the drag frame
21662 this.showFrame(x, y);
21665 // overrides Roo.dd.DragDrop
21666 b4EndDrag: function(e) {
21667 Roo.fly(this.getDragEl()).hide();
21670 // overrides Roo.dd.DragDrop
21671 // By default we try to move the element to the last location of the frame.
21672 // This is so that the default behavior mirrors that of Roo.dd.DD.
21673 endDrag: function(e) {
21675 var lel = this.getEl();
21676 var del = this.getDragEl();
21678 // Show the drag frame briefly so we can get its position
21679 del.style.visibility = "";
21682 // Hide the linked element before the move to get around a Safari
21684 lel.style.visibility = "hidden";
21685 Roo.dd.DDM.moveToEl(lel, del);
21686 del.style.visibility = "hidden";
21687 lel.style.visibility = "";
21692 beforeMove : function(){
21696 afterDrag : function(){
21700 toString: function() {
21701 return ("DDProxy " + this.id);
21707 * Ext JS Library 1.1.1
21708 * Copyright(c) 2006-2007, Ext JS, LLC.
21710 * Originally Released Under LGPL - original licence link has changed is not relivant.
21713 * <script type="text/javascript">
21717 * @class Roo.dd.DDTarget
21718 * A DragDrop implementation that does not move, but can be a drop
21719 * target. You would get the same result by simply omitting implementation
21720 * for the event callbacks, but this way we reduce the processing cost of the
21721 * event listener and the callbacks.
21722 * @extends Roo.dd.DragDrop
21724 * @param {String} id the id of the element that is a drop target
21725 * @param {String} sGroup the group of related DragDrop objects
21726 * @param {object} config an object containing configurable attributes
21727 * Valid properties for DDTarget in addition to those in
21731 Roo.dd.DDTarget = function(id, sGroup, config) {
21733 this.initTarget(id, sGroup, config);
21735 if (config && (config.listeners || config.events)) {
21736 Roo.dd.DragDrop.superclass.constructor.call(this, {
21737 listeners : config.listeners || {},
21738 events : config.events || {}
21743 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21744 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21745 toString: function() {
21746 return ("DDTarget " + this.id);
21751 * Ext JS Library 1.1.1
21752 * Copyright(c) 2006-2007, Ext JS, LLC.
21754 * Originally Released Under LGPL - original licence link has changed is not relivant.
21757 * <script type="text/javascript">
21762 * @class Roo.dd.ScrollManager
21763 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21764 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21767 Roo.dd.ScrollManager = function(){
21768 var ddm = Roo.dd.DragDropMgr;
21775 var onStop = function(e){
21780 var triggerRefresh = function(){
21781 if(ddm.dragCurrent){
21782 ddm.refreshCache(ddm.dragCurrent.groups);
21786 var doScroll = function(){
21787 if(ddm.dragCurrent){
21788 var dds = Roo.dd.ScrollManager;
21790 if(proc.el.scroll(proc.dir, dds.increment)){
21794 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21799 var clearProc = function(){
21801 clearInterval(proc.id);
21808 var startProc = function(el, dir){
21809 Roo.log('scroll startproc');
21813 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21816 var onFire = function(e, isDrop){
21818 if(isDrop || !ddm.dragCurrent){ return; }
21819 var dds = Roo.dd.ScrollManager;
21820 if(!dragEl || dragEl != ddm.dragCurrent){
21821 dragEl = ddm.dragCurrent;
21822 // refresh regions on drag start
21823 dds.refreshCache();
21826 var xy = Roo.lib.Event.getXY(e);
21827 var pt = new Roo.lib.Point(xy[0], xy[1]);
21828 for(var id in els){
21829 var el = els[id], r = el._region;
21830 if(r && r.contains(pt) && el.isScrollable()){
21831 if(r.bottom - pt.y <= dds.thresh){
21833 startProc(el, "down");
21836 }else if(r.right - pt.x <= dds.thresh){
21838 startProc(el, "left");
21841 }else if(pt.y - r.top <= dds.thresh){
21843 startProc(el, "up");
21846 }else if(pt.x - r.left <= dds.thresh){
21848 startProc(el, "right");
21857 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21858 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21862 * Registers new overflow element(s) to auto scroll
21863 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21865 register : function(el){
21866 if(el instanceof Array){
21867 for(var i = 0, len = el.length; i < len; i++) {
21868 this.register(el[i]);
21874 Roo.dd.ScrollManager.els = els;
21878 * Unregisters overflow element(s) so they are no longer scrolled
21879 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21881 unregister : function(el){
21882 if(el instanceof Array){
21883 for(var i = 0, len = el.length; i < len; i++) {
21884 this.unregister(el[i]);
21893 * The number of pixels from the edge of a container the pointer needs to be to
21894 * trigger scrolling (defaults to 25)
21900 * The number of pixels to scroll in each scroll increment (defaults to 50)
21906 * The frequency of scrolls in milliseconds (defaults to 500)
21912 * True to animate the scroll (defaults to true)
21918 * The animation duration in seconds -
21919 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21925 * Manually trigger a cache refresh.
21927 refreshCache : function(){
21928 for(var id in els){
21929 if(typeof els[id] == 'object'){ // for people extending the object prototype
21930 els[id]._region = els[id].getRegion();
21937 * Ext JS Library 1.1.1
21938 * Copyright(c) 2006-2007, Ext JS, LLC.
21940 * Originally Released Under LGPL - original licence link has changed is not relivant.
21943 * <script type="text/javascript">
21948 * @class Roo.dd.Registry
21949 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21950 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21953 Roo.dd.Registry = function(){
21956 var autoIdSeed = 0;
21958 var getId = function(el, autogen){
21959 if(typeof el == "string"){
21963 if(!id && autogen !== false){
21964 id = "roodd-" + (++autoIdSeed);
21972 * Register a drag drop element
21973 * @param {String|HTMLElement} element The id or DOM node to register
21974 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21975 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21976 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21977 * populated in the data object (if applicable):
21979 Value Description<br />
21980 --------- ------------------------------------------<br />
21981 handles Array of DOM nodes that trigger dragging<br />
21982 for the element being registered<br />
21983 isHandle True if the element passed in triggers<br />
21984 dragging itself, else false
21987 register : function(el, data){
21989 if(typeof el == "string"){
21990 el = document.getElementById(el);
21993 elements[getId(el)] = data;
21994 if(data.isHandle !== false){
21995 handles[data.ddel.id] = data;
21998 var hs = data.handles;
21999 for(var i = 0, len = hs.length; i < len; i++){
22000 handles[getId(hs[i])] = data;
22006 * Unregister a drag drop element
22007 * @param {String|HTMLElement} element The id or DOM node to unregister
22009 unregister : function(el){
22010 var id = getId(el, false);
22011 var data = elements[id];
22013 delete elements[id];
22015 var hs = data.handles;
22016 for(var i = 0, len = hs.length; i < len; i++){
22017 delete handles[getId(hs[i], false)];
22024 * Returns the handle registered for a DOM Node by id
22025 * @param {String|HTMLElement} id The DOM node or id to look up
22026 * @return {Object} handle The custom handle data
22028 getHandle : function(id){
22029 if(typeof id != "string"){ // must be element?
22032 return handles[id];
22036 * Returns the handle that is registered for the DOM node that is the target of the event
22037 * @param {Event} e The event
22038 * @return {Object} handle The custom handle data
22040 getHandleFromEvent : function(e){
22041 var t = Roo.lib.Event.getTarget(e);
22042 return t ? handles[t.id] : null;
22046 * Returns a custom data object that is registered for a DOM node by id
22047 * @param {String|HTMLElement} id The DOM node or id to look up
22048 * @return {Object} data The custom data
22050 getTarget : function(id){
22051 if(typeof id != "string"){ // must be element?
22054 return elements[id];
22058 * Returns a custom data object that is registered for the DOM node that is the target of the event
22059 * @param {Event} e The event
22060 * @return {Object} data The custom data
22062 getTargetFromEvent : function(e){
22063 var t = Roo.lib.Event.getTarget(e);
22064 return t ? elements[t.id] || handles[t.id] : null;
22069 * Ext JS Library 1.1.1
22070 * Copyright(c) 2006-2007, Ext JS, LLC.
22072 * Originally Released Under LGPL - original licence link has changed is not relivant.
22075 * <script type="text/javascript">
22080 * @class Roo.dd.StatusProxy
22081 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22082 * default drag proxy used by all Roo.dd components.
22084 * @param {Object} config
22086 Roo.dd.StatusProxy = function(config){
22087 Roo.apply(this, config);
22088 this.id = this.id || Roo.id();
22089 this.el = new Roo.Layer({
22091 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22092 {tag: "div", cls: "x-dd-drop-icon"},
22093 {tag: "div", cls: "x-dd-drag-ghost"}
22096 shadow: !config || config.shadow !== false
22098 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22099 this.dropStatus = this.dropNotAllowed;
22102 Roo.dd.StatusProxy.prototype = {
22104 * @cfg {String} dropAllowed
22105 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22107 dropAllowed : "x-dd-drop-ok",
22109 * @cfg {String} dropNotAllowed
22110 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22112 dropNotAllowed : "x-dd-drop-nodrop",
22115 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22116 * over the current target element.
22117 * @param {String} cssClass The css class for the new drop status indicator image
22119 setStatus : function(cssClass){
22120 cssClass = cssClass || this.dropNotAllowed;
22121 if(this.dropStatus != cssClass){
22122 this.el.replaceClass(this.dropStatus, cssClass);
22123 this.dropStatus = cssClass;
22128 * Resets the status indicator to the default dropNotAllowed value
22129 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22131 reset : function(clearGhost){
22132 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22133 this.dropStatus = this.dropNotAllowed;
22135 this.ghost.update("");
22140 * Updates the contents of the ghost element
22141 * @param {String} html The html that will replace the current innerHTML of the ghost element
22143 update : function(html){
22144 if(typeof html == "string"){
22145 this.ghost.update(html);
22147 this.ghost.update("");
22148 html.style.margin = "0";
22149 this.ghost.dom.appendChild(html);
22151 // ensure float = none set?? cant remember why though.
22152 var el = this.ghost.dom.firstChild;
22154 Roo.fly(el).setStyle('float', 'none');
22159 * Returns the underlying proxy {@link Roo.Layer}
22160 * @return {Roo.Layer} el
22162 getEl : function(){
22167 * Returns the ghost element
22168 * @return {Roo.Element} el
22170 getGhost : function(){
22176 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22178 hide : function(clear){
22186 * Stops the repair animation if it's currently running
22189 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22195 * Displays this proxy
22202 * Force the Layer to sync its shadow and shim positions to the element
22209 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22210 * invalid drop operation by the item being dragged.
22211 * @param {Array} xy The XY position of the element ([x, y])
22212 * @param {Function} callback The function to call after the repair is complete
22213 * @param {Object} scope The scope in which to execute the callback
22215 repair : function(xy, callback, scope){
22216 this.callback = callback;
22217 this.scope = scope;
22218 if(xy && this.animRepair !== false){
22219 this.el.addClass("x-dd-drag-repair");
22220 this.el.hideUnders(true);
22221 this.anim = this.el.shift({
22222 duration: this.repairDuration || .5,
22226 callback: this.afterRepair,
22230 this.afterRepair();
22235 afterRepair : function(){
22237 if(typeof this.callback == "function"){
22238 this.callback.call(this.scope || this);
22240 this.callback = null;
22245 * Ext JS Library 1.1.1
22246 * Copyright(c) 2006-2007, Ext JS, LLC.
22248 * Originally Released Under LGPL - original licence link has changed is not relivant.
22251 * <script type="text/javascript">
22255 * @class Roo.dd.DragSource
22256 * @extends Roo.dd.DDProxy
22257 * A simple class that provides the basic implementation needed to make any element draggable.
22259 * @param {String/HTMLElement/Element} el The container element
22260 * @param {Object} config
22262 Roo.dd.DragSource = function(el, config){
22263 this.el = Roo.get(el);
22264 this.dragData = {};
22266 Roo.apply(this, config);
22269 this.proxy = new Roo.dd.StatusProxy();
22272 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22273 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22275 this.dragging = false;
22278 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22280 * @cfg {String} dropAllowed
22281 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22283 dropAllowed : "x-dd-drop-ok",
22285 * @cfg {String} dropNotAllowed
22286 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22288 dropNotAllowed : "x-dd-drop-nodrop",
22291 * Returns the data object associated with this drag source
22292 * @return {Object} data An object containing arbitrary data
22294 getDragData : function(e){
22295 return this.dragData;
22299 onDragEnter : function(e, id){
22300 var target = Roo.dd.DragDropMgr.getDDById(id);
22301 this.cachedTarget = target;
22302 if(this.beforeDragEnter(target, e, id) !== false){
22303 if(target.isNotifyTarget){
22304 var status = target.notifyEnter(this, e, this.dragData);
22305 this.proxy.setStatus(status);
22307 this.proxy.setStatus(this.dropAllowed);
22310 if(this.afterDragEnter){
22312 * An empty function by default, but provided so that you can perform a custom action
22313 * when the dragged item enters the drop target by providing an implementation.
22314 * @param {Roo.dd.DragDrop} target The drop target
22315 * @param {Event} e The event object
22316 * @param {String} id The id of the dragged element
22317 * @method afterDragEnter
22319 this.afterDragEnter(target, e, id);
22325 * An empty function by default, but provided so that you can perform a custom action
22326 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22327 * @param {Roo.dd.DragDrop} target The drop target
22328 * @param {Event} e The event object
22329 * @param {String} id The id of the dragged element
22330 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22332 beforeDragEnter : function(target, e, id){
22337 alignElWithMouse: function() {
22338 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22343 onDragOver : function(e, id){
22344 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22345 if(this.beforeDragOver(target, e, id) !== false){
22346 if(target.isNotifyTarget){
22347 var status = target.notifyOver(this, e, this.dragData);
22348 this.proxy.setStatus(status);
22351 if(this.afterDragOver){
22353 * An empty function by default, but provided so that you can perform a custom action
22354 * while the dragged item is over the drop target by providing an implementation.
22355 * @param {Roo.dd.DragDrop} target The drop target
22356 * @param {Event} e The event object
22357 * @param {String} id The id of the dragged element
22358 * @method afterDragOver
22360 this.afterDragOver(target, e, id);
22366 * An empty function by default, but provided so that you can perform a custom action
22367 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22368 * @param {Roo.dd.DragDrop} target The drop target
22369 * @param {Event} e The event object
22370 * @param {String} id The id of the dragged element
22371 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22373 beforeDragOver : function(target, e, id){
22378 onDragOut : function(e, id){
22379 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22380 if(this.beforeDragOut(target, e, id) !== false){
22381 if(target.isNotifyTarget){
22382 target.notifyOut(this, e, this.dragData);
22384 this.proxy.reset();
22385 if(this.afterDragOut){
22387 * An empty function by default, but provided so that you can perform a custom action
22388 * after the dragged item is dragged out of the target without dropping.
22389 * @param {Roo.dd.DragDrop} target The drop target
22390 * @param {Event} e The event object
22391 * @param {String} id The id of the dragged element
22392 * @method afterDragOut
22394 this.afterDragOut(target, e, id);
22397 this.cachedTarget = null;
22401 * An empty function by default, but provided so that you can perform a custom action before the dragged
22402 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22403 * @param {Roo.dd.DragDrop} target The drop target
22404 * @param {Event} e The event object
22405 * @param {String} id The id of the dragged element
22406 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22408 beforeDragOut : function(target, e, id){
22413 onDragDrop : function(e, id){
22414 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22415 if(this.beforeDragDrop(target, e, id) !== false){
22416 if(target.isNotifyTarget){
22417 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22418 this.onValidDrop(target, e, id);
22420 this.onInvalidDrop(target, e, id);
22423 this.onValidDrop(target, e, id);
22426 if(this.afterDragDrop){
22428 * An empty function by default, but provided so that you can perform a custom action
22429 * after a valid drag drop has occurred by providing an implementation.
22430 * @param {Roo.dd.DragDrop} target The drop target
22431 * @param {Event} e The event object
22432 * @param {String} id The id of the dropped element
22433 * @method afterDragDrop
22435 this.afterDragDrop(target, e, id);
22438 delete this.cachedTarget;
22442 * An empty function by default, but provided so that you can perform a custom action before the dragged
22443 * item is dropped onto the target and optionally cancel the onDragDrop.
22444 * @param {Roo.dd.DragDrop} target The drop target
22445 * @param {Event} e The event object
22446 * @param {String} id The id of the dragged element
22447 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22449 beforeDragDrop : function(target, e, id){
22454 onValidDrop : function(target, e, id){
22456 if(this.afterValidDrop){
22458 * An empty function by default, but provided so that you can perform a custom action
22459 * after a valid drop has occurred by providing an implementation.
22460 * @param {Object} target The target DD
22461 * @param {Event} e The event object
22462 * @param {String} id The id of the dropped element
22463 * @method afterInvalidDrop
22465 this.afterValidDrop(target, e, id);
22470 getRepairXY : function(e, data){
22471 return this.el.getXY();
22475 onInvalidDrop : function(target, e, id){
22476 this.beforeInvalidDrop(target, e, id);
22477 if(this.cachedTarget){
22478 if(this.cachedTarget.isNotifyTarget){
22479 this.cachedTarget.notifyOut(this, e, this.dragData);
22481 this.cacheTarget = null;
22483 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22485 if(this.afterInvalidDrop){
22487 * An empty function by default, but provided so that you can perform a custom action
22488 * after an invalid drop has occurred by providing an implementation.
22489 * @param {Event} e The event object
22490 * @param {String} id The id of the dropped element
22491 * @method afterInvalidDrop
22493 this.afterInvalidDrop(e, id);
22498 afterRepair : function(){
22500 this.el.highlight(this.hlColor || "c3daf9");
22502 this.dragging = false;
22506 * An empty function by default, but provided so that you can perform a custom action after an invalid
22507 * drop has occurred.
22508 * @param {Roo.dd.DragDrop} target The drop target
22509 * @param {Event} e The event object
22510 * @param {String} id The id of the dragged element
22511 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22513 beforeInvalidDrop : function(target, e, id){
22518 handleMouseDown : function(e){
22519 if(this.dragging) {
22522 var data = this.getDragData(e);
22523 if(data && this.onBeforeDrag(data, e) !== false){
22524 this.dragData = data;
22526 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22531 * An empty function by default, but provided so that you can perform a custom action before the initial
22532 * drag event begins and optionally cancel it.
22533 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22534 * @param {Event} e The event object
22535 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22537 onBeforeDrag : function(data, e){
22542 * An empty function by default, but provided so that you can perform a custom action once the initial
22543 * drag event has begun. The drag cannot be canceled from this function.
22544 * @param {Number} x The x position of the click on the dragged object
22545 * @param {Number} y The y position of the click on the dragged object
22547 onStartDrag : Roo.emptyFn,
22549 // private - YUI override
22550 startDrag : function(x, y){
22551 this.proxy.reset();
22552 this.dragging = true;
22553 this.proxy.update("");
22554 this.onInitDrag(x, y);
22559 onInitDrag : function(x, y){
22560 var clone = this.el.dom.cloneNode(true);
22561 clone.id = Roo.id(); // prevent duplicate ids
22562 this.proxy.update(clone);
22563 this.onStartDrag(x, y);
22568 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22569 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22571 getProxy : function(){
22576 * Hides the drag source's {@link Roo.dd.StatusProxy}
22578 hideProxy : function(){
22580 this.proxy.reset(true);
22581 this.dragging = false;
22585 triggerCacheRefresh : function(){
22586 Roo.dd.DDM.refreshCache(this.groups);
22589 // private - override to prevent hiding
22590 b4EndDrag: function(e) {
22593 // private - override to prevent moving
22594 endDrag : function(e){
22595 this.onEndDrag(this.dragData, e);
22599 onEndDrag : function(data, e){
22602 // private - pin to cursor
22603 autoOffset : function(x, y) {
22604 this.setDelta(-12, -20);
22608 * Ext JS Library 1.1.1
22609 * Copyright(c) 2006-2007, Ext JS, LLC.
22611 * Originally Released Under LGPL - original licence link has changed is not relivant.
22614 * <script type="text/javascript">
22619 * @class Roo.dd.DropTarget
22620 * @extends Roo.dd.DDTarget
22621 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22622 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22624 * @param {String/HTMLElement/Element} el The container element
22625 * @param {Object} config
22627 Roo.dd.DropTarget = function(el, config){
22628 this.el = Roo.get(el);
22630 var listeners = false; ;
22631 if (config && config.listeners) {
22632 listeners= config.listeners;
22633 delete config.listeners;
22635 Roo.apply(this, config);
22637 if(this.containerScroll){
22638 Roo.dd.ScrollManager.register(this.el);
22642 * @scope Roo.dd.DropTarget
22647 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22648 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22649 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22651 * IMPORTANT : it should set this.valid to true|false
22653 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22654 * @param {Event} e The event
22655 * @param {Object} data An object containing arbitrary data supplied by the drag source
22661 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22662 * This method will be called on every mouse movement while the drag source is over the drop target.
22663 * This default implementation simply returns the dropAllowed config value.
22665 * IMPORTANT : it should set this.valid to true|false
22667 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22668 * @param {Event} e The event
22669 * @param {Object} data An object containing arbitrary data supplied by the drag source
22675 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22676 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22677 * overClass (if any) from the drop element.
22680 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22681 * @param {Event} e The event
22682 * @param {Object} data An object containing arbitrary data supplied by the drag source
22688 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22689 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22690 * implementation that does something to process the drop event and returns true so that the drag source's
22691 * repair action does not run.
22693 * IMPORTANT : it should set this.success
22695 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22696 * @param {Event} e The event
22697 * @param {Object} data An object containing arbitrary data supplied by the drag source
22703 Roo.dd.DropTarget.superclass.constructor.call( this,
22705 this.ddGroup || this.group,
22708 listeners : listeners || {}
22716 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22718 * @cfg {String} overClass
22719 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22722 * @cfg {String} ddGroup
22723 * The drag drop group to handle drop events for
22727 * @cfg {String} dropAllowed
22728 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22730 dropAllowed : "x-dd-drop-ok",
22732 * @cfg {String} dropNotAllowed
22733 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22735 dropNotAllowed : "x-dd-drop-nodrop",
22737 * @cfg {boolean} success
22738 * set this after drop listener..
22742 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22743 * if the drop point is valid for over/enter..
22750 isNotifyTarget : true,
22755 notifyEnter : function(dd, e, data)
22758 this.fireEvent('enter', dd, e, data);
22759 if(this.overClass){
22760 this.el.addClass(this.overClass);
22762 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22763 this.valid ? this.dropAllowed : this.dropNotAllowed
22770 notifyOver : function(dd, e, data)
22773 this.fireEvent('over', dd, e, data);
22774 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22775 this.valid ? this.dropAllowed : this.dropNotAllowed
22782 notifyOut : function(dd, e, data)
22784 this.fireEvent('out', dd, e, data);
22785 if(this.overClass){
22786 this.el.removeClass(this.overClass);
22793 notifyDrop : function(dd, e, data)
22795 this.success = false;
22796 this.fireEvent('drop', dd, e, data);
22797 return this.success;
22801 * Ext JS Library 1.1.1
22802 * Copyright(c) 2006-2007, Ext JS, LLC.
22804 * Originally Released Under LGPL - original licence link has changed is not relivant.
22807 * <script type="text/javascript">
22812 * @class Roo.dd.DragZone
22813 * @extends Roo.dd.DragSource
22814 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22815 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22817 * @param {String/HTMLElement/Element} el The container element
22818 * @param {Object} config
22820 Roo.dd.DragZone = function(el, config){
22821 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22822 if(this.containerScroll){
22823 Roo.dd.ScrollManager.register(this.el);
22827 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22829 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22830 * for auto scrolling during drag operations.
22833 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22834 * method after a failed drop (defaults to "c3daf9" - light blue)
22838 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22839 * for a valid target to drag based on the mouse down. Override this method
22840 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22841 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22842 * @param {EventObject} e The mouse down event
22843 * @return {Object} The dragData
22845 getDragData : function(e){
22846 return Roo.dd.Registry.getHandleFromEvent(e);
22850 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22851 * this.dragData.ddel
22852 * @param {Number} x The x position of the click on the dragged object
22853 * @param {Number} y The y position of the click on the dragged object
22854 * @return {Boolean} true to continue the drag, false to cancel
22856 onInitDrag : function(x, y){
22857 this.proxy.update(this.dragData.ddel.cloneNode(true));
22858 this.onStartDrag(x, y);
22863 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22865 afterRepair : function(){
22867 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22869 this.dragging = false;
22873 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22874 * the XY of this.dragData.ddel
22875 * @param {EventObject} e The mouse up event
22876 * @return {Array} The xy location (e.g. [100, 200])
22878 getRepairXY : function(e){
22879 return Roo.Element.fly(this.dragData.ddel).getXY();
22883 * Ext JS Library 1.1.1
22884 * Copyright(c) 2006-2007, Ext JS, LLC.
22886 * Originally Released Under LGPL - original licence link has changed is not relivant.
22889 * <script type="text/javascript">
22892 * @class Roo.dd.DropZone
22893 * @extends Roo.dd.DropTarget
22894 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22895 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22897 * @param {String/HTMLElement/Element} el The container element
22898 * @param {Object} config
22900 Roo.dd.DropZone = function(el, config){
22901 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22904 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22906 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22907 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22908 * provide your own custom lookup.
22909 * @param {Event} e The event
22910 * @return {Object} data The custom data
22912 getTargetFromEvent : function(e){
22913 return Roo.dd.Registry.getTargetFromEvent(e);
22917 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22918 * that it has registered. This method has no default implementation and should be overridden to provide
22919 * node-specific processing if necessary.
22920 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22921 * {@link #getTargetFromEvent} for this node)
22922 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22923 * @param {Event} e The event
22924 * @param {Object} data An object containing arbitrary data supplied by the drag source
22926 onNodeEnter : function(n, dd, e, data){
22931 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22932 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22933 * overridden to provide the proper feedback.
22934 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22935 * {@link #getTargetFromEvent} for this node)
22936 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22937 * @param {Event} e The event
22938 * @param {Object} data An object containing arbitrary data supplied by the drag source
22939 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22940 * underlying {@link Roo.dd.StatusProxy} can be updated
22942 onNodeOver : function(n, dd, e, data){
22943 return this.dropAllowed;
22947 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22948 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22949 * node-specific processing if necessary.
22950 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22951 * {@link #getTargetFromEvent} for this node)
22952 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22953 * @param {Event} e The event
22954 * @param {Object} data An object containing arbitrary data supplied by the drag source
22956 onNodeOut : function(n, dd, e, data){
22961 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22962 * the drop node. The default implementation returns false, so it should be overridden to provide the
22963 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22964 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22965 * {@link #getTargetFromEvent} for this node)
22966 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22967 * @param {Event} e The event
22968 * @param {Object} data An object containing arbitrary data supplied by the drag source
22969 * @return {Boolean} True if the drop was valid, else false
22971 onNodeDrop : function(n, dd, e, data){
22976 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22977 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22978 * it should be overridden to provide the proper feedback if necessary.
22979 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22980 * @param {Event} e The event
22981 * @param {Object} data An object containing arbitrary data supplied by the drag source
22982 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22983 * underlying {@link Roo.dd.StatusProxy} can be updated
22985 onContainerOver : function(dd, e, data){
22986 return this.dropNotAllowed;
22990 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22991 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22992 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22993 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22994 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22995 * @param {Event} e The event
22996 * @param {Object} data An object containing arbitrary data supplied by the drag source
22997 * @return {Boolean} True if the drop was valid, else false
22999 onContainerDrop : function(dd, e, data){
23004 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23005 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
23006 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23007 * you should override this method and provide a custom implementation.
23008 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23009 * @param {Event} e The event
23010 * @param {Object} data An object containing arbitrary data supplied by the drag source
23011 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23012 * underlying {@link Roo.dd.StatusProxy} can be updated
23014 notifyEnter : function(dd, e, data){
23015 return this.dropNotAllowed;
23019 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23020 * This method will be called on every mouse movement while the drag source is over the drop zone.
23021 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23022 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23023 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23024 * registered node, it will call {@link #onContainerOver}.
23025 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23026 * @param {Event} e The event
23027 * @param {Object} data An object containing arbitrary data supplied by the drag source
23028 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23029 * underlying {@link Roo.dd.StatusProxy} can be updated
23031 notifyOver : function(dd, e, data){
23032 var n = this.getTargetFromEvent(e);
23033 if(!n){ // not over valid drop target
23034 if(this.lastOverNode){
23035 this.onNodeOut(this.lastOverNode, dd, e, data);
23036 this.lastOverNode = null;
23038 return this.onContainerOver(dd, e, data);
23040 if(this.lastOverNode != n){
23041 if(this.lastOverNode){
23042 this.onNodeOut(this.lastOverNode, dd, e, data);
23044 this.onNodeEnter(n, dd, e, data);
23045 this.lastOverNode = n;
23047 return this.onNodeOver(n, dd, e, data);
23051 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23052 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23053 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23054 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23055 * @param {Event} e The event
23056 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23058 notifyOut : function(dd, e, data){
23059 if(this.lastOverNode){
23060 this.onNodeOut(this.lastOverNode, dd, e, data);
23061 this.lastOverNode = null;
23066 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23067 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23068 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23069 * otherwise it will call {@link #onContainerDrop}.
23070 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23071 * @param {Event} e The event
23072 * @param {Object} data An object containing arbitrary data supplied by the drag source
23073 * @return {Boolean} True if the drop was valid, else false
23075 notifyDrop : function(dd, e, data){
23076 if(this.lastOverNode){
23077 this.onNodeOut(this.lastOverNode, dd, e, data);
23078 this.lastOverNode = null;
23080 var n = this.getTargetFromEvent(e);
23082 this.onNodeDrop(n, dd, e, data) :
23083 this.onContainerDrop(dd, e, data);
23087 triggerCacheRefresh : function(){
23088 Roo.dd.DDM.refreshCache(this.groups);
23092 * Ext JS Library 1.1.1
23093 * Copyright(c) 2006-2007, Ext JS, LLC.
23095 * Originally Released Under LGPL - original licence link has changed is not relivant.
23098 * <script type="text/javascript">
23103 * @class Roo.data.SortTypes
23105 * Defines the default sorting (casting?) comparison functions used when sorting data.
23107 Roo.data.SortTypes = {
23109 * Default sort that does nothing
23110 * @param {Mixed} s The value being converted
23111 * @return {Mixed} The comparison value
23113 none : function(s){
23118 * The regular expression used to strip tags
23122 stripTagsRE : /<\/?[^>]+>/gi,
23125 * Strips all HTML tags to sort on text only
23126 * @param {Mixed} s The value being converted
23127 * @return {String} The comparison value
23129 asText : function(s){
23130 return String(s).replace(this.stripTagsRE, "");
23134 * Strips all HTML tags to sort on text only - Case insensitive
23135 * @param {Mixed} s The value being converted
23136 * @return {String} The comparison value
23138 asUCText : function(s){
23139 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23143 * Case insensitive string
23144 * @param {Mixed} s The value being converted
23145 * @return {String} The comparison value
23147 asUCString : function(s) {
23148 return String(s).toUpperCase();
23153 * @param {Mixed} s The value being converted
23154 * @return {Number} The comparison value
23156 asDate : function(s) {
23160 if(s instanceof Date){
23161 return s.getTime();
23163 return Date.parse(String(s));
23168 * @param {Mixed} s The value being converted
23169 * @return {Float} The comparison value
23171 asFloat : function(s) {
23172 var val = parseFloat(String(s).replace(/,/g, ""));
23181 * @param {Mixed} s The value being converted
23182 * @return {Number} The comparison value
23184 asInt : function(s) {
23185 var val = parseInt(String(s).replace(/,/g, ""));
23193 * Ext JS Library 1.1.1
23194 * Copyright(c) 2006-2007, Ext JS, LLC.
23196 * Originally Released Under LGPL - original licence link has changed is not relivant.
23199 * <script type="text/javascript">
23203 * @class Roo.data.Record
23204 * Instances of this class encapsulate both record <em>definition</em> information, and record
23205 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
23206 * to access Records cached in an {@link Roo.data.Store} object.<br>
23208 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
23209 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
23212 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
23214 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
23215 * {@link #create}. The parameters are the same.
23216 * @param {Array} data An associative Array of data values keyed by the field name.
23217 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
23218 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
23219 * not specified an integer id is generated.
23221 Roo.data.Record = function(data, id){
23222 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
23227 * Generate a constructor for a specific record layout.
23228 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
23229 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
23230 * Each field definition object may contain the following properties: <ul>
23231 * <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,
23232 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
23233 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
23234 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
23235 * is being used, then this is a string containing the javascript expression to reference the data relative to
23236 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
23237 * to the data item relative to the record element. If the mapping expression is the same as the field name,
23238 * this may be omitted.</p></li>
23239 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
23240 * <ul><li>auto (Default, implies no conversion)</li>
23245 * <li>date</li></ul></p></li>
23246 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
23247 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
23248 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
23249 * by the Reader into an object that will be stored in the Record. It is passed the
23250 * following parameters:<ul>
23251 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
23253 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
23255 * <br>usage:<br><pre><code>
23256 var TopicRecord = Roo.data.Record.create(
23257 {name: 'title', mapping: 'topic_title'},
23258 {name: 'author', mapping: 'username'},
23259 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
23260 {name: 'lastPost', mapping: 'post_time', type: 'date'},
23261 {name: 'lastPoster', mapping: 'user2'},
23262 {name: 'excerpt', mapping: 'post_text'}
23265 var myNewRecord = new TopicRecord({
23266 title: 'Do my job please',
23269 lastPost: new Date(),
23270 lastPoster: 'Animal',
23271 excerpt: 'No way dude!'
23273 myStore.add(myNewRecord);
23278 Roo.data.Record.create = function(o){
23279 var f = function(){
23280 f.superclass.constructor.apply(this, arguments);
23282 Roo.extend(f, Roo.data.Record);
23283 var p = f.prototype;
23284 p.fields = new Roo.util.MixedCollection(false, function(field){
23287 for(var i = 0, len = o.length; i < len; i++){
23288 p.fields.add(new Roo.data.Field(o[i]));
23290 f.getField = function(name){
23291 return p.fields.get(name);
23296 Roo.data.Record.AUTO_ID = 1000;
23297 Roo.data.Record.EDIT = 'edit';
23298 Roo.data.Record.REJECT = 'reject';
23299 Roo.data.Record.COMMIT = 'commit';
23301 Roo.data.Record.prototype = {
23303 * Readonly flag - true if this record has been modified.
23312 join : function(store){
23313 this.store = store;
23317 * Set the named field to the specified value.
23318 * @param {String} name The name of the field to set.
23319 * @param {Object} value The value to set the field to.
23321 set : function(name, value){
23322 if(this.data[name] == value){
23326 if(!this.modified){
23327 this.modified = {};
23329 if(typeof this.modified[name] == 'undefined'){
23330 this.modified[name] = this.data[name];
23332 this.data[name] = value;
23333 if(!this.editing && this.store){
23334 this.store.afterEdit(this);
23339 * Get the value of the named field.
23340 * @param {String} name The name of the field to get the value of.
23341 * @return {Object} The value of the field.
23343 get : function(name){
23344 return this.data[name];
23348 beginEdit : function(){
23349 this.editing = true;
23350 this.modified = {};
23354 cancelEdit : function(){
23355 this.editing = false;
23356 delete this.modified;
23360 endEdit : function(){
23361 this.editing = false;
23362 if(this.dirty && this.store){
23363 this.store.afterEdit(this);
23368 * Usually called by the {@link Roo.data.Store} which owns the Record.
23369 * Rejects all changes made to the Record since either creation, or the last commit operation.
23370 * Modified fields are reverted to their original values.
23372 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23373 * of reject operations.
23375 reject : function(){
23376 var m = this.modified;
23378 if(typeof m[n] != "function"){
23379 this.data[n] = m[n];
23382 this.dirty = false;
23383 delete this.modified;
23384 this.editing = false;
23386 this.store.afterReject(this);
23391 * Usually called by the {@link Roo.data.Store} which owns the Record.
23392 * Commits all changes made to the Record since either creation, or the last commit operation.
23394 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23395 * of commit operations.
23397 commit : function(){
23398 this.dirty = false;
23399 delete this.modified;
23400 this.editing = false;
23402 this.store.afterCommit(this);
23407 hasError : function(){
23408 return this.error != null;
23412 clearError : function(){
23417 * Creates a copy of this record.
23418 * @param {String} id (optional) A new record id if you don't want to use this record's id
23421 copy : function(newId) {
23422 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
23426 * Ext JS Library 1.1.1
23427 * Copyright(c) 2006-2007, Ext JS, LLC.
23429 * Originally Released Under LGPL - original licence link has changed is not relivant.
23432 * <script type="text/javascript">
23438 * @class Roo.data.Store
23439 * @extends Roo.util.Observable
23440 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
23441 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
23443 * 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
23444 * has no knowledge of the format of the data returned by the Proxy.<br>
23446 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
23447 * instances from the data object. These records are cached and made available through accessor functions.
23449 * Creates a new Store.
23450 * @param {Object} config A config object containing the objects needed for the Store to access data,
23451 * and read the data into Records.
23453 Roo.data.Store = function(config){
23454 this.data = new Roo.util.MixedCollection(false);
23455 this.data.getKey = function(o){
23458 this.baseParams = {};
23460 this.paramNames = {
23465 "multisort" : "_multisort"
23468 if(config && config.data){
23469 this.inlineData = config.data;
23470 delete config.data;
23473 Roo.apply(this, config);
23475 if(this.reader){ // reader passed
23476 this.reader = Roo.factory(this.reader, Roo.data);
23477 this.reader.xmodule = this.xmodule || false;
23478 if(!this.recordType){
23479 this.recordType = this.reader.recordType;
23481 if(this.reader.onMetaChange){
23482 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
23486 if(this.recordType){
23487 this.fields = this.recordType.prototype.fields;
23489 this.modified = [];
23493 * @event datachanged
23494 * Fires when the data cache has changed, and a widget which is using this Store
23495 * as a Record cache should refresh its view.
23496 * @param {Store} this
23498 datachanged : true,
23500 * @event metachange
23501 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
23502 * @param {Store} this
23503 * @param {Object} meta The JSON metadata
23508 * Fires when Records have been added to the Store
23509 * @param {Store} this
23510 * @param {Roo.data.Record[]} records The array of Records added
23511 * @param {Number} index The index at which the record(s) were added
23516 * Fires when a Record has been removed from the Store
23517 * @param {Store} this
23518 * @param {Roo.data.Record} record The Record that was removed
23519 * @param {Number} index The index at which the record was removed
23524 * Fires when a Record has been updated
23525 * @param {Store} this
23526 * @param {Roo.data.Record} record The Record that was updated
23527 * @param {String} operation The update operation being performed. Value may be one of:
23529 Roo.data.Record.EDIT
23530 Roo.data.Record.REJECT
23531 Roo.data.Record.COMMIT
23537 * Fires when the data cache has been cleared.
23538 * @param {Store} this
23542 * @event beforeload
23543 * Fires before a request is made for a new data object. If the beforeload handler returns false
23544 * the load action will be canceled.
23545 * @param {Store} this
23546 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23550 * @event beforeloadadd
23551 * Fires after a new set of Records has been loaded.
23552 * @param {Store} this
23553 * @param {Roo.data.Record[]} records The Records that were loaded
23554 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23556 beforeloadadd : true,
23559 * Fires after a new set of Records has been loaded, before they are added to the store.
23560 * @param {Store} this
23561 * @param {Roo.data.Record[]} records The Records that were loaded
23562 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23563 * @params {Object} return from reader
23567 * @event loadexception
23568 * Fires if an exception occurs in the Proxy during loading.
23569 * Called with the signature of the Proxy's "loadexception" event.
23570 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
23573 * @param {Object} return from JsonData.reader() - success, totalRecords, records
23574 * @param {Object} load options
23575 * @param {Object} jsonData from your request (normally this contains the Exception)
23577 loadexception : true
23581 this.proxy = Roo.factory(this.proxy, Roo.data);
23582 this.proxy.xmodule = this.xmodule || false;
23583 this.relayEvents(this.proxy, ["loadexception"]);
23585 this.sortToggle = {};
23586 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
23588 Roo.data.Store.superclass.constructor.call(this);
23590 if(this.inlineData){
23591 this.loadData(this.inlineData);
23592 delete this.inlineData;
23596 Roo.extend(Roo.data.Store, Roo.util.Observable, {
23598 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
23599 * without a remote query - used by combo/forms at present.
23603 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
23606 * @cfg {Array} data Inline data to be loaded when the store is initialized.
23609 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
23610 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
23613 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
23614 * on any HTTP request
23617 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
23620 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
23624 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
23625 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
23627 remoteSort : false,
23630 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
23631 * loaded or when a record is removed. (defaults to false).
23633 pruneModifiedRecords : false,
23636 lastOptions : null,
23639 * Add Records to the Store and fires the add event.
23640 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23642 add : function(records){
23643 records = [].concat(records);
23644 for(var i = 0, len = records.length; i < len; i++){
23645 records[i].join(this);
23647 var index = this.data.length;
23648 this.data.addAll(records);
23649 this.fireEvent("add", this, records, index);
23653 * Remove a Record from the Store and fires the remove event.
23654 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23656 remove : function(record){
23657 var index = this.data.indexOf(record);
23658 this.data.removeAt(index);
23660 if(this.pruneModifiedRecords){
23661 this.modified.remove(record);
23663 this.fireEvent("remove", this, record, index);
23667 * Remove all Records from the Store and fires the clear event.
23669 removeAll : function(){
23671 if(this.pruneModifiedRecords){
23672 this.modified = [];
23674 this.fireEvent("clear", this);
23678 * Inserts Records to the Store at the given index and fires the add event.
23679 * @param {Number} index The start index at which to insert the passed Records.
23680 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23682 insert : function(index, records){
23683 records = [].concat(records);
23684 for(var i = 0, len = records.length; i < len; i++){
23685 this.data.insert(index, records[i]);
23686 records[i].join(this);
23688 this.fireEvent("add", this, records, index);
23692 * Get the index within the cache of the passed Record.
23693 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23694 * @return {Number} The index of the passed Record. Returns -1 if not found.
23696 indexOf : function(record){
23697 return this.data.indexOf(record);
23701 * Get the index within the cache of the Record with the passed id.
23702 * @param {String} id The id of the Record to find.
23703 * @return {Number} The index of the Record. Returns -1 if not found.
23705 indexOfId : function(id){
23706 return this.data.indexOfKey(id);
23710 * Get the Record with the specified id.
23711 * @param {String} id The id of the Record to find.
23712 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23714 getById : function(id){
23715 return this.data.key(id);
23719 * Get the Record at the specified index.
23720 * @param {Number} index The index of the Record to find.
23721 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23723 getAt : function(index){
23724 return this.data.itemAt(index);
23728 * Returns a range of Records between specified indices.
23729 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23730 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23731 * @return {Roo.data.Record[]} An array of Records
23733 getRange : function(start, end){
23734 return this.data.getRange(start, end);
23738 storeOptions : function(o){
23739 o = Roo.apply({}, o);
23742 this.lastOptions = o;
23746 * Loads the Record cache from the configured Proxy using the configured Reader.
23748 * If using remote paging, then the first load call must specify the <em>start</em>
23749 * and <em>limit</em> properties in the options.params property to establish the initial
23750 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23752 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23753 * and this call will return before the new data has been loaded. Perform any post-processing
23754 * in a callback function, or in a "load" event handler.</strong>
23756 * @param {Object} options An object containing properties which control loading options:<ul>
23757 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23758 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23759 * passed the following arguments:<ul>
23760 * <li>r : Roo.data.Record[]</li>
23761 * <li>options: Options object from the load call</li>
23762 * <li>success: Boolean success indicator</li></ul></li>
23763 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23764 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23767 load : function(options){
23768 options = options || {};
23769 if(this.fireEvent("beforeload", this, options) !== false){
23770 this.storeOptions(options);
23771 var p = Roo.apply(options.params || {}, this.baseParams);
23772 // if meta was not loaded from remote source.. try requesting it.
23773 if (!this.reader.metaFromRemote) {
23774 p._requestMeta = 1;
23776 if(this.sortInfo && this.remoteSort){
23777 var pn = this.paramNames;
23778 p[pn["sort"]] = this.sortInfo.field;
23779 p[pn["dir"]] = this.sortInfo.direction;
23781 if (this.multiSort) {
23782 var pn = this.paramNames;
23783 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23786 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23791 * Reloads the Record cache from the configured Proxy using the configured Reader and
23792 * the options from the last load operation performed.
23793 * @param {Object} options (optional) An object containing properties which may override the options
23794 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23795 * the most recently used options are reused).
23797 reload : function(options){
23798 this.load(Roo.applyIf(options||{}, this.lastOptions));
23802 // Called as a callback by the Reader during a load operation.
23803 loadRecords : function(o, options, success){
23804 if(!o || success === false){
23805 if(success !== false){
23806 this.fireEvent("load", this, [], options, o);
23808 if(options.callback){
23809 options.callback.call(options.scope || this, [], options, false);
23813 // if data returned failure - throw an exception.
23814 if (o.success === false) {
23815 // show a message if no listener is registered.
23816 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23817 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23819 // loadmask wil be hooked into this..
23820 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23823 var r = o.records, t = o.totalRecords || r.length;
23825 this.fireEvent("beforeloadadd", this, r, options, o);
23827 if(!options || options.add !== true){
23828 if(this.pruneModifiedRecords){
23829 this.modified = [];
23831 for(var i = 0, len = r.length; i < len; i++){
23835 this.data = this.snapshot;
23836 delete this.snapshot;
23839 this.data.addAll(r);
23840 this.totalLength = t;
23842 this.fireEvent("datachanged", this);
23844 this.totalLength = Math.max(t, this.data.length+r.length);
23848 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23850 var e = new Roo.data.Record({});
23852 e.set(this.parent.displayField, this.parent.emptyTitle);
23853 e.set(this.parent.valueField, '');
23858 this.fireEvent("load", this, r, options, o);
23859 if(options.callback){
23860 options.callback.call(options.scope || this, r, options, true);
23866 * Loads data from a passed data block. A Reader which understands the format of the data
23867 * must have been configured in the constructor.
23868 * @param {Object} data The data block from which to read the Records. The format of the data expected
23869 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23870 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23872 loadData : function(o, append){
23873 var r = this.reader.readRecords(o);
23874 this.loadRecords(r, {add: append}, true);
23878 * using 'cn' the nested child reader read the child array into it's child stores.
23879 * @param {Object} rec The record with a 'children array
23881 loadDataFromChildren : function(rec)
23883 this.loadData(this.reader.toLoadData(rec));
23888 * Gets the number of cached records.
23890 * <em>If using paging, this may not be the total size of the dataset. If the data object
23891 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23892 * the data set size</em>
23894 getCount : function(){
23895 return this.data.length || 0;
23899 * Gets the total number of records in the dataset as returned by the server.
23901 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23902 * the dataset size</em>
23904 getTotalCount : function(){
23905 return this.totalLength || 0;
23909 * Returns the sort state of the Store as an object with two properties:
23911 field {String} The name of the field by which the Records are sorted
23912 direction {String} The sort order, "ASC" or "DESC"
23915 getSortState : function(){
23916 return this.sortInfo;
23920 applySort : function(){
23921 if(this.sortInfo && !this.remoteSort){
23922 var s = this.sortInfo, f = s.field;
23923 var st = this.fields.get(f).sortType;
23924 var fn = function(r1, r2){
23925 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23926 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23928 this.data.sort(s.direction, fn);
23929 if(this.snapshot && this.snapshot != this.data){
23930 this.snapshot.sort(s.direction, fn);
23936 * Sets the default sort column and order to be used by the next load operation.
23937 * @param {String} fieldName The name of the field to sort by.
23938 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23940 setDefaultSort : function(field, dir){
23941 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23945 * Sort the Records.
23946 * If remote sorting is used, the sort is performed on the server, and the cache is
23947 * reloaded. If local sorting is used, the cache is sorted internally.
23948 * @param {String} fieldName The name of the field to sort by.
23949 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23951 sort : function(fieldName, dir){
23952 var f = this.fields.get(fieldName);
23954 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23956 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23957 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23962 this.sortToggle[f.name] = dir;
23963 this.sortInfo = {field: f.name, direction: dir};
23964 if(!this.remoteSort){
23966 this.fireEvent("datachanged", this);
23968 this.load(this.lastOptions);
23973 * Calls the specified function for each of the Records in the cache.
23974 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23975 * Returning <em>false</em> aborts and exits the iteration.
23976 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23978 each : function(fn, scope){
23979 this.data.each(fn, scope);
23983 * Gets all records modified since the last commit. Modified records are persisted across load operations
23984 * (e.g., during paging).
23985 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23987 getModifiedRecords : function(){
23988 return this.modified;
23992 createFilterFn : function(property, value, anyMatch){
23993 if(!value.exec){ // not a regex
23994 value = String(value);
23995 if(value.length == 0){
23998 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
24000 return function(r){
24001 return value.test(r.data[property]);
24006 * Sums the value of <i>property</i> for each record between start and end and returns the result.
24007 * @param {String} property A field on your records
24008 * @param {Number} start The record index to start at (defaults to 0)
24009 * @param {Number} end The last record index to include (defaults to length - 1)
24010 * @return {Number} The sum
24012 sum : function(property, start, end){
24013 var rs = this.data.items, v = 0;
24014 start = start || 0;
24015 end = (end || end === 0) ? end : rs.length-1;
24017 for(var i = start; i <= end; i++){
24018 v += (rs[i].data[property] || 0);
24024 * Filter the records by a specified property.
24025 * @param {String} field A field on your records
24026 * @param {String/RegExp} value Either a string that the field
24027 * should start with or a RegExp to test against the field
24028 * @param {Boolean} anyMatch True to match any part not just the beginning
24030 filter : function(property, value, anyMatch){
24031 var fn = this.createFilterFn(property, value, anyMatch);
24032 return fn ? this.filterBy(fn) : this.clearFilter();
24036 * Filter by a function. The specified function will be called with each
24037 * record in this data source. If the function returns true the record is included,
24038 * otherwise it is filtered.
24039 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24040 * @param {Object} scope (optional) The scope of the function (defaults to this)
24042 filterBy : function(fn, scope){
24043 this.snapshot = this.snapshot || this.data;
24044 this.data = this.queryBy(fn, scope||this);
24045 this.fireEvent("datachanged", this);
24049 * Query the records by a specified property.
24050 * @param {String} field A field on your records
24051 * @param {String/RegExp} value Either a string that the field
24052 * should start with or a RegExp to test against the field
24053 * @param {Boolean} anyMatch True to match any part not just the beginning
24054 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24056 query : function(property, value, anyMatch){
24057 var fn = this.createFilterFn(property, value, anyMatch);
24058 return fn ? this.queryBy(fn) : this.data.clone();
24062 * Query by a function. The specified function will be called with each
24063 * record in this data source. If the function returns true the record is included
24065 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24066 * @param {Object} scope (optional) The scope of the function (defaults to this)
24067 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24069 queryBy : function(fn, scope){
24070 var data = this.snapshot || this.data;
24071 return data.filterBy(fn, scope||this);
24075 * Collects unique values for a particular dataIndex from this store.
24076 * @param {String} dataIndex The property to collect
24077 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24078 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24079 * @return {Array} An array of the unique values
24081 collect : function(dataIndex, allowNull, bypassFilter){
24082 var d = (bypassFilter === true && this.snapshot) ?
24083 this.snapshot.items : this.data.items;
24084 var v, sv, r = [], l = {};
24085 for(var i = 0, len = d.length; i < len; i++){
24086 v = d[i].data[dataIndex];
24088 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24097 * Revert to a view of the Record cache with no filtering applied.
24098 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24100 clearFilter : function(suppressEvent){
24101 if(this.snapshot && this.snapshot != this.data){
24102 this.data = this.snapshot;
24103 delete this.snapshot;
24104 if(suppressEvent !== true){
24105 this.fireEvent("datachanged", this);
24111 afterEdit : function(record){
24112 if(this.modified.indexOf(record) == -1){
24113 this.modified.push(record);
24115 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24119 afterReject : function(record){
24120 this.modified.remove(record);
24121 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24125 afterCommit : function(record){
24126 this.modified.remove(record);
24127 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24131 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24132 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24134 commitChanges : function(){
24135 var m = this.modified.slice(0);
24136 this.modified = [];
24137 for(var i = 0, len = m.length; i < len; i++){
24143 * Cancel outstanding changes on all changed records.
24145 rejectChanges : function(){
24146 var m = this.modified.slice(0);
24147 this.modified = [];
24148 for(var i = 0, len = m.length; i < len; i++){
24153 onMetaChange : function(meta, rtype, o){
24154 this.recordType = rtype;
24155 this.fields = rtype.prototype.fields;
24156 delete this.snapshot;
24157 this.sortInfo = meta.sortInfo || this.sortInfo;
24158 this.modified = [];
24159 this.fireEvent('metachange', this, this.reader.meta);
24162 moveIndex : function(data, type)
24164 var index = this.indexOf(data);
24166 var newIndex = index + type;
24170 this.insert(newIndex, data);
24175 * Ext JS Library 1.1.1
24176 * Copyright(c) 2006-2007, Ext JS, LLC.
24178 * Originally Released Under LGPL - original licence link has changed is not relivant.
24181 * <script type="text/javascript">
24185 * @class Roo.data.SimpleStore
24186 * @extends Roo.data.Store
24187 * Small helper class to make creating Stores from Array data easier.
24188 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24189 * @cfg {Array} fields An array of field definition objects, or field name strings.
24190 * @cfg {Object} an existing reader (eg. copied from another store)
24191 * @cfg {Array} data The multi-dimensional array of data
24193 * @param {Object} config
24195 Roo.data.SimpleStore = function(config)
24197 Roo.data.SimpleStore.superclass.constructor.call(this, {
24199 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24202 Roo.data.Record.create(config.fields)
24204 proxy : new Roo.data.MemoryProxy(config.data)
24208 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24210 * Ext JS Library 1.1.1
24211 * Copyright(c) 2006-2007, Ext JS, LLC.
24213 * Originally Released Under LGPL - original licence link has changed is not relivant.
24216 * <script type="text/javascript">
24221 * @extends Roo.data.Store
24222 * @class Roo.data.JsonStore
24223 * Small helper class to make creating Stores for JSON data easier. <br/>
24225 var store = new Roo.data.JsonStore({
24226 url: 'get-images.php',
24228 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24231 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24232 * JsonReader and HttpProxy (unless inline data is provided).</b>
24233 * @cfg {Array} fields An array of field definition objects, or field name strings.
24235 * @param {Object} config
24237 Roo.data.JsonStore = function(c){
24238 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24239 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24240 reader: new Roo.data.JsonReader(c, c.fields)
24243 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
24245 * Ext JS Library 1.1.1
24246 * Copyright(c) 2006-2007, Ext JS, LLC.
24248 * Originally Released Under LGPL - original licence link has changed is not relivant.
24251 * <script type="text/javascript">
24255 Roo.data.Field = function(config){
24256 if(typeof config == "string"){
24257 config = {name: config};
24259 Roo.apply(this, config);
24262 this.type = "auto";
24265 var st = Roo.data.SortTypes;
24266 // named sortTypes are supported, here we look them up
24267 if(typeof this.sortType == "string"){
24268 this.sortType = st[this.sortType];
24271 // set default sortType for strings and dates
24272 if(!this.sortType){
24275 this.sortType = st.asUCString;
24278 this.sortType = st.asDate;
24281 this.sortType = st.none;
24286 var stripRe = /[\$,%]/g;
24288 // prebuilt conversion function for this field, instead of
24289 // switching every time we're reading a value
24291 var cv, dateFormat = this.dateFormat;
24296 cv = function(v){ return v; };
24299 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24303 return v !== undefined && v !== null && v !== '' ?
24304 parseInt(String(v).replace(stripRe, ""), 10) : '';
24309 return v !== undefined && v !== null && v !== '' ?
24310 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24315 cv = function(v){ return v === true || v === "true" || v == 1; };
24322 if(v instanceof Date){
24326 if(dateFormat == "timestamp"){
24327 return new Date(v*1000);
24329 return Date.parseDate(v, dateFormat);
24331 var parsed = Date.parse(v);
24332 return parsed ? new Date(parsed) : null;
24341 Roo.data.Field.prototype = {
24349 * Ext JS Library 1.1.1
24350 * Copyright(c) 2006-2007, Ext JS, LLC.
24352 * Originally Released Under LGPL - original licence link has changed is not relivant.
24355 * <script type="text/javascript">
24358 // Base class for reading structured data from a data source. This class is intended to be
24359 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24362 * @class Roo.data.DataReader
24363 * Base class for reading structured data from a data source. This class is intended to be
24364 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24367 Roo.data.DataReader = function(meta, recordType){
24371 this.recordType = recordType instanceof Array ?
24372 Roo.data.Record.create(recordType) : recordType;
24375 Roo.data.DataReader.prototype = {
24378 readerType : 'Data',
24380 * Create an empty record
24381 * @param {Object} data (optional) - overlay some values
24382 * @return {Roo.data.Record} record created.
24384 newRow : function(d) {
24386 this.recordType.prototype.fields.each(function(c) {
24388 case 'int' : da[c.name] = 0; break;
24389 case 'date' : da[c.name] = new Date(); break;
24390 case 'float' : da[c.name] = 0.0; break;
24391 case 'boolean' : da[c.name] = false; break;
24392 default : da[c.name] = ""; break;
24396 return new this.recordType(Roo.apply(da, d));
24402 * Ext JS Library 1.1.1
24403 * Copyright(c) 2006-2007, Ext JS, LLC.
24405 * Originally Released Under LGPL - original licence link has changed is not relivant.
24408 * <script type="text/javascript">
24412 * @class Roo.data.DataProxy
24413 * @extends Roo.data.Observable
24414 * This class is an abstract base class for implementations which provide retrieval of
24415 * unformatted data objects.<br>
24417 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24418 * (of the appropriate type which knows how to parse the data object) to provide a block of
24419 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24421 * Custom implementations must implement the load method as described in
24422 * {@link Roo.data.HttpProxy#load}.
24424 Roo.data.DataProxy = function(){
24427 * @event beforeload
24428 * Fires before a network request is made to retrieve a data object.
24429 * @param {Object} This DataProxy object.
24430 * @param {Object} params The params parameter to the load function.
24435 * Fires before the load method's callback is called.
24436 * @param {Object} This DataProxy object.
24437 * @param {Object} o The data object.
24438 * @param {Object} arg The callback argument object passed to the load function.
24442 * @event loadexception
24443 * Fires if an Exception occurs during data retrieval.
24444 * @param {Object} This DataProxy object.
24445 * @param {Object} o The data object.
24446 * @param {Object} arg The callback argument object passed to the load function.
24447 * @param {Object} e The Exception.
24449 loadexception : true
24451 Roo.data.DataProxy.superclass.constructor.call(this);
24454 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24457 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24461 * Ext JS Library 1.1.1
24462 * Copyright(c) 2006-2007, Ext JS, LLC.
24464 * Originally Released Under LGPL - original licence link has changed is not relivant.
24467 * <script type="text/javascript">
24470 * @class Roo.data.MemoryProxy
24471 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24472 * to the Reader when its load method is called.
24474 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24476 Roo.data.MemoryProxy = function(data){
24480 Roo.data.MemoryProxy.superclass.constructor.call(this);
24484 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24487 * Load data from the requested source (in this case an in-memory
24488 * data object passed to the constructor), read the data object into
24489 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24490 * process that block using the passed callback.
24491 * @param {Object} params This parameter is not used by the MemoryProxy class.
24492 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24493 * object into a block of Roo.data.Records.
24494 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24495 * The function must be passed <ul>
24496 * <li>The Record block object</li>
24497 * <li>The "arg" argument from the load function</li>
24498 * <li>A boolean success indicator</li>
24500 * @param {Object} scope The scope in which to call the callback
24501 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24503 load : function(params, reader, callback, scope, arg){
24504 params = params || {};
24507 result = reader.readRecords(params.data ? params.data :this.data);
24509 this.fireEvent("loadexception", this, arg, null, e);
24510 callback.call(scope, null, arg, false);
24513 callback.call(scope, result, arg, true);
24517 update : function(params, records){
24522 * Ext JS Library 1.1.1
24523 * Copyright(c) 2006-2007, Ext JS, LLC.
24525 * Originally Released Under LGPL - original licence link has changed is not relivant.
24528 * <script type="text/javascript">
24531 * @class Roo.data.HttpProxy
24532 * @extends Roo.data.DataProxy
24533 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24534 * configured to reference a certain URL.<br><br>
24536 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24537 * from which the running page was served.<br><br>
24539 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24541 * Be aware that to enable the browser to parse an XML document, the server must set
24542 * the Content-Type header in the HTTP response to "text/xml".
24544 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24545 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24546 * will be used to make the request.
24548 Roo.data.HttpProxy = function(conn){
24549 Roo.data.HttpProxy.superclass.constructor.call(this);
24550 // is conn a conn config or a real conn?
24552 this.useAjax = !conn || !conn.events;
24556 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24557 // thse are take from connection...
24560 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24563 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24564 * extra parameters to each request made by this object. (defaults to undefined)
24567 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24568 * to each request made by this object. (defaults to undefined)
24571 * @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)
24574 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24577 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24583 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24587 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24588 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24589 * a finer-grained basis than the DataProxy events.
24591 getConnection : function(){
24592 return this.useAjax ? Roo.Ajax : this.conn;
24596 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24597 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24598 * process that block using the passed callback.
24599 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24600 * for the request to the remote server.
24601 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24602 * object into a block of Roo.data.Records.
24603 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24604 * The function must be passed <ul>
24605 * <li>The Record block object</li>
24606 * <li>The "arg" argument from the load function</li>
24607 * <li>A boolean success indicator</li>
24609 * @param {Object} scope The scope in which to call the callback
24610 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24612 load : function(params, reader, callback, scope, arg){
24613 if(this.fireEvent("beforeload", this, params) !== false){
24615 params : params || {},
24617 callback : callback,
24622 callback : this.loadResponse,
24626 Roo.applyIf(o, this.conn);
24627 if(this.activeRequest){
24628 Roo.Ajax.abort(this.activeRequest);
24630 this.activeRequest = Roo.Ajax.request(o);
24632 this.conn.request(o);
24635 callback.call(scope||this, null, arg, false);
24640 loadResponse : function(o, success, response){
24641 delete this.activeRequest;
24643 this.fireEvent("loadexception", this, o, response);
24644 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24649 result = o.reader.read(response);
24651 this.fireEvent("loadexception", this, o, response, e);
24652 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24656 this.fireEvent("load", this, o, o.request.arg);
24657 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24661 update : function(dataSet){
24666 updateResponse : function(dataSet){
24671 * Ext JS Library 1.1.1
24672 * Copyright(c) 2006-2007, Ext JS, LLC.
24674 * Originally Released Under LGPL - original licence link has changed is not relivant.
24677 * <script type="text/javascript">
24681 * @class Roo.data.ScriptTagProxy
24682 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24683 * other than the originating domain of the running page.<br><br>
24685 * <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
24686 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24688 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24689 * source code that is used as the source inside a <script> tag.<br><br>
24691 * In order for the browser to process the returned data, the server must wrap the data object
24692 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24693 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24694 * depending on whether the callback name was passed:
24697 boolean scriptTag = false;
24698 String cb = request.getParameter("callback");
24701 response.setContentType("text/javascript");
24703 response.setContentType("application/x-json");
24705 Writer out = response.getWriter();
24707 out.write(cb + "(");
24709 out.print(dataBlock.toJsonString());
24716 * @param {Object} config A configuration object.
24718 Roo.data.ScriptTagProxy = function(config){
24719 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24720 Roo.apply(this, config);
24721 this.head = document.getElementsByTagName("head")[0];
24724 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24726 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24728 * @cfg {String} url The URL from which to request the data object.
24731 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24735 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24736 * the server the name of the callback function set up by the load call to process the returned data object.
24737 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24738 * javascript output which calls this named function passing the data object as its only parameter.
24740 callbackParam : "callback",
24742 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24743 * name to the request.
24748 * Load data from the configured URL, read the data object into
24749 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24750 * process that block using the passed callback.
24751 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24752 * for the request to the remote server.
24753 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24754 * object into a block of Roo.data.Records.
24755 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24756 * The function must be passed <ul>
24757 * <li>The Record block object</li>
24758 * <li>The "arg" argument from the load function</li>
24759 * <li>A boolean success indicator</li>
24761 * @param {Object} scope The scope in which to call the callback
24762 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24764 load : function(params, reader, callback, scope, arg){
24765 if(this.fireEvent("beforeload", this, params) !== false){
24767 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24769 var url = this.url;
24770 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24772 url += "&_dc=" + (new Date().getTime());
24774 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24777 cb : "stcCallback"+transId,
24778 scriptId : "stcScript"+transId,
24782 callback : callback,
24788 window[trans.cb] = function(o){
24789 conn.handleResponse(o, trans);
24792 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24794 if(this.autoAbort !== false){
24798 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24800 var script = document.createElement("script");
24801 script.setAttribute("src", url);
24802 script.setAttribute("type", "text/javascript");
24803 script.setAttribute("id", trans.scriptId);
24804 this.head.appendChild(script);
24806 this.trans = trans;
24808 callback.call(scope||this, null, arg, false);
24813 isLoading : function(){
24814 return this.trans ? true : false;
24818 * Abort the current server request.
24820 abort : function(){
24821 if(this.isLoading()){
24822 this.destroyTrans(this.trans);
24827 destroyTrans : function(trans, isLoaded){
24828 this.head.removeChild(document.getElementById(trans.scriptId));
24829 clearTimeout(trans.timeoutId);
24831 window[trans.cb] = undefined;
24833 delete window[trans.cb];
24836 // if hasn't been loaded, wait for load to remove it to prevent script error
24837 window[trans.cb] = function(){
24838 window[trans.cb] = undefined;
24840 delete window[trans.cb];
24847 handleResponse : function(o, trans){
24848 this.trans = false;
24849 this.destroyTrans(trans, true);
24852 result = trans.reader.readRecords(o);
24854 this.fireEvent("loadexception", this, o, trans.arg, e);
24855 trans.callback.call(trans.scope||window, null, trans.arg, false);
24858 this.fireEvent("load", this, o, trans.arg);
24859 trans.callback.call(trans.scope||window, result, trans.arg, true);
24863 handleFailure : function(trans){
24864 this.trans = false;
24865 this.destroyTrans(trans, false);
24866 this.fireEvent("loadexception", this, null, trans.arg);
24867 trans.callback.call(trans.scope||window, null, trans.arg, false);
24871 * Ext JS Library 1.1.1
24872 * Copyright(c) 2006-2007, Ext JS, LLC.
24874 * Originally Released Under LGPL - original licence link has changed is not relivant.
24877 * <script type="text/javascript">
24881 * @class Roo.data.JsonReader
24882 * @extends Roo.data.DataReader
24883 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24884 * based on mappings in a provided Roo.data.Record constructor.
24886 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24887 * in the reply previously.
24892 var RecordDef = Roo.data.Record.create([
24893 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24894 {name: 'occupation'} // This field will use "occupation" as the mapping.
24896 var myReader = new Roo.data.JsonReader({
24897 totalProperty: "results", // The property which contains the total dataset size (optional)
24898 root: "rows", // The property which contains an Array of row objects
24899 id: "id" // The property within each row object that provides an ID for the record (optional)
24903 * This would consume a JSON file like this:
24905 { 'results': 2, 'rows': [
24906 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24907 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24910 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24911 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24912 * paged from the remote server.
24913 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24914 * @cfg {String} root name of the property which contains the Array of row objects.
24915 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24916 * @cfg {Array} fields Array of field definition objects
24918 * Create a new JsonReader
24919 * @param {Object} meta Metadata configuration options
24920 * @param {Object} recordType Either an Array of field definition objects,
24921 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24923 Roo.data.JsonReader = function(meta, recordType){
24926 // set some defaults:
24927 Roo.applyIf(meta, {
24928 totalProperty: 'total',
24929 successProperty : 'success',
24934 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24936 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24938 readerType : 'Json',
24941 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24942 * Used by Store query builder to append _requestMeta to params.
24945 metaFromRemote : false,
24947 * This method is only used by a DataProxy which has retrieved data from a remote server.
24948 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24949 * @return {Object} data A data block which is used by an Roo.data.Store object as
24950 * a cache of Roo.data.Records.
24952 read : function(response){
24953 var json = response.responseText;
24955 var o = /* eval:var:o */ eval("("+json+")");
24957 throw {message: "JsonReader.read: Json object not found"};
24963 this.metaFromRemote = true;
24964 this.meta = o.metaData;
24965 this.recordType = Roo.data.Record.create(o.metaData.fields);
24966 this.onMetaChange(this.meta, this.recordType, o);
24968 return this.readRecords(o);
24971 // private function a store will implement
24972 onMetaChange : function(meta, recordType, o){
24979 simpleAccess: function(obj, subsc) {
24986 getJsonAccessor: function(){
24988 return function(expr) {
24990 return(re.test(expr))
24991 ? new Function("obj", "return obj." + expr)
24996 return Roo.emptyFn;
25001 * Create a data block containing Roo.data.Records from an XML document.
25002 * @param {Object} o An object which contains an Array of row objects in the property specified
25003 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
25004 * which contains the total size of the dataset.
25005 * @return {Object} data A data block which is used by an Roo.data.Store object as
25006 * a cache of Roo.data.Records.
25008 readRecords : function(o){
25010 * After any data loads, the raw JSON data is available for further custom processing.
25014 var s = this.meta, Record = this.recordType,
25015 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
25017 // Generate extraction functions for the totalProperty, the root, the id, and for each field
25019 if(s.totalProperty) {
25020 this.getTotal = this.getJsonAccessor(s.totalProperty);
25022 if(s.successProperty) {
25023 this.getSuccess = this.getJsonAccessor(s.successProperty);
25025 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
25027 var g = this.getJsonAccessor(s.id);
25028 this.getId = function(rec) {
25030 return (r === undefined || r === "") ? null : r;
25033 this.getId = function(){return null;};
25036 for(var jj = 0; jj < fl; jj++){
25038 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
25039 this.ef[jj] = this.getJsonAccessor(map);
25043 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
25044 if(s.totalProperty){
25045 var vt = parseInt(this.getTotal(o), 10);
25050 if(s.successProperty){
25051 var vs = this.getSuccess(o);
25052 if(vs === false || vs === 'false'){
25057 for(var i = 0; i < c; i++){
25060 var id = this.getId(n);
25061 for(var j = 0; j < fl; j++){
25063 var v = this.ef[j](n);
25065 Roo.log('missing convert for ' + f.name);
25069 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25071 var record = new Record(values, id);
25073 records[i] = record;
25079 totalRecords : totalRecords
25082 // used when loading children.. @see loadDataFromChildren
25083 toLoadData: function(rec)
25085 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25086 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25087 return { data : data, total : data.length };
25092 * Ext JS Library 1.1.1
25093 * Copyright(c) 2006-2007, Ext JS, LLC.
25095 * Originally Released Under LGPL - original licence link has changed is not relivant.
25098 * <script type="text/javascript">
25102 * @class Roo.data.XmlReader
25103 * @extends Roo.data.DataReader
25104 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25105 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25107 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25108 * header in the HTTP response must be set to "text/xml".</em>
25112 var RecordDef = Roo.data.Record.create([
25113 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25114 {name: 'occupation'} // This field will use "occupation" as the mapping.
25116 var myReader = new Roo.data.XmlReader({
25117 totalRecords: "results", // The element which contains the total dataset size (optional)
25118 record: "row", // The repeated element which contains row information
25119 id: "id" // The element within the row that provides an ID for the record (optional)
25123 * This would consume an XML file like this:
25127 <results>2</results>
25130 <name>Bill</name>
25131 <occupation>Gardener</occupation>
25135 <name>Ben</name>
25136 <occupation>Horticulturalist</occupation>
25140 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25141 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25142 * paged from the remote server.
25143 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25144 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25145 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25146 * a record identifier value.
25148 * Create a new XmlReader
25149 * @param {Object} meta Metadata configuration options
25150 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25151 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25152 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25154 Roo.data.XmlReader = function(meta, recordType){
25156 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25158 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25160 readerType : 'Xml',
25163 * This method is only used by a DataProxy which has retrieved data from a remote server.
25164 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25165 * to contain a method called 'responseXML' that returns an XML document object.
25166 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25167 * a cache of Roo.data.Records.
25169 read : function(response){
25170 var doc = response.responseXML;
25172 throw {message: "XmlReader.read: XML Document not available"};
25174 return this.readRecords(doc);
25178 * Create a data block containing Roo.data.Records from an XML document.
25179 * @param {Object} doc A parsed XML document.
25180 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25181 * a cache of Roo.data.Records.
25183 readRecords : function(doc){
25185 * After any data loads/reads, the raw XML Document is available for further custom processing.
25186 * @type XMLDocument
25188 this.xmlData = doc;
25189 var root = doc.documentElement || doc;
25190 var q = Roo.DomQuery;
25191 var recordType = this.recordType, fields = recordType.prototype.fields;
25192 var sid = this.meta.id;
25193 var totalRecords = 0, success = true;
25194 if(this.meta.totalRecords){
25195 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25198 if(this.meta.success){
25199 var sv = q.selectValue(this.meta.success, root, true);
25200 success = sv !== false && sv !== 'false';
25203 var ns = q.select(this.meta.record, root);
25204 for(var i = 0, len = ns.length; i < len; i++) {
25207 var id = sid ? q.selectValue(sid, n) : undefined;
25208 for(var j = 0, jlen = fields.length; j < jlen; j++){
25209 var f = fields.items[j];
25210 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25212 values[f.name] = v;
25214 var record = new recordType(values, id);
25216 records[records.length] = record;
25222 totalRecords : totalRecords || records.length
25227 * Ext JS Library 1.1.1
25228 * Copyright(c) 2006-2007, Ext JS, LLC.
25230 * Originally Released Under LGPL - original licence link has changed is not relivant.
25233 * <script type="text/javascript">
25237 * @class Roo.data.ArrayReader
25238 * @extends Roo.data.DataReader
25239 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25240 * Each element of that Array represents a row of data fields. The
25241 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25242 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25246 var RecordDef = Roo.data.Record.create([
25247 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25248 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25250 var myReader = new Roo.data.ArrayReader({
25251 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25255 * This would consume an Array like this:
25257 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25261 * Create a new JsonReader
25262 * @param {Object} meta Metadata configuration options.
25263 * @param {Object|Array} recordType Either an Array of field definition objects
25265 * @cfg {Array} fields Array of field definition objects
25266 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25267 * as specified to {@link Roo.data.Record#create},
25268 * or an {@link Roo.data.Record} object
25271 * created using {@link Roo.data.Record#create}.
25273 Roo.data.ArrayReader = function(meta, recordType)
25275 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25278 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25281 * Create a data block containing Roo.data.Records from an XML document.
25282 * @param {Object} o An Array of row objects which represents the dataset.
25283 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25284 * a cache of Roo.data.Records.
25286 readRecords : function(o)
25288 var sid = this.meta ? this.meta.id : null;
25289 var recordType = this.recordType, fields = recordType.prototype.fields;
25292 for(var i = 0; i < root.length; i++){
25295 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25296 for(var j = 0, jlen = fields.length; j < jlen; j++){
25297 var f = fields.items[j];
25298 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25299 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25301 values[f.name] = v;
25303 var record = new recordType(values, id);
25305 records[records.length] = record;
25309 totalRecords : records.length
25312 // used when loading children.. @see loadDataFromChildren
25313 toLoadData: function(rec)
25315 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25316 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25323 * Ext JS Library 1.1.1
25324 * Copyright(c) 2006-2007, Ext JS, LLC.
25326 * Originally Released Under LGPL - original licence link has changed is not relivant.
25329 * <script type="text/javascript">
25334 * @class Roo.data.Tree
25335 * @extends Roo.util.Observable
25336 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25337 * in the tree have most standard DOM functionality.
25339 * @param {Node} root (optional) The root node
25341 Roo.data.Tree = function(root){
25342 this.nodeHash = {};
25344 * The root node for this tree
25349 this.setRootNode(root);
25354 * Fires when a new child node is appended to a node in this tree.
25355 * @param {Tree} tree The owner tree
25356 * @param {Node} parent The parent node
25357 * @param {Node} node The newly appended node
25358 * @param {Number} index The index of the newly appended node
25363 * Fires when a child node is removed from a node in this tree.
25364 * @param {Tree} tree The owner tree
25365 * @param {Node} parent The parent node
25366 * @param {Node} node The child node removed
25371 * Fires when a node is moved to a new location in the tree
25372 * @param {Tree} tree The owner tree
25373 * @param {Node} node The node moved
25374 * @param {Node} oldParent The old parent of this node
25375 * @param {Node} newParent The new parent of this node
25376 * @param {Number} index The index it was moved to
25381 * Fires when a new child node is inserted in a node in this tree.
25382 * @param {Tree} tree The owner tree
25383 * @param {Node} parent The parent node
25384 * @param {Node} node The child node inserted
25385 * @param {Node} refNode The child node the node was inserted before
25389 * @event beforeappend
25390 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25391 * @param {Tree} tree The owner tree
25392 * @param {Node} parent The parent node
25393 * @param {Node} node The child node to be appended
25395 "beforeappend" : true,
25397 * @event beforeremove
25398 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25399 * @param {Tree} tree The owner tree
25400 * @param {Node} parent The parent node
25401 * @param {Node} node The child node to be removed
25403 "beforeremove" : true,
25405 * @event beforemove
25406 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25407 * @param {Tree} tree The owner tree
25408 * @param {Node} node The node being moved
25409 * @param {Node} oldParent The parent of the node
25410 * @param {Node} newParent The new parent the node is moving to
25411 * @param {Number} index The index it is being moved to
25413 "beforemove" : true,
25415 * @event beforeinsert
25416 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25417 * @param {Tree} tree The owner tree
25418 * @param {Node} parent The parent node
25419 * @param {Node} node The child node to be inserted
25420 * @param {Node} refNode The child node the node is being inserted before
25422 "beforeinsert" : true
25425 Roo.data.Tree.superclass.constructor.call(this);
25428 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25429 pathSeparator: "/",
25431 proxyNodeEvent : function(){
25432 return this.fireEvent.apply(this, arguments);
25436 * Returns the root node for this tree.
25439 getRootNode : function(){
25444 * Sets the root node for this tree.
25445 * @param {Node} node
25448 setRootNode : function(node){
25450 node.ownerTree = this;
25451 node.isRoot = true;
25452 this.registerNode(node);
25457 * Gets a node in this tree by its id.
25458 * @param {String} id
25461 getNodeById : function(id){
25462 return this.nodeHash[id];
25465 registerNode : function(node){
25466 this.nodeHash[node.id] = node;
25469 unregisterNode : function(node){
25470 delete this.nodeHash[node.id];
25473 toString : function(){
25474 return "[Tree"+(this.id?" "+this.id:"")+"]";
25479 * @class Roo.data.Node
25480 * @extends Roo.util.Observable
25481 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25482 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25484 * @param {Object} attributes The attributes/config for the node
25486 Roo.data.Node = function(attributes){
25488 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25491 this.attributes = attributes || {};
25492 this.leaf = this.attributes.leaf;
25494 * The node id. @type String
25496 this.id = this.attributes.id;
25498 this.id = Roo.id(null, "ynode-");
25499 this.attributes.id = this.id;
25504 * All child nodes of this node. @type Array
25506 this.childNodes = [];
25507 if(!this.childNodes.indexOf){ // indexOf is a must
25508 this.childNodes.indexOf = function(o){
25509 for(var i = 0, len = this.length; i < len; i++){
25518 * The parent node for this node. @type Node
25520 this.parentNode = null;
25522 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25524 this.firstChild = null;
25526 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25528 this.lastChild = null;
25530 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25532 this.previousSibling = null;
25534 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25536 this.nextSibling = null;
25541 * Fires when a new child node is appended
25542 * @param {Tree} tree The owner tree
25543 * @param {Node} this This node
25544 * @param {Node} node The newly appended node
25545 * @param {Number} index The index of the newly appended node
25550 * Fires when a child node is removed
25551 * @param {Tree} tree The owner tree
25552 * @param {Node} this This node
25553 * @param {Node} node The removed node
25558 * Fires when this node is moved to a new location in the tree
25559 * @param {Tree} tree The owner tree
25560 * @param {Node} this This node
25561 * @param {Node} oldParent The old parent of this node
25562 * @param {Node} newParent The new parent of this node
25563 * @param {Number} index The index it was moved to
25568 * Fires when a new child node is inserted.
25569 * @param {Tree} tree The owner tree
25570 * @param {Node} this This node
25571 * @param {Node} node The child node inserted
25572 * @param {Node} refNode The child node the node was inserted before
25576 * @event beforeappend
25577 * Fires before a new child is appended, return false to cancel the append.
25578 * @param {Tree} tree The owner tree
25579 * @param {Node} this This node
25580 * @param {Node} node The child node to be appended
25582 "beforeappend" : true,
25584 * @event beforeremove
25585 * Fires before a child is removed, return false to cancel the remove.
25586 * @param {Tree} tree The owner tree
25587 * @param {Node} this This node
25588 * @param {Node} node The child node to be removed
25590 "beforeremove" : true,
25592 * @event beforemove
25593 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25594 * @param {Tree} tree The owner tree
25595 * @param {Node} this This node
25596 * @param {Node} oldParent The parent of this node
25597 * @param {Node} newParent The new parent this node is moving to
25598 * @param {Number} index The index it is being moved to
25600 "beforemove" : true,
25602 * @event beforeinsert
25603 * Fires before a new child is inserted, return false to cancel the insert.
25604 * @param {Tree} tree The owner tree
25605 * @param {Node} this This node
25606 * @param {Node} node The child node to be inserted
25607 * @param {Node} refNode The child node the node is being inserted before
25609 "beforeinsert" : true
25611 this.listeners = this.attributes.listeners;
25612 Roo.data.Node.superclass.constructor.call(this);
25615 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25616 fireEvent : function(evtName){
25617 // first do standard event for this node
25618 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25621 // then bubble it up to the tree if the event wasn't cancelled
25622 var ot = this.getOwnerTree();
25624 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25632 * Returns true if this node is a leaf
25633 * @return {Boolean}
25635 isLeaf : function(){
25636 return this.leaf === true;
25640 setFirstChild : function(node){
25641 this.firstChild = node;
25645 setLastChild : function(node){
25646 this.lastChild = node;
25651 * Returns true if this node is the last child of its parent
25652 * @return {Boolean}
25654 isLast : function(){
25655 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25659 * Returns true if this node is the first child of its parent
25660 * @return {Boolean}
25662 isFirst : function(){
25663 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25666 hasChildNodes : function(){
25667 return !this.isLeaf() && this.childNodes.length > 0;
25671 * Insert node(s) as the last child node of this node.
25672 * @param {Node/Array} node The node or Array of nodes to append
25673 * @return {Node} The appended node if single append, or null if an array was passed
25675 appendChild : function(node){
25677 if(node instanceof Array){
25679 }else if(arguments.length > 1){
25683 // if passed an array or multiple args do them one by one
25685 for(var i = 0, len = multi.length; i < len; i++) {
25686 this.appendChild(multi[i]);
25689 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25692 var index = this.childNodes.length;
25693 var oldParent = node.parentNode;
25694 // it's a move, make sure we move it cleanly
25696 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25699 oldParent.removeChild(node);
25702 index = this.childNodes.length;
25704 this.setFirstChild(node);
25706 this.childNodes.push(node);
25707 node.parentNode = this;
25708 var ps = this.childNodes[index-1];
25710 node.previousSibling = ps;
25711 ps.nextSibling = node;
25713 node.previousSibling = null;
25715 node.nextSibling = null;
25716 this.setLastChild(node);
25717 node.setOwnerTree(this.getOwnerTree());
25718 this.fireEvent("append", this.ownerTree, this, node, index);
25719 if(this.ownerTree) {
25720 this.ownerTree.fireEvent("appendnode", this, node, index);
25723 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25730 * Removes a child node from this node.
25731 * @param {Node} node The node to remove
25732 * @return {Node} The removed node
25734 removeChild : function(node){
25735 var index = this.childNodes.indexOf(node);
25739 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25743 // remove it from childNodes collection
25744 this.childNodes.splice(index, 1);
25747 if(node.previousSibling){
25748 node.previousSibling.nextSibling = node.nextSibling;
25750 if(node.nextSibling){
25751 node.nextSibling.previousSibling = node.previousSibling;
25754 // update child refs
25755 if(this.firstChild == node){
25756 this.setFirstChild(node.nextSibling);
25758 if(this.lastChild == node){
25759 this.setLastChild(node.previousSibling);
25762 node.setOwnerTree(null);
25763 // clear any references from the node
25764 node.parentNode = null;
25765 node.previousSibling = null;
25766 node.nextSibling = null;
25767 this.fireEvent("remove", this.ownerTree, this, node);
25772 * Inserts the first node before the second node in this nodes childNodes collection.
25773 * @param {Node} node The node to insert
25774 * @param {Node} refNode The node to insert before (if null the node is appended)
25775 * @return {Node} The inserted node
25777 insertBefore : function(node, refNode){
25778 if(!refNode){ // like standard Dom, refNode can be null for append
25779 return this.appendChild(node);
25782 if(node == refNode){
25786 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25789 var index = this.childNodes.indexOf(refNode);
25790 var oldParent = node.parentNode;
25791 var refIndex = index;
25793 // when moving internally, indexes will change after remove
25794 if(oldParent == this && this.childNodes.indexOf(node) < index){
25798 // it's a move, make sure we move it cleanly
25800 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25803 oldParent.removeChild(node);
25806 this.setFirstChild(node);
25808 this.childNodes.splice(refIndex, 0, node);
25809 node.parentNode = this;
25810 var ps = this.childNodes[refIndex-1];
25812 node.previousSibling = ps;
25813 ps.nextSibling = node;
25815 node.previousSibling = null;
25817 node.nextSibling = refNode;
25818 refNode.previousSibling = node;
25819 node.setOwnerTree(this.getOwnerTree());
25820 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25822 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25828 * Returns the child node at the specified index.
25829 * @param {Number} index
25832 item : function(index){
25833 return this.childNodes[index];
25837 * Replaces one child node in this node with another.
25838 * @param {Node} newChild The replacement node
25839 * @param {Node} oldChild The node to replace
25840 * @return {Node} The replaced node
25842 replaceChild : function(newChild, oldChild){
25843 this.insertBefore(newChild, oldChild);
25844 this.removeChild(oldChild);
25849 * Returns the index of a child node
25850 * @param {Node} node
25851 * @return {Number} The index of the node or -1 if it was not found
25853 indexOf : function(child){
25854 return this.childNodes.indexOf(child);
25858 * Returns the tree this node is in.
25861 getOwnerTree : function(){
25862 // if it doesn't have one, look for one
25863 if(!this.ownerTree){
25867 this.ownerTree = p.ownerTree;
25873 return this.ownerTree;
25877 * Returns depth of this node (the root node has a depth of 0)
25880 getDepth : function(){
25883 while(p.parentNode){
25891 setOwnerTree : function(tree){
25892 // if it's move, we need to update everyone
25893 if(tree != this.ownerTree){
25894 if(this.ownerTree){
25895 this.ownerTree.unregisterNode(this);
25897 this.ownerTree = tree;
25898 var cs = this.childNodes;
25899 for(var i = 0, len = cs.length; i < len; i++) {
25900 cs[i].setOwnerTree(tree);
25903 tree.registerNode(this);
25909 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25910 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25911 * @return {String} The path
25913 getPath : function(attr){
25914 attr = attr || "id";
25915 var p = this.parentNode;
25916 var b = [this.attributes[attr]];
25918 b.unshift(p.attributes[attr]);
25921 var sep = this.getOwnerTree().pathSeparator;
25922 return sep + b.join(sep);
25926 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25927 * function call will be the scope provided or the current node. The arguments to the function
25928 * will be the args provided or the current node. If the function returns false at any point,
25929 * the bubble is stopped.
25930 * @param {Function} fn The function to call
25931 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25932 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25934 bubble : function(fn, scope, args){
25937 if(fn.call(scope || p, args || p) === false){
25945 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25946 * function call will be the scope provided or the current node. The arguments to the function
25947 * will be the args provided or the current node. If the function returns false at any point,
25948 * the cascade is stopped on that branch.
25949 * @param {Function} fn The function to call
25950 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25951 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25953 cascade : function(fn, scope, args){
25954 if(fn.call(scope || this, args || this) !== false){
25955 var cs = this.childNodes;
25956 for(var i = 0, len = cs.length; i < len; i++) {
25957 cs[i].cascade(fn, scope, args);
25963 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25964 * function call will be the scope provided or the current node. The arguments to the function
25965 * will be the args provided or the current node. If the function returns false at any point,
25966 * the iteration stops.
25967 * @param {Function} fn The function to call
25968 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25969 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25971 eachChild : function(fn, scope, args){
25972 var cs = this.childNodes;
25973 for(var i = 0, len = cs.length; i < len; i++) {
25974 if(fn.call(scope || this, args || cs[i]) === false){
25981 * Finds the first child that has the attribute with the specified value.
25982 * @param {String} attribute The attribute name
25983 * @param {Mixed} value The value to search for
25984 * @return {Node} The found child or null if none was found
25986 findChild : function(attribute, value){
25987 var cs = this.childNodes;
25988 for(var i = 0, len = cs.length; i < len; i++) {
25989 if(cs[i].attributes[attribute] == value){
25997 * Finds the first child by a custom function. The child matches if the function passed
25999 * @param {Function} fn
26000 * @param {Object} scope (optional)
26001 * @return {Node} The found child or null if none was found
26003 findChildBy : function(fn, scope){
26004 var cs = this.childNodes;
26005 for(var i = 0, len = cs.length; i < len; i++) {
26006 if(fn.call(scope||cs[i], cs[i]) === true){
26014 * Sorts this nodes children using the supplied sort function
26015 * @param {Function} fn
26016 * @param {Object} scope (optional)
26018 sort : function(fn, scope){
26019 var cs = this.childNodes;
26020 var len = cs.length;
26022 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
26024 for(var i = 0; i < len; i++){
26026 n.previousSibling = cs[i-1];
26027 n.nextSibling = cs[i+1];
26029 this.setFirstChild(n);
26032 this.setLastChild(n);
26039 * Returns true if this node is an ancestor (at any point) of the passed node.
26040 * @param {Node} node
26041 * @return {Boolean}
26043 contains : function(node){
26044 return node.isAncestor(this);
26048 * Returns true if the passed node is an ancestor (at any point) of this node.
26049 * @param {Node} node
26050 * @return {Boolean}
26052 isAncestor : function(node){
26053 var p = this.parentNode;
26063 toString : function(){
26064 return "[Node"+(this.id?" "+this.id:"")+"]";
26068 * Ext JS Library 1.1.1
26069 * Copyright(c) 2006-2007, Ext JS, LLC.
26071 * Originally Released Under LGPL - original licence link has changed is not relivant.
26074 * <script type="text/javascript">
26079 * @class Roo.Shadow
26080 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26081 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26082 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26084 * Create a new Shadow
26085 * @param {Object} config The config object
26087 Roo.Shadow = function(config){
26088 Roo.apply(this, config);
26089 if(typeof this.mode != "string"){
26090 this.mode = this.defaultMode;
26092 var o = this.offset, a = {h: 0};
26093 var rad = Math.floor(this.offset/2);
26094 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26100 a.l -= this.offset + rad;
26101 a.t -= this.offset + rad;
26112 a.l -= (this.offset - rad);
26113 a.t -= this.offset + rad;
26115 a.w -= (this.offset - rad)*2;
26126 a.l -= (this.offset - rad);
26127 a.t -= (this.offset - rad);
26129 a.w -= (this.offset + rad + 1);
26130 a.h -= (this.offset + rad);
26139 Roo.Shadow.prototype = {
26141 * @cfg {String} mode
26142 * The shadow display mode. Supports the following options:<br />
26143 * sides: Shadow displays on both sides and bottom only<br />
26144 * frame: Shadow displays equally on all four sides<br />
26145 * drop: Traditional bottom-right drop shadow (default)
26148 * @cfg {String} offset
26149 * The number of pixels to offset the shadow from the element (defaults to 4)
26154 defaultMode: "drop",
26157 * Displays the shadow under the target element
26158 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26160 show : function(target){
26161 target = Roo.get(target);
26163 this.el = Roo.Shadow.Pool.pull();
26164 if(this.el.dom.nextSibling != target.dom){
26165 this.el.insertBefore(target);
26168 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26170 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26173 target.getLeft(true),
26174 target.getTop(true),
26178 this.el.dom.style.display = "block";
26182 * Returns true if the shadow is visible, else false
26184 isVisible : function(){
26185 return this.el ? true : false;
26189 * Direct alignment when values are already available. Show must be called at least once before
26190 * calling this method to ensure it is initialized.
26191 * @param {Number} left The target element left position
26192 * @param {Number} top The target element top position
26193 * @param {Number} width The target element width
26194 * @param {Number} height The target element height
26196 realign : function(l, t, w, h){
26200 var a = this.adjusts, d = this.el.dom, s = d.style;
26202 s.left = (l+a.l)+"px";
26203 s.top = (t+a.t)+"px";
26204 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26206 if(s.width != sws || s.height != shs){
26210 var cn = d.childNodes;
26211 var sww = Math.max(0, (sw-12))+"px";
26212 cn[0].childNodes[1].style.width = sww;
26213 cn[1].childNodes[1].style.width = sww;
26214 cn[2].childNodes[1].style.width = sww;
26215 cn[1].style.height = Math.max(0, (sh-12))+"px";
26221 * Hides this shadow
26225 this.el.dom.style.display = "none";
26226 Roo.Shadow.Pool.push(this.el);
26232 * Adjust the z-index of this shadow
26233 * @param {Number} zindex The new z-index
26235 setZIndex : function(z){
26238 this.el.setStyle("z-index", z);
26243 // Private utility class that manages the internal Shadow cache
26244 Roo.Shadow.Pool = function(){
26246 var markup = Roo.isIE ?
26247 '<div class="x-ie-shadow"></div>' :
26248 '<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>';
26251 var sh = p.shift();
26253 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26254 sh.autoBoxAdjust = false;
26259 push : function(sh){
26265 * Ext JS Library 1.1.1
26266 * Copyright(c) 2006-2007, Ext JS, LLC.
26268 * Originally Released Under LGPL - original licence link has changed is not relivant.
26271 * <script type="text/javascript">
26276 * @class Roo.SplitBar
26277 * @extends Roo.util.Observable
26278 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26282 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26283 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26284 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26285 split.minSize = 100;
26286 split.maxSize = 600;
26287 split.animate = true;
26288 split.on('moved', splitterMoved);
26291 * Create a new SplitBar
26292 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26293 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26294 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26295 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26296 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26297 position of the SplitBar).
26299 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26302 this.el = Roo.get(dragElement, true);
26303 this.el.dom.unselectable = "on";
26305 this.resizingEl = Roo.get(resizingElement, true);
26309 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26310 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26313 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26316 * The minimum size of the resizing element. (Defaults to 0)
26322 * The maximum size of the resizing element. (Defaults to 2000)
26325 this.maxSize = 2000;
26328 * Whether to animate the transition to the new size
26331 this.animate = false;
26334 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26337 this.useShim = false;
26342 if(!existingProxy){
26344 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26346 this.proxy = Roo.get(existingProxy).dom;
26349 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26352 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26355 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26358 this.dragSpecs = {};
26361 * @private The adapter to use to positon and resize elements
26363 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26364 this.adapter.init(this);
26366 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26368 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26369 this.el.addClass("x-splitbar-h");
26372 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26373 this.el.addClass("x-splitbar-v");
26379 * Fires when the splitter is moved (alias for {@link #event-moved})
26380 * @param {Roo.SplitBar} this
26381 * @param {Number} newSize the new width or height
26386 * Fires when the splitter is moved
26387 * @param {Roo.SplitBar} this
26388 * @param {Number} newSize the new width or height
26392 * @event beforeresize
26393 * Fires before the splitter is dragged
26394 * @param {Roo.SplitBar} this
26396 "beforeresize" : true,
26398 "beforeapply" : true
26401 Roo.util.Observable.call(this);
26404 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26405 onStartProxyDrag : function(x, y){
26406 this.fireEvent("beforeresize", this);
26408 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26410 o.enableDisplayMode("block");
26411 // all splitbars share the same overlay
26412 Roo.SplitBar.prototype.overlay = o;
26414 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26415 this.overlay.show();
26416 Roo.get(this.proxy).setDisplayed("block");
26417 var size = this.adapter.getElementSize(this);
26418 this.activeMinSize = this.getMinimumSize();;
26419 this.activeMaxSize = this.getMaximumSize();;
26420 var c1 = size - this.activeMinSize;
26421 var c2 = Math.max(this.activeMaxSize - size, 0);
26422 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26423 this.dd.resetConstraints();
26424 this.dd.setXConstraint(
26425 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26426 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26428 this.dd.setYConstraint(0, 0);
26430 this.dd.resetConstraints();
26431 this.dd.setXConstraint(0, 0);
26432 this.dd.setYConstraint(
26433 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26434 this.placement == Roo.SplitBar.TOP ? c2 : c1
26437 this.dragSpecs.startSize = size;
26438 this.dragSpecs.startPoint = [x, y];
26439 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26443 * @private Called after the drag operation by the DDProxy
26445 onEndProxyDrag : function(e){
26446 Roo.get(this.proxy).setDisplayed(false);
26447 var endPoint = Roo.lib.Event.getXY(e);
26449 this.overlay.hide();
26452 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26453 newSize = this.dragSpecs.startSize +
26454 (this.placement == Roo.SplitBar.LEFT ?
26455 endPoint[0] - this.dragSpecs.startPoint[0] :
26456 this.dragSpecs.startPoint[0] - endPoint[0]
26459 newSize = this.dragSpecs.startSize +
26460 (this.placement == Roo.SplitBar.TOP ?
26461 endPoint[1] - this.dragSpecs.startPoint[1] :
26462 this.dragSpecs.startPoint[1] - endPoint[1]
26465 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26466 if(newSize != this.dragSpecs.startSize){
26467 if(this.fireEvent('beforeapply', this, newSize) !== false){
26468 this.adapter.setElementSize(this, newSize);
26469 this.fireEvent("moved", this, newSize);
26470 this.fireEvent("resize", this, newSize);
26476 * Get the adapter this SplitBar uses
26477 * @return The adapter object
26479 getAdapter : function(){
26480 return this.adapter;
26484 * Set the adapter this SplitBar uses
26485 * @param {Object} adapter A SplitBar adapter object
26487 setAdapter : function(adapter){
26488 this.adapter = adapter;
26489 this.adapter.init(this);
26493 * Gets the minimum size for the resizing element
26494 * @return {Number} The minimum size
26496 getMinimumSize : function(){
26497 return this.minSize;
26501 * Sets the minimum size for the resizing element
26502 * @param {Number} minSize The minimum size
26504 setMinimumSize : function(minSize){
26505 this.minSize = minSize;
26509 * Gets the maximum size for the resizing element
26510 * @return {Number} The maximum size
26512 getMaximumSize : function(){
26513 return this.maxSize;
26517 * Sets the maximum size for the resizing element
26518 * @param {Number} maxSize The maximum size
26520 setMaximumSize : function(maxSize){
26521 this.maxSize = maxSize;
26525 * Sets the initialize size for the resizing element
26526 * @param {Number} size The initial size
26528 setCurrentSize : function(size){
26529 var oldAnimate = this.animate;
26530 this.animate = false;
26531 this.adapter.setElementSize(this, size);
26532 this.animate = oldAnimate;
26536 * Destroy this splitbar.
26537 * @param {Boolean} removeEl True to remove the element
26539 destroy : function(removeEl){
26541 this.shim.remove();
26544 this.proxy.parentNode.removeChild(this.proxy);
26552 * @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.
26554 Roo.SplitBar.createProxy = function(dir){
26555 var proxy = new Roo.Element(document.createElement("div"));
26556 proxy.unselectable();
26557 var cls = 'x-splitbar-proxy';
26558 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26559 document.body.appendChild(proxy.dom);
26564 * @class Roo.SplitBar.BasicLayoutAdapter
26565 * Default Adapter. It assumes the splitter and resizing element are not positioned
26566 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26568 Roo.SplitBar.BasicLayoutAdapter = function(){
26571 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26572 // do nothing for now
26573 init : function(s){
26577 * Called before drag operations to get the current size of the resizing element.
26578 * @param {Roo.SplitBar} s The SplitBar using this adapter
26580 getElementSize : function(s){
26581 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26582 return s.resizingEl.getWidth();
26584 return s.resizingEl.getHeight();
26589 * Called after drag operations to set the size of the resizing element.
26590 * @param {Roo.SplitBar} s The SplitBar using this adapter
26591 * @param {Number} newSize The new size to set
26592 * @param {Function} onComplete A function to be invoked when resizing is complete
26594 setElementSize : function(s, newSize, onComplete){
26595 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26597 s.resizingEl.setWidth(newSize);
26599 onComplete(s, newSize);
26602 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26607 s.resizingEl.setHeight(newSize);
26609 onComplete(s, newSize);
26612 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26619 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26620 * @extends Roo.SplitBar.BasicLayoutAdapter
26621 * Adapter that moves the splitter element to align with the resized sizing element.
26622 * Used with an absolute positioned SplitBar.
26623 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26624 * document.body, make sure you assign an id to the body element.
26626 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26627 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26628 this.container = Roo.get(container);
26631 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26632 init : function(s){
26633 this.basic.init(s);
26636 getElementSize : function(s){
26637 return this.basic.getElementSize(s);
26640 setElementSize : function(s, newSize, onComplete){
26641 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26644 moveSplitter : function(s){
26645 var yes = Roo.SplitBar;
26646 switch(s.placement){
26648 s.el.setX(s.resizingEl.getRight());
26651 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26654 s.el.setY(s.resizingEl.getBottom());
26657 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26664 * Orientation constant - Create a vertical SplitBar
26668 Roo.SplitBar.VERTICAL = 1;
26671 * Orientation constant - Create a horizontal SplitBar
26675 Roo.SplitBar.HORIZONTAL = 2;
26678 * Placement constant - The resizing element is to the left of the splitter element
26682 Roo.SplitBar.LEFT = 1;
26685 * Placement constant - The resizing element is to the right of the splitter element
26689 Roo.SplitBar.RIGHT = 2;
26692 * Placement constant - The resizing element is positioned above the splitter element
26696 Roo.SplitBar.TOP = 3;
26699 * Placement constant - The resizing element is positioned under splitter element
26703 Roo.SplitBar.BOTTOM = 4;
26706 * Ext JS Library 1.1.1
26707 * Copyright(c) 2006-2007, Ext JS, LLC.
26709 * Originally Released Under LGPL - original licence link has changed is not relivant.
26712 * <script type="text/javascript">
26717 * @extends Roo.util.Observable
26718 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26719 * This class also supports single and multi selection modes. <br>
26720 * Create a data model bound view:
26722 var store = new Roo.data.Store(...);
26724 var view = new Roo.View({
26726 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26728 singleSelect: true,
26729 selectedClass: "ydataview-selected",
26733 // listen for node click?
26734 view.on("click", function(vw, index, node, e){
26735 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26739 dataModel.load("foobar.xml");
26741 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26743 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26744 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26746 * Note: old style constructor is still suported (container, template, config)
26749 * Create a new View
26750 * @param {Object} config The config object
26753 Roo.View = function(config, depreciated_tpl, depreciated_config){
26755 this.parent = false;
26757 if (typeof(depreciated_tpl) == 'undefined') {
26758 // new way.. - universal constructor.
26759 Roo.apply(this, config);
26760 this.el = Roo.get(this.el);
26763 this.el = Roo.get(config);
26764 this.tpl = depreciated_tpl;
26765 Roo.apply(this, depreciated_config);
26767 this.wrapEl = this.el.wrap().wrap();
26768 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26771 if(typeof(this.tpl) == "string"){
26772 this.tpl = new Roo.Template(this.tpl);
26774 // support xtype ctors..
26775 this.tpl = new Roo.factory(this.tpl, Roo);
26779 this.tpl.compile();
26784 * @event beforeclick
26785 * Fires before a click is processed. Returns false to cancel the default action.
26786 * @param {Roo.View} this
26787 * @param {Number} index The index of the target node
26788 * @param {HTMLElement} node The target node
26789 * @param {Roo.EventObject} e The raw event object
26791 "beforeclick" : true,
26794 * Fires when a template node is clicked.
26795 * @param {Roo.View} this
26796 * @param {Number} index The index of the target node
26797 * @param {HTMLElement} node The target node
26798 * @param {Roo.EventObject} e The raw event object
26803 * Fires when a template node is double clicked.
26804 * @param {Roo.View} this
26805 * @param {Number} index The index of the target node
26806 * @param {HTMLElement} node The target node
26807 * @param {Roo.EventObject} e The raw event object
26811 * @event contextmenu
26812 * Fires when a template node is right clicked.
26813 * @param {Roo.View} this
26814 * @param {Number} index The index of the target node
26815 * @param {HTMLElement} node The target node
26816 * @param {Roo.EventObject} e The raw event object
26818 "contextmenu" : true,
26820 * @event selectionchange
26821 * Fires when the selected nodes change.
26822 * @param {Roo.View} this
26823 * @param {Array} selections Array of the selected nodes
26825 "selectionchange" : true,
26828 * @event beforeselect
26829 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26830 * @param {Roo.View} this
26831 * @param {HTMLElement} node The node to be selected
26832 * @param {Array} selections Array of currently selected nodes
26834 "beforeselect" : true,
26836 * @event preparedata
26837 * Fires on every row to render, to allow you to change the data.
26838 * @param {Roo.View} this
26839 * @param {Object} data to be rendered (change this)
26841 "preparedata" : true
26849 "click": this.onClick,
26850 "dblclick": this.onDblClick,
26851 "contextmenu": this.onContextMenu,
26855 this.selections = [];
26857 this.cmp = new Roo.CompositeElementLite([]);
26859 this.store = Roo.factory(this.store, Roo.data);
26860 this.setStore(this.store, true);
26863 if ( this.footer && this.footer.xtype) {
26865 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26867 this.footer.dataSource = this.store;
26868 this.footer.container = fctr;
26869 this.footer = Roo.factory(this.footer, Roo);
26870 fctr.insertFirst(this.el);
26872 // this is a bit insane - as the paging toolbar seems to detach the el..
26873 // dom.parentNode.parentNode.parentNode
26874 // they get detached?
26878 Roo.View.superclass.constructor.call(this);
26883 Roo.extend(Roo.View, Roo.util.Observable, {
26886 * @cfg {Roo.data.Store} store Data store to load data from.
26891 * @cfg {String|Roo.Element} el The container element.
26896 * @cfg {String|Roo.Template} tpl The template used by this View
26900 * @cfg {String} dataName the named area of the template to use as the data area
26901 * Works with domtemplates roo-name="name"
26905 * @cfg {String} selectedClass The css class to add to selected nodes
26907 selectedClass : "x-view-selected",
26909 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26914 * @cfg {String} text to display on mask (default Loading)
26918 * @cfg {Boolean} multiSelect Allow multiple selection
26920 multiSelect : false,
26922 * @cfg {Boolean} singleSelect Allow single selection
26924 singleSelect: false,
26927 * @cfg {Boolean} toggleSelect - selecting
26929 toggleSelect : false,
26932 * @cfg {Boolean} tickable - selecting
26937 * Returns the element this view is bound to.
26938 * @return {Roo.Element}
26940 getEl : function(){
26941 return this.wrapEl;
26947 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26949 refresh : function(){
26950 //Roo.log('refresh');
26953 // if we are using something like 'domtemplate', then
26954 // the what gets used is:
26955 // t.applySubtemplate(NAME, data, wrapping data..)
26956 // the outer template then get' applied with
26957 // the store 'extra data'
26958 // and the body get's added to the
26959 // roo-name="data" node?
26960 // <span class='roo-tpl-{name}'></span> ?????
26964 this.clearSelections();
26965 this.el.update("");
26967 var records = this.store.getRange();
26968 if(records.length < 1) {
26970 // is this valid?? = should it render a template??
26972 this.el.update(this.emptyText);
26976 if (this.dataName) {
26977 this.el.update(t.apply(this.store.meta)); //????
26978 el = this.el.child('.roo-tpl-' + this.dataName);
26981 for(var i = 0, len = records.length; i < len; i++){
26982 var data = this.prepareData(records[i].data, i, records[i]);
26983 this.fireEvent("preparedata", this, data, i, records[i]);
26985 var d = Roo.apply({}, data);
26988 Roo.apply(d, {'roo-id' : Roo.id()});
26992 Roo.each(this.parent.item, function(item){
26993 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26996 Roo.apply(d, {'roo-data-checked' : 'checked'});
27000 html[html.length] = Roo.util.Format.trim(
27002 t.applySubtemplate(this.dataName, d, this.store.meta) :
27009 el.update(html.join(""));
27010 this.nodes = el.dom.childNodes;
27011 this.updateIndexes(0);
27016 * Function to override to reformat the data that is sent to
27017 * the template for each node.
27018 * DEPRICATED - use the preparedata event handler.
27019 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
27020 * a JSON object for an UpdateManager bound view).
27022 prepareData : function(data, index, record)
27024 this.fireEvent("preparedata", this, data, index, record);
27028 onUpdate : function(ds, record){
27029 // Roo.log('on update');
27030 this.clearSelections();
27031 var index = this.store.indexOf(record);
27032 var n = this.nodes[index];
27033 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
27034 n.parentNode.removeChild(n);
27035 this.updateIndexes(index, index);
27041 onAdd : function(ds, records, index)
27043 //Roo.log(['on Add', ds, records, index] );
27044 this.clearSelections();
27045 if(this.nodes.length == 0){
27049 var n = this.nodes[index];
27050 for(var i = 0, len = records.length; i < len; i++){
27051 var d = this.prepareData(records[i].data, i, records[i]);
27053 this.tpl.insertBefore(n, d);
27056 this.tpl.append(this.el, d);
27059 this.updateIndexes(index);
27062 onRemove : function(ds, record, index){
27063 // Roo.log('onRemove');
27064 this.clearSelections();
27065 var el = this.dataName ?
27066 this.el.child('.roo-tpl-' + this.dataName) :
27069 el.dom.removeChild(this.nodes[index]);
27070 this.updateIndexes(index);
27074 * Refresh an individual node.
27075 * @param {Number} index
27077 refreshNode : function(index){
27078 this.onUpdate(this.store, this.store.getAt(index));
27081 updateIndexes : function(startIndex, endIndex){
27082 var ns = this.nodes;
27083 startIndex = startIndex || 0;
27084 endIndex = endIndex || ns.length - 1;
27085 for(var i = startIndex; i <= endIndex; i++){
27086 ns[i].nodeIndex = i;
27091 * Changes the data store this view uses and refresh the view.
27092 * @param {Store} store
27094 setStore : function(store, initial){
27095 if(!initial && this.store){
27096 this.store.un("datachanged", this.refresh);
27097 this.store.un("add", this.onAdd);
27098 this.store.un("remove", this.onRemove);
27099 this.store.un("update", this.onUpdate);
27100 this.store.un("clear", this.refresh);
27101 this.store.un("beforeload", this.onBeforeLoad);
27102 this.store.un("load", this.onLoad);
27103 this.store.un("loadexception", this.onLoad);
27107 store.on("datachanged", this.refresh, this);
27108 store.on("add", this.onAdd, this);
27109 store.on("remove", this.onRemove, this);
27110 store.on("update", this.onUpdate, this);
27111 store.on("clear", this.refresh, this);
27112 store.on("beforeload", this.onBeforeLoad, this);
27113 store.on("load", this.onLoad, this);
27114 store.on("loadexception", this.onLoad, this);
27122 * onbeforeLoad - masks the loading area.
27125 onBeforeLoad : function(store,opts)
27127 //Roo.log('onBeforeLoad');
27129 this.el.update("");
27131 this.el.mask(this.mask ? this.mask : "Loading" );
27133 onLoad : function ()
27140 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27141 * @param {HTMLElement} node
27142 * @return {HTMLElement} The template node
27144 findItemFromChild : function(node){
27145 var el = this.dataName ?
27146 this.el.child('.roo-tpl-' + this.dataName,true) :
27149 if(!node || node.parentNode == el){
27152 var p = node.parentNode;
27153 while(p && p != el){
27154 if(p.parentNode == el){
27163 onClick : function(e){
27164 var item = this.findItemFromChild(e.getTarget());
27166 var index = this.indexOf(item);
27167 if(this.onItemClick(item, index, e) !== false){
27168 this.fireEvent("click", this, index, item, e);
27171 this.clearSelections();
27176 onContextMenu : function(e){
27177 var item = this.findItemFromChild(e.getTarget());
27179 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27184 onDblClick : function(e){
27185 var item = this.findItemFromChild(e.getTarget());
27187 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27191 onItemClick : function(item, index, e)
27193 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27196 if (this.toggleSelect) {
27197 var m = this.isSelected(item) ? 'unselect' : 'select';
27200 _t[m](item, true, false);
27203 if(this.multiSelect || this.singleSelect){
27204 if(this.multiSelect && e.shiftKey && this.lastSelection){
27205 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27207 this.select(item, this.multiSelect && e.ctrlKey);
27208 this.lastSelection = item;
27211 if(!this.tickable){
27212 e.preventDefault();
27220 * Get the number of selected nodes.
27223 getSelectionCount : function(){
27224 return this.selections.length;
27228 * Get the currently selected nodes.
27229 * @return {Array} An array of HTMLElements
27231 getSelectedNodes : function(){
27232 return this.selections;
27236 * Get the indexes of the selected nodes.
27239 getSelectedIndexes : function(){
27240 var indexes = [], s = this.selections;
27241 for(var i = 0, len = s.length; i < len; i++){
27242 indexes.push(s[i].nodeIndex);
27248 * Clear all selections
27249 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27251 clearSelections : function(suppressEvent){
27252 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27253 this.cmp.elements = this.selections;
27254 this.cmp.removeClass(this.selectedClass);
27255 this.selections = [];
27256 if(!suppressEvent){
27257 this.fireEvent("selectionchange", this, this.selections);
27263 * Returns true if the passed node is selected
27264 * @param {HTMLElement/Number} node The node or node index
27265 * @return {Boolean}
27267 isSelected : function(node){
27268 var s = this.selections;
27272 node = this.getNode(node);
27273 return s.indexOf(node) !== -1;
27278 * @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
27279 * @param {Boolean} keepExisting (optional) true to keep existing selections
27280 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27282 select : function(nodeInfo, keepExisting, suppressEvent){
27283 if(nodeInfo instanceof Array){
27285 this.clearSelections(true);
27287 for(var i = 0, len = nodeInfo.length; i < len; i++){
27288 this.select(nodeInfo[i], true, true);
27292 var node = this.getNode(nodeInfo);
27293 if(!node || this.isSelected(node)){
27294 return; // already selected.
27297 this.clearSelections(true);
27300 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27301 Roo.fly(node).addClass(this.selectedClass);
27302 this.selections.push(node);
27303 if(!suppressEvent){
27304 this.fireEvent("selectionchange", this, this.selections);
27312 * @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
27313 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27314 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27316 unselect : function(nodeInfo, keepExisting, suppressEvent)
27318 if(nodeInfo instanceof Array){
27319 Roo.each(this.selections, function(s) {
27320 this.unselect(s, nodeInfo);
27324 var node = this.getNode(nodeInfo);
27325 if(!node || !this.isSelected(node)){
27326 //Roo.log("not selected");
27327 return; // not selected.
27331 Roo.each(this.selections, function(s) {
27333 Roo.fly(node).removeClass(this.selectedClass);
27340 this.selections= ns;
27341 this.fireEvent("selectionchange", this, this.selections);
27345 * Gets a template node.
27346 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27347 * @return {HTMLElement} The node or null if it wasn't found
27349 getNode : function(nodeInfo){
27350 if(typeof nodeInfo == "string"){
27351 return document.getElementById(nodeInfo);
27352 }else if(typeof nodeInfo == "number"){
27353 return this.nodes[nodeInfo];
27359 * Gets a range template nodes.
27360 * @param {Number} startIndex
27361 * @param {Number} endIndex
27362 * @return {Array} An array of nodes
27364 getNodes : function(start, end){
27365 var ns = this.nodes;
27366 start = start || 0;
27367 end = typeof end == "undefined" ? ns.length - 1 : end;
27370 for(var i = start; i <= end; i++){
27374 for(var i = start; i >= end; i--){
27382 * Finds the index of the passed node
27383 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27384 * @return {Number} The index of the node or -1
27386 indexOf : function(node){
27387 node = this.getNode(node);
27388 if(typeof node.nodeIndex == "number"){
27389 return node.nodeIndex;
27391 var ns = this.nodes;
27392 for(var i = 0, len = ns.length; i < len; i++){
27402 * Ext JS Library 1.1.1
27403 * Copyright(c) 2006-2007, Ext JS, LLC.
27405 * Originally Released Under LGPL - original licence link has changed is not relivant.
27408 * <script type="text/javascript">
27412 * @class Roo.JsonView
27413 * @extends Roo.View
27414 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27416 var view = new Roo.JsonView({
27417 container: "my-element",
27418 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27423 // listen for node click?
27424 view.on("click", function(vw, index, node, e){
27425 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27428 // direct load of JSON data
27429 view.load("foobar.php");
27431 // Example from my blog list
27432 var tpl = new Roo.Template(
27433 '<div class="entry">' +
27434 '<a class="entry-title" href="{link}">{title}</a>' +
27435 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27436 "</div><hr />"
27439 var moreView = new Roo.JsonView({
27440 container : "entry-list",
27444 moreView.on("beforerender", this.sortEntries, this);
27446 url: "/blog/get-posts.php",
27447 params: "allposts=true",
27448 text: "Loading Blog Entries..."
27452 * Note: old code is supported with arguments : (container, template, config)
27456 * Create a new JsonView
27458 * @param {Object} config The config object
27461 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27464 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27466 var um = this.el.getUpdateManager();
27467 um.setRenderer(this);
27468 um.on("update", this.onLoad, this);
27469 um.on("failure", this.onLoadException, this);
27472 * @event beforerender
27473 * Fires before rendering of the downloaded JSON data.
27474 * @param {Roo.JsonView} this
27475 * @param {Object} data The JSON data loaded
27479 * Fires when data is loaded.
27480 * @param {Roo.JsonView} this
27481 * @param {Object} data The JSON data loaded
27482 * @param {Object} response The raw Connect response object
27485 * @event loadexception
27486 * Fires when loading fails.
27487 * @param {Roo.JsonView} this
27488 * @param {Object} response The raw Connect response object
27491 'beforerender' : true,
27493 'loadexception' : true
27496 Roo.extend(Roo.JsonView, Roo.View, {
27498 * @type {String} The root property in the loaded JSON object that contains the data
27503 * Refreshes the view.
27505 refresh : function(){
27506 this.clearSelections();
27507 this.el.update("");
27509 var o = this.jsonData;
27510 if(o && o.length > 0){
27511 for(var i = 0, len = o.length; i < len; i++){
27512 var data = this.prepareData(o[i], i, o);
27513 html[html.length] = this.tpl.apply(data);
27516 html.push(this.emptyText);
27518 this.el.update(html.join(""));
27519 this.nodes = this.el.dom.childNodes;
27520 this.updateIndexes(0);
27524 * 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.
27525 * @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:
27528 url: "your-url.php",
27529 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27530 callback: yourFunction,
27531 scope: yourObject, //(optional scope)
27534 text: "Loading...",
27539 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27540 * 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.
27541 * @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}
27542 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27543 * @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.
27546 var um = this.el.getUpdateManager();
27547 um.update.apply(um, arguments);
27550 // note - render is a standard framework call...
27551 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27552 render : function(el, response){
27554 this.clearSelections();
27555 this.el.update("");
27558 if (response != '') {
27559 o = Roo.util.JSON.decode(response.responseText);
27562 o = o[this.jsonRoot];
27568 * The current JSON data or null
27571 this.beforeRender();
27576 * Get the number of records in the current JSON dataset
27579 getCount : function(){
27580 return this.jsonData ? this.jsonData.length : 0;
27584 * Returns the JSON object for the specified node(s)
27585 * @param {HTMLElement/Array} node The node or an array of nodes
27586 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27587 * you get the JSON object for the node
27589 getNodeData : function(node){
27590 if(node instanceof Array){
27592 for(var i = 0, len = node.length; i < len; i++){
27593 data.push(this.getNodeData(node[i]));
27597 return this.jsonData[this.indexOf(node)] || null;
27600 beforeRender : function(){
27601 this.snapshot = this.jsonData;
27603 this.sort.apply(this, this.sortInfo);
27605 this.fireEvent("beforerender", this, this.jsonData);
27608 onLoad : function(el, o){
27609 this.fireEvent("load", this, this.jsonData, o);
27612 onLoadException : function(el, o){
27613 this.fireEvent("loadexception", this, o);
27617 * Filter the data by a specific property.
27618 * @param {String} property A property on your JSON objects
27619 * @param {String/RegExp} value Either string that the property values
27620 * should start with, or a RegExp to test against the property
27622 filter : function(property, value){
27625 var ss = this.snapshot;
27626 if(typeof value == "string"){
27627 var vlen = value.length;
27629 this.clearFilter();
27632 value = value.toLowerCase();
27633 for(var i = 0, len = ss.length; i < len; i++){
27635 if(o[property].substr(0, vlen).toLowerCase() == value){
27639 } else if(value.exec){ // regex?
27640 for(var i = 0, len = ss.length; i < len; i++){
27642 if(value.test(o[property])){
27649 this.jsonData = data;
27655 * Filter by a function. The passed function will be called with each
27656 * object in the current dataset. If the function returns true the value is kept,
27657 * otherwise it is filtered.
27658 * @param {Function} fn
27659 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27661 filterBy : function(fn, scope){
27664 var ss = this.snapshot;
27665 for(var i = 0, len = ss.length; i < len; i++){
27667 if(fn.call(scope || this, o)){
27671 this.jsonData = data;
27677 * Clears the current filter.
27679 clearFilter : function(){
27680 if(this.snapshot && this.jsonData != this.snapshot){
27681 this.jsonData = this.snapshot;
27688 * Sorts the data for this view and refreshes it.
27689 * @param {String} property A property on your JSON objects to sort on
27690 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27691 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27693 sort : function(property, dir, sortType){
27694 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27697 var dsc = dir && dir.toLowerCase() == "desc";
27698 var f = function(o1, o2){
27699 var v1 = sortType ? sortType(o1[p]) : o1[p];
27700 var v2 = sortType ? sortType(o2[p]) : o2[p];
27703 return dsc ? +1 : -1;
27704 } else if(v1 > v2){
27705 return dsc ? -1 : +1;
27710 this.jsonData.sort(f);
27712 if(this.jsonData != this.snapshot){
27713 this.snapshot.sort(f);
27719 * Ext JS Library 1.1.1
27720 * Copyright(c) 2006-2007, Ext JS, LLC.
27722 * Originally Released Under LGPL - original licence link has changed is not relivant.
27725 * <script type="text/javascript">
27730 * @class Roo.ColorPalette
27731 * @extends Roo.Component
27732 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27733 * Here's an example of typical usage:
27735 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27736 cp.render('my-div');
27738 cp.on('select', function(palette, selColor){
27739 // do something with selColor
27743 * Create a new ColorPalette
27744 * @param {Object} config The config object
27746 Roo.ColorPalette = function(config){
27747 Roo.ColorPalette.superclass.constructor.call(this, config);
27751 * Fires when a color is selected
27752 * @param {ColorPalette} this
27753 * @param {String} color The 6-digit color hex code (without the # symbol)
27759 this.on("select", this.handler, this.scope, true);
27762 Roo.extend(Roo.ColorPalette, Roo.Component, {
27764 * @cfg {String} itemCls
27765 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27767 itemCls : "x-color-palette",
27769 * @cfg {String} value
27770 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27771 * the hex codes are case-sensitive.
27774 clickEvent:'click',
27776 ctype: "Roo.ColorPalette",
27779 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27781 allowReselect : false,
27784 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27785 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27786 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27787 * of colors with the width setting until the box is symmetrical.</p>
27788 * <p>You can override individual colors if needed:</p>
27790 var cp = new Roo.ColorPalette();
27791 cp.colors[0] = "FF0000"; // change the first box to red
27794 Or you can provide a custom array of your own for complete control:
27796 var cp = new Roo.ColorPalette();
27797 cp.colors = ["000000", "993300", "333300"];
27802 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27803 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27804 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27805 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27806 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27810 onRender : function(container, position){
27811 var t = new Roo.MasterTemplate(
27812 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27814 var c = this.colors;
27815 for(var i = 0, len = c.length; i < len; i++){
27818 var el = document.createElement("div");
27819 el.className = this.itemCls;
27821 container.dom.insertBefore(el, position);
27822 this.el = Roo.get(el);
27823 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27824 if(this.clickEvent != 'click'){
27825 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27830 afterRender : function(){
27831 Roo.ColorPalette.superclass.afterRender.call(this);
27833 var s = this.value;
27840 handleClick : function(e, t){
27841 e.preventDefault();
27842 if(!this.disabled){
27843 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27844 this.select(c.toUpperCase());
27849 * Selects the specified color in the palette (fires the select event)
27850 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27852 select : function(color){
27853 color = color.replace("#", "");
27854 if(color != this.value || this.allowReselect){
27857 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27859 el.child("a.color-"+color).addClass("x-color-palette-sel");
27860 this.value = color;
27861 this.fireEvent("select", this, color);
27866 * Ext JS Library 1.1.1
27867 * Copyright(c) 2006-2007, Ext JS, LLC.
27869 * Originally Released Under LGPL - original licence link has changed is not relivant.
27872 * <script type="text/javascript">
27876 * @class Roo.DatePicker
27877 * @extends Roo.Component
27878 * Simple date picker class.
27880 * Create a new DatePicker
27881 * @param {Object} config The config object
27883 Roo.DatePicker = function(config){
27884 Roo.DatePicker.superclass.constructor.call(this, config);
27886 this.value = config && config.value ?
27887 config.value.clearTime() : new Date().clearTime();
27892 * Fires when a date is selected
27893 * @param {DatePicker} this
27894 * @param {Date} date The selected date
27898 * @event monthchange
27899 * Fires when the displayed month changes
27900 * @param {DatePicker} this
27901 * @param {Date} date The selected month
27903 'monthchange': true
27907 this.on("select", this.handler, this.scope || this);
27909 // build the disabledDatesRE
27910 if(!this.disabledDatesRE && this.disabledDates){
27911 var dd = this.disabledDates;
27913 for(var i = 0; i < dd.length; i++){
27915 if(i != dd.length-1) {
27919 this.disabledDatesRE = new RegExp(re + ")");
27923 Roo.extend(Roo.DatePicker, Roo.Component, {
27925 * @cfg {String} todayText
27926 * The text to display on the button that selects the current date (defaults to "Today")
27928 todayText : "Today",
27930 * @cfg {String} okText
27931 * The text to display on the ok button
27933 okText : " OK ", //   to give the user extra clicking room
27935 * @cfg {String} cancelText
27936 * The text to display on the cancel button
27938 cancelText : "Cancel",
27940 * @cfg {String} todayTip
27941 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27943 todayTip : "{0} (Spacebar)",
27945 * @cfg {Date} minDate
27946 * Minimum allowable date (JavaScript date object, defaults to null)
27950 * @cfg {Date} maxDate
27951 * Maximum allowable date (JavaScript date object, defaults to null)
27955 * @cfg {String} minText
27956 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27958 minText : "This date is before the minimum date",
27960 * @cfg {String} maxText
27961 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27963 maxText : "This date is after the maximum date",
27965 * @cfg {String} format
27966 * The default date format string which can be overriden for localization support. The format must be
27967 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27971 * @cfg {Array} disabledDays
27972 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27974 disabledDays : null,
27976 * @cfg {String} disabledDaysText
27977 * The tooltip to display when the date falls on a disabled day (defaults to "")
27979 disabledDaysText : "",
27981 * @cfg {RegExp} disabledDatesRE
27982 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27984 disabledDatesRE : null,
27986 * @cfg {String} disabledDatesText
27987 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27989 disabledDatesText : "",
27991 * @cfg {Boolean} constrainToViewport
27992 * True to constrain the date picker to the viewport (defaults to true)
27994 constrainToViewport : true,
27996 * @cfg {Array} monthNames
27997 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27999 monthNames : Date.monthNames,
28001 * @cfg {Array} dayNames
28002 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
28004 dayNames : Date.dayNames,
28006 * @cfg {String} nextText
28007 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
28009 nextText: 'Next Month (Control+Right)',
28011 * @cfg {String} prevText
28012 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
28014 prevText: 'Previous Month (Control+Left)',
28016 * @cfg {String} monthYearText
28017 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
28019 monthYearText: 'Choose a month (Control+Up/Down to move years)',
28021 * @cfg {Number} startDay
28022 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
28026 * @cfg {Bool} showClear
28027 * Show a clear button (usefull for date form elements that can be blank.)
28033 * Sets the value of the date field
28034 * @param {Date} value The date to set
28036 setValue : function(value){
28037 var old = this.value;
28039 if (typeof(value) == 'string') {
28041 value = Date.parseDate(value, this.format);
28044 value = new Date();
28047 this.value = value.clearTime(true);
28049 this.update(this.value);
28054 * Gets the current selected value of the date field
28055 * @return {Date} The selected date
28057 getValue : function(){
28062 focus : function(){
28064 this.update(this.activeDate);
28069 onRender : function(container, position){
28072 '<table cellspacing="0">',
28073 '<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>',
28074 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28075 var dn = this.dayNames;
28076 for(var i = 0; i < 7; i++){
28077 var d = this.startDay+i;
28081 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28083 m[m.length] = "</tr></thead><tbody><tr>";
28084 for(var i = 0; i < 42; i++) {
28085 if(i % 7 == 0 && i != 0){
28086 m[m.length] = "</tr><tr>";
28088 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28090 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28091 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28093 var el = document.createElement("div");
28094 el.className = "x-date-picker";
28095 el.innerHTML = m.join("");
28097 container.dom.insertBefore(el, position);
28099 this.el = Roo.get(el);
28100 this.eventEl = Roo.get(el.firstChild);
28102 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28103 handler: this.showPrevMonth,
28105 preventDefault:true,
28109 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28110 handler: this.showNextMonth,
28112 preventDefault:true,
28116 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28118 this.monthPicker = this.el.down('div.x-date-mp');
28119 this.monthPicker.enableDisplayMode('block');
28121 var kn = new Roo.KeyNav(this.eventEl, {
28122 "left" : function(e){
28124 this.showPrevMonth() :
28125 this.update(this.activeDate.add("d", -1));
28128 "right" : function(e){
28130 this.showNextMonth() :
28131 this.update(this.activeDate.add("d", 1));
28134 "up" : function(e){
28136 this.showNextYear() :
28137 this.update(this.activeDate.add("d", -7));
28140 "down" : function(e){
28142 this.showPrevYear() :
28143 this.update(this.activeDate.add("d", 7));
28146 "pageUp" : function(e){
28147 this.showNextMonth();
28150 "pageDown" : function(e){
28151 this.showPrevMonth();
28154 "enter" : function(e){
28155 e.stopPropagation();
28162 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28164 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28166 this.el.unselectable();
28168 this.cells = this.el.select("table.x-date-inner tbody td");
28169 this.textNodes = this.el.query("table.x-date-inner tbody span");
28171 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28173 tooltip: this.monthYearText
28176 this.mbtn.on('click', this.showMonthPicker, this);
28177 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28180 var today = (new Date()).dateFormat(this.format);
28182 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28183 if (this.showClear) {
28184 baseTb.add( new Roo.Toolbar.Fill());
28187 text: String.format(this.todayText, today),
28188 tooltip: String.format(this.todayTip, today),
28189 handler: this.selectToday,
28193 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28196 if (this.showClear) {
28198 baseTb.add( new Roo.Toolbar.Fill());
28201 cls: 'x-btn-icon x-btn-clear',
28202 handler: function() {
28204 this.fireEvent("select", this, '');
28214 this.update(this.value);
28217 createMonthPicker : function(){
28218 if(!this.monthPicker.dom.firstChild){
28219 var buf = ['<table border="0" cellspacing="0">'];
28220 for(var i = 0; i < 6; i++){
28222 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28223 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28225 '<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>' :
28226 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28230 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28232 '</button><button type="button" class="x-date-mp-cancel">',
28234 '</button></td></tr>',
28237 this.monthPicker.update(buf.join(''));
28238 this.monthPicker.on('click', this.onMonthClick, this);
28239 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28241 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28242 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28244 this.mpMonths.each(function(m, a, i){
28247 m.dom.xmonth = 5 + Math.round(i * .5);
28249 m.dom.xmonth = Math.round((i-1) * .5);
28255 showMonthPicker : function(){
28256 this.createMonthPicker();
28257 var size = this.el.getSize();
28258 this.monthPicker.setSize(size);
28259 this.monthPicker.child('table').setSize(size);
28261 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28262 this.updateMPMonth(this.mpSelMonth);
28263 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28264 this.updateMPYear(this.mpSelYear);
28266 this.monthPicker.slideIn('t', {duration:.2});
28269 updateMPYear : function(y){
28271 var ys = this.mpYears.elements;
28272 for(var i = 1; i <= 10; i++){
28273 var td = ys[i-1], y2;
28275 y2 = y + Math.round(i * .5);
28276 td.firstChild.innerHTML = y2;
28279 y2 = y - (5-Math.round(i * .5));
28280 td.firstChild.innerHTML = y2;
28283 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28287 updateMPMonth : function(sm){
28288 this.mpMonths.each(function(m, a, i){
28289 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28293 selectMPMonth: function(m){
28297 onMonthClick : function(e, t){
28299 var el = new Roo.Element(t), pn;
28300 if(el.is('button.x-date-mp-cancel')){
28301 this.hideMonthPicker();
28303 else if(el.is('button.x-date-mp-ok')){
28304 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28305 this.hideMonthPicker();
28307 else if(pn = el.up('td.x-date-mp-month', 2)){
28308 this.mpMonths.removeClass('x-date-mp-sel');
28309 pn.addClass('x-date-mp-sel');
28310 this.mpSelMonth = pn.dom.xmonth;
28312 else if(pn = el.up('td.x-date-mp-year', 2)){
28313 this.mpYears.removeClass('x-date-mp-sel');
28314 pn.addClass('x-date-mp-sel');
28315 this.mpSelYear = pn.dom.xyear;
28317 else if(el.is('a.x-date-mp-prev')){
28318 this.updateMPYear(this.mpyear-10);
28320 else if(el.is('a.x-date-mp-next')){
28321 this.updateMPYear(this.mpyear+10);
28325 onMonthDblClick : function(e, t){
28327 var el = new Roo.Element(t), pn;
28328 if(pn = el.up('td.x-date-mp-month', 2)){
28329 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28330 this.hideMonthPicker();
28332 else if(pn = el.up('td.x-date-mp-year', 2)){
28333 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28334 this.hideMonthPicker();
28338 hideMonthPicker : function(disableAnim){
28339 if(this.monthPicker){
28340 if(disableAnim === true){
28341 this.monthPicker.hide();
28343 this.monthPicker.slideOut('t', {duration:.2});
28349 showPrevMonth : function(e){
28350 this.update(this.activeDate.add("mo", -1));
28354 showNextMonth : function(e){
28355 this.update(this.activeDate.add("mo", 1));
28359 showPrevYear : function(){
28360 this.update(this.activeDate.add("y", -1));
28364 showNextYear : function(){
28365 this.update(this.activeDate.add("y", 1));
28369 handleMouseWheel : function(e){
28370 var delta = e.getWheelDelta();
28372 this.showPrevMonth();
28374 } else if(delta < 0){
28375 this.showNextMonth();
28381 handleDateClick : function(e, t){
28383 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28384 this.setValue(new Date(t.dateValue));
28385 this.fireEvent("select", this, this.value);
28390 selectToday : function(){
28391 this.setValue(new Date().clearTime());
28392 this.fireEvent("select", this, this.value);
28396 update : function(date)
28398 var vd = this.activeDate;
28399 this.activeDate = date;
28401 var t = date.getTime();
28402 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28403 this.cells.removeClass("x-date-selected");
28404 this.cells.each(function(c){
28405 if(c.dom.firstChild.dateValue == t){
28406 c.addClass("x-date-selected");
28407 setTimeout(function(){
28408 try{c.dom.firstChild.focus();}catch(e){}
28417 var days = date.getDaysInMonth();
28418 var firstOfMonth = date.getFirstDateOfMonth();
28419 var startingPos = firstOfMonth.getDay()-this.startDay;
28421 if(startingPos <= this.startDay){
28425 var pm = date.add("mo", -1);
28426 var prevStart = pm.getDaysInMonth()-startingPos;
28428 var cells = this.cells.elements;
28429 var textEls = this.textNodes;
28430 days += startingPos;
28432 // convert everything to numbers so it's fast
28433 var day = 86400000;
28434 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28435 var today = new Date().clearTime().getTime();
28436 var sel = date.clearTime().getTime();
28437 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28438 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28439 var ddMatch = this.disabledDatesRE;
28440 var ddText = this.disabledDatesText;
28441 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28442 var ddaysText = this.disabledDaysText;
28443 var format = this.format;
28445 var setCellClass = function(cal, cell){
28447 var t = d.getTime();
28448 cell.firstChild.dateValue = t;
28450 cell.className += " x-date-today";
28451 cell.title = cal.todayText;
28454 cell.className += " x-date-selected";
28455 setTimeout(function(){
28456 try{cell.firstChild.focus();}catch(e){}
28461 cell.className = " x-date-disabled";
28462 cell.title = cal.minText;
28466 cell.className = " x-date-disabled";
28467 cell.title = cal.maxText;
28471 if(ddays.indexOf(d.getDay()) != -1){
28472 cell.title = ddaysText;
28473 cell.className = " x-date-disabled";
28476 if(ddMatch && format){
28477 var fvalue = d.dateFormat(format);
28478 if(ddMatch.test(fvalue)){
28479 cell.title = ddText.replace("%0", fvalue);
28480 cell.className = " x-date-disabled";
28486 for(; i < startingPos; i++) {
28487 textEls[i].innerHTML = (++prevStart);
28488 d.setDate(d.getDate()+1);
28489 cells[i].className = "x-date-prevday";
28490 setCellClass(this, cells[i]);
28492 for(; i < days; i++){
28493 intDay = i - startingPos + 1;
28494 textEls[i].innerHTML = (intDay);
28495 d.setDate(d.getDate()+1);
28496 cells[i].className = "x-date-active";
28497 setCellClass(this, cells[i]);
28500 for(; i < 42; i++) {
28501 textEls[i].innerHTML = (++extraDays);
28502 d.setDate(d.getDate()+1);
28503 cells[i].className = "x-date-nextday";
28504 setCellClass(this, cells[i]);
28507 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28508 this.fireEvent('monthchange', this, date);
28510 if(!this.internalRender){
28511 var main = this.el.dom.firstChild;
28512 var w = main.offsetWidth;
28513 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28514 Roo.fly(main).setWidth(w);
28515 this.internalRender = true;
28516 // opera does not respect the auto grow header center column
28517 // then, after it gets a width opera refuses to recalculate
28518 // without a second pass
28519 if(Roo.isOpera && !this.secondPass){
28520 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28521 this.secondPass = true;
28522 this.update.defer(10, this, [date]);
28530 * Ext JS Library 1.1.1
28531 * Copyright(c) 2006-2007, Ext JS, LLC.
28533 * Originally Released Under LGPL - original licence link has changed is not relivant.
28536 * <script type="text/javascript">
28539 * @class Roo.TabPanel
28540 * @extends Roo.util.Observable
28541 * A lightweight tab container.
28545 // basic tabs 1, built from existing content
28546 var tabs = new Roo.TabPanel("tabs1");
28547 tabs.addTab("script", "View Script");
28548 tabs.addTab("markup", "View Markup");
28549 tabs.activate("script");
28551 // more advanced tabs, built from javascript
28552 var jtabs = new Roo.TabPanel("jtabs");
28553 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28555 // set up the UpdateManager
28556 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28557 var updater = tab2.getUpdateManager();
28558 updater.setDefaultUrl("ajax1.htm");
28559 tab2.on('activate', updater.refresh, updater, true);
28561 // Use setUrl for Ajax loading
28562 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28563 tab3.setUrl("ajax2.htm", null, true);
28566 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28569 jtabs.activate("jtabs-1");
28572 * Create a new TabPanel.
28573 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28574 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28576 Roo.TabPanel = function(container, config){
28578 * The container element for this TabPanel.
28579 * @type Roo.Element
28581 this.el = Roo.get(container, true);
28583 if(typeof config == "boolean"){
28584 this.tabPosition = config ? "bottom" : "top";
28586 Roo.apply(this, config);
28589 if(this.tabPosition == "bottom"){
28590 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28591 this.el.addClass("x-tabs-bottom");
28593 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28594 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28595 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28597 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28599 if(this.tabPosition != "bottom"){
28600 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28601 * @type Roo.Element
28603 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28604 this.el.addClass("x-tabs-top");
28608 this.bodyEl.setStyle("position", "relative");
28610 this.active = null;
28611 this.activateDelegate = this.activate.createDelegate(this);
28616 * Fires when the active tab changes
28617 * @param {Roo.TabPanel} this
28618 * @param {Roo.TabPanelItem} activePanel The new active tab
28622 * @event beforetabchange
28623 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28624 * @param {Roo.TabPanel} this
28625 * @param {Object} e Set cancel to true on this object to cancel the tab change
28626 * @param {Roo.TabPanelItem} tab The tab being changed to
28628 "beforetabchange" : true
28631 Roo.EventManager.onWindowResize(this.onResize, this);
28632 this.cpad = this.el.getPadding("lr");
28633 this.hiddenCount = 0;
28636 // toolbar on the tabbar support...
28637 if (this.toolbar) {
28638 var tcfg = this.toolbar;
28639 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28640 this.toolbar = new Roo.Toolbar(tcfg);
28641 if (Roo.isSafari) {
28642 var tbl = tcfg.container.child('table', true);
28643 tbl.setAttribute('width', '100%');
28650 Roo.TabPanel.superclass.constructor.call(this);
28653 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28655 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28657 tabPosition : "top",
28659 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28661 currentTabWidth : 0,
28663 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28667 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28671 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28673 preferredTabWidth : 175,
28675 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28677 resizeTabs : false,
28679 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28681 monitorResize : true,
28683 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28688 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28689 * @param {String} id The id of the div to use <b>or create</b>
28690 * @param {String} text The text for the tab
28691 * @param {String} content (optional) Content to put in the TabPanelItem body
28692 * @param {Boolean} closable (optional) True to create a close icon on the tab
28693 * @return {Roo.TabPanelItem} The created TabPanelItem
28695 addTab : function(id, text, content, closable){
28696 var item = new Roo.TabPanelItem(this, id, text, closable);
28697 this.addTabItem(item);
28699 item.setContent(content);
28705 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28706 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28707 * @return {Roo.TabPanelItem}
28709 getTab : function(id){
28710 return this.items[id];
28714 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28715 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28717 hideTab : function(id){
28718 var t = this.items[id];
28721 this.hiddenCount++;
28722 this.autoSizeTabs();
28727 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28728 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28730 unhideTab : function(id){
28731 var t = this.items[id];
28733 t.setHidden(false);
28734 this.hiddenCount--;
28735 this.autoSizeTabs();
28740 * Adds an existing {@link Roo.TabPanelItem}.
28741 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28743 addTabItem : function(item){
28744 this.items[item.id] = item;
28745 this.items.push(item);
28746 if(this.resizeTabs){
28747 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28748 this.autoSizeTabs();
28755 * Removes a {@link Roo.TabPanelItem}.
28756 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28758 removeTab : function(id){
28759 var items = this.items;
28760 var tab = items[id];
28761 if(!tab) { return; }
28762 var index = items.indexOf(tab);
28763 if(this.active == tab && items.length > 1){
28764 var newTab = this.getNextAvailable(index);
28769 this.stripEl.dom.removeChild(tab.pnode.dom);
28770 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28771 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28773 items.splice(index, 1);
28774 delete this.items[tab.id];
28775 tab.fireEvent("close", tab);
28776 tab.purgeListeners();
28777 this.autoSizeTabs();
28780 getNextAvailable : function(start){
28781 var items = this.items;
28783 // look for a next tab that will slide over to
28784 // replace the one being removed
28785 while(index < items.length){
28786 var item = items[++index];
28787 if(item && !item.isHidden()){
28791 // if one isn't found select the previous tab (on the left)
28794 var item = items[--index];
28795 if(item && !item.isHidden()){
28803 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28804 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28806 disableTab : function(id){
28807 var tab = this.items[id];
28808 if(tab && this.active != tab){
28814 * Enables a {@link Roo.TabPanelItem} that is disabled.
28815 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28817 enableTab : function(id){
28818 var tab = this.items[id];
28823 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28824 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28825 * @return {Roo.TabPanelItem} The TabPanelItem.
28827 activate : function(id){
28828 var tab = this.items[id];
28832 if(tab == this.active || tab.disabled){
28836 this.fireEvent("beforetabchange", this, e, tab);
28837 if(e.cancel !== true && !tab.disabled){
28839 this.active.hide();
28841 this.active = this.items[id];
28842 this.active.show();
28843 this.fireEvent("tabchange", this, this.active);
28849 * Gets the active {@link Roo.TabPanelItem}.
28850 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28852 getActiveTab : function(){
28853 return this.active;
28857 * Updates the tab body element to fit the height of the container element
28858 * for overflow scrolling
28859 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28861 syncHeight : function(targetHeight){
28862 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28863 var bm = this.bodyEl.getMargins();
28864 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28865 this.bodyEl.setHeight(newHeight);
28869 onResize : function(){
28870 if(this.monitorResize){
28871 this.autoSizeTabs();
28876 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28878 beginUpdate : function(){
28879 this.updating = true;
28883 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28885 endUpdate : function(){
28886 this.updating = false;
28887 this.autoSizeTabs();
28891 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28893 autoSizeTabs : function(){
28894 var count = this.items.length;
28895 var vcount = count - this.hiddenCount;
28896 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28899 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28900 var availWidth = Math.floor(w / vcount);
28901 var b = this.stripBody;
28902 if(b.getWidth() > w){
28903 var tabs = this.items;
28904 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28905 if(availWidth < this.minTabWidth){
28906 /*if(!this.sleft){ // incomplete scrolling code
28907 this.createScrollButtons();
28910 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28913 if(this.currentTabWidth < this.preferredTabWidth){
28914 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28920 * Returns the number of tabs in this TabPanel.
28923 getCount : function(){
28924 return this.items.length;
28928 * Resizes all the tabs to the passed width
28929 * @param {Number} The new width
28931 setTabWidth : function(width){
28932 this.currentTabWidth = width;
28933 for(var i = 0, len = this.items.length; i < len; i++) {
28934 if(!this.items[i].isHidden()) {
28935 this.items[i].setWidth(width);
28941 * Destroys this TabPanel
28942 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28944 destroy : function(removeEl){
28945 Roo.EventManager.removeResizeListener(this.onResize, this);
28946 for(var i = 0, len = this.items.length; i < len; i++){
28947 this.items[i].purgeListeners();
28949 if(removeEl === true){
28950 this.el.update("");
28957 * @class Roo.TabPanelItem
28958 * @extends Roo.util.Observable
28959 * Represents an individual item (tab plus body) in a TabPanel.
28960 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28961 * @param {String} id The id of this TabPanelItem
28962 * @param {String} text The text for the tab of this TabPanelItem
28963 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28965 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28967 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28968 * @type Roo.TabPanel
28970 this.tabPanel = tabPanel;
28972 * The id for this TabPanelItem
28977 this.disabled = false;
28981 this.loaded = false;
28982 this.closable = closable;
28985 * The body element for this TabPanelItem.
28986 * @type Roo.Element
28988 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28989 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28990 this.bodyEl.setStyle("display", "block");
28991 this.bodyEl.setStyle("zoom", "1");
28994 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28996 this.el = Roo.get(els.el, true);
28997 this.inner = Roo.get(els.inner, true);
28998 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28999 this.pnode = Roo.get(els.el.parentNode, true);
29000 this.el.on("mousedown", this.onTabMouseDown, this);
29001 this.el.on("click", this.onTabClick, this);
29004 var c = Roo.get(els.close, true);
29005 c.dom.title = this.closeText;
29006 c.addClassOnOver("close-over");
29007 c.on("click", this.closeClick, this);
29013 * Fires when this tab becomes the active tab.
29014 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29015 * @param {Roo.TabPanelItem} this
29019 * @event beforeclose
29020 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
29021 * @param {Roo.TabPanelItem} this
29022 * @param {Object} e Set cancel to true on this object to cancel the close.
29024 "beforeclose": true,
29027 * Fires when this tab is closed.
29028 * @param {Roo.TabPanelItem} this
29032 * @event deactivate
29033 * Fires when this tab is no longer the active tab.
29034 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29035 * @param {Roo.TabPanelItem} this
29037 "deactivate" : true
29039 this.hidden = false;
29041 Roo.TabPanelItem.superclass.constructor.call(this);
29044 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
29045 purgeListeners : function(){
29046 Roo.util.Observable.prototype.purgeListeners.call(this);
29047 this.el.removeAllListeners();
29050 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
29053 this.pnode.addClass("on");
29056 this.tabPanel.stripWrap.repaint();
29058 this.fireEvent("activate", this.tabPanel, this);
29062 * Returns true if this tab is the active tab.
29063 * @return {Boolean}
29065 isActive : function(){
29066 return this.tabPanel.getActiveTab() == this;
29070 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29073 this.pnode.removeClass("on");
29075 this.fireEvent("deactivate", this.tabPanel, this);
29078 hideAction : function(){
29079 this.bodyEl.hide();
29080 this.bodyEl.setStyle("position", "absolute");
29081 this.bodyEl.setLeft("-20000px");
29082 this.bodyEl.setTop("-20000px");
29085 showAction : function(){
29086 this.bodyEl.setStyle("position", "relative");
29087 this.bodyEl.setTop("");
29088 this.bodyEl.setLeft("");
29089 this.bodyEl.show();
29093 * Set the tooltip for the tab.
29094 * @param {String} tooltip The tab's tooltip
29096 setTooltip : function(text){
29097 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29098 this.textEl.dom.qtip = text;
29099 this.textEl.dom.removeAttribute('title');
29101 this.textEl.dom.title = text;
29105 onTabClick : function(e){
29106 e.preventDefault();
29107 this.tabPanel.activate(this.id);
29110 onTabMouseDown : function(e){
29111 e.preventDefault();
29112 this.tabPanel.activate(this.id);
29115 getWidth : function(){
29116 return this.inner.getWidth();
29119 setWidth : function(width){
29120 var iwidth = width - this.pnode.getPadding("lr");
29121 this.inner.setWidth(iwidth);
29122 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29123 this.pnode.setWidth(width);
29127 * Show or hide the tab
29128 * @param {Boolean} hidden True to hide or false to show.
29130 setHidden : function(hidden){
29131 this.hidden = hidden;
29132 this.pnode.setStyle("display", hidden ? "none" : "");
29136 * Returns true if this tab is "hidden"
29137 * @return {Boolean}
29139 isHidden : function(){
29140 return this.hidden;
29144 * Returns the text for this tab
29147 getText : function(){
29151 autoSize : function(){
29152 //this.el.beginMeasure();
29153 this.textEl.setWidth(1);
29155 * #2804 [new] Tabs in Roojs
29156 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29158 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29159 //this.el.endMeasure();
29163 * Sets the text for the tab (Note: this also sets the tooltip text)
29164 * @param {String} text The tab's text and tooltip
29166 setText : function(text){
29168 this.textEl.update(text);
29169 this.setTooltip(text);
29170 if(!this.tabPanel.resizeTabs){
29175 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29177 activate : function(){
29178 this.tabPanel.activate(this.id);
29182 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29184 disable : function(){
29185 if(this.tabPanel.active != this){
29186 this.disabled = true;
29187 this.pnode.addClass("disabled");
29192 * Enables this TabPanelItem if it was previously disabled.
29194 enable : function(){
29195 this.disabled = false;
29196 this.pnode.removeClass("disabled");
29200 * Sets the content for this TabPanelItem.
29201 * @param {String} content The content
29202 * @param {Boolean} loadScripts true to look for and load scripts
29204 setContent : function(content, loadScripts){
29205 this.bodyEl.update(content, loadScripts);
29209 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29210 * @return {Roo.UpdateManager} The UpdateManager
29212 getUpdateManager : function(){
29213 return this.bodyEl.getUpdateManager();
29217 * Set a URL to be used to load the content for this TabPanelItem.
29218 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29219 * @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)
29220 * @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)
29221 * @return {Roo.UpdateManager} The UpdateManager
29223 setUrl : function(url, params, loadOnce){
29224 if(this.refreshDelegate){
29225 this.un('activate', this.refreshDelegate);
29227 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29228 this.on("activate", this.refreshDelegate);
29229 return this.bodyEl.getUpdateManager();
29233 _handleRefresh : function(url, params, loadOnce){
29234 if(!loadOnce || !this.loaded){
29235 var updater = this.bodyEl.getUpdateManager();
29236 updater.update(url, params, this._setLoaded.createDelegate(this));
29241 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29242 * Will fail silently if the setUrl method has not been called.
29243 * This does not activate the panel, just updates its content.
29245 refresh : function(){
29246 if(this.refreshDelegate){
29247 this.loaded = false;
29248 this.refreshDelegate();
29253 _setLoaded : function(){
29254 this.loaded = true;
29258 closeClick : function(e){
29261 this.fireEvent("beforeclose", this, o);
29262 if(o.cancel !== true){
29263 this.tabPanel.removeTab(this.id);
29267 * The text displayed in the tooltip for the close icon.
29270 closeText : "Close this tab"
29274 Roo.TabPanel.prototype.createStrip = function(container){
29275 var strip = document.createElement("div");
29276 strip.className = "x-tabs-wrap";
29277 container.appendChild(strip);
29281 Roo.TabPanel.prototype.createStripList = function(strip){
29282 // div wrapper for retard IE
29283 // returns the "tr" element.
29284 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29285 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29286 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29287 return strip.firstChild.firstChild.firstChild.firstChild;
29290 Roo.TabPanel.prototype.createBody = function(container){
29291 var body = document.createElement("div");
29292 Roo.id(body, "tab-body");
29293 Roo.fly(body).addClass("x-tabs-body");
29294 container.appendChild(body);
29298 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29299 var body = Roo.getDom(id);
29301 body = document.createElement("div");
29304 Roo.fly(body).addClass("x-tabs-item-body");
29305 bodyEl.insertBefore(body, bodyEl.firstChild);
29309 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29310 var td = document.createElement("td");
29311 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29312 //stripEl.appendChild(td);
29314 td.className = "x-tabs-closable";
29315 if(!this.closeTpl){
29316 this.closeTpl = new Roo.Template(
29317 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29318 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29319 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29322 var el = this.closeTpl.overwrite(td, {"text": text});
29323 var close = el.getElementsByTagName("div")[0];
29324 var inner = el.getElementsByTagName("em")[0];
29325 return {"el": el, "close": close, "inner": inner};
29328 this.tabTpl = new Roo.Template(
29329 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29330 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29333 var el = this.tabTpl.overwrite(td, {"text": text});
29334 var inner = el.getElementsByTagName("em")[0];
29335 return {"el": el, "inner": inner};
29339 * Ext JS Library 1.1.1
29340 * Copyright(c) 2006-2007, Ext JS, LLC.
29342 * Originally Released Under LGPL - original licence link has changed is not relivant.
29345 * <script type="text/javascript">
29349 * @class Roo.Button
29350 * @extends Roo.util.Observable
29351 * Simple Button class
29352 * @cfg {String} text The button text
29353 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29354 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29355 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29356 * @cfg {Object} scope The scope of the handler
29357 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29358 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29359 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29360 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29361 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29362 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29363 applies if enableToggle = true)
29364 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29365 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29366 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29368 * Create a new button
29369 * @param {Object} config The config object
29371 Roo.Button = function(renderTo, config)
29375 renderTo = config.renderTo || false;
29378 Roo.apply(this, config);
29382 * Fires when this button is clicked
29383 * @param {Button} this
29384 * @param {EventObject} e The click event
29389 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29390 * @param {Button} this
29391 * @param {Boolean} pressed
29396 * Fires when the mouse hovers over the button
29397 * @param {Button} this
29398 * @param {Event} e The event object
29400 'mouseover' : true,
29403 * Fires when the mouse exits the button
29404 * @param {Button} this
29405 * @param {Event} e The event object
29410 * Fires when the button is rendered
29411 * @param {Button} this
29416 this.menu = Roo.menu.MenuMgr.get(this.menu);
29418 // register listeners first!! - so render can be captured..
29419 Roo.util.Observable.call(this);
29421 this.render(renderTo);
29427 Roo.extend(Roo.Button, Roo.util.Observable, {
29433 * Read-only. True if this button is hidden
29438 * Read-only. True if this button is disabled
29443 * Read-only. True if this button is pressed (only if enableToggle = true)
29449 * @cfg {Number} tabIndex
29450 * The DOM tabIndex for this button (defaults to undefined)
29452 tabIndex : undefined,
29455 * @cfg {Boolean} enableToggle
29456 * True to enable pressed/not pressed toggling (defaults to false)
29458 enableToggle: false,
29460 * @cfg {Mixed} menu
29461 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29465 * @cfg {String} menuAlign
29466 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29468 menuAlign : "tl-bl?",
29471 * @cfg {String} iconCls
29472 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29474 iconCls : undefined,
29476 * @cfg {String} type
29477 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29482 menuClassTarget: 'tr',
29485 * @cfg {String} clickEvent
29486 * The type of event to map to the button's event handler (defaults to 'click')
29488 clickEvent : 'click',
29491 * @cfg {Boolean} handleMouseEvents
29492 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29494 handleMouseEvents : true,
29497 * @cfg {String} tooltipType
29498 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29500 tooltipType : 'qtip',
29503 * @cfg {String} cls
29504 * A CSS class to apply to the button's main element.
29508 * @cfg {Roo.Template} template (Optional)
29509 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29510 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29511 * require code modifications if required elements (e.g. a button) aren't present.
29515 render : function(renderTo){
29517 if(this.hideParent){
29518 this.parentEl = Roo.get(renderTo);
29520 if(!this.dhconfig){
29521 if(!this.template){
29522 if(!Roo.Button.buttonTemplate){
29523 // hideous table template
29524 Roo.Button.buttonTemplate = new Roo.Template(
29525 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29526 '<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>',
29527 "</tr></tbody></table>");
29529 this.template = Roo.Button.buttonTemplate;
29531 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29532 var btnEl = btn.child("button:first");
29533 btnEl.on('focus', this.onFocus, this);
29534 btnEl.on('blur', this.onBlur, this);
29536 btn.addClass(this.cls);
29539 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29542 btnEl.addClass(this.iconCls);
29544 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29547 if(this.tabIndex !== undefined){
29548 btnEl.dom.tabIndex = this.tabIndex;
29551 if(typeof this.tooltip == 'object'){
29552 Roo.QuickTips.tips(Roo.apply({
29556 btnEl.dom[this.tooltipType] = this.tooltip;
29560 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29564 this.el.dom.id = this.el.id = this.id;
29567 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29568 this.menu.on("show", this.onMenuShow, this);
29569 this.menu.on("hide", this.onMenuHide, this);
29571 btn.addClass("x-btn");
29572 if(Roo.isIE && !Roo.isIE7){
29573 this.autoWidth.defer(1, this);
29577 if(this.handleMouseEvents){
29578 btn.on("mouseover", this.onMouseOver, this);
29579 btn.on("mouseout", this.onMouseOut, this);
29580 btn.on("mousedown", this.onMouseDown, this);
29582 btn.on(this.clickEvent, this.onClick, this);
29583 //btn.on("mouseup", this.onMouseUp, this);
29590 Roo.ButtonToggleMgr.register(this);
29592 this.el.addClass("x-btn-pressed");
29595 var repeater = new Roo.util.ClickRepeater(btn,
29596 typeof this.repeat == "object" ? this.repeat : {}
29598 repeater.on("click", this.onClick, this);
29601 this.fireEvent('render', this);
29605 * Returns the button's underlying element
29606 * @return {Roo.Element} The element
29608 getEl : function(){
29613 * Destroys this Button and removes any listeners.
29615 destroy : function(){
29616 Roo.ButtonToggleMgr.unregister(this);
29617 this.el.removeAllListeners();
29618 this.purgeListeners();
29623 autoWidth : function(){
29625 this.el.setWidth("auto");
29626 if(Roo.isIE7 && Roo.isStrict){
29627 var ib = this.el.child('button');
29628 if(ib && ib.getWidth() > 20){
29630 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29635 this.el.beginMeasure();
29637 if(this.el.getWidth() < this.minWidth){
29638 this.el.setWidth(this.minWidth);
29641 this.el.endMeasure();
29648 * Assigns this button's click handler
29649 * @param {Function} handler The function to call when the button is clicked
29650 * @param {Object} scope (optional) Scope for the function passed in
29652 setHandler : function(handler, scope){
29653 this.handler = handler;
29654 this.scope = scope;
29658 * Sets this button's text
29659 * @param {String} text The button text
29661 setText : function(text){
29664 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29670 * Gets the text for this button
29671 * @return {String} The button text
29673 getText : function(){
29681 this.hidden = false;
29683 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29691 this.hidden = true;
29693 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29698 * Convenience function for boolean show/hide
29699 * @param {Boolean} visible True to show, false to hide
29701 setVisible: function(visible){
29710 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29711 * @param {Boolean} state (optional) Force a particular state
29713 toggle : function(state){
29714 state = state === undefined ? !this.pressed : state;
29715 if(state != this.pressed){
29717 this.el.addClass("x-btn-pressed");
29718 this.pressed = true;
29719 this.fireEvent("toggle", this, true);
29721 this.el.removeClass("x-btn-pressed");
29722 this.pressed = false;
29723 this.fireEvent("toggle", this, false);
29725 if(this.toggleHandler){
29726 this.toggleHandler.call(this.scope || this, this, state);
29734 focus : function(){
29735 this.el.child('button:first').focus();
29739 * Disable this button
29741 disable : function(){
29743 this.el.addClass("x-btn-disabled");
29745 this.disabled = true;
29749 * Enable this button
29751 enable : function(){
29753 this.el.removeClass("x-btn-disabled");
29755 this.disabled = false;
29759 * Convenience function for boolean enable/disable
29760 * @param {Boolean} enabled True to enable, false to disable
29762 setDisabled : function(v){
29763 this[v !== true ? "enable" : "disable"]();
29767 onClick : function(e)
29770 e.preventDefault();
29775 if(!this.disabled){
29776 if(this.enableToggle){
29779 if(this.menu && !this.menu.isVisible()){
29780 this.menu.show(this.el, this.menuAlign);
29782 this.fireEvent("click", this, e);
29784 this.el.removeClass("x-btn-over");
29785 this.handler.call(this.scope || this, this, e);
29790 onMouseOver : function(e){
29791 if(!this.disabled){
29792 this.el.addClass("x-btn-over");
29793 this.fireEvent('mouseover', this, e);
29797 onMouseOut : function(e){
29798 if(!e.within(this.el, true)){
29799 this.el.removeClass("x-btn-over");
29800 this.fireEvent('mouseout', this, e);
29804 onFocus : function(e){
29805 if(!this.disabled){
29806 this.el.addClass("x-btn-focus");
29810 onBlur : function(e){
29811 this.el.removeClass("x-btn-focus");
29814 onMouseDown : function(e){
29815 if(!this.disabled && e.button == 0){
29816 this.el.addClass("x-btn-click");
29817 Roo.get(document).on('mouseup', this.onMouseUp, this);
29821 onMouseUp : function(e){
29823 this.el.removeClass("x-btn-click");
29824 Roo.get(document).un('mouseup', this.onMouseUp, this);
29828 onMenuShow : function(e){
29829 this.el.addClass("x-btn-menu-active");
29832 onMenuHide : function(e){
29833 this.el.removeClass("x-btn-menu-active");
29837 // Private utility class used by Button
29838 Roo.ButtonToggleMgr = function(){
29841 function toggleGroup(btn, state){
29843 var g = groups[btn.toggleGroup];
29844 for(var i = 0, l = g.length; i < l; i++){
29846 g[i].toggle(false);
29853 register : function(btn){
29854 if(!btn.toggleGroup){
29857 var g = groups[btn.toggleGroup];
29859 g = groups[btn.toggleGroup] = [];
29862 btn.on("toggle", toggleGroup);
29865 unregister : function(btn){
29866 if(!btn.toggleGroup){
29869 var g = groups[btn.toggleGroup];
29872 btn.un("toggle", toggleGroup);
29878 * Ext JS Library 1.1.1
29879 * Copyright(c) 2006-2007, Ext JS, LLC.
29881 * Originally Released Under LGPL - original licence link has changed is not relivant.
29884 * <script type="text/javascript">
29888 * @class Roo.SplitButton
29889 * @extends Roo.Button
29890 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29891 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29892 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29893 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29894 * @cfg {String} arrowTooltip The title attribute of the arrow
29896 * Create a new menu button
29897 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29898 * @param {Object} config The config object
29900 Roo.SplitButton = function(renderTo, config){
29901 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29903 * @event arrowclick
29904 * Fires when this button's arrow is clicked
29905 * @param {SplitButton} this
29906 * @param {EventObject} e The click event
29908 this.addEvents({"arrowclick":true});
29911 Roo.extend(Roo.SplitButton, Roo.Button, {
29912 render : function(renderTo){
29913 // this is one sweet looking template!
29914 var tpl = new Roo.Template(
29915 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29916 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29917 '<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>',
29918 "</tbody></table></td><td>",
29919 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29920 '<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>',
29921 "</tbody></table></td></tr></table>"
29923 var btn = tpl.append(renderTo, [this.text, this.type], true);
29924 var btnEl = btn.child("button");
29926 btn.addClass(this.cls);
29929 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29932 btnEl.addClass(this.iconCls);
29934 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29938 if(this.handleMouseEvents){
29939 btn.on("mouseover", this.onMouseOver, this);
29940 btn.on("mouseout", this.onMouseOut, this);
29941 btn.on("mousedown", this.onMouseDown, this);
29942 btn.on("mouseup", this.onMouseUp, this);
29944 btn.on(this.clickEvent, this.onClick, this);
29946 if(typeof this.tooltip == 'object'){
29947 Roo.QuickTips.tips(Roo.apply({
29951 btnEl.dom[this.tooltipType] = this.tooltip;
29954 if(this.arrowTooltip){
29955 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29964 this.el.addClass("x-btn-pressed");
29966 if(Roo.isIE && !Roo.isIE7){
29967 this.autoWidth.defer(1, this);
29972 this.menu.on("show", this.onMenuShow, this);
29973 this.menu.on("hide", this.onMenuHide, this);
29975 this.fireEvent('render', this);
29979 autoWidth : function(){
29981 var tbl = this.el.child("table:first");
29982 var tbl2 = this.el.child("table:last");
29983 this.el.setWidth("auto");
29984 tbl.setWidth("auto");
29985 if(Roo.isIE7 && Roo.isStrict){
29986 var ib = this.el.child('button:first');
29987 if(ib && ib.getWidth() > 20){
29989 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29994 this.el.beginMeasure();
29996 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29997 tbl.setWidth(this.minWidth-tbl2.getWidth());
30000 this.el.endMeasure();
30003 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
30007 * Sets this button's click handler
30008 * @param {Function} handler The function to call when the button is clicked
30009 * @param {Object} scope (optional) Scope for the function passed above
30011 setHandler : function(handler, scope){
30012 this.handler = handler;
30013 this.scope = scope;
30017 * Sets this button's arrow click handler
30018 * @param {Function} handler The function to call when the arrow is clicked
30019 * @param {Object} scope (optional) Scope for the function passed above
30021 setArrowHandler : function(handler, scope){
30022 this.arrowHandler = handler;
30023 this.scope = scope;
30029 focus : function(){
30031 this.el.child("button:first").focus();
30036 onClick : function(e){
30037 e.preventDefault();
30038 if(!this.disabled){
30039 if(e.getTarget(".x-btn-menu-arrow-wrap")){
30040 if(this.menu && !this.menu.isVisible()){
30041 this.menu.show(this.el, this.menuAlign);
30043 this.fireEvent("arrowclick", this, e);
30044 if(this.arrowHandler){
30045 this.arrowHandler.call(this.scope || this, this, e);
30048 this.fireEvent("click", this, e);
30050 this.handler.call(this.scope || this, this, e);
30056 onMouseDown : function(e){
30057 if(!this.disabled){
30058 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30062 onMouseUp : function(e){
30063 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30068 // backwards compat
30069 Roo.MenuButton = Roo.SplitButton;/*
30071 * Ext JS Library 1.1.1
30072 * Copyright(c) 2006-2007, Ext JS, LLC.
30074 * Originally Released Under LGPL - original licence link has changed is not relivant.
30077 * <script type="text/javascript">
30081 * @class Roo.Toolbar
30082 * Basic Toolbar class.
30084 * Creates a new Toolbar
30085 * @param {Object} container The config object
30087 Roo.Toolbar = function(container, buttons, config)
30089 /// old consturctor format still supported..
30090 if(container instanceof Array){ // omit the container for later rendering
30091 buttons = container;
30095 if (typeof(container) == 'object' && container.xtype) {
30096 config = container;
30097 container = config.container;
30098 buttons = config.buttons || []; // not really - use items!!
30101 if (config && config.items) {
30102 xitems = config.items;
30103 delete config.items;
30105 Roo.apply(this, config);
30106 this.buttons = buttons;
30109 this.render(container);
30111 this.xitems = xitems;
30112 Roo.each(xitems, function(b) {
30118 Roo.Toolbar.prototype = {
30120 * @cfg {Array} items
30121 * array of button configs or elements to add (will be converted to a MixedCollection)
30125 * @cfg {String/HTMLElement/Element} container
30126 * The id or element that will contain the toolbar
30129 render : function(ct){
30130 this.el = Roo.get(ct);
30132 this.el.addClass(this.cls);
30134 // using a table allows for vertical alignment
30135 // 100% width is needed by Safari...
30136 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30137 this.tr = this.el.child("tr", true);
30139 this.items = new Roo.util.MixedCollection(false, function(o){
30140 return o.id || ("item" + (++autoId));
30143 this.add.apply(this, this.buttons);
30144 delete this.buttons;
30149 * Adds element(s) to the toolbar -- this function takes a variable number of
30150 * arguments of mixed type and adds them to the toolbar.
30151 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30153 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30154 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30155 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30156 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30157 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30158 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30159 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30160 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30161 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30163 * @param {Mixed} arg2
30164 * @param {Mixed} etc.
30167 var a = arguments, l = a.length;
30168 for(var i = 0; i < l; i++){
30173 _add : function(el) {
30176 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30179 if (el.applyTo){ // some kind of form field
30180 return this.addField(el);
30182 if (el.render){ // some kind of Toolbar.Item
30183 return this.addItem(el);
30185 if (typeof el == "string"){ // string
30186 if(el == "separator" || el == "-"){
30187 return this.addSeparator();
30190 return this.addSpacer();
30193 return this.addFill();
30195 return this.addText(el);
30198 if(el.tagName){ // element
30199 return this.addElement(el);
30201 if(typeof el == "object"){ // must be button config?
30202 return this.addButton(el);
30204 // and now what?!?!
30210 * Add an Xtype element
30211 * @param {Object} xtype Xtype Object
30212 * @return {Object} created Object
30214 addxtype : function(e){
30215 return this.add(e);
30219 * Returns the Element for this toolbar.
30220 * @return {Roo.Element}
30222 getEl : function(){
30228 * @return {Roo.Toolbar.Item} The separator item
30230 addSeparator : function(){
30231 return this.addItem(new Roo.Toolbar.Separator());
30235 * Adds a spacer element
30236 * @return {Roo.Toolbar.Spacer} The spacer item
30238 addSpacer : function(){
30239 return this.addItem(new Roo.Toolbar.Spacer());
30243 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30244 * @return {Roo.Toolbar.Fill} The fill item
30246 addFill : function(){
30247 return this.addItem(new Roo.Toolbar.Fill());
30251 * Adds any standard HTML element to the toolbar
30252 * @param {String/HTMLElement/Element} el The element or id of the element to add
30253 * @return {Roo.Toolbar.Item} The element's item
30255 addElement : function(el){
30256 return this.addItem(new Roo.Toolbar.Item(el));
30259 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30260 * @type Roo.util.MixedCollection
30265 * Adds any Toolbar.Item or subclass
30266 * @param {Roo.Toolbar.Item} item
30267 * @return {Roo.Toolbar.Item} The item
30269 addItem : function(item){
30270 var td = this.nextBlock();
30272 this.items.add(item);
30277 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30278 * @param {Object/Array} config A button config or array of configs
30279 * @return {Roo.Toolbar.Button/Array}
30281 addButton : function(config){
30282 if(config instanceof Array){
30284 for(var i = 0, len = config.length; i < len; i++) {
30285 buttons.push(this.addButton(config[i]));
30290 if(!(config instanceof Roo.Toolbar.Button)){
30292 new Roo.Toolbar.SplitButton(config) :
30293 new Roo.Toolbar.Button(config);
30295 var td = this.nextBlock();
30302 * Adds text to the toolbar
30303 * @param {String} text The text to add
30304 * @return {Roo.Toolbar.Item} The element's item
30306 addText : function(text){
30307 return this.addItem(new Roo.Toolbar.TextItem(text));
30311 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30312 * @param {Number} index The index where the item is to be inserted
30313 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30314 * @return {Roo.Toolbar.Button/Item}
30316 insertButton : function(index, item){
30317 if(item instanceof Array){
30319 for(var i = 0, len = item.length; i < len; i++) {
30320 buttons.push(this.insertButton(index + i, item[i]));
30324 if (!(item instanceof Roo.Toolbar.Button)){
30325 item = new Roo.Toolbar.Button(item);
30327 var td = document.createElement("td");
30328 this.tr.insertBefore(td, this.tr.childNodes[index]);
30330 this.items.insert(index, item);
30335 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30336 * @param {Object} config
30337 * @return {Roo.Toolbar.Item} The element's item
30339 addDom : function(config, returnEl){
30340 var td = this.nextBlock();
30341 Roo.DomHelper.overwrite(td, config);
30342 var ti = new Roo.Toolbar.Item(td.firstChild);
30344 this.items.add(ti);
30349 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30350 * @type Roo.util.MixedCollection
30355 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30356 * Note: the field should not have been rendered yet. For a field that has already been
30357 * rendered, use {@link #addElement}.
30358 * @param {Roo.form.Field} field
30359 * @return {Roo.ToolbarItem}
30363 addField : function(field) {
30364 if (!this.fields) {
30366 this.fields = new Roo.util.MixedCollection(false, function(o){
30367 return o.id || ("item" + (++autoId));
30372 var td = this.nextBlock();
30374 var ti = new Roo.Toolbar.Item(td.firstChild);
30376 this.items.add(ti);
30377 this.fields.add(field);
30388 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30389 this.el.child('div').hide();
30397 this.el.child('div').show();
30401 nextBlock : function(){
30402 var td = document.createElement("td");
30403 this.tr.appendChild(td);
30408 destroy : function(){
30409 if(this.items){ // rendered?
30410 Roo.destroy.apply(Roo, this.items.items);
30412 if(this.fields){ // rendered?
30413 Roo.destroy.apply(Roo, this.fields.items);
30415 Roo.Element.uncache(this.el, this.tr);
30420 * @class Roo.Toolbar.Item
30421 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30423 * Creates a new Item
30424 * @param {HTMLElement} el
30426 Roo.Toolbar.Item = function(el){
30428 if (typeof (el.xtype) != 'undefined') {
30433 this.el = Roo.getDom(el);
30434 this.id = Roo.id(this.el);
30435 this.hidden = false;
30440 * Fires when the button is rendered
30441 * @param {Button} this
30445 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30447 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30448 //Roo.Toolbar.Item.prototype = {
30451 * Get this item's HTML Element
30452 * @return {HTMLElement}
30454 getEl : function(){
30459 render : function(td){
30462 td.appendChild(this.el);
30464 this.fireEvent('render', this);
30468 * Removes and destroys this item.
30470 destroy : function(){
30471 this.td.parentNode.removeChild(this.td);
30478 this.hidden = false;
30479 this.td.style.display = "";
30486 this.hidden = true;
30487 this.td.style.display = "none";
30491 * Convenience function for boolean show/hide.
30492 * @param {Boolean} visible true to show/false to hide
30494 setVisible: function(visible){
30503 * Try to focus this item.
30505 focus : function(){
30506 Roo.fly(this.el).focus();
30510 * Disables this item.
30512 disable : function(){
30513 Roo.fly(this.td).addClass("x-item-disabled");
30514 this.disabled = true;
30515 this.el.disabled = true;
30519 * Enables this item.
30521 enable : function(){
30522 Roo.fly(this.td).removeClass("x-item-disabled");
30523 this.disabled = false;
30524 this.el.disabled = false;
30530 * @class Roo.Toolbar.Separator
30531 * @extends Roo.Toolbar.Item
30532 * A simple toolbar separator class
30534 * Creates a new Separator
30536 Roo.Toolbar.Separator = function(cfg){
30538 var s = document.createElement("span");
30539 s.className = "ytb-sep";
30544 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30546 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30547 enable:Roo.emptyFn,
30548 disable:Roo.emptyFn,
30553 * @class Roo.Toolbar.Spacer
30554 * @extends Roo.Toolbar.Item
30555 * A simple element that adds extra horizontal space to a toolbar.
30557 * Creates a new Spacer
30559 Roo.Toolbar.Spacer = function(cfg){
30560 var s = document.createElement("div");
30561 s.className = "ytb-spacer";
30565 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30567 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30568 enable:Roo.emptyFn,
30569 disable:Roo.emptyFn,
30574 * @class Roo.Toolbar.Fill
30575 * @extends Roo.Toolbar.Spacer
30576 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30578 * Creates a new Spacer
30580 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30582 render : function(td){
30583 td.style.width = '100%';
30584 Roo.Toolbar.Fill.superclass.render.call(this, td);
30589 * @class Roo.Toolbar.TextItem
30590 * @extends Roo.Toolbar.Item
30591 * A simple class that renders text directly into a toolbar.
30593 * Creates a new TextItem
30594 * @cfg {string} text
30596 Roo.Toolbar.TextItem = function(cfg){
30597 var text = cfg || "";
30598 if (typeof(cfg) == 'object') {
30599 text = cfg.text || "";
30603 var s = document.createElement("span");
30604 s.className = "ytb-text";
30605 s.innerHTML = text;
30610 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30612 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30615 enable:Roo.emptyFn,
30616 disable:Roo.emptyFn,
30621 * @class Roo.Toolbar.Button
30622 * @extends Roo.Button
30623 * A button that renders into a toolbar.
30625 * Creates a new Button
30626 * @param {Object} config A standard {@link Roo.Button} config object
30628 Roo.Toolbar.Button = function(config){
30629 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30631 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30632 render : function(td){
30634 Roo.Toolbar.Button.superclass.render.call(this, td);
30638 * Removes and destroys this button
30640 destroy : function(){
30641 Roo.Toolbar.Button.superclass.destroy.call(this);
30642 this.td.parentNode.removeChild(this.td);
30646 * Shows this button
30649 this.hidden = false;
30650 this.td.style.display = "";
30654 * Hides this button
30657 this.hidden = true;
30658 this.td.style.display = "none";
30662 * Disables this item
30664 disable : function(){
30665 Roo.fly(this.td).addClass("x-item-disabled");
30666 this.disabled = true;
30670 * Enables this item
30672 enable : function(){
30673 Roo.fly(this.td).removeClass("x-item-disabled");
30674 this.disabled = false;
30677 // backwards compat
30678 Roo.ToolbarButton = Roo.Toolbar.Button;
30681 * @class Roo.Toolbar.SplitButton
30682 * @extends Roo.SplitButton
30683 * A menu button that renders into a toolbar.
30685 * Creates a new SplitButton
30686 * @param {Object} config A standard {@link Roo.SplitButton} config object
30688 Roo.Toolbar.SplitButton = function(config){
30689 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30691 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30692 render : function(td){
30694 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30698 * Removes and destroys this button
30700 destroy : function(){
30701 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30702 this.td.parentNode.removeChild(this.td);
30706 * Shows this button
30709 this.hidden = false;
30710 this.td.style.display = "";
30714 * Hides this button
30717 this.hidden = true;
30718 this.td.style.display = "none";
30722 // backwards compat
30723 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30725 * Ext JS Library 1.1.1
30726 * Copyright(c) 2006-2007, Ext JS, LLC.
30728 * Originally Released Under LGPL - original licence link has changed is not relivant.
30731 * <script type="text/javascript">
30735 * @class Roo.PagingToolbar
30736 * @extends Roo.Toolbar
30737 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30739 * Create a new PagingToolbar
30740 * @param {Object} config The config object
30742 Roo.PagingToolbar = function(el, ds, config)
30744 // old args format still supported... - xtype is prefered..
30745 if (typeof(el) == 'object' && el.xtype) {
30746 // created from xtype...
30748 ds = el.dataSource;
30749 el = config.container;
30752 if (config.items) {
30753 items = config.items;
30757 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30760 this.renderButtons(this.el);
30763 // supprot items array.
30765 Roo.each(items, function(e) {
30766 this.add(Roo.factory(e));
30771 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30773 * @cfg {Roo.data.Store} dataSource
30774 * The underlying data store providing the paged data
30777 * @cfg {String/HTMLElement/Element} container
30778 * container The id or element that will contain the toolbar
30781 * @cfg {Boolean} displayInfo
30782 * True to display the displayMsg (defaults to false)
30785 * @cfg {Number} pageSize
30786 * The number of records to display per page (defaults to 20)
30790 * @cfg {String} displayMsg
30791 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30793 displayMsg : 'Displaying {0} - {1} of {2}',
30795 * @cfg {String} emptyMsg
30796 * The message to display when no records are found (defaults to "No data to display")
30798 emptyMsg : 'No data to display',
30800 * Customizable piece of the default paging text (defaults to "Page")
30803 beforePageText : "Page",
30805 * Customizable piece of the default paging text (defaults to "of %0")
30808 afterPageText : "of {0}",
30810 * Customizable piece of the default paging text (defaults to "First Page")
30813 firstText : "First Page",
30815 * Customizable piece of the default paging text (defaults to "Previous Page")
30818 prevText : "Previous Page",
30820 * Customizable piece of the default paging text (defaults to "Next Page")
30823 nextText : "Next Page",
30825 * Customizable piece of the default paging text (defaults to "Last Page")
30828 lastText : "Last Page",
30830 * Customizable piece of the default paging text (defaults to "Refresh")
30833 refreshText : "Refresh",
30836 renderButtons : function(el){
30837 Roo.PagingToolbar.superclass.render.call(this, el);
30838 this.first = this.addButton({
30839 tooltip: this.firstText,
30840 cls: "x-btn-icon x-grid-page-first",
30842 handler: this.onClick.createDelegate(this, ["first"])
30844 this.prev = this.addButton({
30845 tooltip: this.prevText,
30846 cls: "x-btn-icon x-grid-page-prev",
30848 handler: this.onClick.createDelegate(this, ["prev"])
30850 //this.addSeparator();
30851 this.add(this.beforePageText);
30852 this.field = Roo.get(this.addDom({
30857 cls: "x-grid-page-number"
30859 this.field.on("keydown", this.onPagingKeydown, this);
30860 this.field.on("focus", function(){this.dom.select();});
30861 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30862 this.field.setHeight(18);
30863 //this.addSeparator();
30864 this.next = this.addButton({
30865 tooltip: this.nextText,
30866 cls: "x-btn-icon x-grid-page-next",
30868 handler: this.onClick.createDelegate(this, ["next"])
30870 this.last = this.addButton({
30871 tooltip: this.lastText,
30872 cls: "x-btn-icon x-grid-page-last",
30874 handler: this.onClick.createDelegate(this, ["last"])
30876 //this.addSeparator();
30877 this.loading = this.addButton({
30878 tooltip: this.refreshText,
30879 cls: "x-btn-icon x-grid-loading",
30880 handler: this.onClick.createDelegate(this, ["refresh"])
30883 if(this.displayInfo){
30884 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30889 updateInfo : function(){
30890 if(this.displayEl){
30891 var count = this.ds.getCount();
30892 var msg = count == 0 ?
30896 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30898 this.displayEl.update(msg);
30903 onLoad : function(ds, r, o){
30904 this.cursor = o.params ? o.params.start : 0;
30905 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30907 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30908 this.field.dom.value = ap;
30909 this.first.setDisabled(ap == 1);
30910 this.prev.setDisabled(ap == 1);
30911 this.next.setDisabled(ap == ps);
30912 this.last.setDisabled(ap == ps);
30913 this.loading.enable();
30918 getPageData : function(){
30919 var total = this.ds.getTotalCount();
30922 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30923 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30928 onLoadError : function(){
30929 this.loading.enable();
30933 onPagingKeydown : function(e){
30934 var k = e.getKey();
30935 var d = this.getPageData();
30937 var v = this.field.dom.value, pageNum;
30938 if(!v || isNaN(pageNum = parseInt(v, 10))){
30939 this.field.dom.value = d.activePage;
30942 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30943 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30946 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))
30948 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30949 this.field.dom.value = pageNum;
30950 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30953 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30955 var v = this.field.dom.value, pageNum;
30956 var increment = (e.shiftKey) ? 10 : 1;
30957 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30960 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30961 this.field.dom.value = d.activePage;
30964 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30966 this.field.dom.value = parseInt(v, 10) + increment;
30967 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30968 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30975 beforeLoad : function(){
30977 this.loading.disable();
30982 onClick : function(which){
30986 ds.load({params:{start: 0, limit: this.pageSize}});
30989 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30992 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30995 var total = ds.getTotalCount();
30996 var extra = total % this.pageSize;
30997 var lastStart = extra ? (total - extra) : total-this.pageSize;
30998 ds.load({params:{start: lastStart, limit: this.pageSize}});
31001 ds.load({params:{start: this.cursor, limit: this.pageSize}});
31007 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
31008 * @param {Roo.data.Store} store The data store to unbind
31010 unbind : function(ds){
31011 ds.un("beforeload", this.beforeLoad, this);
31012 ds.un("load", this.onLoad, this);
31013 ds.un("loadexception", this.onLoadError, this);
31014 ds.un("remove", this.updateInfo, this);
31015 ds.un("add", this.updateInfo, this);
31016 this.ds = undefined;
31020 * Binds the paging toolbar to the specified {@link Roo.data.Store}
31021 * @param {Roo.data.Store} store The data store to bind
31023 bind : function(ds){
31024 ds.on("beforeload", this.beforeLoad, this);
31025 ds.on("load", this.onLoad, this);
31026 ds.on("loadexception", this.onLoadError, this);
31027 ds.on("remove", this.updateInfo, this);
31028 ds.on("add", this.updateInfo, this);
31033 * Ext JS Library 1.1.1
31034 * Copyright(c) 2006-2007, Ext JS, LLC.
31036 * Originally Released Under LGPL - original licence link has changed is not relivant.
31039 * <script type="text/javascript">
31043 * @class Roo.Resizable
31044 * @extends Roo.util.Observable
31045 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
31046 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
31047 * 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
31048 * the element will be wrapped for you automatically.</p>
31049 * <p>Here is the list of valid resize handles:</p>
31052 ------ -------------------
31061 'hd' horizontal drag
31064 * <p>Here's an example showing the creation of a typical Resizable:</p>
31066 var resizer = new Roo.Resizable("element-id", {
31074 resizer.on("resize", myHandler);
31076 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31077 * resizer.east.setDisplayed(false);</p>
31078 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31079 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31080 * resize operation's new size (defaults to [0, 0])
31081 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31082 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31083 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31084 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31085 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31086 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31087 * @cfg {Number} width The width of the element in pixels (defaults to null)
31088 * @cfg {Number} height The height of the element in pixels (defaults to null)
31089 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31090 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31091 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31092 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31093 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31094 * in favor of the handles config option (defaults to false)
31095 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31096 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31097 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31098 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31099 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31100 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31101 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31102 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31103 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31104 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31105 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31107 * Create a new resizable component
31108 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31109 * @param {Object} config configuration options
31111 Roo.Resizable = function(el, config)
31113 this.el = Roo.get(el);
31115 if(config && config.wrap){
31116 config.resizeChild = this.el;
31117 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31118 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31119 this.el.setStyle("overflow", "hidden");
31120 this.el.setPositioning(config.resizeChild.getPositioning());
31121 config.resizeChild.clearPositioning();
31122 if(!config.width || !config.height){
31123 var csize = config.resizeChild.getSize();
31124 this.el.setSize(csize.width, csize.height);
31126 if(config.pinned && !config.adjustments){
31127 config.adjustments = "auto";
31131 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31132 this.proxy.unselectable();
31133 this.proxy.enableDisplayMode('block');
31135 Roo.apply(this, config);
31138 this.disableTrackOver = true;
31139 this.el.addClass("x-resizable-pinned");
31141 // if the element isn't positioned, make it relative
31142 var position = this.el.getStyle("position");
31143 if(position != "absolute" && position != "fixed"){
31144 this.el.setStyle("position", "relative");
31146 if(!this.handles){ // no handles passed, must be legacy style
31147 this.handles = 's,e,se';
31148 if(this.multiDirectional){
31149 this.handles += ',n,w';
31152 if(this.handles == "all"){
31153 this.handles = "n s e w ne nw se sw";
31155 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31156 var ps = Roo.Resizable.positions;
31157 for(var i = 0, len = hs.length; i < len; i++){
31158 if(hs[i] && ps[hs[i]]){
31159 var pos = ps[hs[i]];
31160 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31164 this.corner = this.southeast;
31166 // updateBox = the box can move..
31167 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31168 this.updateBox = true;
31171 this.activeHandle = null;
31173 if(this.resizeChild){
31174 if(typeof this.resizeChild == "boolean"){
31175 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31177 this.resizeChild = Roo.get(this.resizeChild, true);
31181 if(this.adjustments == "auto"){
31182 var rc = this.resizeChild;
31183 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31184 if(rc && (hw || hn)){
31185 rc.position("relative");
31186 rc.setLeft(hw ? hw.el.getWidth() : 0);
31187 rc.setTop(hn ? hn.el.getHeight() : 0);
31189 this.adjustments = [
31190 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31191 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31195 if(this.draggable){
31196 this.dd = this.dynamic ?
31197 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31198 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31204 * @event beforeresize
31205 * Fired before resize is allowed. Set enabled to false to cancel resize.
31206 * @param {Roo.Resizable} this
31207 * @param {Roo.EventObject} e The mousedown event
31209 "beforeresize" : true,
31212 * Fired a resizing.
31213 * @param {Roo.Resizable} this
31214 * @param {Number} x The new x position
31215 * @param {Number} y The new y position
31216 * @param {Number} w The new w width
31217 * @param {Number} h The new h hight
31218 * @param {Roo.EventObject} e The mouseup event
31223 * Fired after a resize.
31224 * @param {Roo.Resizable} this
31225 * @param {Number} width The new width
31226 * @param {Number} height The new height
31227 * @param {Roo.EventObject} e The mouseup event
31232 if(this.width !== null && this.height !== null){
31233 this.resizeTo(this.width, this.height);
31235 this.updateChildSize();
31238 this.el.dom.style.zoom = 1;
31240 Roo.Resizable.superclass.constructor.call(this);
31243 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31244 resizeChild : false,
31245 adjustments : [0, 0],
31255 multiDirectional : false,
31256 disableTrackOver : false,
31257 easing : 'easeOutStrong',
31258 widthIncrement : 0,
31259 heightIncrement : 0,
31263 preserveRatio : false,
31264 transparent: false,
31270 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31272 constrainTo: undefined,
31274 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31276 resizeRegion: undefined,
31280 * Perform a manual resize
31281 * @param {Number} width
31282 * @param {Number} height
31284 resizeTo : function(width, height){
31285 this.el.setSize(width, height);
31286 this.updateChildSize();
31287 this.fireEvent("resize", this, width, height, null);
31291 startSizing : function(e, handle){
31292 this.fireEvent("beforeresize", this, e);
31293 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31296 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31297 this.overlay.unselectable();
31298 this.overlay.enableDisplayMode("block");
31299 this.overlay.on("mousemove", this.onMouseMove, this);
31300 this.overlay.on("mouseup", this.onMouseUp, this);
31302 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31304 this.resizing = true;
31305 this.startBox = this.el.getBox();
31306 this.startPoint = e.getXY();
31307 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31308 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31310 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31311 this.overlay.show();
31313 if(this.constrainTo) {
31314 var ct = Roo.get(this.constrainTo);
31315 this.resizeRegion = ct.getRegion().adjust(
31316 ct.getFrameWidth('t'),
31317 ct.getFrameWidth('l'),
31318 -ct.getFrameWidth('b'),
31319 -ct.getFrameWidth('r')
31323 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31325 this.proxy.setBox(this.startBox);
31327 this.proxy.setStyle('visibility', 'visible');
31333 onMouseDown : function(handle, e){
31336 this.activeHandle = handle;
31337 this.startSizing(e, handle);
31342 onMouseUp : function(e){
31343 var size = this.resizeElement();
31344 this.resizing = false;
31346 this.overlay.hide();
31348 this.fireEvent("resize", this, size.width, size.height, e);
31352 updateChildSize : function(){
31354 if(this.resizeChild){
31356 var child = this.resizeChild;
31357 var adj = this.adjustments;
31358 if(el.dom.offsetWidth){
31359 var b = el.getSize(true);
31360 child.setSize(b.width+adj[0], b.height+adj[1]);
31362 // Second call here for IE
31363 // The first call enables instant resizing and
31364 // the second call corrects scroll bars if they
31367 setTimeout(function(){
31368 if(el.dom.offsetWidth){
31369 var b = el.getSize(true);
31370 child.setSize(b.width+adj[0], b.height+adj[1]);
31378 snap : function(value, inc, min){
31379 if(!inc || !value) {
31382 var newValue = value;
31383 var m = value % inc;
31386 newValue = value + (inc-m);
31388 newValue = value - m;
31391 return Math.max(min, newValue);
31395 resizeElement : function(){
31396 var box = this.proxy.getBox();
31397 if(this.updateBox){
31398 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31400 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31402 this.updateChildSize();
31410 constrain : function(v, diff, m, mx){
31413 }else if(v - diff > mx){
31420 onMouseMove : function(e){
31423 try{// try catch so if something goes wrong the user doesn't get hung
31425 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31429 //var curXY = this.startPoint;
31430 var curSize = this.curSize || this.startBox;
31431 var x = this.startBox.x, y = this.startBox.y;
31432 var ox = x, oy = y;
31433 var w = curSize.width, h = curSize.height;
31434 var ow = w, oh = h;
31435 var mw = this.minWidth, mh = this.minHeight;
31436 var mxw = this.maxWidth, mxh = this.maxHeight;
31437 var wi = this.widthIncrement;
31438 var hi = this.heightIncrement;
31440 var eventXY = e.getXY();
31441 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31442 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31444 var pos = this.activeHandle.position;
31449 w = Math.min(Math.max(mw, w), mxw);
31454 h = Math.min(Math.max(mh, h), mxh);
31459 w = Math.min(Math.max(mw, w), mxw);
31460 h = Math.min(Math.max(mh, h), mxh);
31463 diffY = this.constrain(h, diffY, mh, mxh);
31470 var adiffX = Math.abs(diffX);
31471 var sub = (adiffX % wi); // how much
31472 if (sub > (wi/2)) { // far enough to snap
31473 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31475 // remove difference..
31476 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31480 x = Math.max(this.minX, x);
31483 diffX = this.constrain(w, diffX, mw, mxw);
31489 w = Math.min(Math.max(mw, w), mxw);
31490 diffY = this.constrain(h, diffY, mh, mxh);
31495 diffX = this.constrain(w, diffX, mw, mxw);
31496 diffY = this.constrain(h, diffY, mh, mxh);
31503 diffX = this.constrain(w, diffX, mw, mxw);
31505 h = Math.min(Math.max(mh, h), mxh);
31511 var sw = this.snap(w, wi, mw);
31512 var sh = this.snap(h, hi, mh);
31513 if(sw != w || sh != h){
31536 if(this.preserveRatio){
31541 h = Math.min(Math.max(mh, h), mxh);
31546 w = Math.min(Math.max(mw, w), mxw);
31551 w = Math.min(Math.max(mw, w), mxw);
31557 w = Math.min(Math.max(mw, w), mxw);
31563 h = Math.min(Math.max(mh, h), mxh);
31571 h = Math.min(Math.max(mh, h), mxh);
31581 h = Math.min(Math.max(mh, h), mxh);
31589 if (pos == 'hdrag') {
31592 this.proxy.setBounds(x, y, w, h);
31594 this.resizeElement();
31598 this.fireEvent("resizing", this, x, y, w, h, e);
31602 handleOver : function(){
31604 this.el.addClass("x-resizable-over");
31609 handleOut : function(){
31610 if(!this.resizing){
31611 this.el.removeClass("x-resizable-over");
31616 * Returns the element this component is bound to.
31617 * @return {Roo.Element}
31619 getEl : function(){
31624 * Returns the resizeChild element (or null).
31625 * @return {Roo.Element}
31627 getResizeChild : function(){
31628 return this.resizeChild;
31630 groupHandler : function()
31635 * Destroys this resizable. If the element was wrapped and
31636 * removeEl is not true then the element remains.
31637 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31639 destroy : function(removeEl){
31640 this.proxy.remove();
31642 this.overlay.removeAllListeners();
31643 this.overlay.remove();
31645 var ps = Roo.Resizable.positions;
31647 if(typeof ps[k] != "function" && this[ps[k]]){
31648 var h = this[ps[k]];
31649 h.el.removeAllListeners();
31654 this.el.update("");
31661 // hash to map config positions to true positions
31662 Roo.Resizable.positions = {
31663 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31668 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31670 // only initialize the template if resizable is used
31671 var tpl = Roo.DomHelper.createTemplate(
31672 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31675 Roo.Resizable.Handle.prototype.tpl = tpl;
31677 this.position = pos;
31679 // show north drag fro topdra
31680 var handlepos = pos == 'hdrag' ? 'north' : pos;
31682 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31683 if (pos == 'hdrag') {
31684 this.el.setStyle('cursor', 'pointer');
31686 this.el.unselectable();
31688 this.el.setOpacity(0);
31690 this.el.on("mousedown", this.onMouseDown, this);
31691 if(!disableTrackOver){
31692 this.el.on("mouseover", this.onMouseOver, this);
31693 this.el.on("mouseout", this.onMouseOut, this);
31698 Roo.Resizable.Handle.prototype = {
31699 afterResize : function(rz){
31704 onMouseDown : function(e){
31705 this.rz.onMouseDown(this, e);
31708 onMouseOver : function(e){
31709 this.rz.handleOver(this, e);
31712 onMouseOut : function(e){
31713 this.rz.handleOut(this, e);
31717 * Ext JS Library 1.1.1
31718 * Copyright(c) 2006-2007, Ext JS, LLC.
31720 * Originally Released Under LGPL - original licence link has changed is not relivant.
31723 * <script type="text/javascript">
31727 * @class Roo.Editor
31728 * @extends Roo.Component
31729 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31731 * Create a new Editor
31732 * @param {Roo.form.Field} field The Field object (or descendant)
31733 * @param {Object} config The config object
31735 Roo.Editor = function(field, config){
31736 Roo.Editor.superclass.constructor.call(this, config);
31737 this.field = field;
31740 * @event beforestartedit
31741 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31742 * false from the handler of this event.
31743 * @param {Editor} this
31744 * @param {Roo.Element} boundEl The underlying element bound to this editor
31745 * @param {Mixed} value The field value being set
31747 "beforestartedit" : true,
31750 * Fires when this editor is displayed
31751 * @param {Roo.Element} boundEl The underlying element bound to this editor
31752 * @param {Mixed} value The starting field value
31754 "startedit" : true,
31756 * @event beforecomplete
31757 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31758 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31759 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31760 * event will not fire since no edit actually occurred.
31761 * @param {Editor} this
31762 * @param {Mixed} value The current field value
31763 * @param {Mixed} startValue The original field value
31765 "beforecomplete" : true,
31768 * Fires after editing is complete and any changed value has been written to the underlying field.
31769 * @param {Editor} this
31770 * @param {Mixed} value The current field value
31771 * @param {Mixed} startValue The original field value
31775 * @event specialkey
31776 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31777 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31778 * @param {Roo.form.Field} this
31779 * @param {Roo.EventObject} e The event object
31781 "specialkey" : true
31785 Roo.extend(Roo.Editor, Roo.Component, {
31787 * @cfg {Boolean/String} autosize
31788 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31789 * or "height" to adopt the height only (defaults to false)
31792 * @cfg {Boolean} revertInvalid
31793 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31794 * validation fails (defaults to true)
31797 * @cfg {Boolean} ignoreNoChange
31798 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31799 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31800 * will never be ignored.
31803 * @cfg {Boolean} hideEl
31804 * False to keep the bound element visible while the editor is displayed (defaults to true)
31807 * @cfg {Mixed} value
31808 * The data value of the underlying field (defaults to "")
31812 * @cfg {String} alignment
31813 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31817 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31818 * for bottom-right shadow (defaults to "frame")
31822 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31826 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31828 completeOnEnter : false,
31830 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31832 cancelOnEsc : false,
31834 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31839 onRender : function(ct, position){
31840 this.el = new Roo.Layer({
31841 shadow: this.shadow,
31847 constrain: this.constrain
31849 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31850 if(this.field.msgTarget != 'title'){
31851 this.field.msgTarget = 'qtip';
31853 this.field.render(this.el);
31855 this.field.el.dom.setAttribute('autocomplete', 'off');
31857 this.field.on("specialkey", this.onSpecialKey, this);
31858 if(this.swallowKeys){
31859 this.field.el.swallowEvent(['keydown','keypress']);
31862 this.field.on("blur", this.onBlur, this);
31863 if(this.field.grow){
31864 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31868 onSpecialKey : function(field, e)
31870 //Roo.log('editor onSpecialKey');
31871 if(this.completeOnEnter && e.getKey() == e.ENTER){
31873 this.completeEdit();
31876 // do not fire special key otherwise it might hide close the editor...
31877 if(e.getKey() == e.ENTER){
31880 if(this.cancelOnEsc && e.getKey() == e.ESC){
31884 this.fireEvent('specialkey', field, e);
31889 * Starts the editing process and shows the editor.
31890 * @param {String/HTMLElement/Element} el The element to edit
31891 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31892 * to the innerHTML of el.
31894 startEdit : function(el, value){
31896 this.completeEdit();
31898 this.boundEl = Roo.get(el);
31899 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31900 if(!this.rendered){
31901 this.render(this.parentEl || document.body);
31903 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31906 this.startValue = v;
31907 this.field.setValue(v);
31909 var sz = this.boundEl.getSize();
31910 switch(this.autoSize){
31912 this.setSize(sz.width, "");
31915 this.setSize("", sz.height);
31918 this.setSize(sz.width, sz.height);
31921 this.el.alignTo(this.boundEl, this.alignment);
31922 this.editing = true;
31924 Roo.QuickTips.disable();
31930 * Sets the height and width of this editor.
31931 * @param {Number} width The new width
31932 * @param {Number} height The new height
31934 setSize : function(w, h){
31935 this.field.setSize(w, h);
31942 * Realigns the editor to the bound field based on the current alignment config value.
31944 realign : function(){
31945 this.el.alignTo(this.boundEl, this.alignment);
31949 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31950 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31952 completeEdit : function(remainVisible){
31956 var v = this.getValue();
31957 if(this.revertInvalid !== false && !this.field.isValid()){
31958 v = this.startValue;
31959 this.cancelEdit(true);
31961 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31962 this.editing = false;
31966 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31967 this.editing = false;
31968 if(this.updateEl && this.boundEl){
31969 this.boundEl.update(v);
31971 if(remainVisible !== true){
31974 this.fireEvent("complete", this, v, this.startValue);
31979 onShow : function(){
31981 if(this.hideEl !== false){
31982 this.boundEl.hide();
31985 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31986 this.fixIEFocus = true;
31987 this.deferredFocus.defer(50, this);
31989 this.field.focus();
31991 this.fireEvent("startedit", this.boundEl, this.startValue);
31994 deferredFocus : function(){
31996 this.field.focus();
32001 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
32002 * reverted to the original starting value.
32003 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
32004 * cancel (defaults to false)
32006 cancelEdit : function(remainVisible){
32008 this.setValue(this.startValue);
32009 if(remainVisible !== true){
32016 onBlur : function(){
32017 if(this.allowBlur !== true && this.editing){
32018 this.completeEdit();
32023 onHide : function(){
32025 this.completeEdit();
32029 if(this.field.collapse){
32030 this.field.collapse();
32033 if(this.hideEl !== false){
32034 this.boundEl.show();
32037 Roo.QuickTips.enable();
32042 * Sets the data value of the editor
32043 * @param {Mixed} value Any valid value supported by the underlying field
32045 setValue : function(v){
32046 this.field.setValue(v);
32050 * Gets the data value of the editor
32051 * @return {Mixed} The data value
32053 getValue : function(){
32054 return this.field.getValue();
32058 * Ext JS Library 1.1.1
32059 * Copyright(c) 2006-2007, Ext JS, LLC.
32061 * Originally Released Under LGPL - original licence link has changed is not relivant.
32064 * <script type="text/javascript">
32068 * @class Roo.BasicDialog
32069 * @extends Roo.util.Observable
32070 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32072 var dlg = new Roo.BasicDialog("my-dlg", {
32081 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32082 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32083 dlg.addButton('Cancel', dlg.hide, dlg);
32086 <b>A Dialog should always be a direct child of the body element.</b>
32087 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32088 * @cfg {String} title Default text to display in the title bar (defaults to null)
32089 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32090 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32091 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32092 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32093 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32094 * (defaults to null with no animation)
32095 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32096 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32097 * property for valid values (defaults to 'all')
32098 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32099 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32100 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32101 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32102 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32103 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32104 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32105 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32106 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32107 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32108 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32109 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32110 * draggable = true (defaults to false)
32111 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32112 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32113 * shadow (defaults to false)
32114 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32115 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32116 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32117 * @cfg {Array} buttons Array of buttons
32118 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32120 * Create a new BasicDialog.
32121 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32122 * @param {Object} config Configuration options
32124 Roo.BasicDialog = function(el, config){
32125 this.el = Roo.get(el);
32126 var dh = Roo.DomHelper;
32127 if(!this.el && config && config.autoCreate){
32128 if(typeof config.autoCreate == "object"){
32129 if(!config.autoCreate.id){
32130 config.autoCreate.id = el;
32132 this.el = dh.append(document.body,
32133 config.autoCreate, true);
32135 this.el = dh.append(document.body,
32136 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32140 el.setDisplayed(true);
32141 el.hide = this.hideAction;
32143 el.addClass("x-dlg");
32145 Roo.apply(this, config);
32147 this.proxy = el.createProxy("x-dlg-proxy");
32148 this.proxy.hide = this.hideAction;
32149 this.proxy.setOpacity(.5);
32153 el.setWidth(config.width);
32156 el.setHeight(config.height);
32158 this.size = el.getSize();
32159 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32160 this.xy = [config.x,config.y];
32162 this.xy = el.getCenterXY(true);
32164 /** The header element @type Roo.Element */
32165 this.header = el.child("> .x-dlg-hd");
32166 /** The body element @type Roo.Element */
32167 this.body = el.child("> .x-dlg-bd");
32168 /** The footer element @type Roo.Element */
32169 this.footer = el.child("> .x-dlg-ft");
32172 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32175 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32178 this.header.unselectable();
32180 this.header.update(this.title);
32182 // this element allows the dialog to be focused for keyboard event
32183 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32184 this.focusEl.swallowEvent("click", true);
32186 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32188 // wrap the body and footer for special rendering
32189 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32191 this.bwrap.dom.appendChild(this.footer.dom);
32194 this.bg = this.el.createChild({
32195 tag: "div", cls:"x-dlg-bg",
32196 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32198 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32201 if(this.autoScroll !== false && !this.autoTabs){
32202 this.body.setStyle("overflow", "auto");
32205 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32207 if(this.closable !== false){
32208 this.el.addClass("x-dlg-closable");
32209 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32210 this.close.on("click", this.closeClick, this);
32211 this.close.addClassOnOver("x-dlg-close-over");
32213 if(this.collapsible !== false){
32214 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32215 this.collapseBtn.on("click", this.collapseClick, this);
32216 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32217 this.header.on("dblclick", this.collapseClick, this);
32219 if(this.resizable !== false){
32220 this.el.addClass("x-dlg-resizable");
32221 this.resizer = new Roo.Resizable(el, {
32222 minWidth: this.minWidth || 80,
32223 minHeight:this.minHeight || 80,
32224 handles: this.resizeHandles || "all",
32227 this.resizer.on("beforeresize", this.beforeResize, this);
32228 this.resizer.on("resize", this.onResize, this);
32230 if(this.draggable !== false){
32231 el.addClass("x-dlg-draggable");
32232 if (!this.proxyDrag) {
32233 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32236 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32238 dd.setHandleElId(this.header.id);
32239 dd.endDrag = this.endMove.createDelegate(this);
32240 dd.startDrag = this.startMove.createDelegate(this);
32241 dd.onDrag = this.onDrag.createDelegate(this);
32246 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32247 this.mask.enableDisplayMode("block");
32249 this.el.addClass("x-dlg-modal");
32252 this.shadow = new Roo.Shadow({
32253 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32254 offset : this.shadowOffset
32257 this.shadowOffset = 0;
32259 if(Roo.useShims && this.shim !== false){
32260 this.shim = this.el.createShim();
32261 this.shim.hide = this.hideAction;
32269 if (this.buttons) {
32270 var bts= this.buttons;
32272 Roo.each(bts, function(b) {
32281 * Fires when a key is pressed
32282 * @param {Roo.BasicDialog} this
32283 * @param {Roo.EventObject} e
32288 * Fires when this dialog is moved by the user.
32289 * @param {Roo.BasicDialog} this
32290 * @param {Number} x The new page X
32291 * @param {Number} y The new page Y
32296 * Fires when this dialog is resized by the user.
32297 * @param {Roo.BasicDialog} this
32298 * @param {Number} width The new width
32299 * @param {Number} height The new height
32303 * @event beforehide
32304 * Fires before this dialog is hidden.
32305 * @param {Roo.BasicDialog} this
32307 "beforehide" : true,
32310 * Fires when this dialog is hidden.
32311 * @param {Roo.BasicDialog} this
32315 * @event beforeshow
32316 * Fires before this dialog is shown.
32317 * @param {Roo.BasicDialog} this
32319 "beforeshow" : true,
32322 * Fires when this dialog is shown.
32323 * @param {Roo.BasicDialog} this
32327 el.on("keydown", this.onKeyDown, this);
32328 el.on("mousedown", this.toFront, this);
32329 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32331 Roo.DialogManager.register(this);
32332 Roo.BasicDialog.superclass.constructor.call(this);
32335 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32336 shadowOffset: Roo.isIE ? 6 : 5,
32339 minButtonWidth: 75,
32340 defaultButton: null,
32341 buttonAlign: "right",
32346 * Sets the dialog title text
32347 * @param {String} text The title text to display
32348 * @return {Roo.BasicDialog} this
32350 setTitle : function(text){
32351 this.header.update(text);
32356 closeClick : function(){
32361 collapseClick : function(){
32362 this[this.collapsed ? "expand" : "collapse"]();
32366 * Collapses the dialog to its minimized state (only the title bar is visible).
32367 * Equivalent to the user clicking the collapse dialog button.
32369 collapse : function(){
32370 if(!this.collapsed){
32371 this.collapsed = true;
32372 this.el.addClass("x-dlg-collapsed");
32373 this.restoreHeight = this.el.getHeight();
32374 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32379 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32380 * clicking the expand dialog button.
32382 expand : function(){
32383 if(this.collapsed){
32384 this.collapsed = false;
32385 this.el.removeClass("x-dlg-collapsed");
32386 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32391 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32392 * @return {Roo.TabPanel} The tabs component
32394 initTabs : function(){
32395 var tabs = this.getTabs();
32396 while(tabs.getTab(0)){
32399 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32401 tabs.addTab(Roo.id(dom), dom.title);
32409 beforeResize : function(){
32410 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32414 onResize : function(){
32415 this.refreshSize();
32416 this.syncBodyHeight();
32417 this.adjustAssets();
32419 this.fireEvent("resize", this, this.size.width, this.size.height);
32423 onKeyDown : function(e){
32424 if(this.isVisible()){
32425 this.fireEvent("keydown", this, e);
32430 * Resizes the dialog.
32431 * @param {Number} width
32432 * @param {Number} height
32433 * @return {Roo.BasicDialog} this
32435 resizeTo : function(width, height){
32436 this.el.setSize(width, height);
32437 this.size = {width: width, height: height};
32438 this.syncBodyHeight();
32439 if(this.fixedcenter){
32442 if(this.isVisible()){
32443 this.constrainXY();
32444 this.adjustAssets();
32446 this.fireEvent("resize", this, width, height);
32452 * Resizes the dialog to fit the specified content size.
32453 * @param {Number} width
32454 * @param {Number} height
32455 * @return {Roo.BasicDialog} this
32457 setContentSize : function(w, h){
32458 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32459 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32460 //if(!this.el.isBorderBox()){
32461 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32462 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32465 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32466 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32468 this.resizeTo(w, h);
32473 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32474 * executed in response to a particular key being pressed while the dialog is active.
32475 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32476 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32477 * @param {Function} fn The function to call
32478 * @param {Object} scope (optional) The scope of the function
32479 * @return {Roo.BasicDialog} this
32481 addKeyListener : function(key, fn, scope){
32482 var keyCode, shift, ctrl, alt;
32483 if(typeof key == "object" && !(key instanceof Array)){
32484 keyCode = key["key"];
32485 shift = key["shift"];
32486 ctrl = key["ctrl"];
32491 var handler = function(dlg, e){
32492 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32493 var k = e.getKey();
32494 if(keyCode instanceof Array){
32495 for(var i = 0, len = keyCode.length; i < len; i++){
32496 if(keyCode[i] == k){
32497 fn.call(scope || window, dlg, k, e);
32503 fn.call(scope || window, dlg, k, e);
32508 this.on("keydown", handler);
32513 * Returns the TabPanel component (creates it if it doesn't exist).
32514 * Note: If you wish to simply check for the existence of tabs without creating them,
32515 * check for a null 'tabs' property.
32516 * @return {Roo.TabPanel} The tabs component
32518 getTabs : function(){
32520 this.el.addClass("x-dlg-auto-tabs");
32521 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32522 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32528 * Adds a button to the footer section of the dialog.
32529 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32530 * object or a valid Roo.DomHelper element config
32531 * @param {Function} handler The function called when the button is clicked
32532 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32533 * @return {Roo.Button} The new button
32535 addButton : function(config, handler, scope){
32536 var dh = Roo.DomHelper;
32538 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32540 if(!this.btnContainer){
32541 var tb = this.footer.createChild({
32543 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32544 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32546 this.btnContainer = tb.firstChild.firstChild.firstChild;
32551 minWidth: this.minButtonWidth,
32554 if(typeof config == "string"){
32555 bconfig.text = config;
32558 bconfig.dhconfig = config;
32560 Roo.apply(bconfig, config);
32564 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32565 bconfig.position = Math.max(0, bconfig.position);
32566 fc = this.btnContainer.childNodes[bconfig.position];
32569 var btn = new Roo.Button(
32571 this.btnContainer.insertBefore(document.createElement("td"),fc)
32572 : this.btnContainer.appendChild(document.createElement("td")),
32573 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32576 this.syncBodyHeight();
32579 * Array of all the buttons that have been added to this dialog via addButton
32584 this.buttons.push(btn);
32589 * Sets the default button to be focused when the dialog is displayed.
32590 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32591 * @return {Roo.BasicDialog} this
32593 setDefaultButton : function(btn){
32594 this.defaultButton = btn;
32599 getHeaderFooterHeight : function(safe){
32602 height += this.header.getHeight();
32605 var fm = this.footer.getMargins();
32606 height += (this.footer.getHeight()+fm.top+fm.bottom);
32608 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32609 height += this.centerBg.getPadding("tb");
32614 syncBodyHeight : function()
32616 var bd = this.body, // the text
32617 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32619 var height = this.size.height - this.getHeaderFooterHeight(false);
32620 bd.setHeight(height-bd.getMargins("tb"));
32621 var hh = this.header.getHeight();
32622 var h = this.size.height-hh;
32625 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32626 bw.setHeight(h-cb.getPadding("tb"));
32628 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32629 bd.setWidth(bw.getWidth(true));
32631 this.tabs.syncHeight();
32633 this.tabs.el.repaint();
32639 * Restores the previous state of the dialog if Roo.state is configured.
32640 * @return {Roo.BasicDialog} this
32642 restoreState : function(){
32643 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32644 if(box && box.width){
32645 this.xy = [box.x, box.y];
32646 this.resizeTo(box.width, box.height);
32652 beforeShow : function(){
32654 if(this.fixedcenter){
32655 this.xy = this.el.getCenterXY(true);
32658 Roo.get(document.body).addClass("x-body-masked");
32659 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32662 this.constrainXY();
32666 animShow : function(){
32667 var b = Roo.get(this.animateTarget).getBox();
32668 this.proxy.setSize(b.width, b.height);
32669 this.proxy.setLocation(b.x, b.y);
32671 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32672 true, .35, this.showEl.createDelegate(this));
32676 * Shows the dialog.
32677 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32678 * @return {Roo.BasicDialog} this
32680 show : function(animateTarget){
32681 if (this.fireEvent("beforeshow", this) === false){
32684 if(this.syncHeightBeforeShow){
32685 this.syncBodyHeight();
32686 }else if(this.firstShow){
32687 this.firstShow = false;
32688 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32690 this.animateTarget = animateTarget || this.animateTarget;
32691 if(!this.el.isVisible()){
32693 if(this.animateTarget && Roo.get(this.animateTarget)){
32703 showEl : function(){
32705 this.el.setXY(this.xy);
32707 this.adjustAssets(true);
32710 // IE peekaboo bug - fix found by Dave Fenwick
32714 this.fireEvent("show", this);
32718 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32719 * dialog itself will receive focus.
32721 focus : function(){
32722 if(this.defaultButton){
32723 this.defaultButton.focus();
32725 this.focusEl.focus();
32730 constrainXY : function(){
32731 if(this.constraintoviewport !== false){
32732 if(!this.viewSize){
32733 if(this.container){
32734 var s = this.container.getSize();
32735 this.viewSize = [s.width, s.height];
32737 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32740 var s = Roo.get(this.container||document).getScroll();
32742 var x = this.xy[0], y = this.xy[1];
32743 var w = this.size.width, h = this.size.height;
32744 var vw = this.viewSize[0], vh = this.viewSize[1];
32745 // only move it if it needs it
32747 // first validate right/bottom
32748 if(x + w > vw+s.left){
32752 if(y + h > vh+s.top){
32756 // then make sure top/left isn't negative
32768 if(this.isVisible()){
32769 this.el.setLocation(x, y);
32770 this.adjustAssets();
32777 onDrag : function(){
32778 if(!this.proxyDrag){
32779 this.xy = this.el.getXY();
32780 this.adjustAssets();
32785 adjustAssets : function(doShow){
32786 var x = this.xy[0], y = this.xy[1];
32787 var w = this.size.width, h = this.size.height;
32788 if(doShow === true){
32790 this.shadow.show(this.el);
32796 if(this.shadow && this.shadow.isVisible()){
32797 this.shadow.show(this.el);
32799 if(this.shim && this.shim.isVisible()){
32800 this.shim.setBounds(x, y, w, h);
32805 adjustViewport : function(w, h){
32807 w = Roo.lib.Dom.getViewWidth();
32808 h = Roo.lib.Dom.getViewHeight();
32811 this.viewSize = [w, h];
32812 if(this.modal && this.mask.isVisible()){
32813 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32814 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32816 if(this.isVisible()){
32817 this.constrainXY();
32822 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32823 * shadow, proxy, mask, etc.) Also removes all event listeners.
32824 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32826 destroy : function(removeEl){
32827 if(this.isVisible()){
32828 this.animateTarget = null;
32831 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32833 this.tabs.destroy(removeEl);
32846 for(var i = 0, len = this.buttons.length; i < len; i++){
32847 this.buttons[i].destroy();
32850 this.el.removeAllListeners();
32851 if(removeEl === true){
32852 this.el.update("");
32855 Roo.DialogManager.unregister(this);
32859 startMove : function(){
32860 if(this.proxyDrag){
32863 if(this.constraintoviewport !== false){
32864 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32869 endMove : function(){
32870 if(!this.proxyDrag){
32871 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32873 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32876 this.refreshSize();
32877 this.adjustAssets();
32879 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32883 * Brings this dialog to the front of any other visible dialogs
32884 * @return {Roo.BasicDialog} this
32886 toFront : function(){
32887 Roo.DialogManager.bringToFront(this);
32892 * Sends this dialog to the back (under) of any other visible dialogs
32893 * @return {Roo.BasicDialog} this
32895 toBack : function(){
32896 Roo.DialogManager.sendToBack(this);
32901 * Centers this dialog in the viewport
32902 * @return {Roo.BasicDialog} this
32904 center : function(){
32905 var xy = this.el.getCenterXY(true);
32906 this.moveTo(xy[0], xy[1]);
32911 * Moves the dialog's top-left corner to the specified point
32912 * @param {Number} x
32913 * @param {Number} y
32914 * @return {Roo.BasicDialog} this
32916 moveTo : function(x, y){
32918 if(this.isVisible()){
32919 this.el.setXY(this.xy);
32920 this.adjustAssets();
32926 * Aligns the dialog to the specified element
32927 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32928 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32929 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32930 * @return {Roo.BasicDialog} this
32932 alignTo : function(element, position, offsets){
32933 this.xy = this.el.getAlignToXY(element, position, offsets);
32934 if(this.isVisible()){
32935 this.el.setXY(this.xy);
32936 this.adjustAssets();
32942 * Anchors an element to another element and realigns it when the window is resized.
32943 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32944 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32945 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32946 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32947 * is a number, it is used as the buffer delay (defaults to 50ms).
32948 * @return {Roo.BasicDialog} this
32950 anchorTo : function(el, alignment, offsets, monitorScroll){
32951 var action = function(){
32952 this.alignTo(el, alignment, offsets);
32954 Roo.EventManager.onWindowResize(action, this);
32955 var tm = typeof monitorScroll;
32956 if(tm != 'undefined'){
32957 Roo.EventManager.on(window, 'scroll', action, this,
32958 {buffer: tm == 'number' ? monitorScroll : 50});
32965 * Returns true if the dialog is visible
32966 * @return {Boolean}
32968 isVisible : function(){
32969 return this.el.isVisible();
32973 animHide : function(callback){
32974 var b = Roo.get(this.animateTarget).getBox();
32976 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32978 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32979 this.hideEl.createDelegate(this, [callback]));
32983 * Hides the dialog.
32984 * @param {Function} callback (optional) Function to call when the dialog is hidden
32985 * @return {Roo.BasicDialog} this
32987 hide : function(callback){
32988 if (this.fireEvent("beforehide", this) === false){
32992 this.shadow.hide();
32997 // sometimes animateTarget seems to get set.. causing problems...
32998 // this just double checks..
32999 if(this.animateTarget && Roo.get(this.animateTarget)) {
33000 this.animHide(callback);
33003 this.hideEl(callback);
33009 hideEl : function(callback){
33013 Roo.get(document.body).removeClass("x-body-masked");
33015 this.fireEvent("hide", this);
33016 if(typeof callback == "function"){
33022 hideAction : function(){
33023 this.setLeft("-10000px");
33024 this.setTop("-10000px");
33025 this.setStyle("visibility", "hidden");
33029 refreshSize : function(){
33030 this.size = this.el.getSize();
33031 this.xy = this.el.getXY();
33032 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
33036 // z-index is managed by the DialogManager and may be overwritten at any time
33037 setZIndex : function(index){
33039 this.mask.setStyle("z-index", index);
33042 this.shim.setStyle("z-index", ++index);
33045 this.shadow.setZIndex(++index);
33047 this.el.setStyle("z-index", ++index);
33049 this.proxy.setStyle("z-index", ++index);
33052 this.resizer.proxy.setStyle("z-index", ++index);
33055 this.lastZIndex = index;
33059 * Returns the element for this dialog
33060 * @return {Roo.Element} The underlying dialog Element
33062 getEl : function(){
33068 * @class Roo.DialogManager
33069 * Provides global access to BasicDialogs that have been created and
33070 * support for z-indexing (layering) multiple open dialogs.
33072 Roo.DialogManager = function(){
33074 var accessList = [];
33078 var sortDialogs = function(d1, d2){
33079 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33083 var orderDialogs = function(){
33084 accessList.sort(sortDialogs);
33085 var seed = Roo.DialogManager.zseed;
33086 for(var i = 0, len = accessList.length; i < len; i++){
33087 var dlg = accessList[i];
33089 dlg.setZIndex(seed + (i*10));
33096 * The starting z-index for BasicDialogs (defaults to 9000)
33097 * @type Number The z-index value
33102 register : function(dlg){
33103 list[dlg.id] = dlg;
33104 accessList.push(dlg);
33108 unregister : function(dlg){
33109 delete list[dlg.id];
33112 if(!accessList.indexOf){
33113 for( i = 0, len = accessList.length; i < len; i++){
33114 if(accessList[i] == dlg){
33115 accessList.splice(i, 1);
33120 i = accessList.indexOf(dlg);
33122 accessList.splice(i, 1);
33128 * Gets a registered dialog by id
33129 * @param {String/Object} id The id of the dialog or a dialog
33130 * @return {Roo.BasicDialog} this
33132 get : function(id){
33133 return typeof id == "object" ? id : list[id];
33137 * Brings the specified dialog to the front
33138 * @param {String/Object} dlg The id of the dialog or a dialog
33139 * @return {Roo.BasicDialog} this
33141 bringToFront : function(dlg){
33142 dlg = this.get(dlg);
33145 dlg._lastAccess = new Date().getTime();
33152 * Sends the specified dialog to the back
33153 * @param {String/Object} dlg The id of the dialog or a dialog
33154 * @return {Roo.BasicDialog} this
33156 sendToBack : function(dlg){
33157 dlg = this.get(dlg);
33158 dlg._lastAccess = -(new Date().getTime());
33164 * Hides all dialogs
33166 hideAll : function(){
33167 for(var id in list){
33168 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33177 * @class Roo.LayoutDialog
33178 * @extends Roo.BasicDialog
33179 * Dialog which provides adjustments for working with a layout in a Dialog.
33180 * Add your necessary layout config options to the dialog's config.<br>
33181 * Example usage (including a nested layout):
33184 dialog = new Roo.LayoutDialog("download-dlg", {
33193 // layout config merges with the dialog config
33195 tabPosition: "top",
33196 alwaysShowTabs: true
33199 dialog.addKeyListener(27, dialog.hide, dialog);
33200 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33201 dialog.addButton("Build It!", this.getDownload, this);
33203 // we can even add nested layouts
33204 var innerLayout = new Roo.BorderLayout("dl-inner", {
33214 innerLayout.beginUpdate();
33215 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33216 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33217 innerLayout.endUpdate(true);
33219 var layout = dialog.getLayout();
33220 layout.beginUpdate();
33221 layout.add("center", new Roo.ContentPanel("standard-panel",
33222 {title: "Download the Source", fitToFrame:true}));
33223 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33224 {title: "Build your own roo.js"}));
33225 layout.getRegion("center").showPanel(sp);
33226 layout.endUpdate();
33230 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33231 * @param {Object} config configuration options
33233 Roo.LayoutDialog = function(el, cfg){
33236 if (typeof(cfg) == 'undefined') {
33237 config = Roo.apply({}, el);
33238 // not sure why we use documentElement here.. - it should always be body.
33239 // IE7 borks horribly if we use documentElement.
33240 // webkit also does not like documentElement - it creates a body element...
33241 el = Roo.get( document.body || document.documentElement ).createChild();
33242 //config.autoCreate = true;
33246 config.autoTabs = false;
33247 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33248 this.body.setStyle({overflow:"hidden", position:"relative"});
33249 this.layout = new Roo.BorderLayout(this.body.dom, config);
33250 this.layout.monitorWindowResize = false;
33251 this.el.addClass("x-dlg-auto-layout");
33252 // fix case when center region overwrites center function
33253 this.center = Roo.BasicDialog.prototype.center;
33254 this.on("show", this.layout.layout, this.layout, true);
33255 if (config.items) {
33256 var xitems = config.items;
33257 delete config.items;
33258 Roo.each(xitems, this.addxtype, this);
33263 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33265 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33268 endUpdate : function(){
33269 this.layout.endUpdate();
33273 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33276 beginUpdate : function(){
33277 this.layout.beginUpdate();
33281 * Get the BorderLayout for this dialog
33282 * @return {Roo.BorderLayout}
33284 getLayout : function(){
33285 return this.layout;
33288 showEl : function(){
33289 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33291 this.layout.layout();
33296 // Use the syncHeightBeforeShow config option to control this automatically
33297 syncBodyHeight : function(){
33298 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33299 if(this.layout){this.layout.layout();}
33303 * Add an xtype element (actually adds to the layout.)
33304 * @return {Object} xdata xtype object data.
33307 addxtype : function(c) {
33308 return this.layout.addxtype(c);
33312 * Ext JS Library 1.1.1
33313 * Copyright(c) 2006-2007, Ext JS, LLC.
33315 * Originally Released Under LGPL - original licence link has changed is not relivant.
33318 * <script type="text/javascript">
33322 * @class Roo.MessageBox
33323 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33327 Roo.Msg.alert('Status', 'Changes saved successfully.');
33329 // Prompt for user data:
33330 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33332 // process text value...
33336 // Show a dialog using config options:
33338 title:'Save Changes?',
33339 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33340 buttons: Roo.Msg.YESNOCANCEL,
33347 Roo.MessageBox = function(){
33348 var dlg, opt, mask, waitTimer;
33349 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33350 var buttons, activeTextEl, bwidth;
33353 var handleButton = function(button){
33355 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33359 var handleHide = function(){
33360 if(opt && opt.cls){
33361 dlg.el.removeClass(opt.cls);
33364 Roo.TaskMgr.stop(waitTimer);
33370 var updateButtons = function(b){
33373 buttons["ok"].hide();
33374 buttons["cancel"].hide();
33375 buttons["yes"].hide();
33376 buttons["no"].hide();
33377 dlg.footer.dom.style.display = 'none';
33380 dlg.footer.dom.style.display = '';
33381 for(var k in buttons){
33382 if(typeof buttons[k] != "function"){
33385 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33386 width += buttons[k].el.getWidth()+15;
33396 var handleEsc = function(d, k, e){
33397 if(opt && opt.closable !== false){
33407 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33408 * @return {Roo.BasicDialog} The BasicDialog element
33410 getDialog : function(){
33412 dlg = new Roo.BasicDialog("x-msg-box", {
33417 constraintoviewport:false,
33419 collapsible : false,
33422 width:400, height:100,
33423 buttonAlign:"center",
33424 closeClick : function(){
33425 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33426 handleButton("no");
33428 handleButton("cancel");
33432 dlg.on("hide", handleHide);
33434 dlg.addKeyListener(27, handleEsc);
33436 var bt = this.buttonText;
33437 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33438 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33439 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33440 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33441 bodyEl = dlg.body.createChild({
33443 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>'
33445 msgEl = bodyEl.dom.firstChild;
33446 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33447 textboxEl.enableDisplayMode();
33448 textboxEl.addKeyListener([10,13], function(){
33449 if(dlg.isVisible() && opt && opt.buttons){
33450 if(opt.buttons.ok){
33451 handleButton("ok");
33452 }else if(opt.buttons.yes){
33453 handleButton("yes");
33457 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33458 textareaEl.enableDisplayMode();
33459 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33460 progressEl.enableDisplayMode();
33461 var pf = progressEl.dom.firstChild;
33463 pp = Roo.get(pf.firstChild);
33464 pp.setHeight(pf.offsetHeight);
33472 * Updates the message box body text
33473 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33474 * the XHTML-compliant non-breaking space character '&#160;')
33475 * @return {Roo.MessageBox} This message box
33477 updateText : function(text){
33478 if(!dlg.isVisible() && !opt.width){
33479 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33481 msgEl.innerHTML = text || ' ';
33483 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33484 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33486 Math.min(opt.width || cw , this.maxWidth),
33487 Math.max(opt.minWidth || this.minWidth, bwidth)
33490 activeTextEl.setWidth(w);
33492 if(dlg.isVisible()){
33493 dlg.fixedcenter = false;
33495 // to big, make it scroll. = But as usual stupid IE does not support
33498 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33499 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33500 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33502 bodyEl.dom.style.height = '';
33503 bodyEl.dom.style.overflowY = '';
33506 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33508 bodyEl.dom.style.overflowX = '';
33511 dlg.setContentSize(w, bodyEl.getHeight());
33512 if(dlg.isVisible()){
33513 dlg.fixedcenter = true;
33519 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33520 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33521 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33522 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33523 * @return {Roo.MessageBox} This message box
33525 updateProgress : function(value, text){
33527 this.updateText(text);
33529 if (pp) { // weird bug on my firefox - for some reason this is not defined
33530 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33536 * Returns true if the message box is currently displayed
33537 * @return {Boolean} True if the message box is visible, else false
33539 isVisible : function(){
33540 return dlg && dlg.isVisible();
33544 * Hides the message box if it is displayed
33547 if(this.isVisible()){
33553 * Displays a new message box, or reinitializes an existing message box, based on the config options
33554 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33555 * The following config object properties are supported:
33557 Property Type Description
33558 ---------- --------------- ------------------------------------------------------------------------------------
33559 animEl String/Element An id or Element from which the message box should animate as it opens and
33560 closes (defaults to undefined)
33561 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33562 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33563 closable Boolean False to hide the top-right close button (defaults to true). Note that
33564 progress and wait dialogs will ignore this property and always hide the
33565 close button as they can only be closed programmatically.
33566 cls String A custom CSS class to apply to the message box element
33567 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33568 displayed (defaults to 75)
33569 fn Function A callback function to execute after closing the dialog. The arguments to the
33570 function will be btn (the name of the button that was clicked, if applicable,
33571 e.g. "ok"), and text (the value of the active text field, if applicable).
33572 Progress and wait dialogs will ignore this option since they do not respond to
33573 user actions and can only be closed programmatically, so any required function
33574 should be called by the same code after it closes the dialog.
33575 icon String A CSS class that provides a background image to be used as an icon for
33576 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33577 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33578 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33579 modal Boolean False to allow user interaction with the page while the message box is
33580 displayed (defaults to true)
33581 msg String A string that will replace the existing message box body text (defaults
33582 to the XHTML-compliant non-breaking space character ' ')
33583 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33584 progress Boolean True to display a progress bar (defaults to false)
33585 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33586 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33587 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33588 title String The title text
33589 value String The string value to set into the active textbox element if displayed
33590 wait Boolean True to display a progress bar (defaults to false)
33591 width Number The width of the dialog in pixels
33598 msg: 'Please enter your address:',
33600 buttons: Roo.MessageBox.OKCANCEL,
33603 animEl: 'addAddressBtn'
33606 * @param {Object} config Configuration options
33607 * @return {Roo.MessageBox} This message box
33609 show : function(options)
33612 // this causes nightmares if you show one dialog after another
33613 // especially on callbacks..
33615 if(this.isVisible()){
33618 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33619 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33620 Roo.log("New Dialog Message:" + options.msg )
33621 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33622 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33625 var d = this.getDialog();
33627 d.setTitle(opt.title || " ");
33628 d.close.setDisplayed(opt.closable !== false);
33629 activeTextEl = textboxEl;
33630 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33635 textareaEl.setHeight(typeof opt.multiline == "number" ?
33636 opt.multiline : this.defaultTextHeight);
33637 activeTextEl = textareaEl;
33646 progressEl.setDisplayed(opt.progress === true);
33647 this.updateProgress(0);
33648 activeTextEl.dom.value = opt.value || "";
33650 dlg.setDefaultButton(activeTextEl);
33652 var bs = opt.buttons;
33655 db = buttons["ok"];
33656 }else if(bs && bs.yes){
33657 db = buttons["yes"];
33659 dlg.setDefaultButton(db);
33661 bwidth = updateButtons(opt.buttons);
33662 this.updateText(opt.msg);
33664 d.el.addClass(opt.cls);
33666 d.proxyDrag = opt.proxyDrag === true;
33667 d.modal = opt.modal !== false;
33668 d.mask = opt.modal !== false ? mask : false;
33669 if(!d.isVisible()){
33670 // force it to the end of the z-index stack so it gets a cursor in FF
33671 document.body.appendChild(dlg.el.dom);
33672 d.animateTarget = null;
33673 d.show(options.animEl);
33679 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33680 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33681 * and closing the message box when the process is complete.
33682 * @param {String} title The title bar text
33683 * @param {String} msg The message box body text
33684 * @return {Roo.MessageBox} This message box
33686 progress : function(title, msg){
33693 minWidth: this.minProgressWidth,
33700 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33701 * If a callback function is passed it will be called after the user clicks the button, and the
33702 * id of the button that was clicked will be passed as the only parameter to the callback
33703 * (could also be the top-right close button).
33704 * @param {String} title The title bar text
33705 * @param {String} msg The message box body text
33706 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33707 * @param {Object} scope (optional) The scope of the callback function
33708 * @return {Roo.MessageBox} This message box
33710 alert : function(title, msg, fn, scope){
33723 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33724 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33725 * You are responsible for closing the message box when the process is complete.
33726 * @param {String} msg The message box body text
33727 * @param {String} title (optional) The title bar text
33728 * @return {Roo.MessageBox} This message box
33730 wait : function(msg, title){
33741 waitTimer = Roo.TaskMgr.start({
33743 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33751 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33752 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33753 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33754 * @param {String} title The title bar text
33755 * @param {String} msg The message box body text
33756 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33757 * @param {Object} scope (optional) The scope of the callback function
33758 * @return {Roo.MessageBox} This message box
33760 confirm : function(title, msg, fn, scope){
33764 buttons: this.YESNO,
33773 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33774 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33775 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33776 * (could also be the top-right close button) and the text that was entered will be passed as the two
33777 * parameters to the callback.
33778 * @param {String} title The title bar text
33779 * @param {String} msg The message box body text
33780 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33781 * @param {Object} scope (optional) The scope of the callback function
33782 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33783 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33784 * @return {Roo.MessageBox} This message box
33786 prompt : function(title, msg, fn, scope, multiline){
33790 buttons: this.OKCANCEL,
33795 multiline: multiline,
33802 * Button config that displays a single OK button
33807 * Button config that displays Yes and No buttons
33810 YESNO : {yes:true, no:true},
33812 * Button config that displays OK and Cancel buttons
33815 OKCANCEL : {ok:true, cancel:true},
33817 * Button config that displays Yes, No and Cancel buttons
33820 YESNOCANCEL : {yes:true, no:true, cancel:true},
33823 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33826 defaultTextHeight : 75,
33828 * The maximum width in pixels of the message box (defaults to 600)
33833 * The minimum width in pixels of the message box (defaults to 100)
33838 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33839 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33842 minProgressWidth : 250,
33844 * An object containing the default button text strings that can be overriden for localized language support.
33845 * Supported properties are: ok, cancel, yes and no.
33846 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33859 * Shorthand for {@link Roo.MessageBox}
33861 Roo.Msg = Roo.MessageBox;/*
33863 * Ext JS Library 1.1.1
33864 * Copyright(c) 2006-2007, Ext JS, LLC.
33866 * Originally Released Under LGPL - original licence link has changed is not relivant.
33869 * <script type="text/javascript">
33872 * @class Roo.QuickTips
33873 * Provides attractive and customizable tooltips for any element.
33876 Roo.QuickTips = function(){
33877 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33878 var ce, bd, xy, dd;
33879 var visible = false, disabled = true, inited = false;
33880 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33882 var onOver = function(e){
33886 var t = e.getTarget();
33887 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33890 if(ce && t == ce.el){
33891 clearTimeout(hideProc);
33894 if(t && tagEls[t.id]){
33895 tagEls[t.id].el = t;
33896 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33899 var ttp, et = Roo.fly(t);
33900 var ns = cfg.namespace;
33901 if(tm.interceptTitles && t.title){
33904 t.removeAttribute("title");
33905 e.preventDefault();
33907 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33910 showProc = show.defer(tm.showDelay, tm, [{
33912 text: ttp.replace(/\\n/g,'<br/>'),
33913 width: et.getAttributeNS(ns, cfg.width),
33914 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33915 title: et.getAttributeNS(ns, cfg.title),
33916 cls: et.getAttributeNS(ns, cfg.cls)
33921 var onOut = function(e){
33922 clearTimeout(showProc);
33923 var t = e.getTarget();
33924 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33925 hideProc = setTimeout(hide, tm.hideDelay);
33929 var onMove = function(e){
33935 if(tm.trackMouse && ce){
33940 var onDown = function(e){
33941 clearTimeout(showProc);
33942 clearTimeout(hideProc);
33944 if(tm.hideOnClick){
33947 tm.enable.defer(100, tm);
33952 var getPad = function(){
33953 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33956 var show = function(o){
33960 clearTimeout(dismissProc);
33962 if(removeCls){ // in case manually hidden
33963 el.removeClass(removeCls);
33967 el.addClass(ce.cls);
33968 removeCls = ce.cls;
33971 tipTitle.update(ce.title);
33974 tipTitle.update('');
33977 el.dom.style.width = tm.maxWidth+'px';
33978 //tipBody.dom.style.width = '';
33979 tipBodyText.update(o.text);
33980 var p = getPad(), w = ce.width;
33982 var td = tipBodyText.dom;
33983 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33984 if(aw > tm.maxWidth){
33986 }else if(aw < tm.minWidth){
33992 //tipBody.setWidth(w);
33993 el.setWidth(parseInt(w, 10) + p);
33994 if(ce.autoHide === false){
33995 close.setDisplayed(true);
34000 close.setDisplayed(false);
34006 el.avoidY = xy[1]-18;
34011 el.setStyle("visibility", "visible");
34012 el.fadeIn({callback: afterShow});
34018 var afterShow = function(){
34022 if(tm.autoDismiss && ce.autoHide !== false){
34023 dismissProc = setTimeout(hide, tm.autoDismissDelay);
34028 var hide = function(noanim){
34029 clearTimeout(dismissProc);
34030 clearTimeout(hideProc);
34032 if(el.isVisible()){
34034 if(noanim !== true && tm.animate){
34035 el.fadeOut({callback: afterHide});
34042 var afterHide = function(){
34045 el.removeClass(removeCls);
34052 * @cfg {Number} minWidth
34053 * The minimum width of the quick tip (defaults to 40)
34057 * @cfg {Number} maxWidth
34058 * The maximum width of the quick tip (defaults to 300)
34062 * @cfg {Boolean} interceptTitles
34063 * True to automatically use the element's DOM title value if available (defaults to false)
34065 interceptTitles : false,
34067 * @cfg {Boolean} trackMouse
34068 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34070 trackMouse : false,
34072 * @cfg {Boolean} hideOnClick
34073 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34075 hideOnClick : true,
34077 * @cfg {Number} showDelay
34078 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
34082 * @cfg {Number} hideDelay
34083 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34087 * @cfg {Boolean} autoHide
34088 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34089 * Used in conjunction with hideDelay.
34094 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34095 * (defaults to true). Used in conjunction with autoDismissDelay.
34097 autoDismiss : true,
34100 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34102 autoDismissDelay : 5000,
34104 * @cfg {Boolean} animate
34105 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34110 * @cfg {String} title
34111 * Title text to display (defaults to ''). This can be any valid HTML markup.
34115 * @cfg {String} text
34116 * Body text to display (defaults to ''). This can be any valid HTML markup.
34120 * @cfg {String} cls
34121 * A CSS class to apply to the base quick tip element (defaults to '').
34125 * @cfg {Number} width
34126 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34127 * minWidth or maxWidth.
34132 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34133 * or display QuickTips in a page.
34136 tm = Roo.QuickTips;
34137 cfg = tm.tagConfig;
34139 if(!Roo.isReady){ // allow calling of init() before onReady
34140 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34143 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34144 el.fxDefaults = {stopFx: true};
34145 // maximum custom styling
34146 //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>');
34147 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>');
34148 tipTitle = el.child('h3');
34149 tipTitle.enableDisplayMode("block");
34150 tipBody = el.child('div.x-tip-bd');
34151 tipBodyText = el.child('div.x-tip-bd-inner');
34152 //bdLeft = el.child('div.x-tip-bd-left');
34153 //bdRight = el.child('div.x-tip-bd-right');
34154 close = el.child('div.x-tip-close');
34155 close.enableDisplayMode("block");
34156 close.on("click", hide);
34157 var d = Roo.get(document);
34158 d.on("mousedown", onDown);
34159 d.on("mouseover", onOver);
34160 d.on("mouseout", onOut);
34161 d.on("mousemove", onMove);
34162 esc = d.addKeyListener(27, hide);
34165 dd = el.initDD("default", null, {
34166 onDrag : function(){
34170 dd.setHandleElId(tipTitle.id);
34179 * Configures a new quick tip instance and assigns it to a target element. The following config options
34182 Property Type Description
34183 ---------- --------------------- ------------------------------------------------------------------------
34184 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34186 * @param {Object} config The config object
34188 register : function(config){
34189 var cs = config instanceof Array ? config : arguments;
34190 for(var i = 0, len = cs.length; i < len; i++) {
34192 var target = c.target;
34194 if(target instanceof Array){
34195 for(var j = 0, jlen = target.length; j < jlen; j++){
34196 tagEls[target[j]] = c;
34199 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34206 * Removes this quick tip from its element and destroys it.
34207 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34209 unregister : function(el){
34210 delete tagEls[Roo.id(el)];
34214 * Enable this quick tip.
34216 enable : function(){
34217 if(inited && disabled){
34219 if(locks.length < 1){
34226 * Disable this quick tip.
34228 disable : function(){
34230 clearTimeout(showProc);
34231 clearTimeout(hideProc);
34232 clearTimeout(dismissProc);
34240 * Returns true if the quick tip is enabled, else false.
34242 isEnabled : function(){
34248 namespace : "roo", // was ext?? this may break..
34249 alt_namespace : "ext",
34250 attribute : "qtip",
34260 // backwards compat
34261 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34263 * Ext JS Library 1.1.1
34264 * Copyright(c) 2006-2007, Ext JS, LLC.
34266 * Originally Released Under LGPL - original licence link has changed is not relivant.
34269 * <script type="text/javascript">
34274 * @class Roo.tree.TreePanel
34275 * @extends Roo.data.Tree
34277 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34278 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34279 * @cfg {Boolean} enableDD true to enable drag and drop
34280 * @cfg {Boolean} enableDrag true to enable just drag
34281 * @cfg {Boolean} enableDrop true to enable just drop
34282 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34283 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34284 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34285 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34286 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34287 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34288 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34289 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34290 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34291 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34292 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34293 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34294 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34295 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34296 * @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>
34297 * @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>
34300 * @param {String/HTMLElement/Element} el The container element
34301 * @param {Object} config
34303 Roo.tree.TreePanel = function(el, config){
34305 var loader = false;
34307 root = config.root;
34308 delete config.root;
34310 if (config.loader) {
34311 loader = config.loader;
34312 delete config.loader;
34315 Roo.apply(this, config);
34316 Roo.tree.TreePanel.superclass.constructor.call(this);
34317 this.el = Roo.get(el);
34318 this.el.addClass('x-tree');
34319 //console.log(root);
34321 this.setRootNode( Roo.factory(root, Roo.tree));
34324 this.loader = Roo.factory(loader, Roo.tree);
34327 * Read-only. The id of the container element becomes this TreePanel's id.
34329 this.id = this.el.id;
34332 * @event beforeload
34333 * Fires before a node is loaded, return false to cancel
34334 * @param {Node} node The node being loaded
34336 "beforeload" : true,
34339 * Fires when a node is loaded
34340 * @param {Node} node The node that was loaded
34344 * @event textchange
34345 * Fires when the text for a node is changed
34346 * @param {Node} node The node
34347 * @param {String} text The new text
34348 * @param {String} oldText The old text
34350 "textchange" : true,
34352 * @event beforeexpand
34353 * Fires before a node is expanded, return false to cancel.
34354 * @param {Node} node The node
34355 * @param {Boolean} deep
34356 * @param {Boolean} anim
34358 "beforeexpand" : true,
34360 * @event beforecollapse
34361 * Fires before a node is collapsed, return false to cancel.
34362 * @param {Node} node The node
34363 * @param {Boolean} deep
34364 * @param {Boolean} anim
34366 "beforecollapse" : true,
34369 * Fires when a node is expanded
34370 * @param {Node} node The node
34374 * @event disabledchange
34375 * Fires when the disabled status of a node changes
34376 * @param {Node} node The node
34377 * @param {Boolean} disabled
34379 "disabledchange" : true,
34382 * Fires when a node is collapsed
34383 * @param {Node} node The node
34387 * @event beforeclick
34388 * Fires before click processing on a node. Return false to cancel the default action.
34389 * @param {Node} node The node
34390 * @param {Roo.EventObject} e The event object
34392 "beforeclick":true,
34394 * @event checkchange
34395 * Fires when a node with a checkbox's checked property changes
34396 * @param {Node} this This node
34397 * @param {Boolean} checked
34399 "checkchange":true,
34402 * Fires when a node is clicked
34403 * @param {Node} node The node
34404 * @param {Roo.EventObject} e The event object
34409 * Fires when a node is double clicked
34410 * @param {Node} node The node
34411 * @param {Roo.EventObject} e The event object
34415 * @event contextmenu
34416 * Fires when a node is right clicked
34417 * @param {Node} node The node
34418 * @param {Roo.EventObject} e The event object
34420 "contextmenu":true,
34422 * @event beforechildrenrendered
34423 * Fires right before the child nodes for a node are rendered
34424 * @param {Node} node The node
34426 "beforechildrenrendered":true,
34429 * Fires when a node starts being dragged
34430 * @param {Roo.tree.TreePanel} this
34431 * @param {Roo.tree.TreeNode} node
34432 * @param {event} e The raw browser event
34434 "startdrag" : true,
34437 * Fires when a drag operation is complete
34438 * @param {Roo.tree.TreePanel} this
34439 * @param {Roo.tree.TreeNode} node
34440 * @param {event} e The raw browser event
34445 * Fires when a dragged node is dropped on a valid DD target
34446 * @param {Roo.tree.TreePanel} this
34447 * @param {Roo.tree.TreeNode} node
34448 * @param {DD} dd The dd it was dropped on
34449 * @param {event} e The raw browser event
34453 * @event beforenodedrop
34454 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34455 * passed to handlers has the following properties:<br />
34456 * <ul style="padding:5px;padding-left:16px;">
34457 * <li>tree - The TreePanel</li>
34458 * <li>target - The node being targeted for the drop</li>
34459 * <li>data - The drag data from the drag source</li>
34460 * <li>point - The point of the drop - append, above or below</li>
34461 * <li>source - The drag source</li>
34462 * <li>rawEvent - Raw mouse event</li>
34463 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34464 * to be inserted by setting them on this object.</li>
34465 * <li>cancel - Set this to true to cancel the drop.</li>
34467 * @param {Object} dropEvent
34469 "beforenodedrop" : true,
34472 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34473 * passed to handlers has the following properties:<br />
34474 * <ul style="padding:5px;padding-left:16px;">
34475 * <li>tree - The TreePanel</li>
34476 * <li>target - The node being targeted for the drop</li>
34477 * <li>data - The drag data from the drag source</li>
34478 * <li>point - The point of the drop - append, above or below</li>
34479 * <li>source - The drag source</li>
34480 * <li>rawEvent - Raw mouse event</li>
34481 * <li>dropNode - Dropped node(s).</li>
34483 * @param {Object} dropEvent
34487 * @event nodedragover
34488 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34489 * passed to handlers has the following properties:<br />
34490 * <ul style="padding:5px;padding-left:16px;">
34491 * <li>tree - The TreePanel</li>
34492 * <li>target - The node being targeted for the drop</li>
34493 * <li>data - The drag data from the drag source</li>
34494 * <li>point - The point of the drop - append, above or below</li>
34495 * <li>source - The drag source</li>
34496 * <li>rawEvent - Raw mouse event</li>
34497 * <li>dropNode - Drop node(s) provided by the source.</li>
34498 * <li>cancel - Set this to true to signal drop not allowed.</li>
34500 * @param {Object} dragOverEvent
34502 "nodedragover" : true,
34504 * @event appendnode
34505 * Fires when append node to the tree
34506 * @param {Roo.tree.TreePanel} this
34507 * @param {Roo.tree.TreeNode} node
34508 * @param {Number} index The index of the newly appended node
34510 "appendnode" : true
34513 if(this.singleExpand){
34514 this.on("beforeexpand", this.restrictExpand, this);
34517 this.editor.tree = this;
34518 this.editor = Roo.factory(this.editor, Roo.tree);
34521 if (this.selModel) {
34522 this.selModel = Roo.factory(this.selModel, Roo.tree);
34526 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34527 rootVisible : true,
34528 animate: Roo.enableFx,
34531 hlDrop : Roo.enableFx,
34535 rendererTip: false,
34537 restrictExpand : function(node){
34538 var p = node.parentNode;
34540 if(p.expandedChild && p.expandedChild.parentNode == p){
34541 p.expandedChild.collapse();
34543 p.expandedChild = node;
34547 // private override
34548 setRootNode : function(node){
34549 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34550 if(!this.rootVisible){
34551 node.ui = new Roo.tree.RootTreeNodeUI(node);
34557 * Returns the container element for this TreePanel
34559 getEl : function(){
34564 * Returns the default TreeLoader for this TreePanel
34566 getLoader : function(){
34567 return this.loader;
34573 expandAll : function(){
34574 this.root.expand(true);
34578 * Collapse all nodes
34580 collapseAll : function(){
34581 this.root.collapse(true);
34585 * Returns the selection model used by this TreePanel
34587 getSelectionModel : function(){
34588 if(!this.selModel){
34589 this.selModel = new Roo.tree.DefaultSelectionModel();
34591 return this.selModel;
34595 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34596 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34597 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34600 getChecked : function(a, startNode){
34601 startNode = startNode || this.root;
34603 var f = function(){
34604 if(this.attributes.checked){
34605 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34608 startNode.cascade(f);
34613 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34614 * @param {String} path
34615 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34616 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34617 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34619 expandPath : function(path, attr, callback){
34620 attr = attr || "id";
34621 var keys = path.split(this.pathSeparator);
34622 var curNode = this.root;
34623 if(curNode.attributes[attr] != keys[1]){ // invalid root
34625 callback(false, null);
34630 var f = function(){
34631 if(++index == keys.length){
34633 callback(true, curNode);
34637 var c = curNode.findChild(attr, keys[index]);
34640 callback(false, curNode);
34645 c.expand(false, false, f);
34647 curNode.expand(false, false, f);
34651 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34652 * @param {String} path
34653 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34654 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34655 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34657 selectPath : function(path, attr, callback){
34658 attr = attr || "id";
34659 var keys = path.split(this.pathSeparator);
34660 var v = keys.pop();
34661 if(keys.length > 0){
34662 var f = function(success, node){
34663 if(success && node){
34664 var n = node.findChild(attr, v);
34670 }else if(callback){
34671 callback(false, n);
34675 callback(false, n);
34679 this.expandPath(keys.join(this.pathSeparator), attr, f);
34681 this.root.select();
34683 callback(true, this.root);
34688 getTreeEl : function(){
34693 * Trigger rendering of this TreePanel
34695 render : function(){
34696 if (this.innerCt) {
34697 return this; // stop it rendering more than once!!
34700 this.innerCt = this.el.createChild({tag:"ul",
34701 cls:"x-tree-root-ct " +
34702 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34704 if(this.containerScroll){
34705 Roo.dd.ScrollManager.register(this.el);
34707 if((this.enableDD || this.enableDrop) && !this.dropZone){
34709 * The dropZone used by this tree if drop is enabled
34710 * @type Roo.tree.TreeDropZone
34712 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34713 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34716 if((this.enableDD || this.enableDrag) && !this.dragZone){
34718 * The dragZone used by this tree if drag is enabled
34719 * @type Roo.tree.TreeDragZone
34721 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34722 ddGroup: this.ddGroup || "TreeDD",
34723 scroll: this.ddScroll
34726 this.getSelectionModel().init(this);
34728 Roo.log("ROOT not set in tree");
34731 this.root.render();
34732 if(!this.rootVisible){
34733 this.root.renderChildren();
34739 * Ext JS Library 1.1.1
34740 * Copyright(c) 2006-2007, Ext JS, LLC.
34742 * Originally Released Under LGPL - original licence link has changed is not relivant.
34745 * <script type="text/javascript">
34750 * @class Roo.tree.DefaultSelectionModel
34751 * @extends Roo.util.Observable
34752 * The default single selection for a TreePanel.
34753 * @param {Object} cfg Configuration
34755 Roo.tree.DefaultSelectionModel = function(cfg){
34756 this.selNode = null;
34762 * @event selectionchange
34763 * Fires when the selected node changes
34764 * @param {DefaultSelectionModel} this
34765 * @param {TreeNode} node the new selection
34767 "selectionchange" : true,
34770 * @event beforeselect
34771 * Fires before the selected node changes, return false to cancel the change
34772 * @param {DefaultSelectionModel} this
34773 * @param {TreeNode} node the new selection
34774 * @param {TreeNode} node the old selection
34776 "beforeselect" : true
34779 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34782 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34783 init : function(tree){
34785 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34786 tree.on("click", this.onNodeClick, this);
34789 onNodeClick : function(node, e){
34790 if (e.ctrlKey && this.selNode == node) {
34791 this.unselect(node);
34799 * @param {TreeNode} node The node to select
34800 * @return {TreeNode} The selected node
34802 select : function(node){
34803 var last = this.selNode;
34804 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34806 last.ui.onSelectedChange(false);
34808 this.selNode = node;
34809 node.ui.onSelectedChange(true);
34810 this.fireEvent("selectionchange", this, node, last);
34817 * @param {TreeNode} node The node to unselect
34819 unselect : function(node){
34820 if(this.selNode == node){
34821 this.clearSelections();
34826 * Clear all selections
34828 clearSelections : function(){
34829 var n = this.selNode;
34831 n.ui.onSelectedChange(false);
34832 this.selNode = null;
34833 this.fireEvent("selectionchange", this, null);
34839 * Get the selected node
34840 * @return {TreeNode} The selected node
34842 getSelectedNode : function(){
34843 return this.selNode;
34847 * Returns true if the node is selected
34848 * @param {TreeNode} node The node to check
34849 * @return {Boolean}
34851 isSelected : function(node){
34852 return this.selNode == node;
34856 * Selects the node above the selected node in the tree, intelligently walking the nodes
34857 * @return TreeNode The new selection
34859 selectPrevious : function(){
34860 var s = this.selNode || this.lastSelNode;
34864 var ps = s.previousSibling;
34866 if(!ps.isExpanded() || ps.childNodes.length < 1){
34867 return this.select(ps);
34869 var lc = ps.lastChild;
34870 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34873 return this.select(lc);
34875 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34876 return this.select(s.parentNode);
34882 * Selects the node above the selected node in the tree, intelligently walking the nodes
34883 * @return TreeNode The new selection
34885 selectNext : function(){
34886 var s = this.selNode || this.lastSelNode;
34890 if(s.firstChild && s.isExpanded()){
34891 return this.select(s.firstChild);
34892 }else if(s.nextSibling){
34893 return this.select(s.nextSibling);
34894 }else if(s.parentNode){
34896 s.parentNode.bubble(function(){
34897 if(this.nextSibling){
34898 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34907 onKeyDown : function(e){
34908 var s = this.selNode || this.lastSelNode;
34909 // undesirable, but required
34914 var k = e.getKey();
34922 this.selectPrevious();
34925 e.preventDefault();
34926 if(s.hasChildNodes()){
34927 if(!s.isExpanded()){
34929 }else if(s.firstChild){
34930 this.select(s.firstChild, e);
34935 e.preventDefault();
34936 if(s.hasChildNodes() && s.isExpanded()){
34938 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34939 this.select(s.parentNode, e);
34947 * @class Roo.tree.MultiSelectionModel
34948 * @extends Roo.util.Observable
34949 * Multi selection for a TreePanel.
34950 * @param {Object} cfg Configuration
34952 Roo.tree.MultiSelectionModel = function(){
34953 this.selNodes = [];
34957 * @event selectionchange
34958 * Fires when the selected nodes change
34959 * @param {MultiSelectionModel} this
34960 * @param {Array} nodes Array of the selected nodes
34962 "selectionchange" : true
34964 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34968 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34969 init : function(tree){
34971 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34972 tree.on("click", this.onNodeClick, this);
34975 onNodeClick : function(node, e){
34976 this.select(node, e, e.ctrlKey);
34981 * @param {TreeNode} node The node to select
34982 * @param {EventObject} e (optional) An event associated with the selection
34983 * @param {Boolean} keepExisting True to retain existing selections
34984 * @return {TreeNode} The selected node
34986 select : function(node, e, keepExisting){
34987 if(keepExisting !== true){
34988 this.clearSelections(true);
34990 if(this.isSelected(node)){
34991 this.lastSelNode = node;
34994 this.selNodes.push(node);
34995 this.selMap[node.id] = node;
34996 this.lastSelNode = node;
34997 node.ui.onSelectedChange(true);
34998 this.fireEvent("selectionchange", this, this.selNodes);
35004 * @param {TreeNode} node The node to unselect
35006 unselect : function(node){
35007 if(this.selMap[node.id]){
35008 node.ui.onSelectedChange(false);
35009 var sn = this.selNodes;
35012 index = sn.indexOf(node);
35014 for(var i = 0, len = sn.length; i < len; i++){
35022 this.selNodes.splice(index, 1);
35024 delete this.selMap[node.id];
35025 this.fireEvent("selectionchange", this, this.selNodes);
35030 * Clear all selections
35032 clearSelections : function(suppressEvent){
35033 var sn = this.selNodes;
35035 for(var i = 0, len = sn.length; i < len; i++){
35036 sn[i].ui.onSelectedChange(false);
35038 this.selNodes = [];
35040 if(suppressEvent !== true){
35041 this.fireEvent("selectionchange", this, this.selNodes);
35047 * Returns true if the node is selected
35048 * @param {TreeNode} node The node to check
35049 * @return {Boolean}
35051 isSelected : function(node){
35052 return this.selMap[node.id] ? true : false;
35056 * Returns an array of the selected nodes
35059 getSelectedNodes : function(){
35060 return this.selNodes;
35063 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35065 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35067 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35070 * Ext JS Library 1.1.1
35071 * Copyright(c) 2006-2007, Ext JS, LLC.
35073 * Originally Released Under LGPL - original licence link has changed is not relivant.
35076 * <script type="text/javascript">
35080 * @class Roo.tree.TreeNode
35081 * @extends Roo.data.Node
35082 * @cfg {String} text The text for this node
35083 * @cfg {Boolean} expanded true to start the node expanded
35084 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35085 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35086 * @cfg {Boolean} disabled true to start the node disabled
35087 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35088 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35089 * @cfg {String} cls A css class to be added to the node
35090 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35091 * @cfg {String} href URL of the link used for the node (defaults to #)
35092 * @cfg {String} hrefTarget target frame for the link
35093 * @cfg {String} qtip An Ext QuickTip for the node
35094 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35095 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35096 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35097 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35098 * (defaults to undefined with no checkbox rendered)
35100 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35102 Roo.tree.TreeNode = function(attributes){
35103 attributes = attributes || {};
35104 if(typeof attributes == "string"){
35105 attributes = {text: attributes};
35107 this.childrenRendered = false;
35108 this.rendered = false;
35109 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35110 this.expanded = attributes.expanded === true;
35111 this.isTarget = attributes.isTarget !== false;
35112 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35113 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35116 * Read-only. The text for this node. To change it use setText().
35119 this.text = attributes.text;
35121 * True if this node is disabled.
35124 this.disabled = attributes.disabled === true;
35128 * @event textchange
35129 * Fires when the text for this node is changed
35130 * @param {Node} this This node
35131 * @param {String} text The new text
35132 * @param {String} oldText The old text
35134 "textchange" : true,
35136 * @event beforeexpand
35137 * Fires before this node is expanded, return false to cancel.
35138 * @param {Node} this This node
35139 * @param {Boolean} deep
35140 * @param {Boolean} anim
35142 "beforeexpand" : true,
35144 * @event beforecollapse
35145 * Fires before this node is collapsed, return false to cancel.
35146 * @param {Node} this This node
35147 * @param {Boolean} deep
35148 * @param {Boolean} anim
35150 "beforecollapse" : true,
35153 * Fires when this node is expanded
35154 * @param {Node} this This node
35158 * @event disabledchange
35159 * Fires when the disabled status of this node changes
35160 * @param {Node} this This node
35161 * @param {Boolean} disabled
35163 "disabledchange" : true,
35166 * Fires when this node is collapsed
35167 * @param {Node} this This node
35171 * @event beforeclick
35172 * Fires before click processing. Return false to cancel the default action.
35173 * @param {Node} this This node
35174 * @param {Roo.EventObject} e The event object
35176 "beforeclick":true,
35178 * @event checkchange
35179 * Fires when a node with a checkbox's checked property changes
35180 * @param {Node} this This node
35181 * @param {Boolean} checked
35183 "checkchange":true,
35186 * Fires when this node is clicked
35187 * @param {Node} this This node
35188 * @param {Roo.EventObject} e The event object
35193 * Fires when this node is double clicked
35194 * @param {Node} this This node
35195 * @param {Roo.EventObject} e The event object
35199 * @event contextmenu
35200 * Fires when this node is right clicked
35201 * @param {Node} this This node
35202 * @param {Roo.EventObject} e The event object
35204 "contextmenu":true,
35206 * @event beforechildrenrendered
35207 * Fires right before the child nodes for this node are rendered
35208 * @param {Node} this This node
35210 "beforechildrenrendered":true
35213 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35216 * Read-only. The UI for this node
35219 this.ui = new uiClass(this);
35221 // finally support items[]
35222 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35227 Roo.each(this.attributes.items, function(c) {
35228 this.appendChild(Roo.factory(c,Roo.Tree));
35230 delete this.attributes.items;
35235 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35236 preventHScroll: true,
35238 * Returns true if this node is expanded
35239 * @return {Boolean}
35241 isExpanded : function(){
35242 return this.expanded;
35246 * Returns the UI object for this node
35247 * @return {TreeNodeUI}
35249 getUI : function(){
35253 // private override
35254 setFirstChild : function(node){
35255 var of = this.firstChild;
35256 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35257 if(this.childrenRendered && of && node != of){
35258 of.renderIndent(true, true);
35261 this.renderIndent(true, true);
35265 // private override
35266 setLastChild : function(node){
35267 var ol = this.lastChild;
35268 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35269 if(this.childrenRendered && ol && node != ol){
35270 ol.renderIndent(true, true);
35273 this.renderIndent(true, true);
35277 // these methods are overridden to provide lazy rendering support
35278 // private override
35279 appendChild : function()
35281 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35282 if(node && this.childrenRendered){
35285 this.ui.updateExpandIcon();
35289 // private override
35290 removeChild : function(node){
35291 this.ownerTree.getSelectionModel().unselect(node);
35292 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35293 // if it's been rendered remove dom node
35294 if(this.childrenRendered){
35297 if(this.childNodes.length < 1){
35298 this.collapse(false, false);
35300 this.ui.updateExpandIcon();
35302 if(!this.firstChild) {
35303 this.childrenRendered = false;
35308 // private override
35309 insertBefore : function(node, refNode){
35310 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35311 if(newNode && refNode && this.childrenRendered){
35314 this.ui.updateExpandIcon();
35319 * Sets the text for this node
35320 * @param {String} text
35322 setText : function(text){
35323 var oldText = this.text;
35325 this.attributes.text = text;
35326 if(this.rendered){ // event without subscribing
35327 this.ui.onTextChange(this, text, oldText);
35329 this.fireEvent("textchange", this, text, oldText);
35333 * Triggers selection of this node
35335 select : function(){
35336 this.getOwnerTree().getSelectionModel().select(this);
35340 * Triggers deselection of this node
35342 unselect : function(){
35343 this.getOwnerTree().getSelectionModel().unselect(this);
35347 * Returns true if this node is selected
35348 * @return {Boolean}
35350 isSelected : function(){
35351 return this.getOwnerTree().getSelectionModel().isSelected(this);
35355 * Expand this node.
35356 * @param {Boolean} deep (optional) True to expand all children as well
35357 * @param {Boolean} anim (optional) false to cancel the default animation
35358 * @param {Function} callback (optional) A callback to be called when
35359 * expanding this node completes (does not wait for deep expand to complete).
35360 * Called with 1 parameter, this node.
35362 expand : function(deep, anim, callback){
35363 if(!this.expanded){
35364 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35367 if(!this.childrenRendered){
35368 this.renderChildren();
35370 this.expanded = true;
35372 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35373 this.ui.animExpand(function(){
35374 this.fireEvent("expand", this);
35375 if(typeof callback == "function"){
35379 this.expandChildNodes(true);
35381 }.createDelegate(this));
35385 this.fireEvent("expand", this);
35386 if(typeof callback == "function"){
35391 if(typeof callback == "function"){
35396 this.expandChildNodes(true);
35400 isHiddenRoot : function(){
35401 return this.isRoot && !this.getOwnerTree().rootVisible;
35405 * Collapse this node.
35406 * @param {Boolean} deep (optional) True to collapse all children as well
35407 * @param {Boolean} anim (optional) false to cancel the default animation
35409 collapse : function(deep, anim){
35410 if(this.expanded && !this.isHiddenRoot()){
35411 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35414 this.expanded = false;
35415 if((this.getOwnerTree().animate && anim !== false) || anim){
35416 this.ui.animCollapse(function(){
35417 this.fireEvent("collapse", this);
35419 this.collapseChildNodes(true);
35421 }.createDelegate(this));
35424 this.ui.collapse();
35425 this.fireEvent("collapse", this);
35429 var cs = this.childNodes;
35430 for(var i = 0, len = cs.length; i < len; i++) {
35431 cs[i].collapse(true, false);
35437 delayedExpand : function(delay){
35438 if(!this.expandProcId){
35439 this.expandProcId = this.expand.defer(delay, this);
35444 cancelExpand : function(){
35445 if(this.expandProcId){
35446 clearTimeout(this.expandProcId);
35448 this.expandProcId = false;
35452 * Toggles expanded/collapsed state of the node
35454 toggle : function(){
35463 * Ensures all parent nodes are expanded
35465 ensureVisible : function(callback){
35466 var tree = this.getOwnerTree();
35467 tree.expandPath(this.parentNode.getPath(), false, function(){
35468 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35469 Roo.callback(callback);
35470 }.createDelegate(this));
35474 * Expand all child nodes
35475 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35477 expandChildNodes : function(deep){
35478 var cs = this.childNodes;
35479 for(var i = 0, len = cs.length; i < len; i++) {
35480 cs[i].expand(deep);
35485 * Collapse all child nodes
35486 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35488 collapseChildNodes : function(deep){
35489 var cs = this.childNodes;
35490 for(var i = 0, len = cs.length; i < len; i++) {
35491 cs[i].collapse(deep);
35496 * Disables this node
35498 disable : function(){
35499 this.disabled = true;
35501 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35502 this.ui.onDisableChange(this, true);
35504 this.fireEvent("disabledchange", this, true);
35508 * Enables this node
35510 enable : function(){
35511 this.disabled = false;
35512 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35513 this.ui.onDisableChange(this, false);
35515 this.fireEvent("disabledchange", this, false);
35519 renderChildren : function(suppressEvent){
35520 if(suppressEvent !== false){
35521 this.fireEvent("beforechildrenrendered", this);
35523 var cs = this.childNodes;
35524 for(var i = 0, len = cs.length; i < len; i++){
35525 cs[i].render(true);
35527 this.childrenRendered = true;
35531 sort : function(fn, scope){
35532 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35533 if(this.childrenRendered){
35534 var cs = this.childNodes;
35535 for(var i = 0, len = cs.length; i < len; i++){
35536 cs[i].render(true);
35542 render : function(bulkRender){
35543 this.ui.render(bulkRender);
35544 if(!this.rendered){
35545 this.rendered = true;
35547 this.expanded = false;
35548 this.expand(false, false);
35554 renderIndent : function(deep, refresh){
35556 this.ui.childIndent = null;
35558 this.ui.renderIndent();
35559 if(deep === true && this.childrenRendered){
35560 var cs = this.childNodes;
35561 for(var i = 0, len = cs.length; i < len; i++){
35562 cs[i].renderIndent(true, refresh);
35568 * Ext JS Library 1.1.1
35569 * Copyright(c) 2006-2007, Ext JS, LLC.
35571 * Originally Released Under LGPL - original licence link has changed is not relivant.
35574 * <script type="text/javascript">
35578 * @class Roo.tree.AsyncTreeNode
35579 * @extends Roo.tree.TreeNode
35580 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35582 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35584 Roo.tree.AsyncTreeNode = function(config){
35585 this.loaded = false;
35586 this.loading = false;
35587 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35589 * @event beforeload
35590 * Fires before this node is loaded, return false to cancel
35591 * @param {Node} this This node
35593 this.addEvents({'beforeload':true, 'load': true});
35596 * Fires when this node is loaded
35597 * @param {Node} this This node
35600 * The loader used by this node (defaults to using the tree's defined loader)
35605 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35606 expand : function(deep, anim, callback){
35607 if(this.loading){ // if an async load is already running, waiting til it's done
35609 var f = function(){
35610 if(!this.loading){ // done loading
35611 clearInterval(timer);
35612 this.expand(deep, anim, callback);
35614 }.createDelegate(this);
35615 timer = setInterval(f, 200);
35619 if(this.fireEvent("beforeload", this) === false){
35622 this.loading = true;
35623 this.ui.beforeLoad(this);
35624 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35626 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35630 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35634 * Returns true if this node is currently loading
35635 * @return {Boolean}
35637 isLoading : function(){
35638 return this.loading;
35641 loadComplete : function(deep, anim, callback){
35642 this.loading = false;
35643 this.loaded = true;
35644 this.ui.afterLoad(this);
35645 this.fireEvent("load", this);
35646 this.expand(deep, anim, callback);
35650 * Returns true if this node has been loaded
35651 * @return {Boolean}
35653 isLoaded : function(){
35654 return this.loaded;
35657 hasChildNodes : function(){
35658 if(!this.isLeaf() && !this.loaded){
35661 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35666 * Trigger a reload for this node
35667 * @param {Function} callback
35669 reload : function(callback){
35670 this.collapse(false, false);
35671 while(this.firstChild){
35672 this.removeChild(this.firstChild);
35674 this.childrenRendered = false;
35675 this.loaded = false;
35676 if(this.isHiddenRoot()){
35677 this.expanded = false;
35679 this.expand(false, false, callback);
35683 * Ext JS Library 1.1.1
35684 * Copyright(c) 2006-2007, Ext JS, LLC.
35686 * Originally Released Under LGPL - original licence link has changed is not relivant.
35689 * <script type="text/javascript">
35693 * @class Roo.tree.TreeNodeUI
35695 * @param {Object} node The node to render
35696 * The TreeNode UI implementation is separate from the
35697 * tree implementation. Unless you are customizing the tree UI,
35698 * you should never have to use this directly.
35700 Roo.tree.TreeNodeUI = function(node){
35702 this.rendered = false;
35703 this.animating = false;
35704 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35707 Roo.tree.TreeNodeUI.prototype = {
35708 removeChild : function(node){
35710 this.ctNode.removeChild(node.ui.getEl());
35714 beforeLoad : function(){
35715 this.addClass("x-tree-node-loading");
35718 afterLoad : function(){
35719 this.removeClass("x-tree-node-loading");
35722 onTextChange : function(node, text, oldText){
35724 this.textNode.innerHTML = text;
35728 onDisableChange : function(node, state){
35729 this.disabled = state;
35731 this.addClass("x-tree-node-disabled");
35733 this.removeClass("x-tree-node-disabled");
35737 onSelectedChange : function(state){
35740 this.addClass("x-tree-selected");
35743 this.removeClass("x-tree-selected");
35747 onMove : function(tree, node, oldParent, newParent, index, refNode){
35748 this.childIndent = null;
35750 var targetNode = newParent.ui.getContainer();
35751 if(!targetNode){//target not rendered
35752 this.holder = document.createElement("div");
35753 this.holder.appendChild(this.wrap);
35756 var insertBefore = refNode ? refNode.ui.getEl() : null;
35758 targetNode.insertBefore(this.wrap, insertBefore);
35760 targetNode.appendChild(this.wrap);
35762 this.node.renderIndent(true);
35766 addClass : function(cls){
35768 Roo.fly(this.elNode).addClass(cls);
35772 removeClass : function(cls){
35774 Roo.fly(this.elNode).removeClass(cls);
35778 remove : function(){
35780 this.holder = document.createElement("div");
35781 this.holder.appendChild(this.wrap);
35785 fireEvent : function(){
35786 return this.node.fireEvent.apply(this.node, arguments);
35789 initEvents : function(){
35790 this.node.on("move", this.onMove, this);
35791 var E = Roo.EventManager;
35792 var a = this.anchor;
35794 var el = Roo.fly(a, '_treeui');
35796 if(Roo.isOpera){ // opera render bug ignores the CSS
35797 el.setStyle("text-decoration", "none");
35800 el.on("click", this.onClick, this);
35801 el.on("dblclick", this.onDblClick, this);
35804 Roo.EventManager.on(this.checkbox,
35805 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35808 el.on("contextmenu", this.onContextMenu, this);
35810 var icon = Roo.fly(this.iconNode);
35811 icon.on("click", this.onClick, this);
35812 icon.on("dblclick", this.onDblClick, this);
35813 icon.on("contextmenu", this.onContextMenu, this);
35814 E.on(this.ecNode, "click", this.ecClick, this, true);
35816 if(this.node.disabled){
35817 this.addClass("x-tree-node-disabled");
35819 if(this.node.hidden){
35820 this.addClass("x-tree-node-disabled");
35822 var ot = this.node.getOwnerTree();
35823 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35824 if(dd && (!this.node.isRoot || ot.rootVisible)){
35825 Roo.dd.Registry.register(this.elNode, {
35827 handles: this.getDDHandles(),
35833 getDDHandles : function(){
35834 return [this.iconNode, this.textNode];
35839 this.wrap.style.display = "none";
35845 this.wrap.style.display = "";
35849 onContextMenu : function(e){
35850 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35851 e.preventDefault();
35853 this.fireEvent("contextmenu", this.node, e);
35857 onClick : function(e){
35862 if(this.fireEvent("beforeclick", this.node, e) !== false){
35863 if(!this.disabled && this.node.attributes.href){
35864 this.fireEvent("click", this.node, e);
35867 e.preventDefault();
35872 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35873 this.node.toggle();
35876 this.fireEvent("click", this.node, e);
35882 onDblClick : function(e){
35883 e.preventDefault();
35888 this.toggleCheck();
35890 if(!this.animating && this.node.hasChildNodes()){
35891 this.node.toggle();
35893 this.fireEvent("dblclick", this.node, e);
35896 onCheckChange : function(){
35897 var checked = this.checkbox.checked;
35898 this.node.attributes.checked = checked;
35899 this.fireEvent('checkchange', this.node, checked);
35902 ecClick : function(e){
35903 if(!this.animating && this.node.hasChildNodes()){
35904 this.node.toggle();
35908 startDrop : function(){
35909 this.dropping = true;
35912 // delayed drop so the click event doesn't get fired on a drop
35913 endDrop : function(){
35914 setTimeout(function(){
35915 this.dropping = false;
35916 }.createDelegate(this), 50);
35919 expand : function(){
35920 this.updateExpandIcon();
35921 this.ctNode.style.display = "";
35924 focus : function(){
35925 if(!this.node.preventHScroll){
35926 try{this.anchor.focus();
35928 }else if(!Roo.isIE){
35930 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35931 var l = noscroll.scrollLeft;
35932 this.anchor.focus();
35933 noscroll.scrollLeft = l;
35938 toggleCheck : function(value){
35939 var cb = this.checkbox;
35941 cb.checked = (value === undefined ? !cb.checked : value);
35947 this.anchor.blur();
35951 animExpand : function(callback){
35952 var ct = Roo.get(this.ctNode);
35954 if(!this.node.hasChildNodes()){
35955 this.updateExpandIcon();
35956 this.ctNode.style.display = "";
35957 Roo.callback(callback);
35960 this.animating = true;
35961 this.updateExpandIcon();
35964 callback : function(){
35965 this.animating = false;
35966 Roo.callback(callback);
35969 duration: this.node.ownerTree.duration || .25
35973 highlight : function(){
35974 var tree = this.node.getOwnerTree();
35975 Roo.fly(this.wrap).highlight(
35976 tree.hlColor || "C3DAF9",
35977 {endColor: tree.hlBaseColor}
35981 collapse : function(){
35982 this.updateExpandIcon();
35983 this.ctNode.style.display = "none";
35986 animCollapse : function(callback){
35987 var ct = Roo.get(this.ctNode);
35988 ct.enableDisplayMode('block');
35991 this.animating = true;
35992 this.updateExpandIcon();
35995 callback : function(){
35996 this.animating = false;
35997 Roo.callback(callback);
36000 duration: this.node.ownerTree.duration || .25
36004 getContainer : function(){
36005 return this.ctNode;
36008 getEl : function(){
36012 appendDDGhost : function(ghostNode){
36013 ghostNode.appendChild(this.elNode.cloneNode(true));
36016 getDDRepairXY : function(){
36017 return Roo.lib.Dom.getXY(this.iconNode);
36020 onRender : function(){
36024 render : function(bulkRender){
36025 var n = this.node, a = n.attributes;
36026 var targetNode = n.parentNode ?
36027 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
36029 if(!this.rendered){
36030 this.rendered = true;
36032 this.renderElements(n, a, targetNode, bulkRender);
36035 if(this.textNode.setAttributeNS){
36036 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
36038 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
36041 this.textNode.setAttribute("ext:qtip", a.qtip);
36043 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
36046 }else if(a.qtipCfg){
36047 a.qtipCfg.target = Roo.id(this.textNode);
36048 Roo.QuickTips.register(a.qtipCfg);
36051 if(!this.node.expanded){
36052 this.updateExpandIcon();
36055 if(bulkRender === true) {
36056 targetNode.appendChild(this.wrap);
36061 renderElements : function(n, a, targetNode, bulkRender)
36063 // add some indent caching, this helps performance when rendering a large tree
36064 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36065 var t = n.getOwnerTree();
36066 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36067 if (typeof(n.attributes.html) != 'undefined') {
36068 txt = n.attributes.html;
36070 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36071 var cb = typeof a.checked == 'boolean';
36072 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36073 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36074 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36075 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36076 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
36077 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
36078 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
36079 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
36080 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
36081 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36084 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36085 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36086 n.nextSibling.ui.getEl(), buf.join(""));
36088 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36091 this.elNode = this.wrap.childNodes[0];
36092 this.ctNode = this.wrap.childNodes[1];
36093 var cs = this.elNode.childNodes;
36094 this.indentNode = cs[0];
36095 this.ecNode = cs[1];
36096 this.iconNode = cs[2];
36099 this.checkbox = cs[3];
36102 this.anchor = cs[index];
36103 this.textNode = cs[index].firstChild;
36106 getAnchor : function(){
36107 return this.anchor;
36110 getTextEl : function(){
36111 return this.textNode;
36114 getIconEl : function(){
36115 return this.iconNode;
36118 isChecked : function(){
36119 return this.checkbox ? this.checkbox.checked : false;
36122 updateExpandIcon : function(){
36124 var n = this.node, c1, c2;
36125 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36126 var hasChild = n.hasChildNodes();
36130 c1 = "x-tree-node-collapsed";
36131 c2 = "x-tree-node-expanded";
36134 c1 = "x-tree-node-expanded";
36135 c2 = "x-tree-node-collapsed";
36138 this.removeClass("x-tree-node-leaf");
36139 this.wasLeaf = false;
36141 if(this.c1 != c1 || this.c2 != c2){
36142 Roo.fly(this.elNode).replaceClass(c1, c2);
36143 this.c1 = c1; this.c2 = c2;
36146 // this changes non-leafs into leafs if they have no children.
36147 // it's not very rational behaviour..
36149 if(!this.wasLeaf && this.node.leaf){
36150 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36153 this.wasLeaf = true;
36156 var ecc = "x-tree-ec-icon "+cls;
36157 if(this.ecc != ecc){
36158 this.ecNode.className = ecc;
36164 getChildIndent : function(){
36165 if(!this.childIndent){
36169 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36171 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36173 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36178 this.childIndent = buf.join("");
36180 return this.childIndent;
36183 renderIndent : function(){
36186 var p = this.node.parentNode;
36188 indent = p.ui.getChildIndent();
36190 if(this.indentMarkup != indent){ // don't rerender if not required
36191 this.indentNode.innerHTML = indent;
36192 this.indentMarkup = indent;
36194 this.updateExpandIcon();
36199 Roo.tree.RootTreeNodeUI = function(){
36200 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36202 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36203 render : function(){
36204 if(!this.rendered){
36205 var targetNode = this.node.ownerTree.innerCt.dom;
36206 this.node.expanded = true;
36207 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36208 this.wrap = this.ctNode = targetNode.firstChild;
36211 collapse : function(){
36213 expand : function(){
36217 * Ext JS Library 1.1.1
36218 * Copyright(c) 2006-2007, Ext JS, LLC.
36220 * Originally Released Under LGPL - original licence link has changed is not relivant.
36223 * <script type="text/javascript">
36226 * @class Roo.tree.TreeLoader
36227 * @extends Roo.util.Observable
36228 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36229 * nodes from a specified URL. The response must be a javascript Array definition
36230 * who's elements are node definition objects. eg:
36235 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36236 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36243 * The old style respose with just an array is still supported, but not recommended.
36246 * A server request is sent, and child nodes are loaded only when a node is expanded.
36247 * The loading node's id is passed to the server under the parameter name "node" to
36248 * enable the server to produce the correct child nodes.
36250 * To pass extra parameters, an event handler may be attached to the "beforeload"
36251 * event, and the parameters specified in the TreeLoader's baseParams property:
36253 myTreeLoader.on("beforeload", function(treeLoader, node) {
36254 this.baseParams.category = node.attributes.category;
36259 * This would pass an HTTP parameter called "category" to the server containing
36260 * the value of the Node's "category" attribute.
36262 * Creates a new Treeloader.
36263 * @param {Object} config A config object containing config properties.
36265 Roo.tree.TreeLoader = function(config){
36266 this.baseParams = {};
36267 this.requestMethod = "POST";
36268 Roo.apply(this, config);
36273 * @event beforeload
36274 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36275 * @param {Object} This TreeLoader object.
36276 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36277 * @param {Object} callback The callback function specified in the {@link #load} call.
36282 * Fires when the node has been successfuly loaded.
36283 * @param {Object} This TreeLoader object.
36284 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36285 * @param {Object} response The response object containing the data from the server.
36289 * @event loadexception
36290 * Fires if the network request failed.
36291 * @param {Object} This TreeLoader object.
36292 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36293 * @param {Object} response The response object containing the data from the server.
36295 loadexception : true,
36298 * Fires before a node is created, enabling you to return custom Node types
36299 * @param {Object} This TreeLoader object.
36300 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36305 Roo.tree.TreeLoader.superclass.constructor.call(this);
36308 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36310 * @cfg {String} dataUrl The URL from which to request a Json string which
36311 * specifies an array of node definition object representing the child nodes
36315 * @cfg {String} requestMethod either GET or POST
36316 * defaults to POST (due to BC)
36320 * @cfg {Object} baseParams (optional) An object containing properties which
36321 * specify HTTP parameters to be passed to each request for child nodes.
36324 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36325 * created by this loader. If the attributes sent by the server have an attribute in this object,
36326 * they take priority.
36329 * @cfg {Object} uiProviders (optional) An object containing properties which
36331 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36332 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36333 * <i>uiProvider</i> attribute of a returned child node is a string rather
36334 * than a reference to a TreeNodeUI implementation, this that string value
36335 * is used as a property name in the uiProviders object. You can define the provider named
36336 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36341 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36342 * child nodes before loading.
36344 clearOnLoad : true,
36347 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36348 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36349 * Grid query { data : [ .....] }
36354 * @cfg {String} queryParam (optional)
36355 * Name of the query as it will be passed on the querystring (defaults to 'node')
36356 * eg. the request will be ?node=[id]
36363 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36364 * This is called automatically when a node is expanded, but may be used to reload
36365 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36366 * @param {Roo.tree.TreeNode} node
36367 * @param {Function} callback
36369 load : function(node, callback){
36370 if(this.clearOnLoad){
36371 while(node.firstChild){
36372 node.removeChild(node.firstChild);
36375 if(node.attributes.children){ // preloaded json children
36376 var cs = node.attributes.children;
36377 for(var i = 0, len = cs.length; i < len; i++){
36378 node.appendChild(this.createNode(cs[i]));
36380 if(typeof callback == "function"){
36383 }else if(this.dataUrl){
36384 this.requestData(node, callback);
36388 getParams: function(node){
36389 var buf = [], bp = this.baseParams;
36390 for(var key in bp){
36391 if(typeof bp[key] != "function"){
36392 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36395 var n = this.queryParam === false ? 'node' : this.queryParam;
36396 buf.push(n + "=", encodeURIComponent(node.id));
36397 return buf.join("");
36400 requestData : function(node, callback){
36401 if(this.fireEvent("beforeload", this, node, callback) !== false){
36402 this.transId = Roo.Ajax.request({
36403 method:this.requestMethod,
36404 url: this.dataUrl||this.url,
36405 success: this.handleResponse,
36406 failure: this.handleFailure,
36408 argument: {callback: callback, node: node},
36409 params: this.getParams(node)
36412 // if the load is cancelled, make sure we notify
36413 // the node that we are done
36414 if(typeof callback == "function"){
36420 isLoading : function(){
36421 return this.transId ? true : false;
36424 abort : function(){
36425 if(this.isLoading()){
36426 Roo.Ajax.abort(this.transId);
36431 createNode : function(attr)
36433 // apply baseAttrs, nice idea Corey!
36434 if(this.baseAttrs){
36435 Roo.applyIf(attr, this.baseAttrs);
36437 if(this.applyLoader !== false){
36438 attr.loader = this;
36440 // uiProvider = depreciated..
36442 if(typeof(attr.uiProvider) == 'string'){
36443 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36444 /** eval:var:attr */ eval(attr.uiProvider);
36446 if(typeof(this.uiProviders['default']) != 'undefined') {
36447 attr.uiProvider = this.uiProviders['default'];
36450 this.fireEvent('create', this, attr);
36452 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36454 new Roo.tree.TreeNode(attr) :
36455 new Roo.tree.AsyncTreeNode(attr));
36458 processResponse : function(response, node, callback)
36460 var json = response.responseText;
36463 var o = Roo.decode(json);
36465 if (this.root === false && typeof(o.success) != undefined) {
36466 this.root = 'data'; // the default behaviour for list like data..
36469 if (this.root !== false && !o.success) {
36470 // it's a failure condition.
36471 var a = response.argument;
36472 this.fireEvent("loadexception", this, a.node, response);
36473 Roo.log("Load failed - should have a handler really");
36479 if (this.root !== false) {
36483 for(var i = 0, len = o.length; i < len; i++){
36484 var n = this.createNode(o[i]);
36486 node.appendChild(n);
36489 if(typeof callback == "function"){
36490 callback(this, node);
36493 this.handleFailure(response);
36497 handleResponse : function(response){
36498 this.transId = false;
36499 var a = response.argument;
36500 this.processResponse(response, a.node, a.callback);
36501 this.fireEvent("load", this, a.node, response);
36504 handleFailure : function(response)
36506 // should handle failure better..
36507 this.transId = false;
36508 var a = response.argument;
36509 this.fireEvent("loadexception", this, a.node, response);
36510 if(typeof a.callback == "function"){
36511 a.callback(this, a.node);
36516 * Ext JS Library 1.1.1
36517 * Copyright(c) 2006-2007, Ext JS, LLC.
36519 * Originally Released Under LGPL - original licence link has changed is not relivant.
36522 * <script type="text/javascript">
36526 * @class Roo.tree.TreeFilter
36527 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36528 * @param {TreePanel} tree
36529 * @param {Object} config (optional)
36531 Roo.tree.TreeFilter = function(tree, config){
36533 this.filtered = {};
36534 Roo.apply(this, config);
36537 Roo.tree.TreeFilter.prototype = {
36544 * Filter the data by a specific attribute.
36545 * @param {String/RegExp} value Either string that the attribute value
36546 * should start with or a RegExp to test against the attribute
36547 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36548 * @param {TreeNode} startNode (optional) The node to start the filter at.
36550 filter : function(value, attr, startNode){
36551 attr = attr || "text";
36553 if(typeof value == "string"){
36554 var vlen = value.length;
36555 // auto clear empty filter
36556 if(vlen == 0 && this.clearBlank){
36560 value = value.toLowerCase();
36562 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36564 }else if(value.exec){ // regex?
36566 return value.test(n.attributes[attr]);
36569 throw 'Illegal filter type, must be string or regex';
36571 this.filterBy(f, null, startNode);
36575 * Filter by a function. The passed function will be called with each
36576 * node in the tree (or from the startNode). If the function returns true, the node is kept
36577 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36578 * @param {Function} fn The filter function
36579 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36581 filterBy : function(fn, scope, startNode){
36582 startNode = startNode || this.tree.root;
36583 if(this.autoClear){
36586 var af = this.filtered, rv = this.reverse;
36587 var f = function(n){
36588 if(n == startNode){
36594 var m = fn.call(scope || n, n);
36602 startNode.cascade(f);
36605 if(typeof id != "function"){
36607 if(n && n.parentNode){
36608 n.parentNode.removeChild(n);
36616 * Clears the current filter. Note: with the "remove" option
36617 * set a filter cannot be cleared.
36619 clear : function(){
36621 var af = this.filtered;
36623 if(typeof id != "function"){
36630 this.filtered = {};
36635 * Ext JS Library 1.1.1
36636 * Copyright(c) 2006-2007, Ext JS, LLC.
36638 * Originally Released Under LGPL - original licence link has changed is not relivant.
36641 * <script type="text/javascript">
36646 * @class Roo.tree.TreeSorter
36647 * Provides sorting of nodes in a TreePanel
36649 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36650 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36651 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36652 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36653 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36654 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36656 * @param {TreePanel} tree
36657 * @param {Object} config
36659 Roo.tree.TreeSorter = function(tree, config){
36660 Roo.apply(this, config);
36661 tree.on("beforechildrenrendered", this.doSort, this);
36662 tree.on("append", this.updateSort, this);
36663 tree.on("insert", this.updateSort, this);
36665 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36666 var p = this.property || "text";
36667 var sortType = this.sortType;
36668 var fs = this.folderSort;
36669 var cs = this.caseSensitive === true;
36670 var leafAttr = this.leafAttr || 'leaf';
36672 this.sortFn = function(n1, n2){
36674 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36677 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36681 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36682 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36684 return dsc ? +1 : -1;
36686 return dsc ? -1 : +1;
36693 Roo.tree.TreeSorter.prototype = {
36694 doSort : function(node){
36695 node.sort(this.sortFn);
36698 compareNodes : function(n1, n2){
36699 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36702 updateSort : function(tree, node){
36703 if(node.childrenRendered){
36704 this.doSort.defer(1, this, [node]);
36709 * Ext JS Library 1.1.1
36710 * Copyright(c) 2006-2007, Ext JS, LLC.
36712 * Originally Released Under LGPL - original licence link has changed is not relivant.
36715 * <script type="text/javascript">
36718 if(Roo.dd.DropZone){
36720 Roo.tree.TreeDropZone = function(tree, config){
36721 this.allowParentInsert = false;
36722 this.allowContainerDrop = false;
36723 this.appendOnly = false;
36724 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36726 this.lastInsertClass = "x-tree-no-status";
36727 this.dragOverData = {};
36730 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36731 ddGroup : "TreeDD",
36734 expandDelay : 1000,
36736 expandNode : function(node){
36737 if(node.hasChildNodes() && !node.isExpanded()){
36738 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36742 queueExpand : function(node){
36743 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36746 cancelExpand : function(){
36747 if(this.expandProcId){
36748 clearTimeout(this.expandProcId);
36749 this.expandProcId = false;
36753 isValidDropPoint : function(n, pt, dd, e, data){
36754 if(!n || !data){ return false; }
36755 var targetNode = n.node;
36756 var dropNode = data.node;
36757 // default drop rules
36758 if(!(targetNode && targetNode.isTarget && pt)){
36761 if(pt == "append" && targetNode.allowChildren === false){
36764 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36767 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36770 // reuse the object
36771 var overEvent = this.dragOverData;
36772 overEvent.tree = this.tree;
36773 overEvent.target = targetNode;
36774 overEvent.data = data;
36775 overEvent.point = pt;
36776 overEvent.source = dd;
36777 overEvent.rawEvent = e;
36778 overEvent.dropNode = dropNode;
36779 overEvent.cancel = false;
36780 var result = this.tree.fireEvent("nodedragover", overEvent);
36781 return overEvent.cancel === false && result !== false;
36784 getDropPoint : function(e, n, dd)
36788 return tn.allowChildren !== false ? "append" : false; // always append for root
36790 var dragEl = n.ddel;
36791 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36792 var y = Roo.lib.Event.getPageY(e);
36793 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36795 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36796 var noAppend = tn.allowChildren === false;
36797 if(this.appendOnly || tn.parentNode.allowChildren === false){
36798 return noAppend ? false : "append";
36800 var noBelow = false;
36801 if(!this.allowParentInsert){
36802 noBelow = tn.hasChildNodes() && tn.isExpanded();
36804 var q = (b - t) / (noAppend ? 2 : 3);
36805 if(y >= t && y < (t + q)){
36807 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36814 onNodeEnter : function(n, dd, e, data)
36816 this.cancelExpand();
36819 onNodeOver : function(n, dd, e, data)
36822 var pt = this.getDropPoint(e, n, dd);
36825 // auto node expand check
36826 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36827 this.queueExpand(node);
36828 }else if(pt != "append"){
36829 this.cancelExpand();
36832 // set the insert point style on the target node
36833 var returnCls = this.dropNotAllowed;
36834 if(this.isValidDropPoint(n, pt, dd, e, data)){
36839 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36840 cls = "x-tree-drag-insert-above";
36841 }else if(pt == "below"){
36842 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36843 cls = "x-tree-drag-insert-below";
36845 returnCls = "x-tree-drop-ok-append";
36846 cls = "x-tree-drag-append";
36848 if(this.lastInsertClass != cls){
36849 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36850 this.lastInsertClass = cls;
36857 onNodeOut : function(n, dd, e, data){
36859 this.cancelExpand();
36860 this.removeDropIndicators(n);
36863 onNodeDrop : function(n, dd, e, data){
36864 var point = this.getDropPoint(e, n, dd);
36865 var targetNode = n.node;
36866 targetNode.ui.startDrop();
36867 if(!this.isValidDropPoint(n, point, dd, e, data)){
36868 targetNode.ui.endDrop();
36871 // first try to find the drop node
36872 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36875 target: targetNode,
36880 dropNode: dropNode,
36883 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36884 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36885 targetNode.ui.endDrop();
36888 // allow target changing
36889 targetNode = dropEvent.target;
36890 if(point == "append" && !targetNode.isExpanded()){
36891 targetNode.expand(false, null, function(){
36892 this.completeDrop(dropEvent);
36893 }.createDelegate(this));
36895 this.completeDrop(dropEvent);
36900 completeDrop : function(de){
36901 var ns = de.dropNode, p = de.point, t = de.target;
36902 if(!(ns instanceof Array)){
36906 for(var i = 0, len = ns.length; i < len; i++){
36909 t.parentNode.insertBefore(n, t);
36910 }else if(p == "below"){
36911 t.parentNode.insertBefore(n, t.nextSibling);
36917 if(this.tree.hlDrop){
36921 this.tree.fireEvent("nodedrop", de);
36924 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36925 if(this.tree.hlDrop){
36926 dropNode.ui.focus();
36927 dropNode.ui.highlight();
36929 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36932 getTree : function(){
36936 removeDropIndicators : function(n){
36939 Roo.fly(el).removeClass([
36940 "x-tree-drag-insert-above",
36941 "x-tree-drag-insert-below",
36942 "x-tree-drag-append"]);
36943 this.lastInsertClass = "_noclass";
36947 beforeDragDrop : function(target, e, id){
36948 this.cancelExpand();
36952 afterRepair : function(data){
36953 if(data && Roo.enableFx){
36954 data.node.ui.highlight();
36964 * Ext JS Library 1.1.1
36965 * Copyright(c) 2006-2007, Ext JS, LLC.
36967 * Originally Released Under LGPL - original licence link has changed is not relivant.
36970 * <script type="text/javascript">
36974 if(Roo.dd.DragZone){
36975 Roo.tree.TreeDragZone = function(tree, config){
36976 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36980 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36981 ddGroup : "TreeDD",
36983 onBeforeDrag : function(data, e){
36985 return n && n.draggable && !n.disabled;
36989 onInitDrag : function(e){
36990 var data = this.dragData;
36991 this.tree.getSelectionModel().select(data.node);
36992 this.proxy.update("");
36993 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36994 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36997 getRepairXY : function(e, data){
36998 return data.node.ui.getDDRepairXY();
37001 onEndDrag : function(data, e){
37002 this.tree.fireEvent("enddrag", this.tree, data.node, e);
37007 onValidDrop : function(dd, e, id){
37008 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
37012 beforeInvalidDrop : function(e, id){
37013 // this scrolls the original position back into view
37014 var sm = this.tree.getSelectionModel();
37015 sm.clearSelections();
37016 sm.select(this.dragData.node);
37021 * Ext JS Library 1.1.1
37022 * Copyright(c) 2006-2007, Ext JS, LLC.
37024 * Originally Released Under LGPL - original licence link has changed is not relivant.
37027 * <script type="text/javascript">
37030 * @class Roo.tree.TreeEditor
37031 * @extends Roo.Editor
37032 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
37033 * as the editor field.
37035 * @param {Object} config (used to be the tree panel.)
37036 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
37038 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
37039 * @cfg {Roo.form.TextField|Object} field The field configuration
37043 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
37046 if (oldconfig) { // old style..
37047 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
37050 tree = config.tree;
37051 config.field = config.field || {};
37052 config.field.xtype = 'TextField';
37053 field = Roo.factory(config.field, Roo.form);
37055 config = config || {};
37060 * @event beforenodeedit
37061 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37062 * false from the handler of this event.
37063 * @param {Editor} this
37064 * @param {Roo.tree.Node} node
37066 "beforenodeedit" : true
37070 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37074 tree.on('beforeclick', this.beforeNodeClick, this);
37075 tree.getTreeEl().on('mousedown', this.hide, this);
37076 this.on('complete', this.updateNode, this);
37077 this.on('beforestartedit', this.fitToTree, this);
37078 this.on('startedit', this.bindScroll, this, {delay:10});
37079 this.on('specialkey', this.onSpecialKey, this);
37082 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
37084 * @cfg {String} alignment
37085 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37091 * @cfg {Boolean} hideEl
37092 * True to hide the bound element while the editor is displayed (defaults to false)
37096 * @cfg {String} cls
37097 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37099 cls: "x-small-editor x-tree-editor",
37101 * @cfg {Boolean} shim
37102 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37108 * @cfg {Number} maxWidth
37109 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37110 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37111 * scroll and client offsets into account prior to each edit.
37118 fitToTree : function(ed, el){
37119 var td = this.tree.getTreeEl().dom, nd = el.dom;
37120 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37121 td.scrollLeft = nd.offsetLeft;
37125 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37126 this.setSize(w, '');
37128 return this.fireEvent('beforenodeedit', this, this.editNode);
37133 triggerEdit : function(node){
37134 this.completeEdit();
37135 this.editNode = node;
37136 this.startEdit(node.ui.textNode, node.text);
37140 bindScroll : function(){
37141 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37145 beforeNodeClick : function(node, e){
37146 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37147 this.lastClick = new Date();
37148 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37150 this.triggerEdit(node);
37157 updateNode : function(ed, value){
37158 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37159 this.editNode.setText(value);
37163 onHide : function(){
37164 Roo.tree.TreeEditor.superclass.onHide.call(this);
37166 this.editNode.ui.focus();
37171 onSpecialKey : function(field, e){
37172 var k = e.getKey();
37176 }else if(k == e.ENTER && !e.hasModifier()){
37178 this.completeEdit();
37181 });//<Script type="text/javascript">
37184 * Ext JS Library 1.1.1
37185 * Copyright(c) 2006-2007, Ext JS, LLC.
37187 * Originally Released Under LGPL - original licence link has changed is not relivant.
37190 * <script type="text/javascript">
37194 * Not documented??? - probably should be...
37197 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37198 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37200 renderElements : function(n, a, targetNode, bulkRender){
37201 //consel.log("renderElements?");
37202 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37204 var t = n.getOwnerTree();
37205 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37207 var cols = t.columns;
37208 var bw = t.borderWidth;
37210 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37211 var cb = typeof a.checked == "boolean";
37212 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37213 var colcls = 'x-t-' + tid + '-c0';
37215 '<li class="x-tree-node">',
37218 '<div class="x-tree-node-el ', a.cls,'">',
37220 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37223 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37224 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37225 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37226 (a.icon ? ' x-tree-node-inline-icon' : ''),
37227 (a.iconCls ? ' '+a.iconCls : ''),
37228 '" unselectable="on" />',
37229 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37230 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37232 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37233 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37234 '<span unselectable="on" qtip="' + tx + '">',
37238 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37239 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37241 for(var i = 1, len = cols.length; i < len; i++){
37243 colcls = 'x-t-' + tid + '-c' +i;
37244 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37245 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37246 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37252 '<div class="x-clear"></div></div>',
37253 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37256 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37257 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37258 n.nextSibling.ui.getEl(), buf.join(""));
37260 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37262 var el = this.wrap.firstChild;
37264 this.elNode = el.firstChild;
37265 this.ranchor = el.childNodes[1];
37266 this.ctNode = this.wrap.childNodes[1];
37267 var cs = el.firstChild.childNodes;
37268 this.indentNode = cs[0];
37269 this.ecNode = cs[1];
37270 this.iconNode = cs[2];
37273 this.checkbox = cs[3];
37276 this.anchor = cs[index];
37278 this.textNode = cs[index].firstChild;
37280 //el.on("click", this.onClick, this);
37281 //el.on("dblclick", this.onDblClick, this);
37284 // console.log(this);
37286 initEvents : function(){
37287 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37290 var a = this.ranchor;
37292 var el = Roo.get(a);
37294 if(Roo.isOpera){ // opera render bug ignores the CSS
37295 el.setStyle("text-decoration", "none");
37298 el.on("click", this.onClick, this);
37299 el.on("dblclick", this.onDblClick, this);
37300 el.on("contextmenu", this.onContextMenu, this);
37304 /*onSelectedChange : function(state){
37307 this.addClass("x-tree-selected");
37310 this.removeClass("x-tree-selected");
37313 addClass : function(cls){
37315 Roo.fly(this.elRow).addClass(cls);
37321 removeClass : function(cls){
37323 Roo.fly(this.elRow).removeClass(cls);
37329 });//<Script type="text/javascript">
37333 * Ext JS Library 1.1.1
37334 * Copyright(c) 2006-2007, Ext JS, LLC.
37336 * Originally Released Under LGPL - original licence link has changed is not relivant.
37339 * <script type="text/javascript">
37344 * @class Roo.tree.ColumnTree
37345 * @extends Roo.data.TreePanel
37346 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37347 * @cfg {int} borderWidth compined right/left border allowance
37349 * @param {String/HTMLElement/Element} el The container element
37350 * @param {Object} config
37352 Roo.tree.ColumnTree = function(el, config)
37354 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37358 * Fire this event on a container when it resizes
37359 * @param {int} w Width
37360 * @param {int} h Height
37364 this.on('resize', this.onResize, this);
37367 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37371 borderWidth: Roo.isBorderBox ? 0 : 2,
37374 render : function(){
37375 // add the header.....
37377 Roo.tree.ColumnTree.superclass.render.apply(this);
37379 this.el.addClass('x-column-tree');
37381 this.headers = this.el.createChild(
37382 {cls:'x-tree-headers'},this.innerCt.dom);
37384 var cols = this.columns, c;
37385 var totalWidth = 0;
37387 var len = cols.length;
37388 for(var i = 0; i < len; i++){
37390 totalWidth += c.width;
37391 this.headEls.push(this.headers.createChild({
37392 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37394 cls:'x-tree-hd-text',
37397 style:'width:'+(c.width-this.borderWidth)+'px;'
37400 this.headers.createChild({cls:'x-clear'});
37401 // prevent floats from wrapping when clipped
37402 this.headers.setWidth(totalWidth);
37403 //this.innerCt.setWidth(totalWidth);
37404 this.innerCt.setStyle({ overflow: 'auto' });
37405 this.onResize(this.width, this.height);
37409 onResize : function(w,h)
37414 this.innerCt.setWidth(this.width);
37415 this.innerCt.setHeight(this.height-20);
37418 var cols = this.columns, c;
37419 var totalWidth = 0;
37421 var len = cols.length;
37422 for(var i = 0; i < len; i++){
37424 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37425 // it's the expander..
37426 expEl = this.headEls[i];
37429 totalWidth += c.width;
37433 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37435 this.headers.setWidth(w-20);
37444 * Ext JS Library 1.1.1
37445 * Copyright(c) 2006-2007, Ext JS, LLC.
37447 * Originally Released Under LGPL - original licence link has changed is not relivant.
37450 * <script type="text/javascript">
37454 * @class Roo.menu.Menu
37455 * @extends Roo.util.Observable
37456 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37457 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37459 * Creates a new Menu
37460 * @param {Object} config Configuration options
37462 Roo.menu.Menu = function(config){
37464 Roo.menu.Menu.superclass.constructor.call(this, config);
37466 this.id = this.id || Roo.id();
37469 * @event beforeshow
37470 * Fires before this menu is displayed
37471 * @param {Roo.menu.Menu} this
37475 * @event beforehide
37476 * Fires before this menu is hidden
37477 * @param {Roo.menu.Menu} this
37482 * Fires after this menu is displayed
37483 * @param {Roo.menu.Menu} this
37488 * Fires after this menu is hidden
37489 * @param {Roo.menu.Menu} this
37494 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37495 * @param {Roo.menu.Menu} this
37496 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37497 * @param {Roo.EventObject} e
37502 * Fires when the mouse is hovering over this menu
37503 * @param {Roo.menu.Menu} this
37504 * @param {Roo.EventObject} e
37505 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37510 * Fires when the mouse exits this menu
37511 * @param {Roo.menu.Menu} this
37512 * @param {Roo.EventObject} e
37513 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37518 * Fires when a menu item contained in this menu is clicked
37519 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37520 * @param {Roo.EventObject} e
37524 if (this.registerMenu) {
37525 Roo.menu.MenuMgr.register(this);
37528 var mis = this.items;
37529 this.items = new Roo.util.MixedCollection();
37531 this.add.apply(this, mis);
37535 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37537 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37541 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37542 * for bottom-right shadow (defaults to "sides")
37546 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37547 * this menu (defaults to "tl-tr?")
37549 subMenuAlign : "tl-tr?",
37551 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37552 * relative to its element of origin (defaults to "tl-bl?")
37554 defaultAlign : "tl-bl?",
37556 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37558 allowOtherMenus : false,
37560 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37562 registerMenu : true,
37567 render : function(){
37571 var el = this.el = new Roo.Layer({
37573 shadow:this.shadow,
37575 parentEl: this.parentEl || document.body,
37579 this.keyNav = new Roo.menu.MenuNav(this);
37582 el.addClass("x-menu-plain");
37585 el.addClass(this.cls);
37587 // generic focus element
37588 this.focusEl = el.createChild({
37589 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37591 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37592 //disabling touch- as it's causing issues ..
37593 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37594 ul.on('click' , this.onClick, this);
37597 ul.on("mouseover", this.onMouseOver, this);
37598 ul.on("mouseout", this.onMouseOut, this);
37599 this.items.each(function(item){
37604 var li = document.createElement("li");
37605 li.className = "x-menu-list-item";
37606 ul.dom.appendChild(li);
37607 item.render(li, this);
37614 autoWidth : function(){
37615 var el = this.el, ul = this.ul;
37619 var w = this.width;
37622 }else if(Roo.isIE){
37623 el.setWidth(this.minWidth);
37624 var t = el.dom.offsetWidth; // force recalc
37625 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37630 delayAutoWidth : function(){
37633 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37635 this.awTask.delay(20);
37640 findTargetItem : function(e){
37641 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37642 if(t && t.menuItemId){
37643 return this.items.get(t.menuItemId);
37648 onClick : function(e){
37649 Roo.log("menu.onClick");
37650 var t = this.findTargetItem(e);
37655 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37656 if(t == this.activeItem && t.shouldDeactivate(e)){
37657 this.activeItem.deactivate();
37658 delete this.activeItem;
37662 this.setActiveItem(t, true);
37670 this.fireEvent("click", this, t, e);
37674 setActiveItem : function(item, autoExpand){
37675 if(item != this.activeItem){
37676 if(this.activeItem){
37677 this.activeItem.deactivate();
37679 this.activeItem = item;
37680 item.activate(autoExpand);
37681 }else if(autoExpand){
37687 tryActivate : function(start, step){
37688 var items = this.items;
37689 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37690 var item = items.get(i);
37691 if(!item.disabled && item.canActivate){
37692 this.setActiveItem(item, false);
37700 onMouseOver : function(e){
37702 if(t = this.findTargetItem(e)){
37703 if(t.canActivate && !t.disabled){
37704 this.setActiveItem(t, true);
37707 this.fireEvent("mouseover", this, e, t);
37711 onMouseOut : function(e){
37713 if(t = this.findTargetItem(e)){
37714 if(t == this.activeItem && t.shouldDeactivate(e)){
37715 this.activeItem.deactivate();
37716 delete this.activeItem;
37719 this.fireEvent("mouseout", this, e, t);
37723 * Read-only. Returns true if the menu is currently displayed, else false.
37726 isVisible : function(){
37727 return this.el && !this.hidden;
37731 * Displays this menu relative to another element
37732 * @param {String/HTMLElement/Roo.Element} element The element to align to
37733 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37734 * the element (defaults to this.defaultAlign)
37735 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37737 show : function(el, pos, parentMenu){
37738 this.parentMenu = parentMenu;
37742 this.fireEvent("beforeshow", this);
37743 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37747 * Displays this menu at a specific xy position
37748 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37749 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37751 showAt : function(xy, parentMenu, /* private: */_e){
37752 this.parentMenu = parentMenu;
37757 this.fireEvent("beforeshow", this);
37758 xy = this.el.adjustForConstraints(xy);
37762 this.hidden = false;
37764 this.fireEvent("show", this);
37767 focus : function(){
37769 this.doFocus.defer(50, this);
37773 doFocus : function(){
37775 this.focusEl.focus();
37780 * Hides this menu and optionally all parent menus
37781 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37783 hide : function(deep){
37784 if(this.el && this.isVisible()){
37785 this.fireEvent("beforehide", this);
37786 if(this.activeItem){
37787 this.activeItem.deactivate();
37788 this.activeItem = null;
37791 this.hidden = true;
37792 this.fireEvent("hide", this);
37794 if(deep === true && this.parentMenu){
37795 this.parentMenu.hide(true);
37800 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37801 * Any of the following are valid:
37803 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37804 * <li>An HTMLElement object which will be converted to a menu item</li>
37805 * <li>A menu item config object that will be created as a new menu item</li>
37806 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37807 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37812 var menu = new Roo.menu.Menu();
37814 // Create a menu item to add by reference
37815 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37817 // Add a bunch of items at once using different methods.
37818 // Only the last item added will be returned.
37819 var item = menu.add(
37820 menuItem, // add existing item by ref
37821 'Dynamic Item', // new TextItem
37822 '-', // new separator
37823 { text: 'Config Item' } // new item by config
37826 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37827 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37830 var a = arguments, l = a.length, item;
37831 for(var i = 0; i < l; i++){
37833 if ((typeof(el) == "object") && el.xtype && el.xns) {
37834 el = Roo.factory(el, Roo.menu);
37837 if(el.render){ // some kind of Item
37838 item = this.addItem(el);
37839 }else if(typeof el == "string"){ // string
37840 if(el == "separator" || el == "-"){
37841 item = this.addSeparator();
37843 item = this.addText(el);
37845 }else if(el.tagName || el.el){ // element
37846 item = this.addElement(el);
37847 }else if(typeof el == "object"){ // must be menu item config?
37848 item = this.addMenuItem(el);
37855 * Returns this menu's underlying {@link Roo.Element} object
37856 * @return {Roo.Element} The element
37858 getEl : function(){
37866 * Adds a separator bar to the menu
37867 * @return {Roo.menu.Item} The menu item that was added
37869 addSeparator : function(){
37870 return this.addItem(new Roo.menu.Separator());
37874 * Adds an {@link Roo.Element} object to the menu
37875 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37876 * @return {Roo.menu.Item} The menu item that was added
37878 addElement : function(el){
37879 return this.addItem(new Roo.menu.BaseItem(el));
37883 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37884 * @param {Roo.menu.Item} item The menu item to add
37885 * @return {Roo.menu.Item} The menu item that was added
37887 addItem : function(item){
37888 this.items.add(item);
37890 var li = document.createElement("li");
37891 li.className = "x-menu-list-item";
37892 this.ul.dom.appendChild(li);
37893 item.render(li, this);
37894 this.delayAutoWidth();
37900 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37901 * @param {Object} config A MenuItem config object
37902 * @return {Roo.menu.Item} The menu item that was added
37904 addMenuItem : function(config){
37905 if(!(config instanceof Roo.menu.Item)){
37906 if(typeof config.checked == "boolean"){ // must be check menu item config?
37907 config = new Roo.menu.CheckItem(config);
37909 config = new Roo.menu.Item(config);
37912 return this.addItem(config);
37916 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37917 * @param {String} text The text to display in the menu item
37918 * @return {Roo.menu.Item} The menu item that was added
37920 addText : function(text){
37921 return this.addItem(new Roo.menu.TextItem({ text : text }));
37925 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37926 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37927 * @param {Roo.menu.Item} item The menu item to add
37928 * @return {Roo.menu.Item} The menu item that was added
37930 insert : function(index, item){
37931 this.items.insert(index, item);
37933 var li = document.createElement("li");
37934 li.className = "x-menu-list-item";
37935 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37936 item.render(li, this);
37937 this.delayAutoWidth();
37943 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37944 * @param {Roo.menu.Item} item The menu item to remove
37946 remove : function(item){
37947 this.items.removeKey(item.id);
37952 * Removes and destroys all items in the menu
37954 removeAll : function(){
37956 while(f = this.items.first()){
37962 // MenuNav is a private utility class used internally by the Menu
37963 Roo.menu.MenuNav = function(menu){
37964 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37965 this.scope = this.menu = menu;
37968 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37969 doRelay : function(e, h){
37970 var k = e.getKey();
37971 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37972 this.menu.tryActivate(0, 1);
37975 return h.call(this.scope || this, e, this.menu);
37978 up : function(e, m){
37979 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37980 m.tryActivate(m.items.length-1, -1);
37984 down : function(e, m){
37985 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37986 m.tryActivate(0, 1);
37990 right : function(e, m){
37992 m.activeItem.expandMenu(true);
37996 left : function(e, m){
37998 if(m.parentMenu && m.parentMenu.activeItem){
37999 m.parentMenu.activeItem.activate();
38003 enter : function(e, m){
38005 e.stopPropagation();
38006 m.activeItem.onClick(e);
38007 m.fireEvent("click", this, m.activeItem);
38013 * Ext JS Library 1.1.1
38014 * Copyright(c) 2006-2007, Ext JS, LLC.
38016 * Originally Released Under LGPL - original licence link has changed is not relivant.
38019 * <script type="text/javascript">
38023 * @class Roo.menu.MenuMgr
38024 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
38027 Roo.menu.MenuMgr = function(){
38028 var menus, active, groups = {}, attached = false, lastShow = new Date();
38030 // private - called when first menu is created
38033 active = new Roo.util.MixedCollection();
38034 Roo.get(document).addKeyListener(27, function(){
38035 if(active.length > 0){
38042 function hideAll(){
38043 if(active && active.length > 0){
38044 var c = active.clone();
38045 c.each(function(m){
38052 function onHide(m){
38054 if(active.length < 1){
38055 Roo.get(document).un("mousedown", onMouseDown);
38061 function onShow(m){
38062 var last = active.last();
38063 lastShow = new Date();
38066 Roo.get(document).on("mousedown", onMouseDown);
38070 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38071 m.parentMenu.activeChild = m;
38072 }else if(last && last.isVisible()){
38073 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
38078 function onBeforeHide(m){
38080 m.activeChild.hide();
38082 if(m.autoHideTimer){
38083 clearTimeout(m.autoHideTimer);
38084 delete m.autoHideTimer;
38089 function onBeforeShow(m){
38090 var pm = m.parentMenu;
38091 if(!pm && !m.allowOtherMenus){
38093 }else if(pm && pm.activeChild && active != m){
38094 pm.activeChild.hide();
38099 function onMouseDown(e){
38100 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38106 function onBeforeCheck(mi, state){
38108 var g = groups[mi.group];
38109 for(var i = 0, l = g.length; i < l; i++){
38111 g[i].setChecked(false);
38120 * Hides all menus that are currently visible
38122 hideAll : function(){
38127 register : function(menu){
38131 menus[menu.id] = menu;
38132 menu.on("beforehide", onBeforeHide);
38133 menu.on("hide", onHide);
38134 menu.on("beforeshow", onBeforeShow);
38135 menu.on("show", onShow);
38136 var g = menu.group;
38137 if(g && menu.events["checkchange"]){
38141 groups[g].push(menu);
38142 menu.on("checkchange", onCheck);
38147 * Returns a {@link Roo.menu.Menu} object
38148 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38149 * be used to generate and return a new Menu instance.
38151 get : function(menu){
38152 if(typeof menu == "string"){ // menu id
38153 return menus[menu];
38154 }else if(menu.events){ // menu instance
38156 }else if(typeof menu.length == 'number'){ // array of menu items?
38157 return new Roo.menu.Menu({items:menu});
38158 }else{ // otherwise, must be a config
38159 return new Roo.menu.Menu(menu);
38164 unregister : function(menu){
38165 delete menus[menu.id];
38166 menu.un("beforehide", onBeforeHide);
38167 menu.un("hide", onHide);
38168 menu.un("beforeshow", onBeforeShow);
38169 menu.un("show", onShow);
38170 var g = menu.group;
38171 if(g && menu.events["checkchange"]){
38172 groups[g].remove(menu);
38173 menu.un("checkchange", onCheck);
38178 registerCheckable : function(menuItem){
38179 var g = menuItem.group;
38184 groups[g].push(menuItem);
38185 menuItem.on("beforecheckchange", onBeforeCheck);
38190 unregisterCheckable : function(menuItem){
38191 var g = menuItem.group;
38193 groups[g].remove(menuItem);
38194 menuItem.un("beforecheckchange", onBeforeCheck);
38200 * Ext JS Library 1.1.1
38201 * Copyright(c) 2006-2007, Ext JS, LLC.
38203 * Originally Released Under LGPL - original licence link has changed is not relivant.
38206 * <script type="text/javascript">
38211 * @class Roo.menu.BaseItem
38212 * @extends Roo.Component
38213 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38214 * management and base configuration options shared by all menu components.
38216 * Creates a new BaseItem
38217 * @param {Object} config Configuration options
38219 Roo.menu.BaseItem = function(config){
38220 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38225 * Fires when this item is clicked
38226 * @param {Roo.menu.BaseItem} this
38227 * @param {Roo.EventObject} e
38232 * Fires when this item is activated
38233 * @param {Roo.menu.BaseItem} this
38237 * @event deactivate
38238 * Fires when this item is deactivated
38239 * @param {Roo.menu.BaseItem} this
38245 this.on("click", this.handler, this.scope, true);
38249 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38251 * @cfg {Function} handler
38252 * A function that will handle the click event of this menu item (defaults to undefined)
38255 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38257 canActivate : false,
38260 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38265 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38267 activeClass : "x-menu-item-active",
38269 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38271 hideOnClick : true,
38273 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38278 ctype: "Roo.menu.BaseItem",
38281 actionMode : "container",
38284 render : function(container, parentMenu){
38285 this.parentMenu = parentMenu;
38286 Roo.menu.BaseItem.superclass.render.call(this, container);
38287 this.container.menuItemId = this.id;
38291 onRender : function(container, position){
38292 this.el = Roo.get(this.el);
38293 container.dom.appendChild(this.el.dom);
38297 onClick : function(e){
38298 if(!this.disabled && this.fireEvent("click", this, e) !== false
38299 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38300 this.handleClick(e);
38307 activate : function(){
38311 var li = this.container;
38312 li.addClass(this.activeClass);
38313 this.region = li.getRegion().adjust(2, 2, -2, -2);
38314 this.fireEvent("activate", this);
38319 deactivate : function(){
38320 this.container.removeClass(this.activeClass);
38321 this.fireEvent("deactivate", this);
38325 shouldDeactivate : function(e){
38326 return !this.region || !this.region.contains(e.getPoint());
38330 handleClick : function(e){
38331 if(this.hideOnClick){
38332 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38337 expandMenu : function(autoActivate){
38342 hideMenu : function(){
38347 * Ext JS Library 1.1.1
38348 * Copyright(c) 2006-2007, Ext JS, LLC.
38350 * Originally Released Under LGPL - original licence link has changed is not relivant.
38353 * <script type="text/javascript">
38357 * @class Roo.menu.Adapter
38358 * @extends Roo.menu.BaseItem
38359 * 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.
38360 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38362 * Creates a new Adapter
38363 * @param {Object} config Configuration options
38365 Roo.menu.Adapter = function(component, config){
38366 Roo.menu.Adapter.superclass.constructor.call(this, config);
38367 this.component = component;
38369 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38371 canActivate : true,
38374 onRender : function(container, position){
38375 this.component.render(container);
38376 this.el = this.component.getEl();
38380 activate : function(){
38384 this.component.focus();
38385 this.fireEvent("activate", this);
38390 deactivate : function(){
38391 this.fireEvent("deactivate", this);
38395 disable : function(){
38396 this.component.disable();
38397 Roo.menu.Adapter.superclass.disable.call(this);
38401 enable : function(){
38402 this.component.enable();
38403 Roo.menu.Adapter.superclass.enable.call(this);
38407 * Ext JS Library 1.1.1
38408 * Copyright(c) 2006-2007, Ext JS, LLC.
38410 * Originally Released Under LGPL - original licence link has changed is not relivant.
38413 * <script type="text/javascript">
38417 * @class Roo.menu.TextItem
38418 * @extends Roo.menu.BaseItem
38419 * Adds a static text string to a menu, usually used as either a heading or group separator.
38420 * Note: old style constructor with text is still supported.
38423 * Creates a new TextItem
38424 * @param {Object} cfg Configuration
38426 Roo.menu.TextItem = function(cfg){
38427 if (typeof(cfg) == 'string') {
38430 Roo.apply(this,cfg);
38433 Roo.menu.TextItem.superclass.constructor.call(this);
38436 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38438 * @cfg {String} text Text to show on item.
38443 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38445 hideOnClick : false,
38447 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38449 itemCls : "x-menu-text",
38452 onRender : function(){
38453 var s = document.createElement("span");
38454 s.className = this.itemCls;
38455 s.innerHTML = this.text;
38457 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38461 * Ext JS Library 1.1.1
38462 * Copyright(c) 2006-2007, Ext JS, LLC.
38464 * Originally Released Under LGPL - original licence link has changed is not relivant.
38467 * <script type="text/javascript">
38471 * @class Roo.menu.Separator
38472 * @extends Roo.menu.BaseItem
38473 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38474 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38476 * @param {Object} config Configuration options
38478 Roo.menu.Separator = function(config){
38479 Roo.menu.Separator.superclass.constructor.call(this, config);
38482 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38484 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38486 itemCls : "x-menu-sep",
38488 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38490 hideOnClick : false,
38493 onRender : function(li){
38494 var s = document.createElement("span");
38495 s.className = this.itemCls;
38496 s.innerHTML = " ";
38498 li.addClass("x-menu-sep-li");
38499 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38503 * Ext JS Library 1.1.1
38504 * Copyright(c) 2006-2007, Ext JS, LLC.
38506 * Originally Released Under LGPL - original licence link has changed is not relivant.
38509 * <script type="text/javascript">
38512 * @class Roo.menu.Item
38513 * @extends Roo.menu.BaseItem
38514 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38515 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38516 * activation and click handling.
38518 * Creates a new Item
38519 * @param {Object} config Configuration options
38521 Roo.menu.Item = function(config){
38522 Roo.menu.Item.superclass.constructor.call(this, config);
38524 this.menu = Roo.menu.MenuMgr.get(this.menu);
38527 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38530 * @cfg {String} text
38531 * The text to show on the menu item.
38535 * @cfg {String} HTML to render in menu
38536 * The text to show on the menu item (HTML version).
38540 * @cfg {String} icon
38541 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38545 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38547 itemCls : "x-menu-item",
38549 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38551 canActivate : true,
38553 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38556 // doc'd in BaseItem
38560 ctype: "Roo.menu.Item",
38563 onRender : function(container, position){
38564 var el = document.createElement("a");
38565 el.hideFocus = true;
38566 el.unselectable = "on";
38567 el.href = this.href || "#";
38568 if(this.hrefTarget){
38569 el.target = this.hrefTarget;
38571 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38573 var html = this.html.length ? this.html : String.format('{0}',this.text);
38575 el.innerHTML = String.format(
38576 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38577 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38579 Roo.menu.Item.superclass.onRender.call(this, container, position);
38583 * Sets the text to display in this menu item
38584 * @param {String} text The text to display
38585 * @param {Boolean} isHTML true to indicate text is pure html.
38587 setText : function(text, isHTML){
38595 var html = this.html.length ? this.html : String.format('{0}',this.text);
38597 this.el.update(String.format(
38598 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38599 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38600 this.parentMenu.autoWidth();
38605 handleClick : function(e){
38606 if(!this.href){ // if no link defined, stop the event automatically
38609 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38613 activate : function(autoExpand){
38614 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38624 shouldDeactivate : function(e){
38625 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38626 if(this.menu && this.menu.isVisible()){
38627 return !this.menu.getEl().getRegion().contains(e.getPoint());
38635 deactivate : function(){
38636 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38641 expandMenu : function(autoActivate){
38642 if(!this.disabled && this.menu){
38643 clearTimeout(this.hideTimer);
38644 delete this.hideTimer;
38645 if(!this.menu.isVisible() && !this.showTimer){
38646 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38647 }else if (this.menu.isVisible() && autoActivate){
38648 this.menu.tryActivate(0, 1);
38654 deferExpand : function(autoActivate){
38655 delete this.showTimer;
38656 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38658 this.menu.tryActivate(0, 1);
38663 hideMenu : function(){
38664 clearTimeout(this.showTimer);
38665 delete this.showTimer;
38666 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38667 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38672 deferHide : function(){
38673 delete this.hideTimer;
38678 * Ext JS Library 1.1.1
38679 * Copyright(c) 2006-2007, Ext JS, LLC.
38681 * Originally Released Under LGPL - original licence link has changed is not relivant.
38684 * <script type="text/javascript">
38688 * @class Roo.menu.CheckItem
38689 * @extends Roo.menu.Item
38690 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38692 * Creates a new CheckItem
38693 * @param {Object} config Configuration options
38695 Roo.menu.CheckItem = function(config){
38696 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38699 * @event beforecheckchange
38700 * Fires before the checked value is set, providing an opportunity to cancel if needed
38701 * @param {Roo.menu.CheckItem} this
38702 * @param {Boolean} checked The new checked value that will be set
38704 "beforecheckchange" : true,
38706 * @event checkchange
38707 * Fires after the checked value has been set
38708 * @param {Roo.menu.CheckItem} this
38709 * @param {Boolean} checked The checked value that was set
38711 "checkchange" : true
38713 if(this.checkHandler){
38714 this.on('checkchange', this.checkHandler, this.scope);
38717 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38719 * @cfg {String} group
38720 * All check items with the same group name will automatically be grouped into a single-select
38721 * radio button group (defaults to '')
38724 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38726 itemCls : "x-menu-item x-menu-check-item",
38728 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38730 groupClass : "x-menu-group-item",
38733 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38734 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38735 * initialized with checked = true will be rendered as checked.
38740 ctype: "Roo.menu.CheckItem",
38743 onRender : function(c){
38744 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38746 this.el.addClass(this.groupClass);
38748 Roo.menu.MenuMgr.registerCheckable(this);
38750 this.checked = false;
38751 this.setChecked(true, true);
38756 destroy : function(){
38758 Roo.menu.MenuMgr.unregisterCheckable(this);
38760 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38764 * Set the checked state of this item
38765 * @param {Boolean} checked The new checked value
38766 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38768 setChecked : function(state, suppressEvent){
38769 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38770 if(this.container){
38771 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38773 this.checked = state;
38774 if(suppressEvent !== true){
38775 this.fireEvent("checkchange", this, state);
38781 handleClick : function(e){
38782 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38783 this.setChecked(!this.checked);
38785 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38789 * Ext JS Library 1.1.1
38790 * Copyright(c) 2006-2007, Ext JS, LLC.
38792 * Originally Released Under LGPL - original licence link has changed is not relivant.
38795 * <script type="text/javascript">
38799 * @class Roo.menu.DateItem
38800 * @extends Roo.menu.Adapter
38801 * A menu item that wraps the {@link Roo.DatPicker} component.
38803 * Creates a new DateItem
38804 * @param {Object} config Configuration options
38806 Roo.menu.DateItem = function(config){
38807 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38808 /** The Roo.DatePicker object @type Roo.DatePicker */
38809 this.picker = this.component;
38810 this.addEvents({select: true});
38812 this.picker.on("render", function(picker){
38813 picker.getEl().swallowEvent("click");
38814 picker.container.addClass("x-menu-date-item");
38817 this.picker.on("select", this.onSelect, this);
38820 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38822 onSelect : function(picker, date){
38823 this.fireEvent("select", this, date, picker);
38824 Roo.menu.DateItem.superclass.handleClick.call(this);
38828 * Ext JS Library 1.1.1
38829 * Copyright(c) 2006-2007, Ext JS, LLC.
38831 * Originally Released Under LGPL - original licence link has changed is not relivant.
38834 * <script type="text/javascript">
38838 * @class Roo.menu.ColorItem
38839 * @extends Roo.menu.Adapter
38840 * A menu item that wraps the {@link Roo.ColorPalette} component.
38842 * Creates a new ColorItem
38843 * @param {Object} config Configuration options
38845 Roo.menu.ColorItem = function(config){
38846 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38847 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38848 this.palette = this.component;
38849 this.relayEvents(this.palette, ["select"]);
38850 if(this.selectHandler){
38851 this.on('select', this.selectHandler, this.scope);
38854 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38856 * Ext JS Library 1.1.1
38857 * Copyright(c) 2006-2007, Ext JS, LLC.
38859 * Originally Released Under LGPL - original licence link has changed is not relivant.
38862 * <script type="text/javascript">
38867 * @class Roo.menu.DateMenu
38868 * @extends Roo.menu.Menu
38869 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38871 * Creates a new DateMenu
38872 * @param {Object} config Configuration options
38874 Roo.menu.DateMenu = function(config){
38875 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38877 var di = new Roo.menu.DateItem(config);
38880 * The {@link Roo.DatePicker} instance for this DateMenu
38883 this.picker = di.picker;
38886 * @param {DatePicker} picker
38887 * @param {Date} date
38889 this.relayEvents(di, ["select"]);
38890 this.on('beforeshow', function(){
38892 this.picker.hideMonthPicker(false);
38896 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38900 * Ext JS Library 1.1.1
38901 * Copyright(c) 2006-2007, Ext JS, LLC.
38903 * Originally Released Under LGPL - original licence link has changed is not relivant.
38906 * <script type="text/javascript">
38911 * @class Roo.menu.ColorMenu
38912 * @extends Roo.menu.Menu
38913 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38915 * Creates a new ColorMenu
38916 * @param {Object} config Configuration options
38918 Roo.menu.ColorMenu = function(config){
38919 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38921 var ci = new Roo.menu.ColorItem(config);
38924 * The {@link Roo.ColorPalette} instance for this ColorMenu
38925 * @type ColorPalette
38927 this.palette = ci.palette;
38930 * @param {ColorPalette} palette
38931 * @param {String} color
38933 this.relayEvents(ci, ["select"]);
38935 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38937 * Ext JS Library 1.1.1
38938 * Copyright(c) 2006-2007, Ext JS, LLC.
38940 * Originally Released Under LGPL - original licence link has changed is not relivant.
38943 * <script type="text/javascript">
38947 * @class Roo.form.TextItem
38948 * @extends Roo.BoxComponent
38949 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38951 * Creates a new TextItem
38952 * @param {Object} config Configuration options
38954 Roo.form.TextItem = function(config){
38955 Roo.form.TextItem.superclass.constructor.call(this, config);
38958 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
38961 * @cfg {String} tag the tag for this item (default div)
38965 * @cfg {String} html the content for this item
38969 getAutoCreate : function()
38982 onRender : function(ct, position)
38984 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
38987 var cfg = this.getAutoCreate();
38989 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38991 if (!cfg.name.length) {
38994 this.el = ct.createChild(cfg, position);
38999 * @param {String} html update the Contents of the element.
39001 setHTML : function(html)
39003 this.fieldEl.dom.innerHTML = html;
39008 * Ext JS Library 1.1.1
39009 * Copyright(c) 2006-2007, Ext JS, LLC.
39011 * Originally Released Under LGPL - original licence link has changed is not relivant.
39014 * <script type="text/javascript">
39018 * @class Roo.form.Field
39019 * @extends Roo.BoxComponent
39020 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39022 * Creates a new Field
39023 * @param {Object} config Configuration options
39025 Roo.form.Field = function(config){
39026 Roo.form.Field.superclass.constructor.call(this, config);
39029 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
39031 * @cfg {String} fieldLabel Label to use when rendering a form.
39034 * @cfg {String} qtip Mouse over tip
39038 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
39040 invalidClass : "x-form-invalid",
39042 * @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")
39044 invalidText : "The value in this field is invalid",
39046 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
39048 focusClass : "x-form-focus",
39050 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
39051 automatic validation (defaults to "keyup").
39053 validationEvent : "keyup",
39055 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
39057 validateOnBlur : true,
39059 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39061 validationDelay : 250,
39063 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39064 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39066 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39068 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39070 fieldClass : "x-form-field",
39072 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
39075 ----------- ----------------------------------------------------------------------
39076 qtip Display a quick tip when the user hovers over the field
39077 title Display a default browser title attribute popup
39078 under Add a block div beneath the field containing the error text
39079 side Add an error icon to the right of the field with a popup on hover
39080 [element id] Add the error text directly to the innerHTML of the specified element
39083 msgTarget : 'qtip',
39085 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39090 * @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.
39095 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39100 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39102 inputType : undefined,
39105 * @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).
39107 tabIndex : undefined,
39110 isFormField : true,
39115 * @property {Roo.Element} fieldEl
39116 * Element Containing the rendered Field (with label etc.)
39119 * @cfg {Mixed} value A value to initialize this field with.
39124 * @cfg {String} name The field's HTML name attribute.
39127 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39130 loadedValue : false,
39134 initComponent : function(){
39135 Roo.form.Field.superclass.initComponent.call(this);
39139 * Fires when this field receives input focus.
39140 * @param {Roo.form.Field} this
39145 * Fires when this field loses input focus.
39146 * @param {Roo.form.Field} this
39150 * @event specialkey
39151 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39152 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39153 * @param {Roo.form.Field} this
39154 * @param {Roo.EventObject} e The event object
39159 * Fires just before the field blurs if the field value has changed.
39160 * @param {Roo.form.Field} this
39161 * @param {Mixed} newValue The new value
39162 * @param {Mixed} oldValue The original value
39167 * Fires after the field has been marked as invalid.
39168 * @param {Roo.form.Field} this
39169 * @param {String} msg The validation message
39174 * Fires after the field has been validated with no errors.
39175 * @param {Roo.form.Field} this
39180 * Fires after the key up
39181 * @param {Roo.form.Field} this
39182 * @param {Roo.EventObject} e The event Object
39189 * Returns the name attribute of the field if available
39190 * @return {String} name The field name
39192 getName: function(){
39193 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39197 onRender : function(ct, position){
39198 Roo.form.Field.superclass.onRender.call(this, ct, position);
39200 var cfg = this.getAutoCreate();
39202 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39204 if (!cfg.name.length) {
39207 if(this.inputType){
39208 cfg.type = this.inputType;
39210 this.el = ct.createChild(cfg, position);
39212 var type = this.el.dom.type;
39214 if(type == 'password'){
39217 this.el.addClass('x-form-'+type);
39220 this.el.dom.readOnly = true;
39222 if(this.tabIndex !== undefined){
39223 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39226 this.el.addClass([this.fieldClass, this.cls]);
39231 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39232 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39233 * @return {Roo.form.Field} this
39235 applyTo : function(target){
39236 this.allowDomMove = false;
39237 this.el = Roo.get(target);
39238 this.render(this.el.dom.parentNode);
39243 initValue : function(){
39244 if(this.value !== undefined){
39245 this.setValue(this.value);
39246 }else if(this.el.dom.value.length > 0){
39247 this.setValue(this.el.dom.value);
39252 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39253 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39255 isDirty : function() {
39256 if(this.disabled) {
39259 return String(this.getValue()) !== String(this.originalValue);
39263 * stores the current value in loadedValue
39265 resetHasChanged : function()
39267 this.loadedValue = String(this.getValue());
39270 * checks the current value against the 'loaded' value.
39271 * Note - will return false if 'resetHasChanged' has not been called first.
39273 hasChanged : function()
39275 if(this.disabled || this.readOnly) {
39278 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39284 afterRender : function(){
39285 Roo.form.Field.superclass.afterRender.call(this);
39290 fireKey : function(e){
39291 //Roo.log('field ' + e.getKey());
39292 if(e.isNavKeyPress()){
39293 this.fireEvent("specialkey", this, e);
39298 * Resets the current field value to the originally loaded value and clears any validation messages
39300 reset : function(){
39301 this.setValue(this.resetValue);
39302 this.originalValue = this.getValue();
39303 this.clearInvalid();
39307 initEvents : function(){
39308 // safari killled keypress - so keydown is now used..
39309 this.el.on("keydown" , this.fireKey, this);
39310 this.el.on("focus", this.onFocus, this);
39311 this.el.on("blur", this.onBlur, this);
39312 this.el.relayEvent('keyup', this);
39314 // reference to original value for reset
39315 this.originalValue = this.getValue();
39316 this.resetValue = this.getValue();
39320 onFocus : function(){
39321 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39322 this.el.addClass(this.focusClass);
39324 if(!this.hasFocus){
39325 this.hasFocus = true;
39326 this.startValue = this.getValue();
39327 this.fireEvent("focus", this);
39331 beforeBlur : Roo.emptyFn,
39334 onBlur : function(){
39336 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39337 this.el.removeClass(this.focusClass);
39339 this.hasFocus = false;
39340 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39343 var v = this.getValue();
39344 if(String(v) !== String(this.startValue)){
39345 this.fireEvent('change', this, v, this.startValue);
39347 this.fireEvent("blur", this);
39351 * Returns whether or not the field value is currently valid
39352 * @param {Boolean} preventMark True to disable marking the field invalid
39353 * @return {Boolean} True if the value is valid, else false
39355 isValid : function(preventMark){
39359 var restore = this.preventMark;
39360 this.preventMark = preventMark === true;
39361 var v = this.validateValue(this.processValue(this.getRawValue()));
39362 this.preventMark = restore;
39367 * Validates the field value
39368 * @return {Boolean} True if the value is valid, else false
39370 validate : function(){
39371 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39372 this.clearInvalid();
39378 processValue : function(value){
39383 // Subclasses should provide the validation implementation by overriding this
39384 validateValue : function(value){
39389 * Mark this field as invalid
39390 * @param {String} msg The validation message
39392 markInvalid : function(msg){
39393 if(!this.rendered || this.preventMark){ // not rendered
39397 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39399 obj.el.addClass(this.invalidClass);
39400 msg = msg || this.invalidText;
39401 switch(this.msgTarget){
39403 obj.el.dom.qtip = msg;
39404 obj.el.dom.qclass = 'x-form-invalid-tip';
39405 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39406 Roo.QuickTips.enable();
39410 this.el.dom.title = msg;
39414 var elp = this.el.findParent('.x-form-element', 5, true);
39415 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39416 this.errorEl.setWidth(elp.getWidth(true)-20);
39418 this.errorEl.update(msg);
39419 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39422 if(!this.errorIcon){
39423 var elp = this.el.findParent('.x-form-element', 5, true);
39424 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39426 this.alignErrorIcon();
39427 this.errorIcon.dom.qtip = msg;
39428 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39429 this.errorIcon.show();
39430 this.on('resize', this.alignErrorIcon, this);
39433 var t = Roo.getDom(this.msgTarget);
39435 t.style.display = this.msgDisplay;
39438 this.fireEvent('invalid', this, msg);
39442 alignErrorIcon : function(){
39443 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39447 * Clear any invalid styles/messages for this field
39449 clearInvalid : function(){
39450 if(!this.rendered || this.preventMark){ // not rendered
39453 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39455 obj.el.removeClass(this.invalidClass);
39456 switch(this.msgTarget){
39458 obj.el.dom.qtip = '';
39461 this.el.dom.title = '';
39465 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39469 if(this.errorIcon){
39470 this.errorIcon.dom.qtip = '';
39471 this.errorIcon.hide();
39472 this.un('resize', this.alignErrorIcon, this);
39476 var t = Roo.getDom(this.msgTarget);
39478 t.style.display = 'none';
39481 this.fireEvent('valid', this);
39485 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39486 * @return {Mixed} value The field value
39488 getRawValue : function(){
39489 var v = this.el.getValue();
39495 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39496 * @return {Mixed} value The field value
39498 getValue : function(){
39499 var v = this.el.getValue();
39505 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39506 * @param {Mixed} value The value to set
39508 setRawValue : function(v){
39509 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39513 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39514 * @param {Mixed} value The value to set
39516 setValue : function(v){
39519 this.el.dom.value = (v === null || v === undefined ? '' : v);
39524 adjustSize : function(w, h){
39525 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39526 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39530 adjustWidth : function(tag, w){
39531 tag = tag.toLowerCase();
39532 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39533 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39534 if(tag == 'input'){
39537 if(tag == 'textarea'){
39540 }else if(Roo.isOpera){
39541 if(tag == 'input'){
39544 if(tag == 'textarea'){
39554 // anything other than normal should be considered experimental
39555 Roo.form.Field.msgFx = {
39557 show: function(msgEl, f){
39558 msgEl.setDisplayed('block');
39561 hide : function(msgEl, f){
39562 msgEl.setDisplayed(false).update('');
39567 show: function(msgEl, f){
39568 msgEl.slideIn('t', {stopFx:true});
39571 hide : function(msgEl, f){
39572 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39577 show: function(msgEl, f){
39578 msgEl.fixDisplay();
39579 msgEl.alignTo(f.el, 'tl-tr');
39580 msgEl.slideIn('l', {stopFx:true});
39583 hide : function(msgEl, f){
39584 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39589 * Ext JS Library 1.1.1
39590 * Copyright(c) 2006-2007, Ext JS, LLC.
39592 * Originally Released Under LGPL - original licence link has changed is not relivant.
39595 * <script type="text/javascript">
39600 * @class Roo.form.TextField
39601 * @extends Roo.form.Field
39602 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39603 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39605 * Creates a new TextField
39606 * @param {Object} config Configuration options
39608 Roo.form.TextField = function(config){
39609 Roo.form.TextField.superclass.constructor.call(this, config);
39613 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39614 * according to the default logic, but this event provides a hook for the developer to apply additional
39615 * logic at runtime to resize the field if needed.
39616 * @param {Roo.form.Field} this This text field
39617 * @param {Number} width The new field width
39623 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39625 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39629 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39633 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39637 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39641 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39645 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39647 disableKeyFilter : false,
39649 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39653 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39657 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39659 maxLength : Number.MAX_VALUE,
39661 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39663 minLengthText : "The minimum length for this field is {0}",
39665 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39667 maxLengthText : "The maximum length for this field is {0}",
39669 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39671 selectOnFocus : false,
39673 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39675 allowLeadingSpace : false,
39677 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39679 blankText : "This field is required",
39681 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39682 * If available, this function will be called only after the basic validators all return true, and will be passed the
39683 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39687 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39688 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39689 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39693 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39697 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39703 initEvents : function()
39705 if (this.emptyText) {
39706 this.el.attr('placeholder', this.emptyText);
39709 Roo.form.TextField.superclass.initEvents.call(this);
39710 if(this.validationEvent == 'keyup'){
39711 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39712 this.el.on('keyup', this.filterValidation, this);
39714 else if(this.validationEvent !== false){
39715 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39718 if(this.selectOnFocus){
39719 this.on("focus", this.preFocus, this);
39721 if (!this.allowLeadingSpace) {
39722 this.on('blur', this.cleanLeadingSpace, this);
39725 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39726 this.el.on("keypress", this.filterKeys, this);
39729 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39730 this.el.on("click", this.autoSize, this);
39732 if(this.el.is('input[type=password]') && Roo.isSafari){
39733 this.el.on('keydown', this.SafariOnKeyDown, this);
39737 processValue : function(value){
39738 if(this.stripCharsRe){
39739 var newValue = value.replace(this.stripCharsRe, '');
39740 if(newValue !== value){
39741 this.setRawValue(newValue);
39748 filterValidation : function(e){
39749 if(!e.isNavKeyPress()){
39750 this.validationTask.delay(this.validationDelay);
39755 onKeyUp : function(e){
39756 if(!e.isNavKeyPress()){
39760 // private - clean the leading white space
39761 cleanLeadingSpace : function(e)
39763 if ( this.inputType == 'file') {
39767 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39770 * Resets the current field value to the originally-loaded value and clears any validation messages.
39773 reset : function(){
39774 Roo.form.TextField.superclass.reset.call(this);
39778 preFocus : function(){
39780 if(this.selectOnFocus){
39781 this.el.dom.select();
39787 filterKeys : function(e){
39788 var k = e.getKey();
39789 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39792 var c = e.getCharCode(), cc = String.fromCharCode(c);
39793 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39796 if(!this.maskRe.test(cc)){
39801 setValue : function(v){
39803 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39809 * Validates a value according to the field's validation rules and marks the field as invalid
39810 * if the validation fails
39811 * @param {Mixed} value The value to validate
39812 * @return {Boolean} True if the value is valid, else false
39814 validateValue : function(value){
39815 if(value.length < 1) { // if it's blank
39816 if(this.allowBlank){
39817 this.clearInvalid();
39820 this.markInvalid(this.blankText);
39824 if(value.length < this.minLength){
39825 this.markInvalid(String.format(this.minLengthText, this.minLength));
39828 if(value.length > this.maxLength){
39829 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39833 var vt = Roo.form.VTypes;
39834 if(!vt[this.vtype](value, this)){
39835 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39839 if(typeof this.validator == "function"){
39840 var msg = this.validator(value);
39842 this.markInvalid(msg);
39846 if(this.regex && !this.regex.test(value)){
39847 this.markInvalid(this.regexText);
39854 * Selects text in this field
39855 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39856 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39858 selectText : function(start, end){
39859 var v = this.getRawValue();
39861 start = start === undefined ? 0 : start;
39862 end = end === undefined ? v.length : end;
39863 var d = this.el.dom;
39864 if(d.setSelectionRange){
39865 d.setSelectionRange(start, end);
39866 }else if(d.createTextRange){
39867 var range = d.createTextRange();
39868 range.moveStart("character", start);
39869 range.moveEnd("character", v.length-end);
39876 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39877 * This only takes effect if grow = true, and fires the autosize event.
39879 autoSize : function(){
39880 if(!this.grow || !this.rendered){
39884 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39887 var v = el.dom.value;
39888 var d = document.createElement('div');
39889 d.appendChild(document.createTextNode(v));
39893 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39894 this.el.setWidth(w);
39895 this.fireEvent("autosize", this, w);
39899 SafariOnKeyDown : function(event)
39901 // this is a workaround for a password hang bug on chrome/ webkit.
39903 var isSelectAll = false;
39905 if(this.el.dom.selectionEnd > 0){
39906 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39908 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39909 event.preventDefault();
39914 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39916 event.preventDefault();
39917 // this is very hacky as keydown always get's upper case.
39919 var cc = String.fromCharCode(event.getCharCode());
39922 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39930 * Ext JS Library 1.1.1
39931 * Copyright(c) 2006-2007, Ext JS, LLC.
39933 * Originally Released Under LGPL - original licence link has changed is not relivant.
39936 * <script type="text/javascript">
39940 * @class Roo.form.Hidden
39941 * @extends Roo.form.TextField
39942 * Simple Hidden element used on forms
39944 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39947 * Creates a new Hidden form element.
39948 * @param {Object} config Configuration options
39953 // easy hidden field...
39954 Roo.form.Hidden = function(config){
39955 Roo.form.Hidden.superclass.constructor.call(this, config);
39958 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39960 inputType: 'hidden',
39963 labelSeparator: '',
39965 itemCls : 'x-form-item-display-none'
39973 * Ext JS Library 1.1.1
39974 * Copyright(c) 2006-2007, Ext JS, LLC.
39976 * Originally Released Under LGPL - original licence link has changed is not relivant.
39979 * <script type="text/javascript">
39983 * @class Roo.form.TriggerField
39984 * @extends Roo.form.TextField
39985 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39986 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39987 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39988 * for which you can provide a custom implementation. For example:
39990 var trigger = new Roo.form.TriggerField();
39991 trigger.onTriggerClick = myTriggerFn;
39992 trigger.applyTo('my-field');
39995 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39996 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39997 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39998 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
40000 * Create a new TriggerField.
40001 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
40002 * to the base TextField)
40004 Roo.form.TriggerField = function(config){
40005 this.mimicing = false;
40006 Roo.form.TriggerField.superclass.constructor.call(this, config);
40009 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
40011 * @cfg {String} triggerClass A CSS class to apply to the trigger
40014 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40015 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
40017 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
40019 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
40023 /** @cfg {Boolean} grow @hide */
40024 /** @cfg {Number} growMin @hide */
40025 /** @cfg {Number} growMax @hide */
40031 autoSize: Roo.emptyFn,
40035 deferHeight : true,
40038 actionMode : 'wrap',
40040 onResize : function(w, h){
40041 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
40042 if(typeof w == 'number'){
40043 var x = w - this.trigger.getWidth();
40044 this.el.setWidth(this.adjustWidth('input', x));
40045 this.trigger.setStyle('left', x+'px');
40050 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40053 getResizeEl : function(){
40058 getPositionEl : function(){
40063 alignErrorIcon : function(){
40064 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40068 onRender : function(ct, position){
40069 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40070 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
40071 this.trigger = this.wrap.createChild(this.triggerConfig ||
40072 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
40073 if(this.hideTrigger){
40074 this.trigger.setDisplayed(false);
40076 this.initTrigger();
40078 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
40083 initTrigger : function(){
40084 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40085 this.trigger.addClassOnOver('x-form-trigger-over');
40086 this.trigger.addClassOnClick('x-form-trigger-click');
40090 onDestroy : function(){
40092 this.trigger.removeAllListeners();
40093 this.trigger.remove();
40096 this.wrap.remove();
40098 Roo.form.TriggerField.superclass.onDestroy.call(this);
40102 onFocus : function(){
40103 Roo.form.TriggerField.superclass.onFocus.call(this);
40104 if(!this.mimicing){
40105 this.wrap.addClass('x-trigger-wrap-focus');
40106 this.mimicing = true;
40107 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40108 if(this.monitorTab){
40109 this.el.on("keydown", this.checkTab, this);
40115 checkTab : function(e){
40116 if(e.getKey() == e.TAB){
40117 this.triggerBlur();
40122 onBlur : function(){
40127 mimicBlur : function(e, t){
40128 if(!this.wrap.contains(t) && this.validateBlur()){
40129 this.triggerBlur();
40134 triggerBlur : function(){
40135 this.mimicing = false;
40136 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40137 if(this.monitorTab){
40138 this.el.un("keydown", this.checkTab, this);
40140 this.wrap.removeClass('x-trigger-wrap-focus');
40141 Roo.form.TriggerField.superclass.onBlur.call(this);
40145 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40146 validateBlur : function(e, t){
40151 onDisable : function(){
40152 Roo.form.TriggerField.superclass.onDisable.call(this);
40154 this.wrap.addClass('x-item-disabled');
40159 onEnable : function(){
40160 Roo.form.TriggerField.superclass.onEnable.call(this);
40162 this.wrap.removeClass('x-item-disabled');
40167 onShow : function(){
40168 var ae = this.getActionEl();
40171 ae.dom.style.display = '';
40172 ae.dom.style.visibility = 'visible';
40178 onHide : function(){
40179 var ae = this.getActionEl();
40180 ae.dom.style.display = 'none';
40184 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40185 * by an implementing function.
40187 * @param {EventObject} e
40189 onTriggerClick : Roo.emptyFn
40192 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40193 // to be extended by an implementing class. For an example of implementing this class, see the custom
40194 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40195 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40196 initComponent : function(){
40197 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40199 this.triggerConfig = {
40200 tag:'span', cls:'x-form-twin-triggers', cn:[
40201 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40202 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40206 getTrigger : function(index){
40207 return this.triggers[index];
40210 initTrigger : function(){
40211 var ts = this.trigger.select('.x-form-trigger', true);
40212 this.wrap.setStyle('overflow', 'hidden');
40213 var triggerField = this;
40214 ts.each(function(t, all, index){
40215 t.hide = function(){
40216 var w = triggerField.wrap.getWidth();
40217 this.dom.style.display = 'none';
40218 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40220 t.show = function(){
40221 var w = triggerField.wrap.getWidth();
40222 this.dom.style.display = '';
40223 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40225 var triggerIndex = 'Trigger'+(index+1);
40227 if(this['hide'+triggerIndex]){
40228 t.dom.style.display = 'none';
40230 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40231 t.addClassOnOver('x-form-trigger-over');
40232 t.addClassOnClick('x-form-trigger-click');
40234 this.triggers = ts.elements;
40237 onTrigger1Click : Roo.emptyFn,
40238 onTrigger2Click : Roo.emptyFn
40241 * Ext JS Library 1.1.1
40242 * Copyright(c) 2006-2007, Ext JS, LLC.
40244 * Originally Released Under LGPL - original licence link has changed is not relivant.
40247 * <script type="text/javascript">
40251 * @class Roo.form.TextArea
40252 * @extends Roo.form.TextField
40253 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40254 * support for auto-sizing.
40256 * Creates a new TextArea
40257 * @param {Object} config Configuration options
40259 Roo.form.TextArea = function(config){
40260 Roo.form.TextArea.superclass.constructor.call(this, config);
40261 // these are provided exchanges for backwards compat
40262 // minHeight/maxHeight were replaced by growMin/growMax to be
40263 // compatible with TextField growing config values
40264 if(this.minHeight !== undefined){
40265 this.growMin = this.minHeight;
40267 if(this.maxHeight !== undefined){
40268 this.growMax = this.maxHeight;
40272 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40274 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40278 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40282 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40283 * in the field (equivalent to setting overflow: hidden, defaults to false)
40285 preventScrollbars: false,
40287 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40288 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40292 onRender : function(ct, position){
40294 this.defaultAutoCreate = {
40296 style:"width:300px;height:60px;",
40297 autocomplete: "new-password"
40300 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40302 this.textSizeEl = Roo.DomHelper.append(document.body, {
40303 tag: "pre", cls: "x-form-grow-sizer"
40305 if(this.preventScrollbars){
40306 this.el.setStyle("overflow", "hidden");
40308 this.el.setHeight(this.growMin);
40312 onDestroy : function(){
40313 if(this.textSizeEl){
40314 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40316 Roo.form.TextArea.superclass.onDestroy.call(this);
40320 onKeyUp : function(e){
40321 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40327 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40328 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40330 autoSize : function(){
40331 if(!this.grow || !this.textSizeEl){
40335 var v = el.dom.value;
40336 var ts = this.textSizeEl;
40339 ts.appendChild(document.createTextNode(v));
40342 Roo.fly(ts).setWidth(this.el.getWidth());
40344 v = "  ";
40347 v = v.replace(/\n/g, '<p> </p>');
40349 v += " \n ";
40352 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40353 if(h != this.lastHeight){
40354 this.lastHeight = h;
40355 this.el.setHeight(h);
40356 this.fireEvent("autosize", this, h);
40361 * Ext JS Library 1.1.1
40362 * Copyright(c) 2006-2007, Ext JS, LLC.
40364 * Originally Released Under LGPL - original licence link has changed is not relivant.
40367 * <script type="text/javascript">
40372 * @class Roo.form.NumberField
40373 * @extends Roo.form.TextField
40374 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40376 * Creates a new NumberField
40377 * @param {Object} config Configuration options
40379 Roo.form.NumberField = function(config){
40380 Roo.form.NumberField.superclass.constructor.call(this, config);
40383 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40385 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40387 fieldClass: "x-form-field x-form-num-field",
40389 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40391 allowDecimals : true,
40393 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40395 decimalSeparator : ".",
40397 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40399 decimalPrecision : 2,
40401 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40403 allowNegative : true,
40405 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40407 minValue : Number.NEGATIVE_INFINITY,
40409 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40411 maxValue : Number.MAX_VALUE,
40413 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40415 minText : "The minimum value for this field is {0}",
40417 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40419 maxText : "The maximum value for this field is {0}",
40421 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40422 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40424 nanText : "{0} is not a valid number",
40427 initEvents : function(){
40428 Roo.form.NumberField.superclass.initEvents.call(this);
40429 var allowed = "0123456789";
40430 if(this.allowDecimals){
40431 allowed += this.decimalSeparator;
40433 if(this.allowNegative){
40436 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40437 var keyPress = function(e){
40438 var k = e.getKey();
40439 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40442 var c = e.getCharCode();
40443 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40447 this.el.on("keypress", keyPress, this);
40451 validateValue : function(value){
40452 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40455 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40458 var num = this.parseValue(value);
40460 this.markInvalid(String.format(this.nanText, value));
40463 if(num < this.minValue){
40464 this.markInvalid(String.format(this.minText, this.minValue));
40467 if(num > this.maxValue){
40468 this.markInvalid(String.format(this.maxText, this.maxValue));
40474 getValue : function(){
40475 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40479 parseValue : function(value){
40480 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40481 return isNaN(value) ? '' : value;
40485 fixPrecision : function(value){
40486 var nan = isNaN(value);
40487 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40488 return nan ? '' : value;
40490 return parseFloat(value).toFixed(this.decimalPrecision);
40493 setValue : function(v){
40494 v = this.fixPrecision(v);
40495 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40499 decimalPrecisionFcn : function(v){
40500 return Math.floor(v);
40503 beforeBlur : function(){
40504 var v = this.parseValue(this.getRawValue());
40511 * Ext JS Library 1.1.1
40512 * Copyright(c) 2006-2007, Ext JS, LLC.
40514 * Originally Released Under LGPL - original licence link has changed is not relivant.
40517 * <script type="text/javascript">
40521 * @class Roo.form.DateField
40522 * @extends Roo.form.TriggerField
40523 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40525 * Create a new DateField
40526 * @param {Object} config
40528 Roo.form.DateField = function(config)
40530 Roo.form.DateField.superclass.constructor.call(this, config);
40536 * Fires when a date is selected
40537 * @param {Roo.form.DateField} combo This combo box
40538 * @param {Date} date The date selected
40545 if(typeof this.minValue == "string") {
40546 this.minValue = this.parseDate(this.minValue);
40548 if(typeof this.maxValue == "string") {
40549 this.maxValue = this.parseDate(this.maxValue);
40551 this.ddMatch = null;
40552 if(this.disabledDates){
40553 var dd = this.disabledDates;
40555 for(var i = 0; i < dd.length; i++){
40557 if(i != dd.length-1) {
40561 this.ddMatch = new RegExp(re + ")");
40565 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40567 * @cfg {String} format
40568 * The default date format string which can be overriden for localization support. The format must be
40569 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40573 * @cfg {String} altFormats
40574 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40575 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40577 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40579 * @cfg {Array} disabledDays
40580 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40582 disabledDays : null,
40584 * @cfg {String} disabledDaysText
40585 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40587 disabledDaysText : "Disabled",
40589 * @cfg {Array} disabledDates
40590 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40591 * expression so they are very powerful. Some examples:
40593 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40594 * <li>["03/08", "09/16"] would disable those days for every year</li>
40595 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40596 * <li>["03/../2006"] would disable every day in March 2006</li>
40597 * <li>["^03"] would disable every day in every March</li>
40599 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40600 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40602 disabledDates : null,
40604 * @cfg {String} disabledDatesText
40605 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40607 disabledDatesText : "Disabled",
40609 * @cfg {Date/String} minValue
40610 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40611 * valid format (defaults to null).
40615 * @cfg {Date/String} maxValue
40616 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40617 * valid format (defaults to null).
40621 * @cfg {String} minText
40622 * The error text to display when the date in the cell is before minValue (defaults to
40623 * 'The date in this field must be after {minValue}').
40625 minText : "The date in this field must be equal to or after {0}",
40627 * @cfg {String} maxText
40628 * The error text to display when the date in the cell is after maxValue (defaults to
40629 * 'The date in this field must be before {maxValue}').
40631 maxText : "The date in this field must be equal to or before {0}",
40633 * @cfg {String} invalidText
40634 * The error text to display when the date in the field is invalid (defaults to
40635 * '{value} is not a valid date - it must be in the format {format}').
40637 invalidText : "{0} is not a valid date - it must be in the format {1}",
40639 * @cfg {String} triggerClass
40640 * An additional CSS class used to style the trigger button. The trigger will always get the
40641 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40642 * which displays a calendar icon).
40644 triggerClass : 'x-form-date-trigger',
40648 * @cfg {Boolean} useIso
40649 * if enabled, then the date field will use a hidden field to store the
40650 * real value as iso formated date. default (false)
40654 * @cfg {String/Object} autoCreate
40655 * A DomHelper element spec, or true for a default element spec (defaults to
40656 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40659 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40662 hiddenField: false,
40664 onRender : function(ct, position)
40666 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40668 //this.el.dom.removeAttribute('name');
40669 Roo.log("Changing name?");
40670 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40671 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40673 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40674 // prevent input submission
40675 this.hiddenName = this.name;
40682 validateValue : function(value)
40684 value = this.formatDate(value);
40685 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40686 Roo.log('super failed');
40689 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40692 var svalue = value;
40693 value = this.parseDate(value);
40695 Roo.log('parse date failed' + svalue);
40696 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40699 var time = value.getTime();
40700 if(this.minValue && time < this.minValue.getTime()){
40701 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40704 if(this.maxValue && time > this.maxValue.getTime()){
40705 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40708 if(this.disabledDays){
40709 var day = value.getDay();
40710 for(var i = 0; i < this.disabledDays.length; i++) {
40711 if(day === this.disabledDays[i]){
40712 this.markInvalid(this.disabledDaysText);
40717 var fvalue = this.formatDate(value);
40718 if(this.ddMatch && this.ddMatch.test(fvalue)){
40719 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40726 // Provides logic to override the default TriggerField.validateBlur which just returns true
40727 validateBlur : function(){
40728 return !this.menu || !this.menu.isVisible();
40731 getName: function()
40733 // returns hidden if it's set..
40734 if (!this.rendered) {return ''};
40735 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40740 * Returns the current date value of the date field.
40741 * @return {Date} The date value
40743 getValue : function(){
40745 return this.hiddenField ?
40746 this.hiddenField.value :
40747 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40751 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40752 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40753 * (the default format used is "m/d/y").
40756 //All of these calls set the same date value (May 4, 2006)
40758 //Pass a date object:
40759 var dt = new Date('5/4/06');
40760 dateField.setValue(dt);
40762 //Pass a date string (default format):
40763 dateField.setValue('5/4/06');
40765 //Pass a date string (custom format):
40766 dateField.format = 'Y-m-d';
40767 dateField.setValue('2006-5-4');
40769 * @param {String/Date} date The date or valid date string
40771 setValue : function(date){
40772 if (this.hiddenField) {
40773 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40775 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40776 // make sure the value field is always stored as a date..
40777 this.value = this.parseDate(date);
40783 parseDate : function(value){
40784 if(!value || value instanceof Date){
40787 var v = Date.parseDate(value, this.format);
40788 if (!v && this.useIso) {
40789 v = Date.parseDate(value, 'Y-m-d');
40791 if(!v && this.altFormats){
40792 if(!this.altFormatsArray){
40793 this.altFormatsArray = this.altFormats.split("|");
40795 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40796 v = Date.parseDate(value, this.altFormatsArray[i]);
40803 formatDate : function(date, fmt){
40804 return (!date || !(date instanceof Date)) ?
40805 date : date.dateFormat(fmt || this.format);
40810 select: function(m, d){
40813 this.fireEvent('select', this, d);
40815 show : function(){ // retain focus styling
40819 this.focus.defer(10, this);
40820 var ml = this.menuListeners;
40821 this.menu.un("select", ml.select, this);
40822 this.menu.un("show", ml.show, this);
40823 this.menu.un("hide", ml.hide, this);
40828 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40829 onTriggerClick : function(){
40833 if(this.menu == null){
40834 this.menu = new Roo.menu.DateMenu();
40836 Roo.apply(this.menu.picker, {
40837 showClear: this.allowBlank,
40838 minDate : this.minValue,
40839 maxDate : this.maxValue,
40840 disabledDatesRE : this.ddMatch,
40841 disabledDatesText : this.disabledDatesText,
40842 disabledDays : this.disabledDays,
40843 disabledDaysText : this.disabledDaysText,
40844 format : this.useIso ? 'Y-m-d' : this.format,
40845 minText : String.format(this.minText, this.formatDate(this.minValue)),
40846 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40848 this.menu.on(Roo.apply({}, this.menuListeners, {
40851 this.menu.picker.setValue(this.getValue() || new Date());
40852 this.menu.show(this.el, "tl-bl?");
40855 beforeBlur : function(){
40856 var v = this.parseDate(this.getRawValue());
40866 isDirty : function() {
40867 if(this.disabled) {
40871 if(typeof(this.startValue) === 'undefined'){
40875 return String(this.getValue()) !== String(this.startValue);
40879 cleanLeadingSpace : function(e)
40886 * Ext JS Library 1.1.1
40887 * Copyright(c) 2006-2007, Ext JS, LLC.
40889 * Originally Released Under LGPL - original licence link has changed is not relivant.
40892 * <script type="text/javascript">
40896 * @class Roo.form.MonthField
40897 * @extends Roo.form.TriggerField
40898 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40900 * Create a new MonthField
40901 * @param {Object} config
40903 Roo.form.MonthField = function(config){
40905 Roo.form.MonthField.superclass.constructor.call(this, config);
40911 * Fires when a date is selected
40912 * @param {Roo.form.MonthFieeld} combo This combo box
40913 * @param {Date} date The date selected
40920 if(typeof this.minValue == "string") {
40921 this.minValue = this.parseDate(this.minValue);
40923 if(typeof this.maxValue == "string") {
40924 this.maxValue = this.parseDate(this.maxValue);
40926 this.ddMatch = null;
40927 if(this.disabledDates){
40928 var dd = this.disabledDates;
40930 for(var i = 0; i < dd.length; i++){
40932 if(i != dd.length-1) {
40936 this.ddMatch = new RegExp(re + ")");
40940 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40942 * @cfg {String} format
40943 * The default date format string which can be overriden for localization support. The format must be
40944 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40948 * @cfg {String} altFormats
40949 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40950 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40952 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40954 * @cfg {Array} disabledDays
40955 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40957 disabledDays : [0,1,2,3,4,5,6],
40959 * @cfg {String} disabledDaysText
40960 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40962 disabledDaysText : "Disabled",
40964 * @cfg {Array} disabledDates
40965 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40966 * expression so they are very powerful. Some examples:
40968 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40969 * <li>["03/08", "09/16"] would disable those days for every year</li>
40970 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40971 * <li>["03/../2006"] would disable every day in March 2006</li>
40972 * <li>["^03"] would disable every day in every March</li>
40974 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40975 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40977 disabledDates : null,
40979 * @cfg {String} disabledDatesText
40980 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40982 disabledDatesText : "Disabled",
40984 * @cfg {Date/String} minValue
40985 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40986 * valid format (defaults to null).
40990 * @cfg {Date/String} maxValue
40991 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40992 * valid format (defaults to null).
40996 * @cfg {String} minText
40997 * The error text to display when the date in the cell is before minValue (defaults to
40998 * 'The date in this field must be after {minValue}').
41000 minText : "The date in this field must be equal to or after {0}",
41002 * @cfg {String} maxTextf
41003 * The error text to display when the date in the cell is after maxValue (defaults to
41004 * 'The date in this field must be before {maxValue}').
41006 maxText : "The date in this field must be equal to or before {0}",
41008 * @cfg {String} invalidText
41009 * The error text to display when the date in the field is invalid (defaults to
41010 * '{value} is not a valid date - it must be in the format {format}').
41012 invalidText : "{0} is not a valid date - it must be in the format {1}",
41014 * @cfg {String} triggerClass
41015 * An additional CSS class used to style the trigger button. The trigger will always get the
41016 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41017 * which displays a calendar icon).
41019 triggerClass : 'x-form-date-trigger',
41023 * @cfg {Boolean} useIso
41024 * if enabled, then the date field will use a hidden field to store the
41025 * real value as iso formated date. default (true)
41029 * @cfg {String/Object} autoCreate
41030 * A DomHelper element spec, or true for a default element spec (defaults to
41031 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41034 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
41037 hiddenField: false,
41039 hideMonthPicker : false,
41041 onRender : function(ct, position)
41043 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
41045 this.el.dom.removeAttribute('name');
41046 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41048 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41049 // prevent input submission
41050 this.hiddenName = this.name;
41057 validateValue : function(value)
41059 value = this.formatDate(value);
41060 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41063 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41066 var svalue = value;
41067 value = this.parseDate(value);
41069 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41072 var time = value.getTime();
41073 if(this.minValue && time < this.minValue.getTime()){
41074 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41077 if(this.maxValue && time > this.maxValue.getTime()){
41078 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41081 /*if(this.disabledDays){
41082 var day = value.getDay();
41083 for(var i = 0; i < this.disabledDays.length; i++) {
41084 if(day === this.disabledDays[i]){
41085 this.markInvalid(this.disabledDaysText);
41091 var fvalue = this.formatDate(value);
41092 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41093 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41101 // Provides logic to override the default TriggerField.validateBlur which just returns true
41102 validateBlur : function(){
41103 return !this.menu || !this.menu.isVisible();
41107 * Returns the current date value of the date field.
41108 * @return {Date} The date value
41110 getValue : function(){
41114 return this.hiddenField ?
41115 this.hiddenField.value :
41116 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41120 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41121 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41122 * (the default format used is "m/d/y").
41125 //All of these calls set the same date value (May 4, 2006)
41127 //Pass a date object:
41128 var dt = new Date('5/4/06');
41129 monthField.setValue(dt);
41131 //Pass a date string (default format):
41132 monthField.setValue('5/4/06');
41134 //Pass a date string (custom format):
41135 monthField.format = 'Y-m-d';
41136 monthField.setValue('2006-5-4');
41138 * @param {String/Date} date The date or valid date string
41140 setValue : function(date){
41141 Roo.log('month setValue' + date);
41142 // can only be first of month..
41144 var val = this.parseDate(date);
41146 if (this.hiddenField) {
41147 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41149 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41150 this.value = this.parseDate(date);
41154 parseDate : function(value){
41155 if(!value || value instanceof Date){
41156 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41159 var v = Date.parseDate(value, this.format);
41160 if (!v && this.useIso) {
41161 v = Date.parseDate(value, 'Y-m-d');
41165 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41169 if(!v && this.altFormats){
41170 if(!this.altFormatsArray){
41171 this.altFormatsArray = this.altFormats.split("|");
41173 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41174 v = Date.parseDate(value, this.altFormatsArray[i]);
41181 formatDate : function(date, fmt){
41182 return (!date || !(date instanceof Date)) ?
41183 date : date.dateFormat(fmt || this.format);
41188 select: function(m, d){
41190 this.fireEvent('select', this, d);
41192 show : function(){ // retain focus styling
41196 this.focus.defer(10, this);
41197 var ml = this.menuListeners;
41198 this.menu.un("select", ml.select, this);
41199 this.menu.un("show", ml.show, this);
41200 this.menu.un("hide", ml.hide, this);
41204 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41205 onTriggerClick : function(){
41209 if(this.menu == null){
41210 this.menu = new Roo.menu.DateMenu();
41214 Roo.apply(this.menu.picker, {
41216 showClear: this.allowBlank,
41217 minDate : this.minValue,
41218 maxDate : this.maxValue,
41219 disabledDatesRE : this.ddMatch,
41220 disabledDatesText : this.disabledDatesText,
41222 format : this.useIso ? 'Y-m-d' : this.format,
41223 minText : String.format(this.minText, this.formatDate(this.minValue)),
41224 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41227 this.menu.on(Roo.apply({}, this.menuListeners, {
41235 // hide month picker get's called when we called by 'before hide';
41237 var ignorehide = true;
41238 p.hideMonthPicker = function(disableAnim){
41242 if(this.monthPicker){
41243 Roo.log("hideMonthPicker called");
41244 if(disableAnim === true){
41245 this.monthPicker.hide();
41247 this.monthPicker.slideOut('t', {duration:.2});
41248 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41249 p.fireEvent("select", this, this.value);
41255 Roo.log('picker set value');
41256 Roo.log(this.getValue());
41257 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41258 m.show(this.el, 'tl-bl?');
41259 ignorehide = false;
41260 // this will trigger hideMonthPicker..
41263 // hidden the day picker
41264 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41270 p.showMonthPicker.defer(100, p);
41276 beforeBlur : function(){
41277 var v = this.parseDate(this.getRawValue());
41283 /** @cfg {Boolean} grow @hide */
41284 /** @cfg {Number} growMin @hide */
41285 /** @cfg {Number} growMax @hide */
41292 * Ext JS Library 1.1.1
41293 * Copyright(c) 2006-2007, Ext JS, LLC.
41295 * Originally Released Under LGPL - original licence link has changed is not relivant.
41298 * <script type="text/javascript">
41303 * @class Roo.form.ComboBox
41304 * @extends Roo.form.TriggerField
41305 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41307 * Create a new ComboBox.
41308 * @param {Object} config Configuration options
41310 Roo.form.ComboBox = function(config){
41311 Roo.form.ComboBox.superclass.constructor.call(this, config);
41315 * Fires when the dropdown list is expanded
41316 * @param {Roo.form.ComboBox} combo This combo box
41321 * Fires when the dropdown list is collapsed
41322 * @param {Roo.form.ComboBox} combo This combo box
41326 * @event beforeselect
41327 * Fires before a list item is selected. Return false to cancel the selection.
41328 * @param {Roo.form.ComboBox} combo This combo box
41329 * @param {Roo.data.Record} record The data record returned from the underlying store
41330 * @param {Number} index The index of the selected item in the dropdown list
41332 'beforeselect' : true,
41335 * Fires when a list item is selected
41336 * @param {Roo.form.ComboBox} combo This combo box
41337 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41338 * @param {Number} index The index of the selected item in the dropdown list
41342 * @event beforequery
41343 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41344 * The event object passed has these properties:
41345 * @param {Roo.form.ComboBox} combo This combo box
41346 * @param {String} query The query
41347 * @param {Boolean} forceAll true to force "all" query
41348 * @param {Boolean} cancel true to cancel the query
41349 * @param {Object} e The query event object
41351 'beforequery': true,
41354 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41355 * @param {Roo.form.ComboBox} combo This combo box
41360 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41361 * @param {Roo.form.ComboBox} combo This combo box
41362 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41368 if(this.transform){
41369 this.allowDomMove = false;
41370 var s = Roo.getDom(this.transform);
41371 if(!this.hiddenName){
41372 this.hiddenName = s.name;
41375 this.mode = 'local';
41376 var d = [], opts = s.options;
41377 for(var i = 0, len = opts.length;i < len; i++){
41379 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41381 this.value = value;
41383 d.push([value, o.text]);
41385 this.store = new Roo.data.SimpleStore({
41387 fields: ['value', 'text'],
41390 this.valueField = 'value';
41391 this.displayField = 'text';
41393 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41394 if(!this.lazyRender){
41395 this.target = true;
41396 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41397 s.parentNode.removeChild(s); // remove it
41398 this.render(this.el.parentNode);
41400 s.parentNode.removeChild(s); // remove it
41405 this.store = Roo.factory(this.store, Roo.data);
41408 this.selectedIndex = -1;
41409 if(this.mode == 'local'){
41410 if(config.queryDelay === undefined){
41411 this.queryDelay = 10;
41413 if(config.minChars === undefined){
41419 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41421 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41424 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41425 * rendering into an Roo.Editor, defaults to false)
41428 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41429 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41432 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41435 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41436 * the dropdown list (defaults to undefined, with no header element)
41440 * @cfg {String/Roo.Template} tpl The template to use to render the output
41444 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41446 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41448 listWidth: undefined,
41450 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41451 * mode = 'remote' or 'text' if mode = 'local')
41453 displayField: undefined,
41455 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41456 * mode = 'remote' or 'value' if mode = 'local').
41457 * Note: use of a valueField requires the user make a selection
41458 * in order for a value to be mapped.
41460 valueField: undefined,
41464 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41465 * field's data value (defaults to the underlying DOM element's name)
41467 hiddenName: undefined,
41469 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41473 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41475 selectedClass: 'x-combo-selected',
41477 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41478 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41479 * which displays a downward arrow icon).
41481 triggerClass : 'x-form-arrow-trigger',
41483 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41487 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41488 * anchor positions (defaults to 'tl-bl')
41490 listAlign: 'tl-bl?',
41492 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41496 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41497 * query specified by the allQuery config option (defaults to 'query')
41499 triggerAction: 'query',
41501 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41502 * (defaults to 4, does not apply if editable = false)
41506 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41507 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41511 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41512 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41516 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41517 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41521 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41522 * when editable = true (defaults to false)
41524 selectOnFocus:false,
41526 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41528 queryParam: 'query',
41530 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41531 * when mode = 'remote' (defaults to 'Loading...')
41533 loadingText: 'Loading...',
41535 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41539 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41543 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41544 * traditional select (defaults to true)
41548 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41552 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41556 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41557 * listWidth has a higher value)
41561 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41562 * allow the user to set arbitrary text into the field (defaults to false)
41564 forceSelection:false,
41566 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41567 * if typeAhead = true (defaults to 250)
41569 typeAheadDelay : 250,
41571 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41572 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41574 valueNotFoundText : undefined,
41576 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41578 blockFocus : false,
41581 * @cfg {Boolean} disableClear Disable showing of clear button.
41583 disableClear : false,
41585 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41587 alwaysQuery : false,
41593 // element that contains real text value.. (when hidden is used..)
41596 onRender : function(ct, position)
41598 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41600 if(this.hiddenName){
41601 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41603 this.hiddenField.value =
41604 this.hiddenValue !== undefined ? this.hiddenValue :
41605 this.value !== undefined ? this.value : '';
41607 // prevent input submission
41608 this.el.dom.removeAttribute('name');
41614 this.el.dom.setAttribute('autocomplete', 'off');
41617 var cls = 'x-combo-list';
41619 this.list = new Roo.Layer({
41620 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41623 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41624 this.list.setWidth(lw);
41625 this.list.swallowEvent('mousewheel');
41626 this.assetHeight = 0;
41629 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41630 this.assetHeight += this.header.getHeight();
41633 this.innerList = this.list.createChild({cls:cls+'-inner'});
41634 this.innerList.on('mouseover', this.onViewOver, this);
41635 this.innerList.on('mousemove', this.onViewMove, this);
41636 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41638 if(this.allowBlank && !this.pageSize && !this.disableClear){
41639 this.footer = this.list.createChild({cls:cls+'-ft'});
41640 this.pageTb = new Roo.Toolbar(this.footer);
41644 this.footer = this.list.createChild({cls:cls+'-ft'});
41645 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41646 {pageSize: this.pageSize});
41650 if (this.pageTb && this.allowBlank && !this.disableClear) {
41652 this.pageTb.add(new Roo.Toolbar.Fill(), {
41653 cls: 'x-btn-icon x-btn-clear',
41655 handler: function()
41658 _this.clearValue();
41659 _this.onSelect(false, -1);
41664 this.assetHeight += this.footer.getHeight();
41669 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41672 this.view = new Roo.View(this.innerList, this.tpl, {
41675 selectedClass: this.selectedClass
41678 this.view.on('click', this.onViewClick, this);
41680 this.store.on('beforeload', this.onBeforeLoad, this);
41681 this.store.on('load', this.onLoad, this);
41682 this.store.on('loadexception', this.onLoadException, this);
41684 if(this.resizable){
41685 this.resizer = new Roo.Resizable(this.list, {
41686 pinned:true, handles:'se'
41688 this.resizer.on('resize', function(r, w, h){
41689 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41690 this.listWidth = w;
41691 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41692 this.restrictHeight();
41694 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41696 if(!this.editable){
41697 this.editable = true;
41698 this.setEditable(false);
41702 if (typeof(this.events.add.listeners) != 'undefined') {
41704 this.addicon = this.wrap.createChild(
41705 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41707 this.addicon.on('click', function(e) {
41708 this.fireEvent('add', this);
41711 if (typeof(this.events.edit.listeners) != 'undefined') {
41713 this.editicon = this.wrap.createChild(
41714 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41715 if (this.addicon) {
41716 this.editicon.setStyle('margin-left', '40px');
41718 this.editicon.on('click', function(e) {
41720 // we fire even if inothing is selected..
41721 this.fireEvent('edit', this, this.lastData );
41731 initEvents : function(){
41732 Roo.form.ComboBox.superclass.initEvents.call(this);
41734 this.keyNav = new Roo.KeyNav(this.el, {
41735 "up" : function(e){
41736 this.inKeyMode = true;
41740 "down" : function(e){
41741 if(!this.isExpanded()){
41742 this.onTriggerClick();
41744 this.inKeyMode = true;
41749 "enter" : function(e){
41750 this.onViewClick();
41754 "esc" : function(e){
41758 "tab" : function(e){
41759 this.onViewClick(false);
41760 this.fireEvent("specialkey", this, e);
41766 doRelay : function(foo, bar, hname){
41767 if(hname == 'down' || this.scope.isExpanded()){
41768 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41775 this.queryDelay = Math.max(this.queryDelay || 10,
41776 this.mode == 'local' ? 10 : 250);
41777 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41778 if(this.typeAhead){
41779 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41781 if(this.editable !== false){
41782 this.el.on("keyup", this.onKeyUp, this);
41784 if(this.forceSelection){
41785 this.on('blur', this.doForce, this);
41789 onDestroy : function(){
41791 this.view.setStore(null);
41792 this.view.el.removeAllListeners();
41793 this.view.el.remove();
41794 this.view.purgeListeners();
41797 this.list.destroy();
41800 this.store.un('beforeload', this.onBeforeLoad, this);
41801 this.store.un('load', this.onLoad, this);
41802 this.store.un('loadexception', this.onLoadException, this);
41804 Roo.form.ComboBox.superclass.onDestroy.call(this);
41808 fireKey : function(e){
41809 if(e.isNavKeyPress() && !this.list.isVisible()){
41810 this.fireEvent("specialkey", this, e);
41815 onResize: function(w, h){
41816 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41818 if(typeof w != 'number'){
41819 // we do not handle it!?!?
41822 var tw = this.trigger.getWidth();
41823 tw += this.addicon ? this.addicon.getWidth() : 0;
41824 tw += this.editicon ? this.editicon.getWidth() : 0;
41826 this.el.setWidth( this.adjustWidth('input', x));
41828 this.trigger.setStyle('left', x+'px');
41830 if(this.list && this.listWidth === undefined){
41831 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41832 this.list.setWidth(lw);
41833 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41841 * Allow or prevent the user from directly editing the field text. If false is passed,
41842 * the user will only be able to select from the items defined in the dropdown list. This method
41843 * is the runtime equivalent of setting the 'editable' config option at config time.
41844 * @param {Boolean} value True to allow the user to directly edit the field text
41846 setEditable : function(value){
41847 if(value == this.editable){
41850 this.editable = value;
41852 this.el.dom.setAttribute('readOnly', true);
41853 this.el.on('mousedown', this.onTriggerClick, this);
41854 this.el.addClass('x-combo-noedit');
41856 this.el.dom.setAttribute('readOnly', false);
41857 this.el.un('mousedown', this.onTriggerClick, this);
41858 this.el.removeClass('x-combo-noedit');
41863 onBeforeLoad : function(){
41864 if(!this.hasFocus){
41867 this.innerList.update(this.loadingText ?
41868 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41869 this.restrictHeight();
41870 this.selectedIndex = -1;
41874 onLoad : function(){
41875 if(!this.hasFocus){
41878 if(this.store.getCount() > 0){
41880 this.restrictHeight();
41881 if(this.lastQuery == this.allQuery){
41883 this.el.dom.select();
41885 if(!this.selectByValue(this.value, true)){
41886 this.select(0, true);
41890 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41891 this.taTask.delay(this.typeAheadDelay);
41895 this.onEmptyResults();
41900 onLoadException : function()
41903 Roo.log(this.store.reader.jsonData);
41904 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41905 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41911 onTypeAhead : function(){
41912 if(this.store.getCount() > 0){
41913 var r = this.store.getAt(0);
41914 var newValue = r.data[this.displayField];
41915 var len = newValue.length;
41916 var selStart = this.getRawValue().length;
41917 if(selStart != len){
41918 this.setRawValue(newValue);
41919 this.selectText(selStart, newValue.length);
41925 onSelect : function(record, index){
41926 if(this.fireEvent('beforeselect', this, record, index) !== false){
41927 this.setFromData(index > -1 ? record.data : false);
41929 this.fireEvent('select', this, record, index);
41934 * Returns the currently selected field value or empty string if no value is set.
41935 * @return {String} value The selected value
41937 getValue : function(){
41938 if(this.valueField){
41939 return typeof this.value != 'undefined' ? this.value : '';
41941 return Roo.form.ComboBox.superclass.getValue.call(this);
41945 * Clears any text/value currently set in the field
41947 clearValue : function(){
41948 if(this.hiddenField){
41949 this.hiddenField.value = '';
41952 this.setRawValue('');
41953 this.lastSelectionText = '';
41958 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41959 * will be displayed in the field. If the value does not match the data value of an existing item,
41960 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41961 * Otherwise the field will be blank (although the value will still be set).
41962 * @param {String} value The value to match
41964 setValue : function(v){
41966 if(this.valueField){
41967 var r = this.findRecord(this.valueField, v);
41969 text = r.data[this.displayField];
41970 }else if(this.valueNotFoundText !== undefined){
41971 text = this.valueNotFoundText;
41974 this.lastSelectionText = text;
41975 if(this.hiddenField){
41976 this.hiddenField.value = v;
41978 Roo.form.ComboBox.superclass.setValue.call(this, text);
41982 * @property {Object} the last set data for the element
41987 * Sets the value of the field based on a object which is related to the record format for the store.
41988 * @param {Object} value the value to set as. or false on reset?
41990 setFromData : function(o){
41991 var dv = ''; // display value
41992 var vv = ''; // value value..
41994 if (this.displayField) {
41995 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41997 // this is an error condition!!!
41998 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
42001 if(this.valueField){
42002 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
42004 if(this.hiddenField){
42005 this.hiddenField.value = vv;
42007 this.lastSelectionText = dv;
42008 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42012 // no hidden field.. - we store the value in 'value', but still display
42013 // display field!!!!
42014 this.lastSelectionText = dv;
42015 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42021 reset : function(){
42022 // overridden so that last data is reset..
42023 this.setValue(this.resetValue);
42024 this.originalValue = this.getValue();
42025 this.clearInvalid();
42026 this.lastData = false;
42028 this.view.clearSelections();
42032 findRecord : function(prop, value){
42034 if(this.store.getCount() > 0){
42035 this.store.each(function(r){
42036 if(r.data[prop] == value){
42046 getName: function()
42048 // returns hidden if it's set..
42049 if (!this.rendered) {return ''};
42050 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42054 onViewMove : function(e, t){
42055 this.inKeyMode = false;
42059 onViewOver : function(e, t){
42060 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42063 var item = this.view.findItemFromChild(t);
42065 var index = this.view.indexOf(item);
42066 this.select(index, false);
42071 onViewClick : function(doFocus)
42073 var index = this.view.getSelectedIndexes()[0];
42074 var r = this.store.getAt(index);
42076 this.onSelect(r, index);
42078 if(doFocus !== false && !this.blockFocus){
42084 restrictHeight : function(){
42085 this.innerList.dom.style.height = '';
42086 var inner = this.innerList.dom;
42087 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42088 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42089 this.list.beginUpdate();
42090 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42091 this.list.alignTo(this.el, this.listAlign);
42092 this.list.endUpdate();
42096 onEmptyResults : function(){
42101 * Returns true if the dropdown list is expanded, else false.
42103 isExpanded : function(){
42104 return this.list.isVisible();
42108 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42109 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42110 * @param {String} value The data value of the item to select
42111 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42112 * selected item if it is not currently in view (defaults to true)
42113 * @return {Boolean} True if the value matched an item in the list, else false
42115 selectByValue : function(v, scrollIntoView){
42116 if(v !== undefined && v !== null){
42117 var r = this.findRecord(this.valueField || this.displayField, v);
42119 this.select(this.store.indexOf(r), scrollIntoView);
42127 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42128 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42129 * @param {Number} index The zero-based index of the list item to select
42130 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42131 * selected item if it is not currently in view (defaults to true)
42133 select : function(index, scrollIntoView){
42134 this.selectedIndex = index;
42135 this.view.select(index);
42136 if(scrollIntoView !== false){
42137 var el = this.view.getNode(index);
42139 this.innerList.scrollChildIntoView(el, false);
42145 selectNext : function(){
42146 var ct = this.store.getCount();
42148 if(this.selectedIndex == -1){
42150 }else if(this.selectedIndex < ct-1){
42151 this.select(this.selectedIndex+1);
42157 selectPrev : function(){
42158 var ct = this.store.getCount();
42160 if(this.selectedIndex == -1){
42162 }else if(this.selectedIndex != 0){
42163 this.select(this.selectedIndex-1);
42169 onKeyUp : function(e){
42170 if(this.editable !== false && !e.isSpecialKey()){
42171 this.lastKey = e.getKey();
42172 this.dqTask.delay(this.queryDelay);
42177 validateBlur : function(){
42178 return !this.list || !this.list.isVisible();
42182 initQuery : function(){
42183 this.doQuery(this.getRawValue());
42187 doForce : function(){
42188 if(this.el.dom.value.length > 0){
42189 this.el.dom.value =
42190 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42196 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42197 * query allowing the query action to be canceled if needed.
42198 * @param {String} query The SQL query to execute
42199 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42200 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42201 * saved in the current store (defaults to false)
42203 doQuery : function(q, forceAll){
42204 if(q === undefined || q === null){
42209 forceAll: forceAll,
42213 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42217 forceAll = qe.forceAll;
42218 if(forceAll === true || (q.length >= this.minChars)){
42219 if(this.lastQuery != q || this.alwaysQuery){
42220 this.lastQuery = q;
42221 if(this.mode == 'local'){
42222 this.selectedIndex = -1;
42224 this.store.clearFilter();
42226 this.store.filter(this.displayField, q);
42230 this.store.baseParams[this.queryParam] = q;
42232 params: this.getParams(q)
42237 this.selectedIndex = -1;
42244 getParams : function(q){
42246 //p[this.queryParam] = q;
42249 p.limit = this.pageSize;
42255 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42257 collapse : function(){
42258 if(!this.isExpanded()){
42262 Roo.get(document).un('mousedown', this.collapseIf, this);
42263 Roo.get(document).un('mousewheel', this.collapseIf, this);
42264 if (!this.editable) {
42265 Roo.get(document).un('keydown', this.listKeyPress, this);
42267 this.fireEvent('collapse', this);
42271 collapseIf : function(e){
42272 if(!e.within(this.wrap) && !e.within(this.list)){
42278 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42280 expand : function(){
42281 if(this.isExpanded() || !this.hasFocus){
42284 this.list.alignTo(this.el, this.listAlign);
42286 Roo.get(document).on('mousedown', this.collapseIf, this);
42287 Roo.get(document).on('mousewheel', this.collapseIf, this);
42288 if (!this.editable) {
42289 Roo.get(document).on('keydown', this.listKeyPress, this);
42292 this.fireEvent('expand', this);
42296 // Implements the default empty TriggerField.onTriggerClick function
42297 onTriggerClick : function(){
42301 if(this.isExpanded()){
42303 if (!this.blockFocus) {
42308 this.hasFocus = true;
42309 if(this.triggerAction == 'all') {
42310 this.doQuery(this.allQuery, true);
42312 this.doQuery(this.getRawValue());
42314 if (!this.blockFocus) {
42319 listKeyPress : function(e)
42321 //Roo.log('listkeypress');
42322 // scroll to first matching element based on key pres..
42323 if (e.isSpecialKey()) {
42326 var k = String.fromCharCode(e.getKey()).toUpperCase();
42329 var csel = this.view.getSelectedNodes();
42330 var cselitem = false;
42332 var ix = this.view.indexOf(csel[0]);
42333 cselitem = this.store.getAt(ix);
42334 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42340 this.store.each(function(v) {
42342 // start at existing selection.
42343 if (cselitem.id == v.id) {
42349 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42350 match = this.store.indexOf(v);
42355 if (match === false) {
42356 return true; // no more action?
42359 this.view.select(match);
42360 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42361 sn.scrollIntoView(sn.dom.parentNode, false);
42365 * @cfg {Boolean} grow
42369 * @cfg {Number} growMin
42373 * @cfg {Number} growMax
42381 * Copyright(c) 2010-2012, Roo J Solutions Limited
42388 * @class Roo.form.ComboBoxArray
42389 * @extends Roo.form.TextField
42390 * A facebook style adder... for lists of email / people / countries etc...
42391 * pick multiple items from a combo box, and shows each one.
42393 * Fred [x] Brian [x] [Pick another |v]
42396 * For this to work: it needs various extra information
42397 * - normal combo problay has
42399 * + displayField, valueField
42401 * For our purpose...
42404 * If we change from 'extends' to wrapping...
42411 * Create a new ComboBoxArray.
42412 * @param {Object} config Configuration options
42416 Roo.form.ComboBoxArray = function(config)
42420 * @event beforeremove
42421 * Fires before remove the value from the list
42422 * @param {Roo.form.ComboBoxArray} _self This combo box array
42423 * @param {Roo.form.ComboBoxArray.Item} item removed item
42425 'beforeremove' : true,
42428 * Fires when remove the value from the list
42429 * @param {Roo.form.ComboBoxArray} _self This combo box array
42430 * @param {Roo.form.ComboBoxArray.Item} item removed item
42437 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42439 this.items = new Roo.util.MixedCollection(false);
42441 // construct the child combo...
42451 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42454 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42459 // behavies liek a hiddne field
42460 inputType: 'hidden',
42462 * @cfg {Number} width The width of the box that displays the selected element
42469 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42473 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42475 hiddenName : false,
42477 * @cfg {String} seperator The value seperator normally ','
42481 // private the array of items that are displayed..
42483 // private - the hidden field el.
42485 // private - the filed el..
42488 //validateValue : function() { return true; }, // all values are ok!
42489 //onAddClick: function() { },
42491 onRender : function(ct, position)
42494 // create the standard hidden element
42495 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42498 // give fake names to child combo;
42499 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42500 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42502 this.combo = Roo.factory(this.combo, Roo.form);
42503 this.combo.onRender(ct, position);
42504 if (typeof(this.combo.width) != 'undefined') {
42505 this.combo.onResize(this.combo.width,0);
42508 this.combo.initEvents();
42510 // assigned so form know we need to do this..
42511 this.store = this.combo.store;
42512 this.valueField = this.combo.valueField;
42513 this.displayField = this.combo.displayField ;
42516 this.combo.wrap.addClass('x-cbarray-grp');
42518 var cbwrap = this.combo.wrap.createChild(
42519 {tag: 'div', cls: 'x-cbarray-cb'},
42524 this.hiddenEl = this.combo.wrap.createChild({
42525 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42527 this.el = this.combo.wrap.createChild({
42528 tag: 'input', type:'hidden' , name: this.name, value : ''
42530 // this.el.dom.removeAttribute("name");
42533 this.outerWrap = this.combo.wrap;
42534 this.wrap = cbwrap;
42536 this.outerWrap.setWidth(this.width);
42537 this.outerWrap.dom.removeChild(this.el.dom);
42539 this.wrap.dom.appendChild(this.el.dom);
42540 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42541 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42543 this.combo.trigger.setStyle('position','relative');
42544 this.combo.trigger.setStyle('left', '0px');
42545 this.combo.trigger.setStyle('top', '2px');
42547 this.combo.el.setStyle('vertical-align', 'text-bottom');
42549 //this.trigger.setStyle('vertical-align', 'top');
42551 // this should use the code from combo really... on('add' ....)
42555 this.adder = this.outerWrap.createChild(
42556 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42558 this.adder.on('click', function(e) {
42559 _t.fireEvent('adderclick', this, e);
42563 //this.adder.on('click', this.onAddClick, _t);
42566 this.combo.on('select', function(cb, rec, ix) {
42567 this.addItem(rec.data);
42570 cb.el.dom.value = '';
42571 //cb.lastData = rec.data;
42580 getName: function()
42582 // returns hidden if it's set..
42583 if (!this.rendered) {return ''};
42584 return this.hiddenName ? this.hiddenName : this.name;
42589 onResize: function(w, h){
42592 // not sure if this is needed..
42593 //this.combo.onResize(w,h);
42595 if(typeof w != 'number'){
42596 // we do not handle it!?!?
42599 var tw = this.combo.trigger.getWidth();
42600 tw += this.addicon ? this.addicon.getWidth() : 0;
42601 tw += this.editicon ? this.editicon.getWidth() : 0;
42603 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42605 this.combo.trigger.setStyle('left', '0px');
42607 if(this.list && this.listWidth === undefined){
42608 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42609 this.list.setWidth(lw);
42610 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42617 addItem: function(rec)
42619 var valueField = this.combo.valueField;
42620 var displayField = this.combo.displayField;
42622 if (this.items.indexOfKey(rec[valueField]) > -1) {
42623 //console.log("GOT " + rec.data.id);
42627 var x = new Roo.form.ComboBoxArray.Item({
42628 //id : rec[this.idField],
42630 displayField : displayField ,
42631 tipField : displayField ,
42635 this.items.add(rec[valueField],x);
42636 // add it before the element..
42637 this.updateHiddenEl();
42638 x.render(this.outerWrap, this.wrap.dom);
42639 // add the image handler..
42642 updateHiddenEl : function()
42645 if (!this.hiddenEl) {
42649 var idField = this.combo.valueField;
42651 this.items.each(function(f) {
42652 ar.push(f.data[idField]);
42654 this.hiddenEl.dom.value = ar.join(this.seperator);
42660 this.items.clear();
42662 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42666 this.el.dom.value = '';
42667 if (this.hiddenEl) {
42668 this.hiddenEl.dom.value = '';
42672 getValue: function()
42674 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42676 setValue: function(v) // not a valid action - must use addItems..
42681 if (this.store.isLocal && (typeof(v) == 'string')) {
42682 // then we can use the store to find the values..
42683 // comma seperated at present.. this needs to allow JSON based encoding..
42684 this.hiddenEl.value = v;
42686 Roo.each(v.split(this.seperator), function(k) {
42687 Roo.log("CHECK " + this.valueField + ',' + k);
42688 var li = this.store.query(this.valueField, k);
42693 add[this.valueField] = k;
42694 add[this.displayField] = li.item(0).data[this.displayField];
42700 if (typeof(v) == 'object' ) {
42701 // then let's assume it's an array of objects..
42702 Roo.each(v, function(l) {
42704 if (typeof(l) == 'string') {
42706 add[this.valueField] = l;
42707 add[this.displayField] = l
42716 setFromData: function(v)
42718 // this recieves an object, if setValues is called.
42720 this.el.dom.value = v[this.displayField];
42721 this.hiddenEl.dom.value = v[this.valueField];
42722 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42725 var kv = v[this.valueField];
42726 var dv = v[this.displayField];
42727 kv = typeof(kv) != 'string' ? '' : kv;
42728 dv = typeof(dv) != 'string' ? '' : dv;
42731 var keys = kv.split(this.seperator);
42732 var display = dv.split(this.seperator);
42733 for (var i = 0 ; i < keys.length; i++) {
42735 add[this.valueField] = keys[i];
42736 add[this.displayField] = display[i];
42744 * Validates the combox array value
42745 * @return {Boolean} True if the value is valid, else false
42747 validate : function(){
42748 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42749 this.clearInvalid();
42755 validateValue : function(value){
42756 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42764 isDirty : function() {
42765 if(this.disabled) {
42770 var d = Roo.decode(String(this.originalValue));
42772 return String(this.getValue()) !== String(this.originalValue);
42775 var originalValue = [];
42777 for (var i = 0; i < d.length; i++){
42778 originalValue.push(d[i][this.valueField]);
42781 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42790 * @class Roo.form.ComboBoxArray.Item
42791 * @extends Roo.BoxComponent
42792 * A selected item in the list
42793 * Fred [x] Brian [x] [Pick another |v]
42796 * Create a new item.
42797 * @param {Object} config Configuration options
42800 Roo.form.ComboBoxArray.Item = function(config) {
42801 config.id = Roo.id();
42802 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42805 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42808 displayField : false,
42812 defaultAutoCreate : {
42814 cls: 'x-cbarray-item',
42821 src : Roo.BLANK_IMAGE_URL ,
42829 onRender : function(ct, position)
42831 Roo.form.Field.superclass.onRender.call(this, ct, position);
42834 var cfg = this.getAutoCreate();
42835 this.el = ct.createChild(cfg, position);
42838 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42840 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42841 this.cb.renderer(this.data) :
42842 String.format('{0}',this.data[this.displayField]);
42845 this.el.child('div').dom.setAttribute('qtip',
42846 String.format('{0}',this.data[this.tipField])
42849 this.el.child('img').on('click', this.remove, this);
42853 remove : function()
42855 if(this.cb.disabled){
42859 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42860 this.cb.items.remove(this);
42861 this.el.child('img').un('click', this.remove, this);
42863 this.cb.updateHiddenEl();
42865 this.cb.fireEvent('remove', this.cb, this);
42870 * RooJS Library 1.1.1
42871 * Copyright(c) 2008-2011 Alan Knowles
42878 * @class Roo.form.ComboNested
42879 * @extends Roo.form.ComboBox
42880 * A combobox for that allows selection of nested items in a list,
42895 * Create a new ComboNested
42896 * @param {Object} config Configuration options
42898 Roo.form.ComboNested = function(config){
42899 Roo.form.ComboCheck.superclass.constructor.call(this, config);
42900 // should verify some data...
42902 // hiddenName = required..
42903 // displayField = required
42904 // valudField == required
42905 var req= [ 'hiddenName', 'displayField', 'valueField' ];
42907 Roo.each(req, function(e) {
42908 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
42909 throw "Roo.form.ComboNested : missing value for: " + e;
42916 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
42919 * @config {Number} max Number of columns to show
42924 list : null, // the outermost div..
42925 innerLists : null, // the
42929 loadingChildren : false,
42931 onRender : function(ct, position)
42933 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
42935 if(this.hiddenName){
42936 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42938 this.hiddenField.value =
42939 this.hiddenValue !== undefined ? this.hiddenValue :
42940 this.value !== undefined ? this.value : '';
42942 // prevent input submission
42943 this.el.dom.removeAttribute('name');
42949 this.el.dom.setAttribute('autocomplete', 'off');
42952 var cls = 'x-combo-list';
42954 this.list = new Roo.Layer({
42955 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
42958 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
42959 this.list.setWidth(lw);
42960 this.list.swallowEvent('mousewheel');
42961 this.assetHeight = 0;
42964 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
42965 this.assetHeight += this.header.getHeight();
42967 this.innerLists = [];
42970 for (var i =0 ; i < this.maxColumns; i++) {
42971 this.onRenderList( cls, i);
42974 // always needs footer, as we are going to have an 'OK' button.
42975 this.footer = this.list.createChild({cls:cls+'-ft'});
42976 this.pageTb = new Roo.Toolbar(this.footer);
42981 handler: function()
42987 if ( this.allowBlank && !this.disableClear) {
42989 this.pageTb.add(new Roo.Toolbar.Fill(), {
42990 cls: 'x-btn-icon x-btn-clear',
42992 handler: function()
42995 _this.clearValue();
42996 _this.onSelect(false, -1);
43001 this.assetHeight += this.footer.getHeight();
43005 onRenderList : function ( cls, i)
43008 var lw = Math.floor(
43009 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43012 this.list.setWidth(lw); // default to '1'
43014 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
43015 //il.on('mouseover', this.onViewOver, this, { list: i });
43016 //il.on('mousemove', this.onViewMove, this, { list: i });
43018 il.setStyle({ 'overflow-x' : 'hidden'});
43021 this.tpl = new Roo.Template({
43022 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
43023 isEmpty: function (value, allValues) {
43025 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
43026 return dl ? 'has-children' : 'no-children'
43031 var store = this.store;
43033 store = new Roo.data.SimpleStore({
43034 //fields : this.store.reader.meta.fields,
43035 reader : this.store.reader,
43039 this.stores[i] = store;
43041 var view = this.views[i] = new Roo.View(
43047 selectedClass: this.selectedClass
43050 view.getEl().setWidth(lw);
43051 view.getEl().setStyle({
43052 position: i < 1 ? 'relative' : 'absolute',
43054 left: (i * lw ) + 'px',
43055 display : i > 0 ? 'none' : 'block'
43057 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
43058 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
43059 //view.on('click', this.onViewClick, this, { list : i });
43061 store.on('beforeload', this.onBeforeLoad, this);
43062 store.on('load', this.onLoad, this, { list : i});
43063 store.on('loadexception', this.onLoadException, this);
43065 // hide the other vies..
43071 restrictHeight : function()
43074 Roo.each(this.innerLists, function(il,i) {
43075 var el = this.views[i].getEl();
43076 el.dom.style.height = '';
43077 var inner = el.dom;
43078 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
43079 // only adjust heights on other ones..
43080 mh = Math.max(h, mh);
43083 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43084 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43091 this.list.beginUpdate();
43092 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43093 this.list.alignTo(this.el, this.listAlign);
43094 this.list.endUpdate();
43099 // -- store handlers..
43101 onBeforeLoad : function()
43103 if(!this.hasFocus){
43106 this.innerLists[0].update(this.loadingText ?
43107 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43108 this.restrictHeight();
43109 this.selectedIndex = -1;
43112 onLoad : function(a,b,c,d)
43114 if (!this.loadingChildren) {
43115 // then we are loading the top level. - hide the children
43116 for (var i = 1;i < this.views.length; i++) {
43117 this.views[i].getEl().setStyle({ display : 'none' });
43119 var lw = Math.floor(
43120 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43123 this.list.setWidth(lw); // default to '1'
43127 if(!this.hasFocus){
43131 if(this.store.getCount() > 0) {
43133 this.restrictHeight();
43135 this.onEmptyResults();
43138 if (!this.loadingChildren) {
43139 this.selectActive();
43142 this.stores[1].loadData([]);
43143 this.stores[2].loadData([]);
43152 onLoadException : function()
43155 Roo.log(this.store.reader.jsonData);
43156 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43157 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43162 // no cleaning of leading spaces on blur here.
43163 cleanLeadingSpace : function(e) { },
43166 onSelectChange : function (view, sels, opts )
43168 var ix = view.getSelectedIndexes();
43170 if (opts.list > this.maxColumns - 2) {
43171 if (view.store.getCount()< 1) {
43172 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43176 // used to clear ?? but if we are loading unselected
43177 this.setFromData(view.store.getAt(ix[0]).data);
43186 // this get's fired when trigger opens..
43187 // this.setFromData({});
43188 var str = this.stores[opts.list+1];
43189 str.data.clear(); // removeall wihtout the fire events..
43193 var rec = view.store.getAt(ix[0]);
43195 this.setFromData(rec.data);
43196 this.fireEvent('select', this, rec, ix[0]);
43198 var lw = Math.floor(
43200 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43201 ) / this.maxColumns
43203 this.loadingChildren = true;
43204 this.stores[opts.list+1].loadDataFromChildren( rec );
43205 this.loadingChildren = false;
43206 var dl = this.stores[opts.list+1]. getTotalCount();
43208 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43210 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43211 for (var i = opts.list+2; i < this.views.length;i++) {
43212 this.views[i].getEl().setStyle({ display : 'none' });
43215 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43216 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43218 if (this.isLoading) {
43219 // this.selectActive(opts.list);
43227 onDoubleClick : function()
43229 this.collapse(); //??
43237 recordToStack : function(store, prop, value, stack)
43239 var cstore = new Roo.data.SimpleStore({
43240 //fields : this.store.reader.meta.fields, // we need array reader.. for
43241 reader : this.store.reader,
43245 var record = false;
43247 if(store.getCount() < 1){
43250 store.each(function(r){
43251 if(r.data[prop] == value){
43256 if (r.data.cn && r.data.cn.length) {
43257 cstore.loadDataFromChildren( r);
43258 var cret = _this.recordToStack(cstore, prop, value, stack);
43259 if (cret !== false) {
43268 if (record == false) {
43271 stack.unshift(srec);
43276 * find the stack of stores that match our value.
43281 selectActive : function ()
43283 // if store is not loaded, then we will need to wait for that to happen first.
43285 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43286 for (var i = 0; i < stack.length; i++ ) {
43287 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43299 * Ext JS Library 1.1.1
43300 * Copyright(c) 2006-2007, Ext JS, LLC.
43302 * Originally Released Under LGPL - original licence link has changed is not relivant.
43305 * <script type="text/javascript">
43308 * @class Roo.form.Checkbox
43309 * @extends Roo.form.Field
43310 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43312 * Creates a new Checkbox
43313 * @param {Object} config Configuration options
43315 Roo.form.Checkbox = function(config){
43316 Roo.form.Checkbox.superclass.constructor.call(this, config);
43320 * Fires when the checkbox is checked or unchecked.
43321 * @param {Roo.form.Checkbox} this This checkbox
43322 * @param {Boolean} checked The new checked value
43328 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43330 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43332 focusClass : undefined,
43334 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43336 fieldClass: "x-form-field",
43338 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43342 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43343 * {tag: "input", type: "checkbox", autocomplete: "off"})
43345 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43347 * @cfg {String} boxLabel The text that appears beside the checkbox
43351 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43355 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43357 valueOff: '0', // value when not checked..
43359 actionMode : 'viewEl',
43362 itemCls : 'x-menu-check-item x-form-item',
43363 groupClass : 'x-menu-group-item',
43364 inputType : 'hidden',
43367 inSetChecked: false, // check that we are not calling self...
43369 inputElement: false, // real input element?
43370 basedOn: false, // ????
43372 isFormField: true, // not sure where this is needed!!!!
43374 onResize : function(){
43375 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43376 if(!this.boxLabel){
43377 this.el.alignTo(this.wrap, 'c-c');
43381 initEvents : function(){
43382 Roo.form.Checkbox.superclass.initEvents.call(this);
43383 this.el.on("click", this.onClick, this);
43384 this.el.on("change", this.onClick, this);
43388 getResizeEl : function(){
43392 getPositionEl : function(){
43397 onRender : function(ct, position){
43398 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43400 if(this.inputValue !== undefined){
43401 this.el.dom.value = this.inputValue;
43404 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43405 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43406 var viewEl = this.wrap.createChild({
43407 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43408 this.viewEl = viewEl;
43409 this.wrap.on('click', this.onClick, this);
43411 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43412 this.el.on('propertychange', this.setFromHidden, this); //ie
43417 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43418 // viewEl.on('click', this.onClick, this);
43420 //if(this.checked){
43421 this.setChecked(this.checked);
43423 //this.checked = this.el.dom;
43429 initValue : Roo.emptyFn,
43432 * Returns the checked state of the checkbox.
43433 * @return {Boolean} True if checked, else false
43435 getValue : function(){
43437 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43439 return this.valueOff;
43444 onClick : function(){
43445 if (this.disabled) {
43448 this.setChecked(!this.checked);
43450 //if(this.el.dom.checked != this.checked){
43451 // this.setValue(this.el.dom.checked);
43456 * Sets the checked state of the checkbox.
43457 * On is always based on a string comparison between inputValue and the param.
43458 * @param {Boolean/String} value - the value to set
43459 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43461 setValue : function(v,suppressEvent){
43464 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43465 //if(this.el && this.el.dom){
43466 // this.el.dom.checked = this.checked;
43467 // this.el.dom.defaultChecked = this.checked;
43469 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43470 //this.fireEvent("check", this, this.checked);
43473 setChecked : function(state,suppressEvent)
43475 if (this.inSetChecked) {
43476 this.checked = state;
43482 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43484 this.checked = state;
43485 if(suppressEvent !== true){
43486 this.fireEvent('check', this, state);
43488 this.inSetChecked = true;
43489 this.el.dom.value = state ? this.inputValue : this.valueOff;
43490 this.inSetChecked = false;
43493 // handle setting of hidden value by some other method!!?!?
43494 setFromHidden: function()
43499 //console.log("SET FROM HIDDEN");
43500 //alert('setFrom hidden');
43501 this.setValue(this.el.dom.value);
43504 onDestroy : function()
43507 Roo.get(this.viewEl).remove();
43510 Roo.form.Checkbox.superclass.onDestroy.call(this);
43513 setBoxLabel : function(str)
43515 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43520 * Ext JS Library 1.1.1
43521 * Copyright(c) 2006-2007, Ext JS, LLC.
43523 * Originally Released Under LGPL - original licence link has changed is not relivant.
43526 * <script type="text/javascript">
43530 * @class Roo.form.Radio
43531 * @extends Roo.form.Checkbox
43532 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43533 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43535 * Creates a new Radio
43536 * @param {Object} config Configuration options
43538 Roo.form.Radio = function(){
43539 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43541 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43542 inputType: 'radio',
43545 * If this radio is part of a group, it will return the selected value
43548 getGroupValue : function(){
43549 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43553 onRender : function(ct, position){
43554 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43556 if(this.inputValue !== undefined){
43557 this.el.dom.value = this.inputValue;
43560 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43561 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43562 //var viewEl = this.wrap.createChild({
43563 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43564 //this.viewEl = viewEl;
43565 //this.wrap.on('click', this.onClick, this);
43567 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43568 //this.el.on('propertychange', this.setFromHidden, this); //ie
43573 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43574 // viewEl.on('click', this.onClick, this);
43577 this.el.dom.checked = 'checked' ;
43583 });//<script type="text/javascript">
43586 * Based Ext JS Library 1.1.1
43587 * Copyright(c) 2006-2007, Ext JS, LLC.
43593 * @class Roo.HtmlEditorCore
43594 * @extends Roo.Component
43595 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43597 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43600 Roo.HtmlEditorCore = function(config){
43603 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43608 * @event initialize
43609 * Fires when the editor is fully initialized (including the iframe)
43610 * @param {Roo.HtmlEditorCore} this
43615 * Fires when the editor is first receives the focus. Any insertion must wait
43616 * until after this event.
43617 * @param {Roo.HtmlEditorCore} this
43621 * @event beforesync
43622 * Fires before the textarea is updated with content from the editor iframe. Return false
43623 * to cancel the sync.
43624 * @param {Roo.HtmlEditorCore} this
43625 * @param {String} html
43629 * @event beforepush
43630 * Fires before the iframe editor is updated with content from the textarea. Return false
43631 * to cancel the push.
43632 * @param {Roo.HtmlEditorCore} this
43633 * @param {String} html
43638 * Fires when the textarea is updated with content from the editor iframe.
43639 * @param {Roo.HtmlEditorCore} this
43640 * @param {String} html
43645 * Fires when the iframe editor is updated with content from the textarea.
43646 * @param {Roo.HtmlEditorCore} this
43647 * @param {String} html
43652 * @event editorevent
43653 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43654 * @param {Roo.HtmlEditorCore} this
43660 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43662 // defaults : white / black...
43663 this.applyBlacklists();
43670 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43674 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43680 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43685 * @cfg {Number} height (in pixels)
43689 * @cfg {Number} width (in pixels)
43694 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43697 stylesheets: false,
43702 // private properties
43703 validationEvent : false,
43705 initialized : false,
43707 sourceEditMode : false,
43708 onFocus : Roo.emptyFn,
43710 hideMode:'offsets',
43714 // blacklist + whitelisted elements..
43721 * Protected method that will not generally be called directly. It
43722 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43723 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43725 getDocMarkup : function(){
43729 // inherit styels from page...??
43730 if (this.stylesheets === false) {
43732 Roo.get(document.head).select('style').each(function(node) {
43733 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43736 Roo.get(document.head).select('link').each(function(node) {
43737 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43740 } else if (!this.stylesheets.length) {
43742 st = '<style type="text/css">' +
43743 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43746 for (var i in this.stylesheets) {
43747 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43752 st += '<style type="text/css">' +
43753 'IMG { cursor: pointer } ' +
43756 var cls = 'roo-htmleditor-body';
43758 if(this.bodyCls.length){
43759 cls += ' ' + this.bodyCls;
43762 return '<html><head>' + st +
43763 //<style type="text/css">' +
43764 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43766 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43770 onRender : function(ct, position)
43773 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43774 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43777 this.el.dom.style.border = '0 none';
43778 this.el.dom.setAttribute('tabIndex', -1);
43779 this.el.addClass('x-hidden hide');
43783 if(Roo.isIE){ // fix IE 1px bogus margin
43784 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43788 this.frameId = Roo.id();
43792 var iframe = this.owner.wrap.createChild({
43794 cls: 'form-control', // bootstrap..
43796 name: this.frameId,
43797 frameBorder : 'no',
43798 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43803 this.iframe = iframe.dom;
43805 this.assignDocWin();
43807 this.doc.designMode = 'on';
43810 this.doc.write(this.getDocMarkup());
43814 var task = { // must defer to wait for browser to be ready
43816 //console.log("run task?" + this.doc.readyState);
43817 this.assignDocWin();
43818 if(this.doc.body || this.doc.readyState == 'complete'){
43820 this.doc.designMode="on";
43824 Roo.TaskMgr.stop(task);
43825 this.initEditor.defer(10, this);
43832 Roo.TaskMgr.start(task);
43837 onResize : function(w, h)
43839 Roo.log('resize: ' +w + ',' + h );
43840 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43844 if(typeof w == 'number'){
43846 this.iframe.style.width = w + 'px';
43848 if(typeof h == 'number'){
43850 this.iframe.style.height = h + 'px';
43852 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43859 * Toggles the editor between standard and source edit mode.
43860 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43862 toggleSourceEdit : function(sourceEditMode){
43864 this.sourceEditMode = sourceEditMode === true;
43866 if(this.sourceEditMode){
43868 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43871 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43872 //this.iframe.className = '';
43875 //this.setSize(this.owner.wrap.getSize());
43876 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43883 * Protected method that will not generally be called directly. If you need/want
43884 * custom HTML cleanup, this is the method you should override.
43885 * @param {String} html The HTML to be cleaned
43886 * return {String} The cleaned HTML
43888 cleanHtml : function(html){
43889 html = String(html);
43890 if(html.length > 5){
43891 if(Roo.isSafari){ // strip safari nonsense
43892 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43895 if(html == ' '){
43902 * HTML Editor -> Textarea
43903 * Protected method that will not generally be called directly. Syncs the contents
43904 * of the editor iframe with the textarea.
43906 syncValue : function(){
43907 if(this.initialized){
43908 var bd = (this.doc.body || this.doc.documentElement);
43909 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43910 var html = bd.innerHTML;
43912 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43913 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43915 html = '<div style="'+m[0]+'">' + html + '</div>';
43918 html = this.cleanHtml(html);
43919 // fix up the special chars.. normaly like back quotes in word...
43920 // however we do not want to do this with chinese..
43921 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
43923 var cc = match.charCodeAt();
43925 // Get the character value, handling surrogate pairs
43926 if (match.length == 2) {
43927 // It's a surrogate pair, calculate the Unicode code point
43928 var high = match.charCodeAt(0) - 0xD800;
43929 var low = match.charCodeAt(1) - 0xDC00;
43930 cc = (high * 0x400) + low + 0x10000;
43932 (cc >= 0x4E00 && cc < 0xA000 ) ||
43933 (cc >= 0x3400 && cc < 0x4E00 ) ||
43934 (cc >= 0xf900 && cc < 0xfb00 )
43939 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
43940 return "&#" + cc + ";";
43947 if(this.owner.fireEvent('beforesync', this, html) !== false){
43948 this.el.dom.value = html;
43949 this.owner.fireEvent('sync', this, html);
43955 * Protected method that will not generally be called directly. Pushes the value of the textarea
43956 * into the iframe editor.
43958 pushValue : function(){
43959 if(this.initialized){
43960 var v = this.el.dom.value.trim();
43962 // if(v.length < 1){
43966 if(this.owner.fireEvent('beforepush', this, v) !== false){
43967 var d = (this.doc.body || this.doc.documentElement);
43969 this.cleanUpPaste();
43970 this.el.dom.value = d.innerHTML;
43971 this.owner.fireEvent('push', this, v);
43977 deferFocus : function(){
43978 this.focus.defer(10, this);
43982 focus : function(){
43983 if(this.win && !this.sourceEditMode){
43990 assignDocWin: function()
43992 var iframe = this.iframe;
43995 this.doc = iframe.contentWindow.document;
43996 this.win = iframe.contentWindow;
43998 // if (!Roo.get(this.frameId)) {
44001 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44002 // this.win = Roo.get(this.frameId).dom.contentWindow;
44004 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
44008 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44009 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
44014 initEditor : function(){
44015 //console.log("INIT EDITOR");
44016 this.assignDocWin();
44020 this.doc.designMode="on";
44022 this.doc.write(this.getDocMarkup());
44025 var dbody = (this.doc.body || this.doc.documentElement);
44026 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
44027 // this copies styles from the containing element into thsi one..
44028 // not sure why we need all of this..
44029 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
44031 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
44032 //ss['background-attachment'] = 'fixed'; // w3c
44033 dbody.bgProperties = 'fixed'; // ie
44034 //Roo.DomHelper.applyStyles(dbody, ss);
44035 Roo.EventManager.on(this.doc, {
44036 //'mousedown': this.onEditorEvent,
44037 'mouseup': this.onEditorEvent,
44038 'dblclick': this.onEditorEvent,
44039 'click': this.onEditorEvent,
44040 'keyup': this.onEditorEvent,
44045 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
44047 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
44048 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
44050 this.initialized = true;
44052 this.owner.fireEvent('initialize', this);
44057 onDestroy : function(){
44063 //for (var i =0; i < this.toolbars.length;i++) {
44064 // // fixme - ask toolbars for heights?
44065 // this.toolbars[i].onDestroy();
44068 //this.wrap.dom.innerHTML = '';
44069 //this.wrap.remove();
44074 onFirstFocus : function(){
44076 this.assignDocWin();
44079 this.activated = true;
44082 if(Roo.isGecko){ // prevent silly gecko errors
44084 var s = this.win.getSelection();
44085 if(!s.focusNode || s.focusNode.nodeType != 3){
44086 var r = s.getRangeAt(0);
44087 r.selectNodeContents((this.doc.body || this.doc.documentElement));
44092 this.execCmd('useCSS', true);
44093 this.execCmd('styleWithCSS', false);
44096 this.owner.fireEvent('activate', this);
44100 adjustFont: function(btn){
44101 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44102 //if(Roo.isSafari){ // safari
44105 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44106 if(Roo.isSafari){ // safari
44107 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44108 v = (v < 10) ? 10 : v;
44109 v = (v > 48) ? 48 : v;
44110 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44115 v = Math.max(1, v+adjust);
44117 this.execCmd('FontSize', v );
44120 onEditorEvent : function(e)
44122 this.owner.fireEvent('editorevent', this, e);
44123 // this.updateToolbar();
44124 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44127 insertTag : function(tg)
44129 // could be a bit smarter... -> wrap the current selected tRoo..
44130 if (tg.toLowerCase() == 'span' ||
44131 tg.toLowerCase() == 'code' ||
44132 tg.toLowerCase() == 'sup' ||
44133 tg.toLowerCase() == 'sub'
44136 range = this.createRange(this.getSelection());
44137 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44138 wrappingNode.appendChild(range.extractContents());
44139 range.insertNode(wrappingNode);
44146 this.execCmd("formatblock", tg);
44150 insertText : function(txt)
44154 var range = this.createRange();
44155 range.deleteContents();
44156 //alert(Sender.getAttribute('label'));
44158 range.insertNode(this.doc.createTextNode(txt));
44164 * Executes a Midas editor command on the editor document and performs necessary focus and
44165 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44166 * @param {String} cmd The Midas command
44167 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44169 relayCmd : function(cmd, value){
44171 this.execCmd(cmd, value);
44172 this.owner.fireEvent('editorevent', this);
44173 //this.updateToolbar();
44174 this.owner.deferFocus();
44178 * Executes a Midas editor command directly on the editor document.
44179 * For visual commands, you should use {@link #relayCmd} instead.
44180 * <b>This should only be called after the editor is initialized.</b>
44181 * @param {String} cmd The Midas command
44182 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44184 execCmd : function(cmd, value){
44185 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44192 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44194 * @param {String} text | dom node..
44196 insertAtCursor : function(text)
44199 if(!this.activated){
44205 var r = this.doc.selection.createRange();
44216 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44220 // from jquery ui (MIT licenced)
44222 var win = this.win;
44224 if (win.getSelection && win.getSelection().getRangeAt) {
44225 range = win.getSelection().getRangeAt(0);
44226 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44227 range.insertNode(node);
44228 } else if (win.document.selection && win.document.selection.createRange) {
44229 // no firefox support
44230 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44231 win.document.selection.createRange().pasteHTML(txt);
44233 // no firefox support
44234 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44235 this.execCmd('InsertHTML', txt);
44244 mozKeyPress : function(e){
44246 var c = e.getCharCode(), cmd;
44249 c = String.fromCharCode(c).toLowerCase();
44263 this.cleanUpPaste.defer(100, this);
44271 e.preventDefault();
44279 fixKeys : function(){ // load time branching for fastest keydown performance
44281 return function(e){
44282 var k = e.getKey(), r;
44285 r = this.doc.selection.createRange();
44288 r.pasteHTML('    ');
44295 r = this.doc.selection.createRange();
44297 var target = r.parentElement();
44298 if(!target || target.tagName.toLowerCase() != 'li'){
44300 r.pasteHTML('<br />');
44306 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44307 this.cleanUpPaste.defer(100, this);
44313 }else if(Roo.isOpera){
44314 return function(e){
44315 var k = e.getKey();
44319 this.execCmd('InsertHTML','    ');
44322 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44323 this.cleanUpPaste.defer(100, this);
44328 }else if(Roo.isSafari){
44329 return function(e){
44330 var k = e.getKey();
44334 this.execCmd('InsertText','\t');
44338 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44339 this.cleanUpPaste.defer(100, this);
44347 getAllAncestors: function()
44349 var p = this.getSelectedNode();
44352 a.push(p); // push blank onto stack..
44353 p = this.getParentElement();
44357 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44361 a.push(this.doc.body);
44365 lastSelNode : false,
44368 getSelection : function()
44370 this.assignDocWin();
44371 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44374 getSelectedNode: function()
44376 // this may only work on Gecko!!!
44378 // should we cache this!!!!
44383 var range = this.createRange(this.getSelection()).cloneRange();
44386 var parent = range.parentElement();
44388 var testRange = range.duplicate();
44389 testRange.moveToElementText(parent);
44390 if (testRange.inRange(range)) {
44393 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44396 parent = parent.parentElement;
44401 // is ancestor a text element.
44402 var ac = range.commonAncestorContainer;
44403 if (ac.nodeType == 3) {
44404 ac = ac.parentNode;
44407 var ar = ac.childNodes;
44410 var other_nodes = [];
44411 var has_other_nodes = false;
44412 for (var i=0;i<ar.length;i++) {
44413 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44416 // fullly contained node.
44418 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44423 // probably selected..
44424 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44425 other_nodes.push(ar[i]);
44429 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44434 has_other_nodes = true;
44436 if (!nodes.length && other_nodes.length) {
44437 nodes= other_nodes;
44439 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44445 createRange: function(sel)
44447 // this has strange effects when using with
44448 // top toolbar - not sure if it's a great idea.
44449 //this.editor.contentWindow.focus();
44450 if (typeof sel != "undefined") {
44452 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44454 return this.doc.createRange();
44457 return this.doc.createRange();
44460 getParentElement: function()
44463 this.assignDocWin();
44464 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44466 var range = this.createRange(sel);
44469 var p = range.commonAncestorContainer;
44470 while (p.nodeType == 3) { // text node
44481 * Range intersection.. the hard stuff...
44485 * [ -- selected range --- ]
44489 * if end is before start or hits it. fail.
44490 * if start is after end or hits it fail.
44492 * if either hits (but other is outside. - then it's not
44498 // @see http://www.thismuchiknow.co.uk/?p=64.
44499 rangeIntersectsNode : function(range, node)
44501 var nodeRange = node.ownerDocument.createRange();
44503 nodeRange.selectNode(node);
44505 nodeRange.selectNodeContents(node);
44508 var rangeStartRange = range.cloneRange();
44509 rangeStartRange.collapse(true);
44511 var rangeEndRange = range.cloneRange();
44512 rangeEndRange.collapse(false);
44514 var nodeStartRange = nodeRange.cloneRange();
44515 nodeStartRange.collapse(true);
44517 var nodeEndRange = nodeRange.cloneRange();
44518 nodeEndRange.collapse(false);
44520 return rangeStartRange.compareBoundaryPoints(
44521 Range.START_TO_START, nodeEndRange) == -1 &&
44522 rangeEndRange.compareBoundaryPoints(
44523 Range.START_TO_START, nodeStartRange) == 1;
44527 rangeCompareNode : function(range, node)
44529 var nodeRange = node.ownerDocument.createRange();
44531 nodeRange.selectNode(node);
44533 nodeRange.selectNodeContents(node);
44537 range.collapse(true);
44539 nodeRange.collapse(true);
44541 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44542 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44544 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44546 var nodeIsBefore = ss == 1;
44547 var nodeIsAfter = ee == -1;
44549 if (nodeIsBefore && nodeIsAfter) {
44552 if (!nodeIsBefore && nodeIsAfter) {
44553 return 1; //right trailed.
44556 if (nodeIsBefore && !nodeIsAfter) {
44557 return 2; // left trailed.
44563 // private? - in a new class?
44564 cleanUpPaste : function()
44566 // cleans up the whole document..
44567 Roo.log('cleanuppaste');
44569 this.cleanUpChildren(this.doc.body);
44570 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44571 if (clean != this.doc.body.innerHTML) {
44572 this.doc.body.innerHTML = clean;
44577 cleanWordChars : function(input) {// change the chars to hex code
44578 var he = Roo.HtmlEditorCore;
44580 var output = input;
44581 Roo.each(he.swapCodes, function(sw) {
44582 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44584 output = output.replace(swapper, sw[1]);
44591 cleanUpChildren : function (n)
44593 if (!n.childNodes.length) {
44596 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44597 this.cleanUpChild(n.childNodes[i]);
44604 cleanUpChild : function (node)
44607 //console.log(node);
44608 if (node.nodeName == "#text") {
44609 // clean up silly Windows -- stuff?
44612 if (node.nodeName == "#comment") {
44613 node.parentNode.removeChild(node);
44614 // clean up silly Windows -- stuff?
44617 var lcname = node.tagName.toLowerCase();
44618 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44619 // whitelist of tags..
44621 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44623 node.parentNode.removeChild(node);
44628 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44630 // spans with no attributes - just remove them..
44631 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44632 remove_keep_children = true;
44635 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44636 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44638 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44639 // remove_keep_children = true;
44642 if (remove_keep_children) {
44643 this.cleanUpChildren(node);
44644 // inserts everything just before this node...
44645 while (node.childNodes.length) {
44646 var cn = node.childNodes[0];
44647 node.removeChild(cn);
44648 node.parentNode.insertBefore(cn, node);
44650 node.parentNode.removeChild(node);
44654 if (!node.attributes || !node.attributes.length) {
44659 this.cleanUpChildren(node);
44663 function cleanAttr(n,v)
44666 if (v.match(/^\./) || v.match(/^\//)) {
44669 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44672 if (v.match(/^#/)) {
44675 if (v.match(/^\{/)) { // allow template editing.
44678 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44679 node.removeAttribute(n);
44683 var cwhite = this.cwhite;
44684 var cblack = this.cblack;
44686 function cleanStyle(n,v)
44688 if (v.match(/expression/)) { //XSS?? should we even bother..
44689 node.removeAttribute(n);
44693 var parts = v.split(/;/);
44696 Roo.each(parts, function(p) {
44697 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44701 var l = p.split(':').shift().replace(/\s+/g,'');
44702 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44704 if ( cwhite.length && cblack.indexOf(l) > -1) {
44705 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44706 //node.removeAttribute(n);
44710 // only allow 'c whitelisted system attributes'
44711 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44712 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44713 //node.removeAttribute(n);
44723 if (clean.length) {
44724 node.setAttribute(n, clean.join(';'));
44726 node.removeAttribute(n);
44732 for (var i = node.attributes.length-1; i > -1 ; i--) {
44733 var a = node.attributes[i];
44736 if (a.name.toLowerCase().substr(0,2)=='on') {
44737 node.removeAttribute(a.name);
44740 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44741 node.removeAttribute(a.name);
44744 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44745 cleanAttr(a.name,a.value); // fixme..
44748 if (a.name == 'style') {
44749 cleanStyle(a.name,a.value);
44752 /// clean up MS crap..
44753 // tecnically this should be a list of valid class'es..
44756 if (a.name == 'class') {
44757 if (a.value.match(/^Mso/)) {
44758 node.removeAttribute('class');
44761 if (a.value.match(/^body$/)) {
44762 node.removeAttribute('class');
44773 this.cleanUpChildren(node);
44779 * Clean up MS wordisms...
44781 cleanWord : function(node)
44784 this.cleanWord(this.doc.body);
44789 node.nodeName == 'SPAN' &&
44790 !node.hasAttributes() &&
44791 node.childNodes.length == 1 &&
44792 node.firstChild.nodeName == "#text"
44794 var textNode = node.firstChild;
44795 node.removeChild(textNode);
44796 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44797 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44799 node.parentNode.insertBefore(textNode, node);
44800 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44801 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44803 node.parentNode.removeChild(node);
44806 if (node.nodeName == "#text") {
44807 // clean up silly Windows -- stuff?
44810 if (node.nodeName == "#comment") {
44811 node.parentNode.removeChild(node);
44812 // clean up silly Windows -- stuff?
44816 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44817 node.parentNode.removeChild(node);
44820 //Roo.log(node.tagName);
44821 // remove - but keep children..
44822 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44823 //Roo.log('-- removed');
44824 while (node.childNodes.length) {
44825 var cn = node.childNodes[0];
44826 node.removeChild(cn);
44827 node.parentNode.insertBefore(cn, node);
44828 // move node to parent - and clean it..
44829 this.cleanWord(cn);
44831 node.parentNode.removeChild(node);
44832 /// no need to iterate chidlren = it's got none..
44833 //this.iterateChildren(node, this.cleanWord);
44837 if (node.className.length) {
44839 var cn = node.className.split(/\W+/);
44841 Roo.each(cn, function(cls) {
44842 if (cls.match(/Mso[a-zA-Z]+/)) {
44847 node.className = cna.length ? cna.join(' ') : '';
44849 node.removeAttribute("class");
44853 if (node.hasAttribute("lang")) {
44854 node.removeAttribute("lang");
44857 if (node.hasAttribute("style")) {
44859 var styles = node.getAttribute("style").split(";");
44861 Roo.each(styles, function(s) {
44862 if (!s.match(/:/)) {
44865 var kv = s.split(":");
44866 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44869 // what ever is left... we allow.
44872 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44873 if (!nstyle.length) {
44874 node.removeAttribute('style');
44877 this.iterateChildren(node, this.cleanWord);
44883 * iterateChildren of a Node, calling fn each time, using this as the scole..
44884 * @param {DomNode} node node to iterate children of.
44885 * @param {Function} fn method of this class to call on each item.
44887 iterateChildren : function(node, fn)
44889 if (!node.childNodes.length) {
44892 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44893 fn.call(this, node.childNodes[i])
44899 * cleanTableWidths.
44901 * Quite often pasting from word etc.. results in tables with column and widths.
44902 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44905 cleanTableWidths : function(node)
44910 this.cleanTableWidths(this.doc.body);
44915 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44918 Roo.log(node.tagName);
44919 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44920 this.iterateChildren(node, this.cleanTableWidths);
44923 if (node.hasAttribute('width')) {
44924 node.removeAttribute('width');
44928 if (node.hasAttribute("style")) {
44931 var styles = node.getAttribute("style").split(";");
44933 Roo.each(styles, function(s) {
44934 if (!s.match(/:/)) {
44937 var kv = s.split(":");
44938 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44941 // what ever is left... we allow.
44944 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44945 if (!nstyle.length) {
44946 node.removeAttribute('style');
44950 this.iterateChildren(node, this.cleanTableWidths);
44958 domToHTML : function(currentElement, depth, nopadtext) {
44960 depth = depth || 0;
44961 nopadtext = nopadtext || false;
44963 if (!currentElement) {
44964 return this.domToHTML(this.doc.body);
44967 //Roo.log(currentElement);
44969 var allText = false;
44970 var nodeName = currentElement.nodeName;
44971 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44973 if (nodeName == '#text') {
44975 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44980 if (nodeName != 'BODY') {
44983 // Prints the node tagName, such as <A>, <IMG>, etc
44986 for(i = 0; i < currentElement.attributes.length;i++) {
44988 var aname = currentElement.attributes.item(i).name;
44989 if (!currentElement.attributes.item(i).value.length) {
44992 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44995 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
45004 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
45007 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
45012 // Traverse the tree
45014 var currentElementChild = currentElement.childNodes.item(i);
45015 var allText = true;
45016 var innerHTML = '';
45018 while (currentElementChild) {
45019 // Formatting code (indent the tree so it looks nice on the screen)
45020 var nopad = nopadtext;
45021 if (lastnode == 'SPAN') {
45025 if (currentElementChild.nodeName == '#text') {
45026 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
45027 toadd = nopadtext ? toadd : toadd.trim();
45028 if (!nopad && toadd.length > 80) {
45029 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
45031 innerHTML += toadd;
45034 currentElementChild = currentElement.childNodes.item(i);
45040 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
45042 // Recursively traverse the tree structure of the child node
45043 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
45044 lastnode = currentElementChild.nodeName;
45046 currentElementChild=currentElement.childNodes.item(i);
45052 // The remaining code is mostly for formatting the tree
45053 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
45058 ret+= "</"+tagName+">";
45064 applyBlacklists : function()
45066 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
45067 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
45071 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
45072 if (b.indexOf(tag) > -1) {
45075 this.white.push(tag);
45079 Roo.each(w, function(tag) {
45080 if (b.indexOf(tag) > -1) {
45083 if (this.white.indexOf(tag) > -1) {
45086 this.white.push(tag);
45091 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
45092 if (w.indexOf(tag) > -1) {
45095 this.black.push(tag);
45099 Roo.each(b, function(tag) {
45100 if (w.indexOf(tag) > -1) {
45103 if (this.black.indexOf(tag) > -1) {
45106 this.black.push(tag);
45111 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45112 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45116 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45117 if (b.indexOf(tag) > -1) {
45120 this.cwhite.push(tag);
45124 Roo.each(w, function(tag) {
45125 if (b.indexOf(tag) > -1) {
45128 if (this.cwhite.indexOf(tag) > -1) {
45131 this.cwhite.push(tag);
45136 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45137 if (w.indexOf(tag) > -1) {
45140 this.cblack.push(tag);
45144 Roo.each(b, function(tag) {
45145 if (w.indexOf(tag) > -1) {
45148 if (this.cblack.indexOf(tag) > -1) {
45151 this.cblack.push(tag);
45156 setStylesheets : function(stylesheets)
45158 if(typeof(stylesheets) == 'string'){
45159 Roo.get(this.iframe.contentDocument.head).createChild({
45161 rel : 'stylesheet',
45170 Roo.each(stylesheets, function(s) {
45175 Roo.get(_this.iframe.contentDocument.head).createChild({
45177 rel : 'stylesheet',
45186 removeStylesheets : function()
45190 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45195 setStyle : function(style)
45197 Roo.get(this.iframe.contentDocument.head).createChild({
45206 // hide stuff that is not compatible
45220 * @event specialkey
45224 * @cfg {String} fieldClass @hide
45227 * @cfg {String} focusClass @hide
45230 * @cfg {String} autoCreate @hide
45233 * @cfg {String} inputType @hide
45236 * @cfg {String} invalidClass @hide
45239 * @cfg {String} invalidText @hide
45242 * @cfg {String} msgFx @hide
45245 * @cfg {String} validateOnBlur @hide
45249 Roo.HtmlEditorCore.white = [
45250 'area', 'br', 'img', 'input', 'hr', 'wbr',
45252 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45253 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45254 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45255 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45256 'table', 'ul', 'xmp',
45258 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45261 'dir', 'menu', 'ol', 'ul', 'dl',
45267 Roo.HtmlEditorCore.black = [
45268 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45270 'base', 'basefont', 'bgsound', 'blink', 'body',
45271 'frame', 'frameset', 'head', 'html', 'ilayer',
45272 'iframe', 'layer', 'link', 'meta', 'object',
45273 'script', 'style' ,'title', 'xml' // clean later..
45275 Roo.HtmlEditorCore.clean = [
45276 'script', 'style', 'title', 'xml'
45278 Roo.HtmlEditorCore.remove = [
45283 Roo.HtmlEditorCore.ablack = [
45287 Roo.HtmlEditorCore.aclean = [
45288 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45292 Roo.HtmlEditorCore.pwhite= [
45293 'http', 'https', 'mailto'
45296 // white listed style attributes.
45297 Roo.HtmlEditorCore.cwhite= [
45298 // 'text-align', /// default is to allow most things..
45304 // black listed style attributes.
45305 Roo.HtmlEditorCore.cblack= [
45306 // 'font-size' -- this can be set by the project
45310 Roo.HtmlEditorCore.swapCodes =[
45311 [ 8211, "–" ],
45312 [ 8212, "—" ],
45321 //<script type="text/javascript">
45324 * Ext JS Library 1.1.1
45325 * Copyright(c) 2006-2007, Ext JS, LLC.
45331 Roo.form.HtmlEditor = function(config){
45335 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45337 if (!this.toolbars) {
45338 this.toolbars = [];
45340 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45346 * @class Roo.form.HtmlEditor
45347 * @extends Roo.form.Field
45348 * Provides a lightweight HTML Editor component.
45350 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45352 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45353 * supported by this editor.</b><br/><br/>
45354 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45355 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45357 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45359 * @cfg {Boolean} clearUp
45363 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45368 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45373 * @cfg {Number} height (in pixels)
45377 * @cfg {Number} width (in pixels)
45382 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45385 stylesheets: false,
45389 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45394 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45400 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45405 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45413 // private properties
45414 validationEvent : false,
45416 initialized : false,
45419 onFocus : Roo.emptyFn,
45421 hideMode:'offsets',
45423 actionMode : 'container', // defaults to hiding it...
45425 defaultAutoCreate : { // modified by initCompnoent..
45427 style:"width:500px;height:300px;",
45428 autocomplete: "new-password"
45432 initComponent : function(){
45435 * @event initialize
45436 * Fires when the editor is fully initialized (including the iframe)
45437 * @param {HtmlEditor} this
45442 * Fires when the editor is first receives the focus. Any insertion must wait
45443 * until after this event.
45444 * @param {HtmlEditor} this
45448 * @event beforesync
45449 * Fires before the textarea is updated with content from the editor iframe. Return false
45450 * to cancel the sync.
45451 * @param {HtmlEditor} this
45452 * @param {String} html
45456 * @event beforepush
45457 * Fires before the iframe editor is updated with content from the textarea. Return false
45458 * to cancel the push.
45459 * @param {HtmlEditor} this
45460 * @param {String} html
45465 * Fires when the textarea is updated with content from the editor iframe.
45466 * @param {HtmlEditor} this
45467 * @param {String} html
45472 * Fires when the iframe editor is updated with content from the textarea.
45473 * @param {HtmlEditor} this
45474 * @param {String} html
45478 * @event editmodechange
45479 * Fires when the editor switches edit modes
45480 * @param {HtmlEditor} this
45481 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45483 editmodechange: true,
45485 * @event editorevent
45486 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45487 * @param {HtmlEditor} this
45491 * @event firstfocus
45492 * Fires when on first focus - needed by toolbars..
45493 * @param {HtmlEditor} this
45498 * Auto save the htmlEditor value as a file into Events
45499 * @param {HtmlEditor} this
45503 * @event savedpreview
45504 * preview the saved version of htmlEditor
45505 * @param {HtmlEditor} this
45507 savedpreview: true,
45510 * @event stylesheetsclick
45511 * Fires when press the Sytlesheets button
45512 * @param {Roo.HtmlEditorCore} this
45514 stylesheetsclick: true
45516 this.defaultAutoCreate = {
45518 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45519 autocomplete: "new-password"
45524 * Protected method that will not generally be called directly. It
45525 * is called when the editor creates its toolbar. Override this method if you need to
45526 * add custom toolbar buttons.
45527 * @param {HtmlEditor} editor
45529 createToolbar : function(editor){
45530 Roo.log("create toolbars");
45531 if (!editor.toolbars || !editor.toolbars.length) {
45532 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45535 for (var i =0 ; i < editor.toolbars.length;i++) {
45536 editor.toolbars[i] = Roo.factory(
45537 typeof(editor.toolbars[i]) == 'string' ?
45538 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45539 Roo.form.HtmlEditor);
45540 editor.toolbars[i].init(editor);
45548 onRender : function(ct, position)
45551 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45553 this.wrap = this.el.wrap({
45554 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45557 this.editorcore.onRender(ct, position);
45559 if (this.resizable) {
45560 this.resizeEl = new Roo.Resizable(this.wrap, {
45564 minHeight : this.height,
45565 height: this.height,
45566 handles : this.resizable,
45569 resize : function(r, w, h) {
45570 _t.onResize(w,h); // -something
45576 this.createToolbar(this);
45580 this.setSize(this.wrap.getSize());
45582 if (this.resizeEl) {
45583 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45584 // should trigger onReize..
45587 this.keyNav = new Roo.KeyNav(this.el, {
45589 "tab" : function(e){
45590 e.preventDefault();
45592 var value = this.getValue();
45594 var start = this.el.dom.selectionStart;
45595 var end = this.el.dom.selectionEnd;
45599 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45600 this.el.dom.setSelectionRange(end + 1, end + 1);
45604 var f = value.substring(0, start).split("\t");
45606 if(f.pop().length != 0){
45610 this.setValue(f.join("\t") + value.substring(end));
45611 this.el.dom.setSelectionRange(start - 1, start - 1);
45615 "home" : function(e){
45616 e.preventDefault();
45618 var curr = this.el.dom.selectionStart;
45619 var lines = this.getValue().split("\n");
45626 this.el.dom.setSelectionRange(0, 0);
45632 for (var i = 0; i < lines.length;i++) {
45633 pos += lines[i].length;
45643 pos -= lines[i].length;
45649 this.el.dom.setSelectionRange(pos, pos);
45653 this.el.dom.selectionStart = pos;
45654 this.el.dom.selectionEnd = curr;
45657 "end" : function(e){
45658 e.preventDefault();
45660 var curr = this.el.dom.selectionStart;
45661 var lines = this.getValue().split("\n");
45668 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45674 for (var i = 0; i < lines.length;i++) {
45676 pos += lines[i].length;
45690 this.el.dom.setSelectionRange(pos, pos);
45694 this.el.dom.selectionStart = curr;
45695 this.el.dom.selectionEnd = pos;
45700 doRelay : function(foo, bar, hname){
45701 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45707 // if(this.autosave && this.w){
45708 // this.autoSaveFn = setInterval(this.autosave, 1000);
45713 onResize : function(w, h)
45715 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45720 if(typeof w == 'number'){
45721 var aw = w - this.wrap.getFrameWidth('lr');
45722 this.el.setWidth(this.adjustWidth('textarea', aw));
45725 if(typeof h == 'number'){
45727 for (var i =0; i < this.toolbars.length;i++) {
45728 // fixme - ask toolbars for heights?
45729 tbh += this.toolbars[i].tb.el.getHeight();
45730 if (this.toolbars[i].footer) {
45731 tbh += this.toolbars[i].footer.el.getHeight();
45738 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45739 ah -= 5; // knock a few pixes off for look..
45741 this.el.setHeight(this.adjustWidth('textarea', ah));
45745 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45746 this.editorcore.onResize(ew,eh);
45751 * Toggles the editor between standard and source edit mode.
45752 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45754 toggleSourceEdit : function(sourceEditMode)
45756 this.editorcore.toggleSourceEdit(sourceEditMode);
45758 if(this.editorcore.sourceEditMode){
45759 Roo.log('editor - showing textarea');
45762 // Roo.log(this.syncValue());
45763 this.editorcore.syncValue();
45764 this.el.removeClass('x-hidden');
45765 this.el.dom.removeAttribute('tabIndex');
45768 for (var i = 0; i < this.toolbars.length; i++) {
45769 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45770 this.toolbars[i].tb.hide();
45771 this.toolbars[i].footer.hide();
45776 Roo.log('editor - hiding textarea');
45778 // Roo.log(this.pushValue());
45779 this.editorcore.pushValue();
45781 this.el.addClass('x-hidden');
45782 this.el.dom.setAttribute('tabIndex', -1);
45784 for (var i = 0; i < this.toolbars.length; i++) {
45785 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45786 this.toolbars[i].tb.show();
45787 this.toolbars[i].footer.show();
45791 //this.deferFocus();
45794 this.setSize(this.wrap.getSize());
45795 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45797 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45800 // private (for BoxComponent)
45801 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45803 // private (for BoxComponent)
45804 getResizeEl : function(){
45808 // private (for BoxComponent)
45809 getPositionEl : function(){
45814 initEvents : function(){
45815 this.originalValue = this.getValue();
45819 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45822 markInvalid : Roo.emptyFn,
45824 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45827 clearInvalid : Roo.emptyFn,
45829 setValue : function(v){
45830 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45831 this.editorcore.pushValue();
45836 deferFocus : function(){
45837 this.focus.defer(10, this);
45841 focus : function(){
45842 this.editorcore.focus();
45848 onDestroy : function(){
45854 for (var i =0; i < this.toolbars.length;i++) {
45855 // fixme - ask toolbars for heights?
45856 this.toolbars[i].onDestroy();
45859 this.wrap.dom.innerHTML = '';
45860 this.wrap.remove();
45865 onFirstFocus : function(){
45866 //Roo.log("onFirstFocus");
45867 this.editorcore.onFirstFocus();
45868 for (var i =0; i < this.toolbars.length;i++) {
45869 this.toolbars[i].onFirstFocus();
45875 syncValue : function()
45877 this.editorcore.syncValue();
45880 pushValue : function()
45882 this.editorcore.pushValue();
45885 setStylesheets : function(stylesheets)
45887 this.editorcore.setStylesheets(stylesheets);
45890 removeStylesheets : function()
45892 this.editorcore.removeStylesheets();
45896 // hide stuff that is not compatible
45910 * @event specialkey
45914 * @cfg {String} fieldClass @hide
45917 * @cfg {String} focusClass @hide
45920 * @cfg {String} autoCreate @hide
45923 * @cfg {String} inputType @hide
45926 * @cfg {String} invalidClass @hide
45929 * @cfg {String} invalidText @hide
45932 * @cfg {String} msgFx @hide
45935 * @cfg {String} validateOnBlur @hide
45939 // <script type="text/javascript">
45942 * Ext JS Library 1.1.1
45943 * Copyright(c) 2006-2007, Ext JS, LLC.
45949 * @class Roo.form.HtmlEditorToolbar1
45954 new Roo.form.HtmlEditor({
45957 new Roo.form.HtmlEditorToolbar1({
45958 disable : { fonts: 1 , format: 1, ..., ... , ...],
45964 * @cfg {Object} disable List of elements to disable..
45965 * @cfg {Array} btns List of additional buttons.
45969 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45972 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45975 Roo.apply(this, config);
45977 // default disabled, based on 'good practice'..
45978 this.disable = this.disable || {};
45979 Roo.applyIf(this.disable, {
45982 specialElements : true
45986 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45987 // dont call parent... till later.
45990 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45997 editorcore : false,
45999 * @cfg {Object} disable List of toolbar elements to disable
46006 * @cfg {String} createLinkText The default text for the create link prompt
46008 createLinkText : 'Please enter the URL for the link:',
46010 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
46012 defaultLinkValue : 'http:/'+'/',
46016 * @cfg {Array} fontFamilies An array of available font families
46034 // "á" , ?? a acute?
46039 "°" // , // degrees
46041 // "é" , // e ecute
46042 // "ú" , // u ecute?
46045 specialElements : [
46047 text: "Insert Table",
46050 ihtml : '<table><tr><td>Cell</td></tr></table>'
46054 text: "Insert Image",
46057 ihtml : '<img src="about:blank"/>'
46066 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
46067 "input:submit", "input:button", "select", "textarea", "label" ],
46070 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
46072 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
46081 * @cfg {String} defaultFont default font to use.
46083 defaultFont: 'tahoma',
46085 fontSelect : false,
46088 formatCombo : false,
46090 init : function(editor)
46092 this.editor = editor;
46093 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46094 var editorcore = this.editorcore;
46098 var fid = editorcore.frameId;
46100 function btn(id, toggle, handler){
46101 var xid = fid + '-'+ id ;
46105 cls : 'x-btn-icon x-edit-'+id,
46106 enableToggle:toggle !== false,
46107 scope: _t, // was editor...
46108 handler:handler||_t.relayBtnCmd,
46109 clickEvent:'mousedown',
46110 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46117 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46119 // stop form submits
46120 tb.el.on('click', function(e){
46121 e.preventDefault(); // what does this do?
46124 if(!this.disable.font) { // && !Roo.isSafari){
46125 /* why no safari for fonts
46126 editor.fontSelect = tb.el.createChild({
46129 cls:'x-font-select',
46130 html: this.createFontOptions()
46133 editor.fontSelect.on('change', function(){
46134 var font = editor.fontSelect.dom.value;
46135 editor.relayCmd('fontname', font);
46136 editor.deferFocus();
46140 editor.fontSelect.dom,
46146 if(!this.disable.formats){
46147 this.formatCombo = new Roo.form.ComboBox({
46148 store: new Roo.data.SimpleStore({
46151 data : this.formats // from states.js
46155 //autoCreate : {tag: "div", size: "20"},
46156 displayField:'tag',
46160 triggerAction: 'all',
46161 emptyText:'Add tag',
46162 selectOnFocus:true,
46165 'select': function(c, r, i) {
46166 editorcore.insertTag(r.get('tag'));
46172 tb.addField(this.formatCombo);
46176 if(!this.disable.format){
46181 btn('strikethrough')
46184 if(!this.disable.fontSize){
46189 btn('increasefontsize', false, editorcore.adjustFont),
46190 btn('decreasefontsize', false, editorcore.adjustFont)
46195 if(!this.disable.colors){
46198 id:editorcore.frameId +'-forecolor',
46199 cls:'x-btn-icon x-edit-forecolor',
46200 clickEvent:'mousedown',
46201 tooltip: this.buttonTips['forecolor'] || undefined,
46203 menu : new Roo.menu.ColorMenu({
46204 allowReselect: true,
46205 focus: Roo.emptyFn,
46208 selectHandler: function(cp, color){
46209 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46210 editor.deferFocus();
46213 clickEvent:'mousedown'
46216 id:editorcore.frameId +'backcolor',
46217 cls:'x-btn-icon x-edit-backcolor',
46218 clickEvent:'mousedown',
46219 tooltip: this.buttonTips['backcolor'] || undefined,
46221 menu : new Roo.menu.ColorMenu({
46222 focus: Roo.emptyFn,
46225 allowReselect: true,
46226 selectHandler: function(cp, color){
46228 editorcore.execCmd('useCSS', false);
46229 editorcore.execCmd('hilitecolor', color);
46230 editorcore.execCmd('useCSS', true);
46231 editor.deferFocus();
46233 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46234 Roo.isSafari || Roo.isIE ? '#'+color : color);
46235 editor.deferFocus();
46239 clickEvent:'mousedown'
46244 // now add all the items...
46247 if(!this.disable.alignments){
46250 btn('justifyleft'),
46251 btn('justifycenter'),
46252 btn('justifyright')
46256 //if(!Roo.isSafari){
46257 if(!this.disable.links){
46260 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46264 if(!this.disable.lists){
46267 btn('insertorderedlist'),
46268 btn('insertunorderedlist')
46271 if(!this.disable.sourceEdit){
46274 btn('sourceedit', true, function(btn){
46275 this.toggleSourceEdit(btn.pressed);
46282 // special menu.. - needs to be tidied up..
46283 if (!this.disable.special) {
46286 cls: 'x-edit-none',
46292 for (var i =0; i < this.specialChars.length; i++) {
46293 smenu.menu.items.push({
46295 html: this.specialChars[i],
46296 handler: function(a,b) {
46297 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46298 //editor.insertAtCursor(a.html);
46312 if (!this.disable.cleanStyles) {
46314 cls: 'x-btn-icon x-btn-clear',
46320 for (var i =0; i < this.cleanStyles.length; i++) {
46321 cmenu.menu.items.push({
46322 actiontype : this.cleanStyles[i],
46323 html: 'Remove ' + this.cleanStyles[i],
46324 handler: function(a,b) {
46327 var c = Roo.get(editorcore.doc.body);
46328 c.select('[style]').each(function(s) {
46329 s.dom.style.removeProperty(a.actiontype);
46331 editorcore.syncValue();
46336 cmenu.menu.items.push({
46337 actiontype : 'tablewidths',
46338 html: 'Remove Table Widths',
46339 handler: function(a,b) {
46340 editorcore.cleanTableWidths();
46341 editorcore.syncValue();
46345 cmenu.menu.items.push({
46346 actiontype : 'word',
46347 html: 'Remove MS Word Formating',
46348 handler: function(a,b) {
46349 editorcore.cleanWord();
46350 editorcore.syncValue();
46355 cmenu.menu.items.push({
46356 actiontype : 'all',
46357 html: 'Remove All Styles',
46358 handler: function(a,b) {
46360 var c = Roo.get(editorcore.doc.body);
46361 c.select('[style]').each(function(s) {
46362 s.dom.removeAttribute('style');
46364 editorcore.syncValue();
46369 cmenu.menu.items.push({
46370 actiontype : 'all',
46371 html: 'Remove All CSS Classes',
46372 handler: function(a,b) {
46374 var c = Roo.get(editorcore.doc.body);
46375 c.select('[class]').each(function(s) {
46376 s.dom.removeAttribute('class');
46378 editorcore.cleanWord();
46379 editorcore.syncValue();
46384 cmenu.menu.items.push({
46385 actiontype : 'tidy',
46386 html: 'Tidy HTML Source',
46387 handler: function(a,b) {
46388 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46389 editorcore.syncValue();
46398 if (!this.disable.specialElements) {
46401 cls: 'x-edit-none',
46406 for (var i =0; i < this.specialElements.length; i++) {
46407 semenu.menu.items.push(
46409 handler: function(a,b) {
46410 editor.insertAtCursor(this.ihtml);
46412 }, this.specialElements[i])
46424 for(var i =0; i< this.btns.length;i++) {
46425 var b = Roo.factory(this.btns[i],Roo.form);
46426 b.cls = 'x-edit-none';
46428 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46429 b.cls += ' x-init-enable';
46432 b.scope = editorcore;
46440 // disable everything...
46442 this.tb.items.each(function(item){
46445 item.id != editorcore.frameId+ '-sourceedit' &&
46446 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46452 this.rendered = true;
46454 // the all the btns;
46455 editor.on('editorevent', this.updateToolbar, this);
46456 // other toolbars need to implement this..
46457 //editor.on('editmodechange', this.updateToolbar, this);
46461 relayBtnCmd : function(btn) {
46462 this.editorcore.relayCmd(btn.cmd);
46464 // private used internally
46465 createLink : function(){
46466 Roo.log("create link?");
46467 var url = prompt(this.createLinkText, this.defaultLinkValue);
46468 if(url && url != 'http:/'+'/'){
46469 this.editorcore.relayCmd('createlink', url);
46475 * Protected method that will not generally be called directly. It triggers
46476 * a toolbar update by reading the markup state of the current selection in the editor.
46478 updateToolbar: function(){
46480 if(!this.editorcore.activated){
46481 this.editor.onFirstFocus();
46485 var btns = this.tb.items.map,
46486 doc = this.editorcore.doc,
46487 frameId = this.editorcore.frameId;
46489 if(!this.disable.font && !Roo.isSafari){
46491 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46492 if(name != this.fontSelect.dom.value){
46493 this.fontSelect.dom.value = name;
46497 if(!this.disable.format){
46498 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46499 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46500 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46501 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46503 if(!this.disable.alignments){
46504 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46505 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46506 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46508 if(!Roo.isSafari && !this.disable.lists){
46509 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46510 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46513 var ans = this.editorcore.getAllAncestors();
46514 if (this.formatCombo) {
46517 var store = this.formatCombo.store;
46518 this.formatCombo.setValue("");
46519 for (var i =0; i < ans.length;i++) {
46520 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46522 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46530 // hides menus... - so this cant be on a menu...
46531 Roo.menu.MenuMgr.hideAll();
46533 //this.editorsyncValue();
46537 createFontOptions : function(){
46538 var buf = [], fs = this.fontFamilies, ff, lc;
46542 for(var i = 0, len = fs.length; i< len; i++){
46544 lc = ff.toLowerCase();
46546 '<option value="',lc,'" style="font-family:',ff,';"',
46547 (this.defaultFont == lc ? ' selected="true">' : '>'),
46552 return buf.join('');
46555 toggleSourceEdit : function(sourceEditMode){
46557 Roo.log("toolbar toogle");
46558 if(sourceEditMode === undefined){
46559 sourceEditMode = !this.sourceEditMode;
46561 this.sourceEditMode = sourceEditMode === true;
46562 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46563 // just toggle the button?
46564 if(btn.pressed !== this.sourceEditMode){
46565 btn.toggle(this.sourceEditMode);
46569 if(sourceEditMode){
46570 Roo.log("disabling buttons");
46571 this.tb.items.each(function(item){
46572 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46578 Roo.log("enabling buttons");
46579 if(this.editorcore.initialized){
46580 this.tb.items.each(function(item){
46586 Roo.log("calling toggole on editor");
46587 // tell the editor that it's been pressed..
46588 this.editor.toggleSourceEdit(sourceEditMode);
46592 * Object collection of toolbar tooltips for the buttons in the editor. The key
46593 * is the command id associated with that button and the value is a valid QuickTips object.
46598 title: 'Bold (Ctrl+B)',
46599 text: 'Make the selected text bold.',
46600 cls: 'x-html-editor-tip'
46603 title: 'Italic (Ctrl+I)',
46604 text: 'Make the selected text italic.',
46605 cls: 'x-html-editor-tip'
46613 title: 'Bold (Ctrl+B)',
46614 text: 'Make the selected text bold.',
46615 cls: 'x-html-editor-tip'
46618 title: 'Italic (Ctrl+I)',
46619 text: 'Make the selected text italic.',
46620 cls: 'x-html-editor-tip'
46623 title: 'Underline (Ctrl+U)',
46624 text: 'Underline the selected text.',
46625 cls: 'x-html-editor-tip'
46628 title: 'Strikethrough',
46629 text: 'Strikethrough the selected text.',
46630 cls: 'x-html-editor-tip'
46632 increasefontsize : {
46633 title: 'Grow Text',
46634 text: 'Increase the font size.',
46635 cls: 'x-html-editor-tip'
46637 decreasefontsize : {
46638 title: 'Shrink Text',
46639 text: 'Decrease the font size.',
46640 cls: 'x-html-editor-tip'
46643 title: 'Text Highlight Color',
46644 text: 'Change the background color of the selected text.',
46645 cls: 'x-html-editor-tip'
46648 title: 'Font Color',
46649 text: 'Change the color of the selected text.',
46650 cls: 'x-html-editor-tip'
46653 title: 'Align Text Left',
46654 text: 'Align text to the left.',
46655 cls: 'x-html-editor-tip'
46658 title: 'Center Text',
46659 text: 'Center text in the editor.',
46660 cls: 'x-html-editor-tip'
46663 title: 'Align Text Right',
46664 text: 'Align text to the right.',
46665 cls: 'x-html-editor-tip'
46667 insertunorderedlist : {
46668 title: 'Bullet List',
46669 text: 'Start a bulleted list.',
46670 cls: 'x-html-editor-tip'
46672 insertorderedlist : {
46673 title: 'Numbered List',
46674 text: 'Start a numbered list.',
46675 cls: 'x-html-editor-tip'
46678 title: 'Hyperlink',
46679 text: 'Make the selected text a hyperlink.',
46680 cls: 'x-html-editor-tip'
46683 title: 'Source Edit',
46684 text: 'Switch to source editing mode.',
46685 cls: 'x-html-editor-tip'
46689 onDestroy : function(){
46692 this.tb.items.each(function(item){
46694 item.menu.removeAll();
46696 item.menu.el.destroy();
46704 onFirstFocus: function() {
46705 this.tb.items.each(function(item){
46714 // <script type="text/javascript">
46717 * Ext JS Library 1.1.1
46718 * Copyright(c) 2006-2007, Ext JS, LLC.
46725 * @class Roo.form.HtmlEditor.ToolbarContext
46730 new Roo.form.HtmlEditor({
46733 { xtype: 'ToolbarStandard', styles : {} }
46734 { xtype: 'ToolbarContext', disable : {} }
46740 * @config : {Object} disable List of elements to disable.. (not done yet.)
46741 * @config : {Object} styles Map of styles available.
46745 Roo.form.HtmlEditor.ToolbarContext = function(config)
46748 Roo.apply(this, config);
46749 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46750 // dont call parent... till later.
46751 this.styles = this.styles || {};
46756 Roo.form.HtmlEditor.ToolbarContext.types = {
46768 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46834 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46839 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46849 style : 'fontFamily',
46850 displayField: 'display',
46851 optname : 'font-family',
46900 // should we really allow this??
46901 // should this just be
46912 style : 'fontFamily',
46913 displayField: 'display',
46914 optname : 'font-family',
46921 style : 'fontFamily',
46922 displayField: 'display',
46923 optname : 'font-family',
46930 style : 'fontFamily',
46931 displayField: 'display',
46932 optname : 'font-family',
46943 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46944 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46946 Roo.form.HtmlEditor.ToolbarContext.options = {
46948 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46949 [ 'Courier New', 'Courier New'],
46950 [ 'Tahoma', 'Tahoma'],
46951 [ 'Times New Roman,serif', 'Times'],
46952 [ 'Verdana','Verdana' ]
46956 // fixme - these need to be configurable..
46959 //Roo.form.HtmlEditor.ToolbarContext.types
46962 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46969 editorcore : false,
46971 * @cfg {Object} disable List of toolbar elements to disable
46976 * @cfg {Object} styles List of styles
46977 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46979 * These must be defined in the page, so they get rendered correctly..
46990 init : function(editor)
46992 this.editor = editor;
46993 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46994 var editorcore = this.editorcore;
46996 var fid = editorcore.frameId;
46998 function btn(id, toggle, handler){
46999 var xid = fid + '-'+ id ;
47003 cls : 'x-btn-icon x-edit-'+id,
47004 enableToggle:toggle !== false,
47005 scope: editorcore, // was editor...
47006 handler:handler||editorcore.relayBtnCmd,
47007 clickEvent:'mousedown',
47008 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47012 // create a new element.
47013 var wdiv = editor.wrap.createChild({
47015 }, editor.wrap.dom.firstChild.nextSibling, true);
47017 // can we do this more than once??
47019 // stop form submits
47022 // disable everything...
47023 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47024 this.toolbars = {};
47026 for (var i in ty) {
47028 this.toolbars[i] = this.buildToolbar(ty[i],i);
47030 this.tb = this.toolbars.BODY;
47032 this.buildFooter();
47033 this.footer.show();
47034 editor.on('hide', function( ) { this.footer.hide() }, this);
47035 editor.on('show', function( ) { this.footer.show() }, this);
47038 this.rendered = true;
47040 // the all the btns;
47041 editor.on('editorevent', this.updateToolbar, this);
47042 // other toolbars need to implement this..
47043 //editor.on('editmodechange', this.updateToolbar, this);
47049 * Protected method that will not generally be called directly. It triggers
47050 * a toolbar update by reading the markup state of the current selection in the editor.
47052 * Note you can force an update by calling on('editorevent', scope, false)
47054 updateToolbar: function(editor,ev,sel){
47057 // capture mouse up - this is handy for selecting images..
47058 // perhaps should go somewhere else...
47059 if(!this.editorcore.activated){
47060 this.editor.onFirstFocus();
47066 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
47067 // selectNode - might want to handle IE?
47069 (ev.type == 'mouseup' || ev.type == 'click' ) &&
47070 ev.target && ev.target.tagName == 'IMG') {
47071 // they have click on an image...
47072 // let's see if we can change the selection...
47075 var nodeRange = sel.ownerDocument.createRange();
47077 nodeRange.selectNode(sel);
47079 nodeRange.selectNodeContents(sel);
47081 //nodeRange.collapse(true);
47082 var s = this.editorcore.win.getSelection();
47083 s.removeAllRanges();
47084 s.addRange(nodeRange);
47088 var updateFooter = sel ? false : true;
47091 var ans = this.editorcore.getAllAncestors();
47094 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47097 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47098 sel = sel ? sel : this.editorcore.doc.body;
47099 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47102 // pick a menu that exists..
47103 var tn = sel.tagName.toUpperCase();
47104 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47106 tn = sel.tagName.toUpperCase();
47108 var lastSel = this.tb.selectedNode;
47110 this.tb.selectedNode = sel;
47112 // if current menu does not match..
47114 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47117 ///console.log("show: " + tn);
47118 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47121 this.tb.items.first().el.innerHTML = tn + ': ';
47124 // update attributes
47125 if (this.tb.fields) {
47126 this.tb.fields.each(function(e) {
47128 e.setValue(sel.style[e.stylename]);
47131 e.setValue(sel.getAttribute(e.attrname));
47135 var hasStyles = false;
47136 for(var i in this.styles) {
47143 var st = this.tb.fields.item(0);
47145 st.store.removeAll();
47148 var cn = sel.className.split(/\s+/);
47151 if (this.styles['*']) {
47153 Roo.each(this.styles['*'], function(v) {
47154 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47157 if (this.styles[tn]) {
47158 Roo.each(this.styles[tn], function(v) {
47159 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47163 st.store.loadData(avs);
47167 // flag our selected Node.
47168 this.tb.selectedNode = sel;
47171 Roo.menu.MenuMgr.hideAll();
47175 if (!updateFooter) {
47176 //this.footDisp.dom.innerHTML = '';
47179 // update the footer
47183 this.footerEls = ans.reverse();
47184 Roo.each(this.footerEls, function(a,i) {
47185 if (!a) { return; }
47186 html += html.length ? ' > ' : '';
47188 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47193 var sz = this.footDisp.up('td').getSize();
47194 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47195 this.footDisp.dom.style.marginLeft = '5px';
47197 this.footDisp.dom.style.overflow = 'hidden';
47199 this.footDisp.dom.innerHTML = html;
47201 //this.editorsyncValue();
47208 onDestroy : function(){
47211 this.tb.items.each(function(item){
47213 item.menu.removeAll();
47215 item.menu.el.destroy();
47223 onFirstFocus: function() {
47224 // need to do this for all the toolbars..
47225 this.tb.items.each(function(item){
47229 buildToolbar: function(tlist, nm)
47231 var editor = this.editor;
47232 var editorcore = this.editorcore;
47233 // create a new element.
47234 var wdiv = editor.wrap.createChild({
47236 }, editor.wrap.dom.firstChild.nextSibling, true);
47239 var tb = new Roo.Toolbar(wdiv);
47242 tb.add(nm+ ": ");
47245 for(var i in this.styles) {
47250 if (styles && styles.length) {
47252 // this needs a multi-select checkbox...
47253 tb.addField( new Roo.form.ComboBox({
47254 store: new Roo.data.SimpleStore({
47256 fields: ['val', 'selected'],
47259 name : '-roo-edit-className',
47260 attrname : 'className',
47261 displayField: 'val',
47265 triggerAction: 'all',
47266 emptyText:'Select Style',
47267 selectOnFocus:true,
47270 'select': function(c, r, i) {
47271 // initial support only for on class per el..
47272 tb.selectedNode.className = r ? r.get('val') : '';
47273 editorcore.syncValue();
47280 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47281 var tbops = tbc.options;
47283 for (var i in tlist) {
47285 var item = tlist[i];
47286 tb.add(item.title + ": ");
47289 //optname == used so you can configure the options available..
47290 var opts = item.opts ? item.opts : false;
47291 if (item.optname) {
47292 opts = tbops[item.optname];
47297 // opts == pulldown..
47298 tb.addField( new Roo.form.ComboBox({
47299 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47301 fields: ['val', 'display'],
47304 name : '-roo-edit-' + i,
47306 stylename : item.style ? item.style : false,
47307 displayField: item.displayField ? item.displayField : 'val',
47308 valueField : 'val',
47310 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47312 triggerAction: 'all',
47313 emptyText:'Select',
47314 selectOnFocus:true,
47315 width: item.width ? item.width : 130,
47317 'select': function(c, r, i) {
47319 tb.selectedNode.style[c.stylename] = r.get('val');
47322 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47331 tb.addField( new Roo.form.TextField({
47334 //allowBlank:false,
47339 tb.addField( new Roo.form.TextField({
47340 name: '-roo-edit-' + i,
47347 'change' : function(f, nv, ov) {
47348 tb.selectedNode.setAttribute(f.attrname, nv);
47349 editorcore.syncValue();
47362 text: 'Stylesheets',
47365 click : function ()
47367 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47375 text: 'Remove Tag',
47378 click : function ()
47381 // undo does not work.
47383 var sn = tb.selectedNode;
47385 var pn = sn.parentNode;
47387 var stn = sn.childNodes[0];
47388 var en = sn.childNodes[sn.childNodes.length - 1 ];
47389 while (sn.childNodes.length) {
47390 var node = sn.childNodes[0];
47391 sn.removeChild(node);
47393 pn.insertBefore(node, sn);
47396 pn.removeChild(sn);
47397 var range = editorcore.createRange();
47399 range.setStart(stn,0);
47400 range.setEnd(en,0); //????
47401 //range.selectNode(sel);
47404 var selection = editorcore.getSelection();
47405 selection.removeAllRanges();
47406 selection.addRange(range);
47410 //_this.updateToolbar(null, null, pn);
47411 _this.updateToolbar(null, null, null);
47412 _this.footDisp.dom.innerHTML = '';
47422 tb.el.on('click', function(e){
47423 e.preventDefault(); // what does this do?
47425 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47428 // dont need to disable them... as they will get hidden
47433 buildFooter : function()
47436 var fel = this.editor.wrap.createChild();
47437 this.footer = new Roo.Toolbar(fel);
47438 // toolbar has scrolly on left / right?
47439 var footDisp= new Roo.Toolbar.Fill();
47445 handler : function() {
47446 _t.footDisp.scrollTo('left',0,true)
47450 this.footer.add( footDisp );
47455 handler : function() {
47457 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47461 var fel = Roo.get(footDisp.el);
47462 fel.addClass('x-editor-context');
47463 this.footDispWrap = fel;
47464 this.footDispWrap.overflow = 'hidden';
47466 this.footDisp = fel.createChild();
47467 this.footDispWrap.on('click', this.onContextClick, this)
47471 onContextClick : function (ev,dom)
47473 ev.preventDefault();
47474 var cn = dom.className;
47476 if (!cn.match(/x-ed-loc-/)) {
47479 var n = cn.split('-').pop();
47480 var ans = this.footerEls;
47484 var range = this.editorcore.createRange();
47486 range.selectNodeContents(sel);
47487 //range.selectNode(sel);
47490 var selection = this.editorcore.getSelection();
47491 selection.removeAllRanges();
47492 selection.addRange(range);
47496 this.updateToolbar(null, null, sel);
47513 * Ext JS Library 1.1.1
47514 * Copyright(c) 2006-2007, Ext JS, LLC.
47516 * Originally Released Under LGPL - original licence link has changed is not relivant.
47519 * <script type="text/javascript">
47523 * @class Roo.form.BasicForm
47524 * @extends Roo.util.Observable
47525 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47527 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47528 * @param {Object} config Configuration options
47530 Roo.form.BasicForm = function(el, config){
47531 this.allItems = [];
47532 this.childForms = [];
47533 Roo.apply(this, config);
47535 * The Roo.form.Field items in this form.
47536 * @type MixedCollection
47540 this.items = new Roo.util.MixedCollection(false, function(o){
47541 return o.id || (o.id = Roo.id());
47545 * @event beforeaction
47546 * Fires before any action is performed. Return false to cancel the action.
47547 * @param {Form} this
47548 * @param {Action} action The action to be performed
47550 beforeaction: true,
47552 * @event actionfailed
47553 * Fires when an action fails.
47554 * @param {Form} this
47555 * @param {Action} action The action that failed
47557 actionfailed : true,
47559 * @event actioncomplete
47560 * Fires when an action is completed.
47561 * @param {Form} this
47562 * @param {Action} action The action that completed
47564 actioncomplete : true
47569 Roo.form.BasicForm.superclass.constructor.call(this);
47571 Roo.form.BasicForm.popover.apply();
47574 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47576 * @cfg {String} method
47577 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47580 * @cfg {DataReader} reader
47581 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47582 * This is optional as there is built-in support for processing JSON.
47585 * @cfg {DataReader} errorReader
47586 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47587 * This is completely optional as there is built-in support for processing JSON.
47590 * @cfg {String} url
47591 * The URL to use for form actions if one isn't supplied in the action options.
47594 * @cfg {Boolean} fileUpload
47595 * Set to true if this form is a file upload.
47599 * @cfg {Object} baseParams
47600 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47605 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47610 activeAction : null,
47613 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47614 * or setValues() data instead of when the form was first created.
47616 trackResetOnLoad : false,
47620 * childForms - used for multi-tab forms
47623 childForms : false,
47626 * allItems - full list of fields.
47632 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47633 * element by passing it or its id or mask the form itself by passing in true.
47636 waitMsgTarget : false,
47641 disableMask : false,
47644 * @cfg {Boolean} errorMask (true|false) default false
47649 * @cfg {Number} maskOffset Default 100
47654 initEl : function(el){
47655 this.el = Roo.get(el);
47656 this.id = this.el.id || Roo.id();
47657 this.el.on('submit', this.onSubmit, this);
47658 this.el.addClass('x-form');
47662 onSubmit : function(e){
47667 * Returns true if client-side validation on the form is successful.
47670 isValid : function(){
47672 var target = false;
47673 this.items.each(function(f){
47680 if(!target && f.el.isVisible(true)){
47685 if(this.errorMask && !valid){
47686 Roo.form.BasicForm.popover.mask(this, target);
47692 * Returns array of invalid form fields.
47696 invalidFields : function()
47699 this.items.each(function(f){
47712 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47715 isDirty : function(){
47717 this.items.each(function(f){
47727 * Returns true if any fields in this form have changed since their original load. (New version)
47731 hasChanged : function()
47734 this.items.each(function(f){
47735 if(f.hasChanged()){
47744 * Resets all hasChanged to 'false' -
47745 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47746 * So hasChanged storage is only to be used for this purpose
47749 resetHasChanged : function()
47751 this.items.each(function(f){
47752 f.resetHasChanged();
47759 * Performs a predefined action (submit or load) or custom actions you define on this form.
47760 * @param {String} actionName The name of the action type
47761 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47762 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47763 * accept other config options):
47765 Property Type Description
47766 ---------------- --------------- ----------------------------------------------------------------------------------
47767 url String The url for the action (defaults to the form's url)
47768 method String The form method to use (defaults to the form's method, or POST if not defined)
47769 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47770 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47771 validate the form on the client (defaults to false)
47773 * @return {BasicForm} this
47775 doAction : function(action, options){
47776 if(typeof action == 'string'){
47777 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47779 if(this.fireEvent('beforeaction', this, action) !== false){
47780 this.beforeAction(action);
47781 action.run.defer(100, action);
47787 * Shortcut to do a submit action.
47788 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47789 * @return {BasicForm} this
47791 submit : function(options){
47792 this.doAction('submit', options);
47797 * Shortcut to do a load action.
47798 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47799 * @return {BasicForm} this
47801 load : function(options){
47802 this.doAction('load', options);
47807 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47808 * @param {Record} record The record to edit
47809 * @return {BasicForm} this
47811 updateRecord : function(record){
47812 record.beginEdit();
47813 var fs = record.fields;
47814 fs.each(function(f){
47815 var field = this.findField(f.name);
47817 record.set(f.name, field.getValue());
47825 * Loads an Roo.data.Record into this form.
47826 * @param {Record} record The record to load
47827 * @return {BasicForm} this
47829 loadRecord : function(record){
47830 this.setValues(record.data);
47835 beforeAction : function(action){
47836 var o = action.options;
47838 if(!this.disableMask) {
47839 if(this.waitMsgTarget === true){
47840 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47841 }else if(this.waitMsgTarget){
47842 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47843 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47845 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47853 afterAction : function(action, success){
47854 this.activeAction = null;
47855 var o = action.options;
47857 if(!this.disableMask) {
47858 if(this.waitMsgTarget === true){
47860 }else if(this.waitMsgTarget){
47861 this.waitMsgTarget.unmask();
47863 Roo.MessageBox.updateProgress(1);
47864 Roo.MessageBox.hide();
47872 Roo.callback(o.success, o.scope, [this, action]);
47873 this.fireEvent('actioncomplete', this, action);
47877 // failure condition..
47878 // we have a scenario where updates need confirming.
47879 // eg. if a locking scenario exists..
47880 // we look for { errors : { needs_confirm : true }} in the response.
47882 (typeof(action.result) != 'undefined') &&
47883 (typeof(action.result.errors) != 'undefined') &&
47884 (typeof(action.result.errors.needs_confirm) != 'undefined')
47887 Roo.MessageBox.confirm(
47888 "Change requires confirmation",
47889 action.result.errorMsg,
47894 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47904 Roo.callback(o.failure, o.scope, [this, action]);
47905 // show an error message if no failed handler is set..
47906 if (!this.hasListener('actionfailed')) {
47907 Roo.MessageBox.alert("Error",
47908 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47909 action.result.errorMsg :
47910 "Saving Failed, please check your entries or try again"
47914 this.fireEvent('actionfailed', this, action);
47920 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47921 * @param {String} id The value to search for
47924 findField : function(id){
47925 var field = this.items.get(id);
47927 this.items.each(function(f){
47928 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47934 return field || null;
47938 * Add a secondary form to this one,
47939 * Used to provide tabbed forms. One form is primary, with hidden values
47940 * which mirror the elements from the other forms.
47942 * @param {Roo.form.Form} form to add.
47945 addForm : function(form)
47948 if (this.childForms.indexOf(form) > -1) {
47952 this.childForms.push(form);
47954 Roo.each(form.allItems, function (fe) {
47956 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
47957 if (this.findField(n)) { // already added..
47960 var add = new Roo.form.Hidden({
47963 add.render(this.el);
47970 * Mark fields in this form invalid in bulk.
47971 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
47972 * @return {BasicForm} this
47974 markInvalid : function(errors){
47975 if(errors instanceof Array){
47976 for(var i = 0, len = errors.length; i < len; i++){
47977 var fieldError = errors[i];
47978 var f = this.findField(fieldError.id);
47980 f.markInvalid(fieldError.msg);
47986 if(typeof errors[id] != 'function' && (field = this.findField(id))){
47987 field.markInvalid(errors[id]);
47991 Roo.each(this.childForms || [], function (f) {
47992 f.markInvalid(errors);
47999 * Set values for fields in this form in bulk.
48000 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
48001 * @return {BasicForm} this
48003 setValues : function(values){
48004 if(values instanceof Array){ // array of objects
48005 for(var i = 0, len = values.length; i < len; i++){
48007 var f = this.findField(v.id);
48009 f.setValue(v.value);
48010 if(this.trackResetOnLoad){
48011 f.originalValue = f.getValue();
48015 }else{ // object hash
48018 if(typeof values[id] != 'function' && (field = this.findField(id))){
48020 if (field.setFromData &&
48021 field.valueField &&
48022 field.displayField &&
48023 // combos' with local stores can
48024 // be queried via setValue()
48025 // to set their value..
48026 (field.store && !field.store.isLocal)
48030 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
48031 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
48032 field.setFromData(sd);
48035 field.setValue(values[id]);
48039 if(this.trackResetOnLoad){
48040 field.originalValue = field.getValue();
48045 this.resetHasChanged();
48048 Roo.each(this.childForms || [], function (f) {
48049 f.setValues(values);
48050 f.resetHasChanged();
48057 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
48058 * they are returned as an array.
48059 * @param {Boolean} asString
48062 getValues : function(asString){
48063 if (this.childForms) {
48064 // copy values from the child forms
48065 Roo.each(this.childForms, function (f) {
48066 this.setValues(f.getValues());
48071 if (typeof(FormData) != 'undefined' && asString !== true) {
48072 // this relies on a 'recent' version of chrome apparently...
48074 var fd = (new FormData(this.el.dom)).entries();
48076 var ent = fd.next();
48077 while (!ent.done) {
48078 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
48089 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
48090 if(asString === true){
48093 return Roo.urlDecode(fs);
48097 * Returns the fields in this form as an object with key/value pairs.
48098 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48101 getFieldValues : function(with_hidden)
48103 if (this.childForms) {
48104 // copy values from the child forms
48105 // should this call getFieldValues - probably not as we do not currently copy
48106 // hidden fields when we generate..
48107 Roo.each(this.childForms, function (f) {
48108 this.setValues(f.getValues());
48113 this.items.each(function(f){
48114 if (!f.getName()) {
48117 var v = f.getValue();
48118 if (f.inputType =='radio') {
48119 if (typeof(ret[f.getName()]) == 'undefined') {
48120 ret[f.getName()] = ''; // empty..
48123 if (!f.el.dom.checked) {
48127 v = f.el.dom.value;
48131 // not sure if this supported any more..
48132 if ((typeof(v) == 'object') && f.getRawValue) {
48133 v = f.getRawValue() ; // dates..
48135 // combo boxes where name != hiddenName...
48136 if (f.name != f.getName()) {
48137 ret[f.name] = f.getRawValue();
48139 ret[f.getName()] = v;
48146 * Clears all invalid messages in this form.
48147 * @return {BasicForm} this
48149 clearInvalid : function(){
48150 this.items.each(function(f){
48154 Roo.each(this.childForms || [], function (f) {
48163 * Resets this form.
48164 * @return {BasicForm} this
48166 reset : function(){
48167 this.items.each(function(f){
48171 Roo.each(this.childForms || [], function (f) {
48174 this.resetHasChanged();
48180 * Add Roo.form components to this form.
48181 * @param {Field} field1
48182 * @param {Field} field2 (optional)
48183 * @param {Field} etc (optional)
48184 * @return {BasicForm} this
48187 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48193 * Removes a field from the items collection (does NOT remove its markup).
48194 * @param {Field} field
48195 * @return {BasicForm} this
48197 remove : function(field){
48198 this.items.remove(field);
48203 * Looks at the fields in this form, checks them for an id attribute,
48204 * and calls applyTo on the existing dom element with that id.
48205 * @return {BasicForm} this
48207 render : function(){
48208 this.items.each(function(f){
48209 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48217 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48218 * @param {Object} values
48219 * @return {BasicForm} this
48221 applyToFields : function(o){
48222 this.items.each(function(f){
48229 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48230 * @param {Object} values
48231 * @return {BasicForm} this
48233 applyIfToFields : function(o){
48234 this.items.each(function(f){
48242 Roo.BasicForm = Roo.form.BasicForm;
48244 Roo.apply(Roo.form.BasicForm, {
48258 intervalID : false,
48264 if(this.isApplied){
48269 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48270 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48271 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48272 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48275 this.maskEl.top.enableDisplayMode("block");
48276 this.maskEl.left.enableDisplayMode("block");
48277 this.maskEl.bottom.enableDisplayMode("block");
48278 this.maskEl.right.enableDisplayMode("block");
48280 Roo.get(document.body).on('click', function(){
48284 Roo.get(document.body).on('touchstart', function(){
48288 this.isApplied = true
48291 mask : function(form, target)
48295 this.target = target;
48297 if(!this.form.errorMask || !target.el){
48301 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48303 var ot = this.target.el.calcOffsetsTo(scrollable);
48305 var scrollTo = ot[1] - this.form.maskOffset;
48307 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48309 scrollable.scrollTo('top', scrollTo);
48311 var el = this.target.wrap || this.target.el;
48313 var box = el.getBox();
48315 this.maskEl.top.setStyle('position', 'absolute');
48316 this.maskEl.top.setStyle('z-index', 10000);
48317 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48318 this.maskEl.top.setLeft(0);
48319 this.maskEl.top.setTop(0);
48320 this.maskEl.top.show();
48322 this.maskEl.left.setStyle('position', 'absolute');
48323 this.maskEl.left.setStyle('z-index', 10000);
48324 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48325 this.maskEl.left.setLeft(0);
48326 this.maskEl.left.setTop(box.y - this.padding);
48327 this.maskEl.left.show();
48329 this.maskEl.bottom.setStyle('position', 'absolute');
48330 this.maskEl.bottom.setStyle('z-index', 10000);
48331 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48332 this.maskEl.bottom.setLeft(0);
48333 this.maskEl.bottom.setTop(box.bottom + this.padding);
48334 this.maskEl.bottom.show();
48336 this.maskEl.right.setStyle('position', 'absolute');
48337 this.maskEl.right.setStyle('z-index', 10000);
48338 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48339 this.maskEl.right.setLeft(box.right + this.padding);
48340 this.maskEl.right.setTop(box.y - this.padding);
48341 this.maskEl.right.show();
48343 this.intervalID = window.setInterval(function() {
48344 Roo.form.BasicForm.popover.unmask();
48347 window.onwheel = function(){ return false;};
48349 (function(){ this.isMasked = true; }).defer(500, this);
48353 unmask : function()
48355 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48359 this.maskEl.top.setStyle('position', 'absolute');
48360 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48361 this.maskEl.top.hide();
48363 this.maskEl.left.setStyle('position', 'absolute');
48364 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48365 this.maskEl.left.hide();
48367 this.maskEl.bottom.setStyle('position', 'absolute');
48368 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48369 this.maskEl.bottom.hide();
48371 this.maskEl.right.setStyle('position', 'absolute');
48372 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48373 this.maskEl.right.hide();
48375 window.onwheel = function(){ return true;};
48377 if(this.intervalID){
48378 window.clearInterval(this.intervalID);
48379 this.intervalID = false;
48382 this.isMasked = false;
48390 * Ext JS Library 1.1.1
48391 * Copyright(c) 2006-2007, Ext JS, LLC.
48393 * Originally Released Under LGPL - original licence link has changed is not relivant.
48396 * <script type="text/javascript">
48400 * @class Roo.form.Form
48401 * @extends Roo.form.BasicForm
48402 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48404 * @param {Object} config Configuration options
48406 Roo.form.Form = function(config){
48408 if (config.items) {
48409 xitems = config.items;
48410 delete config.items;
48414 Roo.form.Form.superclass.constructor.call(this, null, config);
48415 this.url = this.url || this.action;
48417 this.root = new Roo.form.Layout(Roo.applyIf({
48421 this.active = this.root;
48423 * Array of all the buttons that have been added to this form via {@link addButton}
48427 this.allItems = [];
48430 * @event clientvalidation
48431 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48432 * @param {Form} this
48433 * @param {Boolean} valid true if the form has passed client-side validation
48435 clientvalidation: true,
48438 * Fires when the form is rendered
48439 * @param {Roo.form.Form} form
48444 if (this.progressUrl) {
48445 // push a hidden field onto the list of fields..
48449 name : 'UPLOAD_IDENTIFIER'
48454 Roo.each(xitems, this.addxtype, this);
48458 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48460 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48463 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48466 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48468 buttonAlign:'center',
48471 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48476 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48477 * This property cascades to child containers if not set.
48482 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48483 * fires a looping event with that state. This is required to bind buttons to the valid
48484 * state using the config value formBind:true on the button.
48486 monitorValid : false,
48489 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48494 * @cfg {String} progressUrl - Url to return progress data
48497 progressUrl : false,
48499 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48500 * sending a formdata with extra parameters - eg uploaded elements.
48506 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48507 * fields are added and the column is closed. If no fields are passed the column remains open
48508 * until end() is called.
48509 * @param {Object} config The config to pass to the column
48510 * @param {Field} field1 (optional)
48511 * @param {Field} field2 (optional)
48512 * @param {Field} etc (optional)
48513 * @return Column The column container object
48515 column : function(c){
48516 var col = new Roo.form.Column(c);
48518 if(arguments.length > 1){ // duplicate code required because of Opera
48519 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48526 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48527 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48528 * until end() is called.
48529 * @param {Object} config The config to pass to the fieldset
48530 * @param {Field} field1 (optional)
48531 * @param {Field} field2 (optional)
48532 * @param {Field} etc (optional)
48533 * @return FieldSet The fieldset container object
48535 fieldset : function(c){
48536 var fs = new Roo.form.FieldSet(c);
48538 if(arguments.length > 1){ // duplicate code required because of Opera
48539 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48546 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48547 * fields are added and the container is closed. If no fields are passed the container remains open
48548 * until end() is called.
48549 * @param {Object} config The config to pass to the Layout
48550 * @param {Field} field1 (optional)
48551 * @param {Field} field2 (optional)
48552 * @param {Field} etc (optional)
48553 * @return Layout The container object
48555 container : function(c){
48556 var l = new Roo.form.Layout(c);
48558 if(arguments.length > 1){ // duplicate code required because of Opera
48559 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48566 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48567 * @param {Object} container A Roo.form.Layout or subclass of Layout
48568 * @return {Form} this
48570 start : function(c){
48571 // cascade label info
48572 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48573 this.active.stack.push(c);
48574 c.ownerCt = this.active;
48580 * Closes the current open container
48581 * @return {Form} this
48584 if(this.active == this.root){
48587 this.active = this.active.ownerCt;
48592 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48593 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48594 * as the label of the field.
48595 * @param {Field} field1
48596 * @param {Field} field2 (optional)
48597 * @param {Field} etc. (optional)
48598 * @return {Form} this
48601 this.active.stack.push.apply(this.active.stack, arguments);
48602 this.allItems.push.apply(this.allItems,arguments);
48604 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48605 if(a[i].isFormField){
48610 Roo.form.Form.superclass.add.apply(this, r);
48620 * Find any element that has been added to a form, using it's ID or name
48621 * This can include framesets, columns etc. along with regular fields..
48622 * @param {String} id - id or name to find.
48624 * @return {Element} e - or false if nothing found.
48626 findbyId : function(id)
48632 Roo.each(this.allItems, function(f){
48633 if (f.id == id || f.name == id ){
48644 * Render this form into the passed container. This should only be called once!
48645 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48646 * @return {Form} this
48648 render : function(ct)
48654 var o = this.autoCreate || {
48656 method : this.method || 'POST',
48657 id : this.id || Roo.id()
48659 this.initEl(ct.createChild(o));
48661 this.root.render(this.el);
48665 this.items.each(function(f){
48666 f.render('x-form-el-'+f.id);
48669 if(this.buttons.length > 0){
48670 // tables are required to maintain order and for correct IE layout
48671 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48672 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48673 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48675 var tr = tb.getElementsByTagName('tr')[0];
48676 for(var i = 0, len = this.buttons.length; i < len; i++) {
48677 var b = this.buttons[i];
48678 var td = document.createElement('td');
48679 td.className = 'x-form-btn-td';
48680 b.render(tr.appendChild(td));
48683 if(this.monitorValid){ // initialize after render
48684 this.startMonitoring();
48686 this.fireEvent('rendered', this);
48691 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48692 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48693 * object or a valid Roo.DomHelper element config
48694 * @param {Function} handler The function called when the button is clicked
48695 * @param {Object} scope (optional) The scope of the handler function
48696 * @return {Roo.Button}
48698 addButton : function(config, handler, scope){
48702 minWidth: this.minButtonWidth,
48705 if(typeof config == "string"){
48708 Roo.apply(bc, config);
48710 var btn = new Roo.Button(null, bc);
48711 this.buttons.push(btn);
48716 * Adds a series of form elements (using the xtype property as the factory method.
48717 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48718 * @param {Object} config
48721 addxtype : function()
48723 var ar = Array.prototype.slice.call(arguments, 0);
48725 for(var i = 0; i < ar.length; i++) {
48727 continue; // skip -- if this happends something invalid got sent, we
48728 // should ignore it, as basically that interface element will not show up
48729 // and that should be pretty obvious!!
48732 if (Roo.form[ar[i].xtype]) {
48734 var fe = Roo.factory(ar[i], Roo.form);
48740 fe.store.form = this;
48745 this.allItems.push(fe);
48746 if (fe.items && fe.addxtype) {
48747 fe.addxtype.apply(fe, fe.items);
48757 // console.log('adding ' + ar[i].xtype);
48759 if (ar[i].xtype == 'Button') {
48760 //console.log('adding button');
48761 //console.log(ar[i]);
48762 this.addButton(ar[i]);
48763 this.allItems.push(fe);
48767 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48768 alert('end is not supported on xtype any more, use items');
48770 // //console.log('adding end');
48778 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48779 * option "monitorValid"
48781 startMonitoring : function(){
48784 Roo.TaskMgr.start({
48785 run : this.bindHandler,
48786 interval : this.monitorPoll || 200,
48793 * Stops monitoring of the valid state of this form
48795 stopMonitoring : function(){
48796 this.bound = false;
48800 bindHandler : function(){
48802 return false; // stops binding
48805 this.items.each(function(f){
48806 if(!f.isValid(true)){
48811 for(var i = 0, len = this.buttons.length; i < len; i++){
48812 var btn = this.buttons[i];
48813 if(btn.formBind === true && btn.disabled === valid){
48814 btn.setDisabled(!valid);
48817 this.fireEvent('clientvalidation', this, valid);
48831 Roo.Form = Roo.form.Form;
48834 * Ext JS Library 1.1.1
48835 * Copyright(c) 2006-2007, Ext JS, LLC.
48837 * Originally Released Under LGPL - original licence link has changed is not relivant.
48840 * <script type="text/javascript">
48843 // as we use this in bootstrap.
48844 Roo.namespace('Roo.form');
48846 * @class Roo.form.Action
48847 * Internal Class used to handle form actions
48849 * @param {Roo.form.BasicForm} el The form element or its id
48850 * @param {Object} config Configuration options
48855 // define the action interface
48856 Roo.form.Action = function(form, options){
48858 this.options = options || {};
48861 * Client Validation Failed
48864 Roo.form.Action.CLIENT_INVALID = 'client';
48866 * Server Validation Failed
48869 Roo.form.Action.SERVER_INVALID = 'server';
48871 * Connect to Server Failed
48874 Roo.form.Action.CONNECT_FAILURE = 'connect';
48876 * Reading Data from Server Failed
48879 Roo.form.Action.LOAD_FAILURE = 'load';
48881 Roo.form.Action.prototype = {
48883 failureType : undefined,
48884 response : undefined,
48885 result : undefined,
48887 // interface method
48888 run : function(options){
48892 // interface method
48893 success : function(response){
48897 // interface method
48898 handleResponse : function(response){
48902 // default connection failure
48903 failure : function(response){
48905 this.response = response;
48906 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48907 this.form.afterAction(this, false);
48910 processResponse : function(response){
48911 this.response = response;
48912 if(!response.responseText){
48915 this.result = this.handleResponse(response);
48916 return this.result;
48919 // utility functions used internally
48920 getUrl : function(appendParams){
48921 var url = this.options.url || this.form.url || this.form.el.dom.action;
48923 var p = this.getParams();
48925 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
48931 getMethod : function(){
48932 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
48935 getParams : function(){
48936 var bp = this.form.baseParams;
48937 var p = this.options.params;
48939 if(typeof p == "object"){
48940 p = Roo.urlEncode(Roo.applyIf(p, bp));
48941 }else if(typeof p == 'string' && bp){
48942 p += '&' + Roo.urlEncode(bp);
48945 p = Roo.urlEncode(bp);
48950 createCallback : function(){
48952 success: this.success,
48953 failure: this.failure,
48955 timeout: (this.form.timeout*1000),
48956 upload: this.form.fileUpload ? this.success : undefined
48961 Roo.form.Action.Submit = function(form, options){
48962 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
48965 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
48968 haveProgress : false,
48969 uploadComplete : false,
48971 // uploadProgress indicator.
48972 uploadProgress : function()
48974 if (!this.form.progressUrl) {
48978 if (!this.haveProgress) {
48979 Roo.MessageBox.progress("Uploading", "Uploading");
48981 if (this.uploadComplete) {
48982 Roo.MessageBox.hide();
48986 this.haveProgress = true;
48988 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
48990 var c = new Roo.data.Connection();
48992 url : this.form.progressUrl,
48997 success : function(req){
48998 //console.log(data);
49002 rdata = Roo.decode(req.responseText)
49004 Roo.log("Invalid data from server..");
49008 if (!rdata || !rdata.success) {
49010 Roo.MessageBox.alert(Roo.encode(rdata));
49013 var data = rdata.data;
49015 if (this.uploadComplete) {
49016 Roo.MessageBox.hide();
49021 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
49022 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
49025 this.uploadProgress.defer(2000,this);
49028 failure: function(data) {
49029 Roo.log('progress url failed ');
49040 // run get Values on the form, so it syncs any secondary forms.
49041 this.form.getValues();
49043 var o = this.options;
49044 var method = this.getMethod();
49045 var isPost = method == 'POST';
49046 if(o.clientValidation === false || this.form.isValid()){
49048 if (this.form.progressUrl) {
49049 this.form.findField('UPLOAD_IDENTIFIER').setValue(
49050 (new Date() * 1) + '' + Math.random());
49055 Roo.Ajax.request(Roo.apply(this.createCallback(), {
49056 form:this.form.el.dom,
49057 url:this.getUrl(!isPost),
49059 params:isPost ? this.getParams() : null,
49060 isUpload: this.form.fileUpload,
49061 formData : this.form.formData
49064 this.uploadProgress();
49066 }else if (o.clientValidation !== false){ // client validation failed
49067 this.failureType = Roo.form.Action.CLIENT_INVALID;
49068 this.form.afterAction(this, false);
49072 success : function(response)
49074 this.uploadComplete= true;
49075 if (this.haveProgress) {
49076 Roo.MessageBox.hide();
49080 var result = this.processResponse(response);
49081 if(result === true || result.success){
49082 this.form.afterAction(this, true);
49086 this.form.markInvalid(result.errors);
49087 this.failureType = Roo.form.Action.SERVER_INVALID;
49089 this.form.afterAction(this, false);
49091 failure : function(response)
49093 this.uploadComplete= true;
49094 if (this.haveProgress) {
49095 Roo.MessageBox.hide();
49098 this.response = response;
49099 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49100 this.form.afterAction(this, false);
49103 handleResponse : function(response){
49104 if(this.form.errorReader){
49105 var rs = this.form.errorReader.read(response);
49108 for(var i = 0, len = rs.records.length; i < len; i++) {
49109 var r = rs.records[i];
49110 errors[i] = r.data;
49113 if(errors.length < 1){
49117 success : rs.success,
49123 ret = Roo.decode(response.responseText);
49127 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49137 Roo.form.Action.Load = function(form, options){
49138 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49139 this.reader = this.form.reader;
49142 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49147 Roo.Ajax.request(Roo.apply(
49148 this.createCallback(), {
49149 method:this.getMethod(),
49150 url:this.getUrl(false),
49151 params:this.getParams()
49155 success : function(response){
49157 var result = this.processResponse(response);
49158 if(result === true || !result.success || !result.data){
49159 this.failureType = Roo.form.Action.LOAD_FAILURE;
49160 this.form.afterAction(this, false);
49163 this.form.clearInvalid();
49164 this.form.setValues(result.data);
49165 this.form.afterAction(this, true);
49168 handleResponse : function(response){
49169 if(this.form.reader){
49170 var rs = this.form.reader.read(response);
49171 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49173 success : rs.success,
49177 return Roo.decode(response.responseText);
49181 Roo.form.Action.ACTION_TYPES = {
49182 'load' : Roo.form.Action.Load,
49183 'submit' : Roo.form.Action.Submit
49186 * Ext JS Library 1.1.1
49187 * Copyright(c) 2006-2007, Ext JS, LLC.
49189 * Originally Released Under LGPL - original licence link has changed is not relivant.
49192 * <script type="text/javascript">
49196 * @class Roo.form.Layout
49197 * @extends Roo.Component
49198 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49200 * @param {Object} config Configuration options
49202 Roo.form.Layout = function(config){
49204 if (config.items) {
49205 xitems = config.items;
49206 delete config.items;
49208 Roo.form.Layout.superclass.constructor.call(this, config);
49210 Roo.each(xitems, this.addxtype, this);
49214 Roo.extend(Roo.form.Layout, Roo.Component, {
49216 * @cfg {String/Object} autoCreate
49217 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49220 * @cfg {String/Object/Function} style
49221 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49222 * a function which returns such a specification.
49225 * @cfg {String} labelAlign
49226 * Valid values are "left," "top" and "right" (defaults to "left")
49229 * @cfg {Number} labelWidth
49230 * Fixed width in pixels of all field labels (defaults to undefined)
49233 * @cfg {Boolean} clear
49234 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49238 * @cfg {String} labelSeparator
49239 * The separator to use after field labels (defaults to ':')
49241 labelSeparator : ':',
49243 * @cfg {Boolean} hideLabels
49244 * True to suppress the display of field labels in this layout (defaults to false)
49246 hideLabels : false,
49249 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49254 onRender : function(ct, position){
49255 if(this.el){ // from markup
49256 this.el = Roo.get(this.el);
49257 }else { // generate
49258 var cfg = this.getAutoCreate();
49259 this.el = ct.createChild(cfg, position);
49262 this.el.applyStyles(this.style);
49264 if(this.labelAlign){
49265 this.el.addClass('x-form-label-'+this.labelAlign);
49267 if(this.hideLabels){
49268 this.labelStyle = "display:none";
49269 this.elementStyle = "padding-left:0;";
49271 if(typeof this.labelWidth == 'number'){
49272 this.labelStyle = "width:"+this.labelWidth+"px;";
49273 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49275 if(this.labelAlign == 'top'){
49276 this.labelStyle = "width:auto;";
49277 this.elementStyle = "padding-left:0;";
49280 var stack = this.stack;
49281 var slen = stack.length;
49283 if(!this.fieldTpl){
49284 var t = new Roo.Template(
49285 '<div class="x-form-item {5}">',
49286 '<label for="{0}" style="{2}">{1}{4}</label>',
49287 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49289 '</div><div class="x-form-clear-left"></div>'
49291 t.disableFormats = true;
49293 Roo.form.Layout.prototype.fieldTpl = t;
49295 for(var i = 0; i < slen; i++) {
49296 if(stack[i].isFormField){
49297 this.renderField(stack[i]);
49299 this.renderComponent(stack[i]);
49304 this.el.createChild({cls:'x-form-clear'});
49309 renderField : function(f){
49310 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49313 f.labelStyle||this.labelStyle||'', //2
49314 this.elementStyle||'', //3
49315 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49316 f.itemCls||this.itemCls||'' //5
49317 ], true).getPrevSibling());
49321 renderComponent : function(c){
49322 c.render(c.isLayout ? this.el : this.el.createChild());
49325 * Adds a object form elements (using the xtype property as the factory method.)
49326 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49327 * @param {Object} config
49329 addxtype : function(o)
49331 // create the lement.
49332 o.form = this.form;
49333 var fe = Roo.factory(o, Roo.form);
49334 this.form.allItems.push(fe);
49335 this.stack.push(fe);
49337 if (fe.isFormField) {
49338 this.form.items.add(fe);
49346 * @class Roo.form.Column
49347 * @extends Roo.form.Layout
49348 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49350 * @param {Object} config Configuration options
49352 Roo.form.Column = function(config){
49353 Roo.form.Column.superclass.constructor.call(this, config);
49356 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49358 * @cfg {Number/String} width
49359 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49362 * @cfg {String/Object} autoCreate
49363 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49367 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49370 onRender : function(ct, position){
49371 Roo.form.Column.superclass.onRender.call(this, ct, position);
49373 this.el.setWidth(this.width);
49380 * @class Roo.form.Row
49381 * @extends Roo.form.Layout
49382 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49384 * @param {Object} config Configuration options
49388 Roo.form.Row = function(config){
49389 Roo.form.Row.superclass.constructor.call(this, config);
49392 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49394 * @cfg {Number/String} width
49395 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49398 * @cfg {Number/String} height
49399 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49401 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49405 onRender : function(ct, position){
49406 //console.log('row render');
49408 var t = new Roo.Template(
49409 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49410 '<label for="{0}" style="{2}">{1}{4}</label>',
49411 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49415 t.disableFormats = true;
49417 Roo.form.Layout.prototype.rowTpl = t;
49419 this.fieldTpl = this.rowTpl;
49421 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49422 var labelWidth = 100;
49424 if ((this.labelAlign != 'top')) {
49425 if (typeof this.labelWidth == 'number') {
49426 labelWidth = this.labelWidth
49428 this.padWidth = 20 + labelWidth;
49432 Roo.form.Column.superclass.onRender.call(this, ct, position);
49434 this.el.setWidth(this.width);
49437 this.el.setHeight(this.height);
49442 renderField : function(f){
49443 f.fieldEl = this.fieldTpl.append(this.el, [
49444 f.id, f.fieldLabel,
49445 f.labelStyle||this.labelStyle||'',
49446 this.elementStyle||'',
49447 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49448 f.itemCls||this.itemCls||'',
49449 f.width ? f.width + this.padWidth : 160 + this.padWidth
49456 * @class Roo.form.FieldSet
49457 * @extends Roo.form.Layout
49458 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49460 * @param {Object} config Configuration options
49462 Roo.form.FieldSet = function(config){
49463 Roo.form.FieldSet.superclass.constructor.call(this, config);
49466 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49468 * @cfg {String} legend
49469 * The text to display as the legend for the FieldSet (defaults to '')
49472 * @cfg {String/Object} autoCreate
49473 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49477 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49480 onRender : function(ct, position){
49481 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49483 this.setLegend(this.legend);
49488 setLegend : function(text){
49490 this.el.child('legend').update(text);
49495 * Ext JS Library 1.1.1
49496 * Copyright(c) 2006-2007, Ext JS, LLC.
49498 * Originally Released Under LGPL - original licence link has changed is not relivant.
49501 * <script type="text/javascript">
49504 * @class Roo.form.VTypes
49505 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49508 Roo.form.VTypes = function(){
49509 // closure these in so they are only created once.
49510 var alpha = /^[a-zA-Z_]+$/;
49511 var alphanum = /^[a-zA-Z0-9_]+$/;
49512 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49513 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49515 // All these messages and functions are configurable
49518 * The function used to validate email addresses
49519 * @param {String} value The email address
49521 'email' : function(v){
49522 return email.test(v);
49525 * The error text to display when the email validation function returns false
49528 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49530 * The keystroke filter mask to be applied on email input
49533 'emailMask' : /[a-z0-9_\.\-@]/i,
49536 * The function used to validate URLs
49537 * @param {String} value The URL
49539 'url' : function(v){
49540 return url.test(v);
49543 * The error text to display when the url validation function returns false
49546 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49549 * The function used to validate alpha values
49550 * @param {String} value The value
49552 'alpha' : function(v){
49553 return alpha.test(v);
49556 * The error text to display when the alpha validation function returns false
49559 'alphaText' : 'This field should only contain letters and _',
49561 * The keystroke filter mask to be applied on alpha input
49564 'alphaMask' : /[a-z_]/i,
49567 * The function used to validate alphanumeric values
49568 * @param {String} value The value
49570 'alphanum' : function(v){
49571 return alphanum.test(v);
49574 * The error text to display when the alphanumeric validation function returns false
49577 'alphanumText' : 'This field should only contain letters, numbers and _',
49579 * The keystroke filter mask to be applied on alphanumeric input
49582 'alphanumMask' : /[a-z0-9_]/i
49584 }();//<script type="text/javascript">
49587 * @class Roo.form.FCKeditor
49588 * @extends Roo.form.TextArea
49589 * Wrapper around the FCKEditor http://www.fckeditor.net
49591 * Creates a new FCKeditor
49592 * @param {Object} config Configuration options
49594 Roo.form.FCKeditor = function(config){
49595 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49598 * @event editorinit
49599 * Fired when the editor is initialized - you can add extra handlers here..
49600 * @param {FCKeditor} this
49601 * @param {Object} the FCK object.
49608 Roo.form.FCKeditor.editors = { };
49609 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49611 //defaultAutoCreate : {
49612 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49616 * @cfg {Object} fck options - see fck manual for details.
49621 * @cfg {Object} fck toolbar set (Basic or Default)
49623 toolbarSet : 'Basic',
49625 * @cfg {Object} fck BasePath
49627 basePath : '/fckeditor/',
49635 onRender : function(ct, position)
49638 this.defaultAutoCreate = {
49640 style:"width:300px;height:60px;",
49641 autocomplete: "new-password"
49644 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49647 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49648 if(this.preventScrollbars){
49649 this.el.setStyle("overflow", "hidden");
49651 this.el.setHeight(this.growMin);
49654 //console.log('onrender' + this.getId() );
49655 Roo.form.FCKeditor.editors[this.getId()] = this;
49658 this.replaceTextarea() ;
49662 getEditor : function() {
49663 return this.fckEditor;
49666 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49667 * @param {Mixed} value The value to set
49671 setValue : function(value)
49673 //console.log('setValue: ' + value);
49675 if(typeof(value) == 'undefined') { // not sure why this is happending...
49678 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49680 //if(!this.el || !this.getEditor()) {
49681 // this.value = value;
49682 //this.setValue.defer(100,this,[value]);
49686 if(!this.getEditor()) {
49690 this.getEditor().SetData(value);
49697 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49698 * @return {Mixed} value The field value
49700 getValue : function()
49703 if (this.frame && this.frame.dom.style.display == 'none') {
49704 return Roo.form.FCKeditor.superclass.getValue.call(this);
49707 if(!this.el || !this.getEditor()) {
49709 // this.getValue.defer(100,this);
49714 var value=this.getEditor().GetData();
49715 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49716 return Roo.form.FCKeditor.superclass.getValue.call(this);
49722 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49723 * @return {Mixed} value The field value
49725 getRawValue : function()
49727 if (this.frame && this.frame.dom.style.display == 'none') {
49728 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49731 if(!this.el || !this.getEditor()) {
49732 //this.getRawValue.defer(100,this);
49739 var value=this.getEditor().GetData();
49740 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49741 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49745 setSize : function(w,h) {
49749 //if (this.frame && this.frame.dom.style.display == 'none') {
49750 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49753 //if(!this.el || !this.getEditor()) {
49754 // this.setSize.defer(100,this, [w,h]);
49760 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49762 this.frame.dom.setAttribute('width', w);
49763 this.frame.dom.setAttribute('height', h);
49764 this.frame.setSize(w,h);
49768 toggleSourceEdit : function(value) {
49772 this.el.dom.style.display = value ? '' : 'none';
49773 this.frame.dom.style.display = value ? 'none' : '';
49778 focus: function(tag)
49780 if (this.frame.dom.style.display == 'none') {
49781 return Roo.form.FCKeditor.superclass.focus.call(this);
49783 if(!this.el || !this.getEditor()) {
49784 this.focus.defer(100,this, [tag]);
49791 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49792 this.getEditor().Focus();
49794 if (!this.getEditor().Selection.GetSelection()) {
49795 this.focus.defer(100,this, [tag]);
49800 var r = this.getEditor().EditorDocument.createRange();
49801 r.setStart(tgs[0],0);
49802 r.setEnd(tgs[0],0);
49803 this.getEditor().Selection.GetSelection().removeAllRanges();
49804 this.getEditor().Selection.GetSelection().addRange(r);
49805 this.getEditor().Focus();
49812 replaceTextarea : function()
49814 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49817 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49819 // We must check the elements firstly using the Id and then the name.
49820 var oTextarea = document.getElementById( this.getId() );
49822 var colElementsByName = document.getElementsByName( this.getId() ) ;
49824 oTextarea.style.display = 'none' ;
49826 if ( oTextarea.tabIndex ) {
49827 this.TabIndex = oTextarea.tabIndex ;
49830 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49831 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49832 this.frame = Roo.get(this.getId() + '___Frame')
49835 _getConfigHtml : function()
49839 for ( var o in this.fckconfig ) {
49840 sConfig += sConfig.length > 0 ? '&' : '';
49841 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49844 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49848 _getIFrameHtml : function()
49850 var sFile = 'fckeditor.html' ;
49851 /* no idea what this is about..
49854 if ( (/fcksource=true/i).test( window.top.location.search ) )
49855 sFile = 'fckeditor.original.html' ;
49860 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49861 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49864 var html = '<iframe id="' + this.getId() +
49865 '___Frame" src="' + sLink +
49866 '" width="' + this.width +
49867 '" height="' + this.height + '"' +
49868 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
49869 ' frameborder="0" scrolling="no"></iframe>' ;
49874 _insertHtmlBefore : function( html, element )
49876 if ( element.insertAdjacentHTML ) {
49878 element.insertAdjacentHTML( 'beforeBegin', html ) ;
49880 var oRange = document.createRange() ;
49881 oRange.setStartBefore( element ) ;
49882 var oFragment = oRange.createContextualFragment( html );
49883 element.parentNode.insertBefore( oFragment, element ) ;
49896 //Roo.reg('fckeditor', Roo.form.FCKeditor);
49898 function FCKeditor_OnComplete(editorInstance){
49899 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
49900 f.fckEditor = editorInstance;
49901 //console.log("loaded");
49902 f.fireEvent('editorinit', f, editorInstance);
49922 //<script type="text/javascript">
49924 * @class Roo.form.GridField
49925 * @extends Roo.form.Field
49926 * Embed a grid (or editable grid into a form)
49929 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
49931 * xgrid.store = Roo.data.Store
49932 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
49933 * xgrid.store.reader = Roo.data.JsonReader
49937 * Creates a new GridField
49938 * @param {Object} config Configuration options
49940 Roo.form.GridField = function(config){
49941 Roo.form.GridField.superclass.constructor.call(this, config);
49945 Roo.extend(Roo.form.GridField, Roo.form.Field, {
49947 * @cfg {Number} width - used to restrict width of grid..
49951 * @cfg {Number} height - used to restrict height of grid..
49955 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
49961 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49962 * {tag: "input", type: "checkbox", autocomplete: "off"})
49964 // defaultAutoCreate : { tag: 'div' },
49965 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
49967 * @cfg {String} addTitle Text to include for adding a title.
49971 onResize : function(){
49972 Roo.form.Field.superclass.onResize.apply(this, arguments);
49975 initEvents : function(){
49976 // Roo.form.Checkbox.superclass.initEvents.call(this);
49977 // has no events...
49982 getResizeEl : function(){
49986 getPositionEl : function(){
49991 onRender : function(ct, position){
49993 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
49994 var style = this.style;
49997 Roo.form.GridField.superclass.onRender.call(this, ct, position);
49998 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
49999 this.viewEl = this.wrap.createChild({ tag: 'div' });
50001 this.viewEl.applyStyles(style);
50004 this.viewEl.setWidth(this.width);
50007 this.viewEl.setHeight(this.height);
50009 //if(this.inputValue !== undefined){
50010 //this.setValue(this.value);
50013 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
50016 this.grid.render();
50017 this.grid.getDataSource().on('remove', this.refreshValue, this);
50018 this.grid.getDataSource().on('update', this.refreshValue, this);
50019 this.grid.on('afteredit', this.refreshValue, this);
50025 * Sets the value of the item.
50026 * @param {String} either an object or a string..
50028 setValue : function(v){
50030 v = v || []; // empty set..
50031 // this does not seem smart - it really only affects memoryproxy grids..
50032 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
50033 var ds = this.grid.getDataSource();
50034 // assumes a json reader..
50036 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
50037 ds.loadData( data);
50039 // clear selection so it does not get stale.
50040 if (this.grid.sm) {
50041 this.grid.sm.clearSelections();
50044 Roo.form.GridField.superclass.setValue.call(this, v);
50045 this.refreshValue();
50046 // should load data in the grid really....
50050 refreshValue: function() {
50052 this.grid.getDataSource().each(function(r) {
50055 this.el.dom.value = Roo.encode(val);
50063 * Ext JS Library 1.1.1
50064 * Copyright(c) 2006-2007, Ext JS, LLC.
50066 * Originally Released Under LGPL - original licence link has changed is not relivant.
50069 * <script type="text/javascript">
50072 * @class Roo.form.DisplayField
50073 * @extends Roo.form.Field
50074 * A generic Field to display non-editable data.
50075 * @cfg {Boolean} closable (true|false) default false
50077 * Creates a new Display Field item.
50078 * @param {Object} config Configuration options
50080 Roo.form.DisplayField = function(config){
50081 Roo.form.DisplayField.superclass.constructor.call(this, config);
50086 * Fires after the click the close btn
50087 * @param {Roo.form.DisplayField} this
50093 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50094 inputType: 'hidden',
50100 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50102 focusClass : undefined,
50104 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50106 fieldClass: 'x-form-field',
50109 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50111 valueRenderer: undefined,
50115 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50116 * {tag: "input", type: "checkbox", autocomplete: "off"})
50119 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50123 onResize : function(){
50124 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50128 initEvents : function(){
50129 // Roo.form.Checkbox.superclass.initEvents.call(this);
50130 // has no events...
50133 this.closeEl.on('click', this.onClose, this);
50139 getResizeEl : function(){
50143 getPositionEl : function(){
50148 onRender : function(ct, position){
50150 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50151 //if(this.inputValue !== undefined){
50152 this.wrap = this.el.wrap();
50154 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50157 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50160 if (this.bodyStyle) {
50161 this.viewEl.applyStyles(this.bodyStyle);
50163 //this.viewEl.setStyle('padding', '2px');
50165 this.setValue(this.value);
50170 initValue : Roo.emptyFn,
50175 onClick : function(){
50180 * Sets the checked state of the checkbox.
50181 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50183 setValue : function(v){
50185 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50186 // this might be called before we have a dom element..
50187 if (!this.viewEl) {
50190 this.viewEl.dom.innerHTML = html;
50191 Roo.form.DisplayField.superclass.setValue.call(this, v);
50195 onClose : function(e)
50197 e.preventDefault();
50199 this.fireEvent('close', this);
50208 * @class Roo.form.DayPicker
50209 * @extends Roo.form.Field
50210 * A Day picker show [M] [T] [W] ....
50212 * Creates a new Day Picker
50213 * @param {Object} config Configuration options
50215 Roo.form.DayPicker= function(config){
50216 Roo.form.DayPicker.superclass.constructor.call(this, config);
50220 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50222 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50224 focusClass : undefined,
50226 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50228 fieldClass: "x-form-field",
50231 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50232 * {tag: "input", type: "checkbox", autocomplete: "off"})
50234 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50237 actionMode : 'viewEl',
50241 inputType : 'hidden',
50244 inputElement: false, // real input element?
50245 basedOn: false, // ????
50247 isFormField: true, // not sure where this is needed!!!!
50249 onResize : function(){
50250 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50251 if(!this.boxLabel){
50252 this.el.alignTo(this.wrap, 'c-c');
50256 initEvents : function(){
50257 Roo.form.Checkbox.superclass.initEvents.call(this);
50258 this.el.on("click", this.onClick, this);
50259 this.el.on("change", this.onClick, this);
50263 getResizeEl : function(){
50267 getPositionEl : function(){
50273 onRender : function(ct, position){
50274 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50276 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50278 var r1 = '<table><tr>';
50279 var r2 = '<tr class="x-form-daypick-icons">';
50280 for (var i=0; i < 7; i++) {
50281 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50282 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50285 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50286 viewEl.select('img').on('click', this.onClick, this);
50287 this.viewEl = viewEl;
50290 // this will not work on Chrome!!!
50291 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50292 this.el.on('propertychange', this.setFromHidden, this); //ie
50300 initValue : Roo.emptyFn,
50303 * Returns the checked state of the checkbox.
50304 * @return {Boolean} True if checked, else false
50306 getValue : function(){
50307 return this.el.dom.value;
50312 onClick : function(e){
50313 //this.setChecked(!this.checked);
50314 Roo.get(e.target).toggleClass('x-menu-item-checked');
50315 this.refreshValue();
50316 //if(this.el.dom.checked != this.checked){
50317 // this.setValue(this.el.dom.checked);
50322 refreshValue : function()
50325 this.viewEl.select('img',true).each(function(e,i,n) {
50326 val += e.is(".x-menu-item-checked") ? String(n) : '';
50328 this.setValue(val, true);
50332 * Sets the checked state of the checkbox.
50333 * On is always based on a string comparison between inputValue and the param.
50334 * @param {Boolean/String} value - the value to set
50335 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50337 setValue : function(v,suppressEvent){
50338 if (!this.el.dom) {
50341 var old = this.el.dom.value ;
50342 this.el.dom.value = v;
50343 if (suppressEvent) {
50347 // update display..
50348 this.viewEl.select('img',true).each(function(e,i,n) {
50350 var on = e.is(".x-menu-item-checked");
50351 var newv = v.indexOf(String(n)) > -1;
50353 e.toggleClass('x-menu-item-checked');
50359 this.fireEvent('change', this, v, old);
50364 // handle setting of hidden value by some other method!!?!?
50365 setFromHidden: function()
50370 //console.log("SET FROM HIDDEN");
50371 //alert('setFrom hidden');
50372 this.setValue(this.el.dom.value);
50375 onDestroy : function()
50378 Roo.get(this.viewEl).remove();
50381 Roo.form.DayPicker.superclass.onDestroy.call(this);
50385 * RooJS Library 1.1.1
50386 * Copyright(c) 2008-2011 Alan Knowles
50393 * @class Roo.form.ComboCheck
50394 * @extends Roo.form.ComboBox
50395 * A combobox for multiple select items.
50397 * FIXME - could do with a reset button..
50400 * Create a new ComboCheck
50401 * @param {Object} config Configuration options
50403 Roo.form.ComboCheck = function(config){
50404 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50405 // should verify some data...
50407 // hiddenName = required..
50408 // displayField = required
50409 // valudField == required
50410 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50412 Roo.each(req, function(e) {
50413 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50414 throw "Roo.form.ComboCheck : missing value for: " + e;
50421 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50426 selectedClass: 'x-menu-item-checked',
50429 onRender : function(ct, position){
50435 var cls = 'x-combo-list';
50438 this.tpl = new Roo.Template({
50439 html : '<div class="'+cls+'-item x-menu-check-item">' +
50440 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50441 '<span>{' + this.displayField + '}</span>' +
50448 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50449 this.view.singleSelect = false;
50450 this.view.multiSelect = true;
50451 this.view.toggleSelect = true;
50452 this.pageTb.add(new Roo.Toolbar.Fill(), {
50455 handler: function()
50462 onViewOver : function(e, t){
50468 onViewClick : function(doFocus,index){
50472 select: function () {
50473 //Roo.log("SELECT CALLED");
50476 selectByValue : function(xv, scrollIntoView){
50477 var ar = this.getValueArray();
50480 Roo.each(ar, function(v) {
50481 if(v === undefined || v === null){
50484 var r = this.findRecord(this.valueField, v);
50486 sels.push(this.store.indexOf(r))
50490 this.view.select(sels);
50496 onSelect : function(record, index){
50497 // Roo.log("onselect Called");
50498 // this is only called by the clear button now..
50499 this.view.clearSelections();
50500 this.setValue('[]');
50501 if (this.value != this.valueBefore) {
50502 this.fireEvent('change', this, this.value, this.valueBefore);
50503 this.valueBefore = this.value;
50506 getValueArray : function()
50511 //Roo.log(this.value);
50512 if (typeof(this.value) == 'undefined') {
50515 var ar = Roo.decode(this.value);
50516 return ar instanceof Array ? ar : []; //?? valid?
50519 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50524 expand : function ()
50527 Roo.form.ComboCheck.superclass.expand.call(this);
50528 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50529 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50534 collapse : function(){
50535 Roo.form.ComboCheck.superclass.collapse.call(this);
50536 var sl = this.view.getSelectedIndexes();
50537 var st = this.store;
50541 Roo.each(sl, function(i) {
50543 nv.push(r.get(this.valueField));
50545 this.setValue(Roo.encode(nv));
50546 if (this.value != this.valueBefore) {
50548 this.fireEvent('change', this, this.value, this.valueBefore);
50549 this.valueBefore = this.value;
50554 setValue : function(v){
50558 var vals = this.getValueArray();
50560 Roo.each(vals, function(k) {
50561 var r = this.findRecord(this.valueField, k);
50563 tv.push(r.data[this.displayField]);
50564 }else if(this.valueNotFoundText !== undefined){
50565 tv.push( this.valueNotFoundText );
50570 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50571 this.hiddenField.value = v;
50577 * Ext JS Library 1.1.1
50578 * Copyright(c) 2006-2007, Ext JS, LLC.
50580 * Originally Released Under LGPL - original licence link has changed is not relivant.
50583 * <script type="text/javascript">
50587 * @class Roo.form.Signature
50588 * @extends Roo.form.Field
50592 * @param {Object} config Configuration options
50595 Roo.form.Signature = function(config){
50596 Roo.form.Signature.superclass.constructor.call(this, config);
50598 this.addEvents({// not in used??
50601 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50602 * @param {Roo.form.Signature} combo This combo box
50607 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50608 * @param {Roo.form.ComboBox} combo This combo box
50609 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50615 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50617 * @cfg {Object} labels Label to use when rendering a form.
50621 * confirm : "Confirm"
50626 confirm : "Confirm"
50629 * @cfg {Number} width The signature panel width (defaults to 300)
50633 * @cfg {Number} height The signature panel height (defaults to 100)
50637 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50639 allowBlank : false,
50642 // {Object} signPanel The signature SVG panel element (defaults to {})
50644 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50645 isMouseDown : false,
50646 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50647 isConfirmed : false,
50648 // {String} signatureTmp SVG mapping string (defaults to empty string)
50652 defaultAutoCreate : { // modified by initCompnoent..
50658 onRender : function(ct, position){
50660 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50662 this.wrap = this.el.wrap({
50663 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50666 this.createToolbar(this);
50667 this.signPanel = this.wrap.createChild({
50669 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50673 this.svgID = Roo.id();
50674 this.svgEl = this.signPanel.createChild({
50675 xmlns : 'http://www.w3.org/2000/svg',
50677 id : this.svgID + "-svg",
50679 height: this.height,
50680 viewBox: '0 0 '+this.width+' '+this.height,
50684 id: this.svgID + "-svg-r",
50686 height: this.height,
50691 id: this.svgID + "-svg-l",
50693 y1: (this.height*0.8), // start set the line in 80% of height
50694 x2: this.width, // end
50695 y2: (this.height*0.8), // end set the line in 80% of height
50697 'stroke-width': "1",
50698 'stroke-dasharray': "3",
50699 'shape-rendering': "crispEdges",
50700 'pointer-events': "none"
50704 id: this.svgID + "-svg-p",
50706 'stroke-width': "3",
50708 'pointer-events': 'none'
50713 this.svgBox = this.svgEl.dom.getScreenCTM();
50715 createSVG : function(){
50716 var svg = this.signPanel;
50717 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50720 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50721 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50722 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50723 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50724 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50725 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50726 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50729 isTouchEvent : function(e){
50730 return e.type.match(/^touch/);
50732 getCoords : function (e) {
50733 var pt = this.svgEl.dom.createSVGPoint();
50736 if (this.isTouchEvent(e)) {
50737 pt.x = e.targetTouches[0].clientX;
50738 pt.y = e.targetTouches[0].clientY;
50740 var a = this.svgEl.dom.getScreenCTM();
50741 var b = a.inverse();
50742 var mx = pt.matrixTransform(b);
50743 return mx.x + ',' + mx.y;
50745 //mouse event headler
50746 down : function (e) {
50747 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50748 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50750 this.isMouseDown = true;
50752 e.preventDefault();
50754 move : function (e) {
50755 if (this.isMouseDown) {
50756 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50757 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50760 e.preventDefault();
50762 up : function (e) {
50763 this.isMouseDown = false;
50764 var sp = this.signatureTmp.split(' ');
50767 if(!sp[sp.length-2].match(/^L/)){
50771 this.signatureTmp = sp.join(" ");
50774 if(this.getValue() != this.signatureTmp){
50775 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50776 this.isConfirmed = false;
50778 e.preventDefault();
50782 * Protected method that will not generally be called directly. It
50783 * is called when the editor creates its toolbar. Override this method if you need to
50784 * add custom toolbar buttons.
50785 * @param {HtmlEditor} editor
50787 createToolbar : function(editor){
50788 function btn(id, toggle, handler){
50789 var xid = fid + '-'+ id ;
50793 cls : 'x-btn-icon x-edit-'+id,
50794 enableToggle:toggle !== false,
50795 scope: editor, // was editor...
50796 handler:handler||editor.relayBtnCmd,
50797 clickEvent:'mousedown',
50798 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50804 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50808 cls : ' x-signature-btn x-signature-'+id,
50809 scope: editor, // was editor...
50810 handler: this.reset,
50811 clickEvent:'mousedown',
50812 text: this.labels.clear
50819 cls : ' x-signature-btn x-signature-'+id,
50820 scope: editor, // was editor...
50821 handler: this.confirmHandler,
50822 clickEvent:'mousedown',
50823 text: this.labels.confirm
50830 * when user is clicked confirm then show this image.....
50832 * @return {String} Image Data URI
50834 getImageDataURI : function(){
50835 var svg = this.svgEl.dom.parentNode.innerHTML;
50836 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50841 * @return {Boolean} this.isConfirmed
50843 getConfirmed : function(){
50844 return this.isConfirmed;
50848 * @return {Number} this.width
50850 getWidth : function(){
50855 * @return {Number} this.height
50857 getHeight : function(){
50858 return this.height;
50861 getSignature : function(){
50862 return this.signatureTmp;
50865 reset : function(){
50866 this.signatureTmp = '';
50867 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50868 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
50869 this.isConfirmed = false;
50870 Roo.form.Signature.superclass.reset.call(this);
50872 setSignature : function(s){
50873 this.signatureTmp = s;
50874 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50875 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
50877 this.isConfirmed = false;
50878 Roo.form.Signature.superclass.reset.call(this);
50881 // Roo.log(this.signPanel.dom.contentWindow.up())
50884 setConfirmed : function(){
50888 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
50891 confirmHandler : function(){
50892 if(!this.getSignature()){
50896 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
50897 this.setValue(this.getSignature());
50898 this.isConfirmed = true;
50900 this.fireEvent('confirm', this);
50903 // Subclasses should provide the validation implementation by overriding this
50904 validateValue : function(value){
50905 if(this.allowBlank){
50909 if(this.isConfirmed){
50916 * Ext JS Library 1.1.1
50917 * Copyright(c) 2006-2007, Ext JS, LLC.
50919 * Originally Released Under LGPL - original licence link has changed is not relivant.
50922 * <script type="text/javascript">
50927 * @class Roo.form.ComboBox
50928 * @extends Roo.form.TriggerField
50929 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
50931 * Create a new ComboBox.
50932 * @param {Object} config Configuration options
50934 Roo.form.Select = function(config){
50935 Roo.form.Select.superclass.constructor.call(this, config);
50939 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
50941 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
50944 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
50945 * rendering into an Roo.Editor, defaults to false)
50948 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
50949 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
50952 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
50955 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
50956 * the dropdown list (defaults to undefined, with no header element)
50960 * @cfg {String/Roo.Template} tpl The template to use to render the output
50964 defaultAutoCreate : {tag: "select" },
50966 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
50968 listWidth: undefined,
50970 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
50971 * mode = 'remote' or 'text' if mode = 'local')
50973 displayField: undefined,
50975 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
50976 * mode = 'remote' or 'value' if mode = 'local').
50977 * Note: use of a valueField requires the user make a selection
50978 * in order for a value to be mapped.
50980 valueField: undefined,
50984 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
50985 * field's data value (defaults to the underlying DOM element's name)
50987 hiddenName: undefined,
50989 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
50993 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
50995 selectedClass: 'x-combo-selected',
50997 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
50998 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
50999 * which displays a downward arrow icon).
51001 triggerClass : 'x-form-arrow-trigger',
51003 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
51007 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
51008 * anchor positions (defaults to 'tl-bl')
51010 listAlign: 'tl-bl?',
51012 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
51016 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
51017 * query specified by the allQuery config option (defaults to 'query')
51019 triggerAction: 'query',
51021 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
51022 * (defaults to 4, does not apply if editable = false)
51026 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
51027 * delay (typeAheadDelay) if it matches a known value (defaults to false)
51031 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
51032 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
51036 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
51037 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
51041 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
51042 * when editable = true (defaults to false)
51044 selectOnFocus:false,
51046 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
51048 queryParam: 'query',
51050 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
51051 * when mode = 'remote' (defaults to 'Loading...')
51053 loadingText: 'Loading...',
51055 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
51059 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
51063 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
51064 * traditional select (defaults to true)
51068 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
51072 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
51076 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
51077 * listWidth has a higher value)
51081 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
51082 * allow the user to set arbitrary text into the field (defaults to false)
51084 forceSelection:false,
51086 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
51087 * if typeAhead = true (defaults to 250)
51089 typeAheadDelay : 250,
51091 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
51092 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51094 valueNotFoundText : undefined,
51097 * @cfg {String} defaultValue The value displayed after loading the store.
51102 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51104 blockFocus : false,
51107 * @cfg {Boolean} disableClear Disable showing of clear button.
51109 disableClear : false,
51111 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51113 alwaysQuery : false,
51119 // element that contains real text value.. (when hidden is used..)
51122 onRender : function(ct, position){
51123 Roo.form.Field.prototype.onRender.call(this, ct, position);
51126 this.store.on('beforeload', this.onBeforeLoad, this);
51127 this.store.on('load', this.onLoad, this);
51128 this.store.on('loadexception', this.onLoadException, this);
51129 this.store.load({});
51137 initEvents : function(){
51138 //Roo.form.ComboBox.superclass.initEvents.call(this);
51142 onDestroy : function(){
51145 this.store.un('beforeload', this.onBeforeLoad, this);
51146 this.store.un('load', this.onLoad, this);
51147 this.store.un('loadexception', this.onLoadException, this);
51149 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51153 fireKey : function(e){
51154 if(e.isNavKeyPress() && !this.list.isVisible()){
51155 this.fireEvent("specialkey", this, e);
51160 onResize: function(w, h){
51168 * Allow or prevent the user from directly editing the field text. If false is passed,
51169 * the user will only be able to select from the items defined in the dropdown list. This method
51170 * is the runtime equivalent of setting the 'editable' config option at config time.
51171 * @param {Boolean} value True to allow the user to directly edit the field text
51173 setEditable : function(value){
51178 onBeforeLoad : function(){
51180 Roo.log("Select before load");
51183 this.innerList.update(this.loadingText ?
51184 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51185 //this.restrictHeight();
51186 this.selectedIndex = -1;
51190 onLoad : function(){
51193 var dom = this.el.dom;
51194 dom.innerHTML = '';
51195 var od = dom.ownerDocument;
51197 if (this.emptyText) {
51198 var op = od.createElement('option');
51199 op.setAttribute('value', '');
51200 op.innerHTML = String.format('{0}', this.emptyText);
51201 dom.appendChild(op);
51203 if(this.store.getCount() > 0){
51205 var vf = this.valueField;
51206 var df = this.displayField;
51207 this.store.data.each(function(r) {
51208 // which colmsn to use... testing - cdoe / title..
51209 var op = od.createElement('option');
51210 op.setAttribute('value', r.data[vf]);
51211 op.innerHTML = String.format('{0}', r.data[df]);
51212 dom.appendChild(op);
51214 if (typeof(this.defaultValue != 'undefined')) {
51215 this.setValue(this.defaultValue);
51220 //this.onEmptyResults();
51225 onLoadException : function()
51227 dom.innerHTML = '';
51229 Roo.log("Select on load exception");
51233 Roo.log(this.store.reader.jsonData);
51234 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51235 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51241 onTypeAhead : function(){
51246 onSelect : function(record, index){
51247 Roo.log('on select?');
51249 if(this.fireEvent('beforeselect', this, record, index) !== false){
51250 this.setFromData(index > -1 ? record.data : false);
51252 this.fireEvent('select', this, record, index);
51257 * Returns the currently selected field value or empty string if no value is set.
51258 * @return {String} value The selected value
51260 getValue : function(){
51261 var dom = this.el.dom;
51262 this.value = dom.options[dom.selectedIndex].value;
51268 * Clears any text/value currently set in the field
51270 clearValue : function(){
51272 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51277 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51278 * will be displayed in the field. If the value does not match the data value of an existing item,
51279 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51280 * Otherwise the field will be blank (although the value will still be set).
51281 * @param {String} value The value to match
51283 setValue : function(v){
51284 var d = this.el.dom;
51285 for (var i =0; i < d.options.length;i++) {
51286 if (v == d.options[i].value) {
51287 d.selectedIndex = i;
51295 * @property {Object} the last set data for the element
51300 * Sets the value of the field based on a object which is related to the record format for the store.
51301 * @param {Object} value the value to set as. or false on reset?
51303 setFromData : function(o){
51304 Roo.log('setfrom data?');
51310 reset : function(){
51314 findRecord : function(prop, value){
51319 if(this.store.getCount() > 0){
51320 this.store.each(function(r){
51321 if(r.data[prop] == value){
51331 getName: function()
51333 // returns hidden if it's set..
51334 if (!this.rendered) {return ''};
51335 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51343 onEmptyResults : function(){
51344 Roo.log('empty results');
51349 * Returns true if the dropdown list is expanded, else false.
51351 isExpanded : function(){
51356 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51357 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51358 * @param {String} value The data value of the item to select
51359 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51360 * selected item if it is not currently in view (defaults to true)
51361 * @return {Boolean} True if the value matched an item in the list, else false
51363 selectByValue : function(v, scrollIntoView){
51364 Roo.log('select By Value');
51367 if(v !== undefined && v !== null){
51368 var r = this.findRecord(this.valueField || this.displayField, v);
51370 this.select(this.store.indexOf(r), scrollIntoView);
51378 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51379 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51380 * @param {Number} index The zero-based index of the list item to select
51381 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51382 * selected item if it is not currently in view (defaults to true)
51384 select : function(index, scrollIntoView){
51385 Roo.log('select ');
51388 this.selectedIndex = index;
51389 this.view.select(index);
51390 if(scrollIntoView !== false){
51391 var el = this.view.getNode(index);
51393 this.innerList.scrollChildIntoView(el, false);
51401 validateBlur : function(){
51408 initQuery : function(){
51409 this.doQuery(this.getRawValue());
51413 doForce : function(){
51414 if(this.el.dom.value.length > 0){
51415 this.el.dom.value =
51416 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51422 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51423 * query allowing the query action to be canceled if needed.
51424 * @param {String} query The SQL query to execute
51425 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51426 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51427 * saved in the current store (defaults to false)
51429 doQuery : function(q, forceAll){
51431 Roo.log('doQuery?');
51432 if(q === undefined || q === null){
51437 forceAll: forceAll,
51441 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51445 forceAll = qe.forceAll;
51446 if(forceAll === true || (q.length >= this.minChars)){
51447 if(this.lastQuery != q || this.alwaysQuery){
51448 this.lastQuery = q;
51449 if(this.mode == 'local'){
51450 this.selectedIndex = -1;
51452 this.store.clearFilter();
51454 this.store.filter(this.displayField, q);
51458 this.store.baseParams[this.queryParam] = q;
51460 params: this.getParams(q)
51465 this.selectedIndex = -1;
51472 getParams : function(q){
51474 //p[this.queryParam] = q;
51477 p.limit = this.pageSize;
51483 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51485 collapse : function(){
51490 collapseIf : function(e){
51495 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51497 expand : function(){
51505 * @cfg {Boolean} grow
51509 * @cfg {Number} growMin
51513 * @cfg {Number} growMax
51521 setWidth : function()
51525 getResizeEl : function(){
51528 });//<script type="text/javasscript">
51532 * @class Roo.DDView
51533 * A DnD enabled version of Roo.View.
51534 * @param {Element/String} container The Element in which to create the View.
51535 * @param {String} tpl The template string used to create the markup for each element of the View
51536 * @param {Object} config The configuration properties. These include all the config options of
51537 * {@link Roo.View} plus some specific to this class.<br>
51539 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51540 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51542 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51543 .x-view-drag-insert-above {
51544 border-top:1px dotted #3366cc;
51546 .x-view-drag-insert-below {
51547 border-bottom:1px dotted #3366cc;
51553 Roo.DDView = function(container, tpl, config) {
51554 Roo.DDView.superclass.constructor.apply(this, arguments);
51555 this.getEl().setStyle("outline", "0px none");
51556 this.getEl().unselectable();
51557 if (this.dragGroup) {
51558 this.setDraggable(this.dragGroup.split(","));
51560 if (this.dropGroup) {
51561 this.setDroppable(this.dropGroup.split(","));
51563 if (this.deletable) {
51564 this.setDeletable();
51566 this.isDirtyFlag = false;
51572 Roo.extend(Roo.DDView, Roo.View, {
51573 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51574 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51575 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51576 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51580 reset: Roo.emptyFn,
51582 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51584 validate: function() {
51588 destroy: function() {
51589 this.purgeListeners();
51590 this.getEl.removeAllListeners();
51591 this.getEl().remove();
51592 if (this.dragZone) {
51593 if (this.dragZone.destroy) {
51594 this.dragZone.destroy();
51597 if (this.dropZone) {
51598 if (this.dropZone.destroy) {
51599 this.dropZone.destroy();
51604 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51605 getName: function() {
51609 /** Loads the View from a JSON string representing the Records to put into the Store. */
51610 setValue: function(v) {
51612 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51615 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51616 this.store.proxy = new Roo.data.MemoryProxy(data);
51620 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51621 getValue: function() {
51623 this.store.each(function(rec) {
51624 result += rec.id + ',';
51626 return result.substr(0, result.length - 1) + ')';
51629 getIds: function() {
51630 var i = 0, result = new Array(this.store.getCount());
51631 this.store.each(function(rec) {
51632 result[i++] = rec.id;
51637 isDirty: function() {
51638 return this.isDirtyFlag;
51642 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51643 * whole Element becomes the target, and this causes the drop gesture to append.
51645 getTargetFromEvent : function(e) {
51646 var target = e.getTarget();
51647 while ((target !== null) && (target.parentNode != this.el.dom)) {
51648 target = target.parentNode;
51651 target = this.el.dom.lastChild || this.el.dom;
51657 * Create the drag data which consists of an object which has the property "ddel" as
51658 * the drag proxy element.
51660 getDragData : function(e) {
51661 var target = this.findItemFromChild(e.getTarget());
51663 this.handleSelection(e);
51664 var selNodes = this.getSelectedNodes();
51667 copy: this.copy || (this.allowCopy && e.ctrlKey),
51671 var selectedIndices = this.getSelectedIndexes();
51672 for (var i = 0; i < selectedIndices.length; i++) {
51673 dragData.records.push(this.store.getAt(selectedIndices[i]));
51675 if (selNodes.length == 1) {
51676 dragData.ddel = target.cloneNode(true); // the div element
51678 var div = document.createElement('div'); // create the multi element drag "ghost"
51679 div.className = 'multi-proxy';
51680 for (var i = 0, len = selNodes.length; i < len; i++) {
51681 div.appendChild(selNodes[i].cloneNode(true));
51683 dragData.ddel = div;
51685 //console.log(dragData)
51686 //console.log(dragData.ddel.innerHTML)
51689 //console.log('nodragData')
51693 /** Specify to which ddGroup items in this DDView may be dragged. */
51694 setDraggable: function(ddGroup) {
51695 if (ddGroup instanceof Array) {
51696 Roo.each(ddGroup, this.setDraggable, this);
51699 if (this.dragZone) {
51700 this.dragZone.addToGroup(ddGroup);
51702 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51703 containerScroll: true,
51707 // Draggability implies selection. DragZone's mousedown selects the element.
51708 if (!this.multiSelect) { this.singleSelect = true; }
51710 // Wire the DragZone's handlers up to methods in *this*
51711 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51715 /** Specify from which ddGroup this DDView accepts drops. */
51716 setDroppable: function(ddGroup) {
51717 if (ddGroup instanceof Array) {
51718 Roo.each(ddGroup, this.setDroppable, this);
51721 if (this.dropZone) {
51722 this.dropZone.addToGroup(ddGroup);
51724 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51725 containerScroll: true,
51729 // Wire the DropZone's handlers up to methods in *this*
51730 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51731 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51732 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51733 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51734 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51738 /** Decide whether to drop above or below a View node. */
51739 getDropPoint : function(e, n, dd){
51740 if (n == this.el.dom) { return "above"; }
51741 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51742 var c = t + (b - t) / 2;
51743 var y = Roo.lib.Event.getPageY(e);
51751 onNodeEnter : function(n, dd, e, data){
51755 onNodeOver : function(n, dd, e, data){
51756 var pt = this.getDropPoint(e, n, dd);
51757 // set the insert point style on the target node
51758 var dragElClass = this.dropNotAllowed;
51761 if (pt == "above"){
51762 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51763 targetElClass = "x-view-drag-insert-above";
51765 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51766 targetElClass = "x-view-drag-insert-below";
51768 if (this.lastInsertClass != targetElClass){
51769 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51770 this.lastInsertClass = targetElClass;
51773 return dragElClass;
51776 onNodeOut : function(n, dd, e, data){
51777 this.removeDropIndicators(n);
51780 onNodeDrop : function(n, dd, e, data){
51781 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51784 var pt = this.getDropPoint(e, n, dd);
51785 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51786 if (pt == "below") { insertAt++; }
51787 for (var i = 0; i < data.records.length; i++) {
51788 var r = data.records[i];
51789 var dup = this.store.getById(r.id);
51790 if (dup && (dd != this.dragZone)) {
51791 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51794 this.store.insert(insertAt++, r.copy());
51796 data.source.isDirtyFlag = true;
51798 this.store.insert(insertAt++, r);
51800 this.isDirtyFlag = true;
51803 this.dragZone.cachedTarget = null;
51807 removeDropIndicators : function(n){
51809 Roo.fly(n).removeClass([
51810 "x-view-drag-insert-above",
51811 "x-view-drag-insert-below"]);
51812 this.lastInsertClass = "_noclass";
51817 * Utility method. Add a delete option to the DDView's context menu.
51818 * @param {String} imageUrl The URL of the "delete" icon image.
51820 setDeletable: function(imageUrl) {
51821 if (!this.singleSelect && !this.multiSelect) {
51822 this.singleSelect = true;
51824 var c = this.getContextMenu();
51825 this.contextMenu.on("itemclick", function(item) {
51828 this.remove(this.getSelectedIndexes());
51832 this.contextMenu.add({
51839 /** Return the context menu for this DDView. */
51840 getContextMenu: function() {
51841 if (!this.contextMenu) {
51842 // Create the View's context menu
51843 this.contextMenu = new Roo.menu.Menu({
51844 id: this.id + "-contextmenu"
51846 this.el.on("contextmenu", this.showContextMenu, this);
51848 return this.contextMenu;
51851 disableContextMenu: function() {
51852 if (this.contextMenu) {
51853 this.el.un("contextmenu", this.showContextMenu, this);
51857 showContextMenu: function(e, item) {
51858 item = this.findItemFromChild(e.getTarget());
51861 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51862 this.contextMenu.showAt(e.getXY());
51867 * Remove {@link Roo.data.Record}s at the specified indices.
51868 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
51870 remove: function(selectedIndices) {
51871 selectedIndices = [].concat(selectedIndices);
51872 for (var i = 0; i < selectedIndices.length; i++) {
51873 var rec = this.store.getAt(selectedIndices[i]);
51874 this.store.remove(rec);
51879 * Double click fires the event, but also, if this is draggable, and there is only one other
51880 * related DropZone, it transfers the selected node.
51882 onDblClick : function(e){
51883 var item = this.findItemFromChild(e.getTarget());
51885 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
51888 if (this.dragGroup) {
51889 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
51890 while (targets.indexOf(this.dropZone) > -1) {
51891 targets.remove(this.dropZone);
51893 if (targets.length == 1) {
51894 this.dragZone.cachedTarget = null;
51895 var el = Roo.get(targets[0].getEl());
51896 var box = el.getBox(true);
51897 targets[0].onNodeDrop(el.dom, {
51899 xy: [box.x, box.y + box.height - 1]
51900 }, null, this.getDragData(e));
51906 handleSelection: function(e) {
51907 this.dragZone.cachedTarget = null;
51908 var item = this.findItemFromChild(e.getTarget());
51910 this.clearSelections(true);
51913 if (item && (this.multiSelect || this.singleSelect)){
51914 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
51915 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
51916 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
51917 this.unselect(item);
51919 this.select(item, this.multiSelect && e.ctrlKey);
51920 this.lastSelection = item;
51925 onItemClick : function(item, index, e){
51926 if(this.fireEvent("beforeclick", this, index, item, e) === false){
51932 unselect : function(nodeInfo, suppressEvent){
51933 var node = this.getNode(nodeInfo);
51934 if(node && this.isSelected(node)){
51935 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
51936 Roo.fly(node).removeClass(this.selectedClass);
51937 this.selections.remove(node);
51938 if(!suppressEvent){
51939 this.fireEvent("selectionchange", this, this.selections);
51947 * Ext JS Library 1.1.1
51948 * Copyright(c) 2006-2007, Ext JS, LLC.
51950 * Originally Released Under LGPL - original licence link has changed is not relivant.
51953 * <script type="text/javascript">
51957 * @class Roo.LayoutManager
51958 * @extends Roo.util.Observable
51959 * Base class for layout managers.
51961 Roo.LayoutManager = function(container, config){
51962 Roo.LayoutManager.superclass.constructor.call(this);
51963 this.el = Roo.get(container);
51964 // ie scrollbar fix
51965 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
51966 document.body.scroll = "no";
51967 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
51968 this.el.position('relative');
51970 this.id = this.el.id;
51971 this.el.addClass("x-layout-container");
51972 /** false to disable window resize monitoring @type Boolean */
51973 this.monitorWindowResize = true;
51978 * Fires when a layout is performed.
51979 * @param {Roo.LayoutManager} this
51983 * @event regionresized
51984 * Fires when the user resizes a region.
51985 * @param {Roo.LayoutRegion} region The resized region
51986 * @param {Number} newSize The new size (width for east/west, height for north/south)
51988 "regionresized" : true,
51990 * @event regioncollapsed
51991 * Fires when a region is collapsed.
51992 * @param {Roo.LayoutRegion} region The collapsed region
51994 "regioncollapsed" : true,
51996 * @event regionexpanded
51997 * Fires when a region is expanded.
51998 * @param {Roo.LayoutRegion} region The expanded region
52000 "regionexpanded" : true
52002 this.updating = false;
52003 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52006 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
52008 * Returns true if this layout is currently being updated
52009 * @return {Boolean}
52011 isUpdating : function(){
52012 return this.updating;
52016 * Suspend the LayoutManager from doing auto-layouts while
52017 * making multiple add or remove calls
52019 beginUpdate : function(){
52020 this.updating = true;
52024 * Restore auto-layouts and optionally disable the manager from performing a layout
52025 * @param {Boolean} noLayout true to disable a layout update
52027 endUpdate : function(noLayout){
52028 this.updating = false;
52034 layout: function(){
52038 onRegionResized : function(region, newSize){
52039 this.fireEvent("regionresized", region, newSize);
52043 onRegionCollapsed : function(region){
52044 this.fireEvent("regioncollapsed", region);
52047 onRegionExpanded : function(region){
52048 this.fireEvent("regionexpanded", region);
52052 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
52053 * performs box-model adjustments.
52054 * @return {Object} The size as an object {width: (the width), height: (the height)}
52056 getViewSize : function(){
52058 if(this.el.dom != document.body){
52059 size = this.el.getSize();
52061 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
52063 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
52064 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
52069 * Returns the Element this layout is bound to.
52070 * @return {Roo.Element}
52072 getEl : function(){
52077 * Returns the specified region.
52078 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
52079 * @return {Roo.LayoutRegion}
52081 getRegion : function(target){
52082 return this.regions[target.toLowerCase()];
52085 onWindowResize : function(){
52086 if(this.monitorWindowResize){
52092 * Ext JS Library 1.1.1
52093 * Copyright(c) 2006-2007, Ext JS, LLC.
52095 * Originally Released Under LGPL - original licence link has changed is not relivant.
52098 * <script type="text/javascript">
52101 * @class Roo.BorderLayout
52102 * @extends Roo.LayoutManager
52103 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52104 * please see: <br><br>
52105 * <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>
52106 * <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>
52109 var layout = new Roo.BorderLayout(document.body, {
52143 preferredTabWidth: 150
52148 var CP = Roo.ContentPanel;
52150 layout.beginUpdate();
52151 layout.add("north", new CP("north", "North"));
52152 layout.add("south", new CP("south", {title: "South", closable: true}));
52153 layout.add("west", new CP("west", {title: "West"}));
52154 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52155 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52156 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52157 layout.getRegion("center").showPanel("center1");
52158 layout.endUpdate();
52161 <b>The container the layout is rendered into can be either the body element or any other element.
52162 If it is not the body element, the container needs to either be an absolute positioned element,
52163 or you will need to add "position:relative" to the css of the container. You will also need to specify
52164 the container size if it is not the body element.</b>
52167 * Create a new BorderLayout
52168 * @param {String/HTMLElement/Element} container The container this layout is bound to
52169 * @param {Object} config Configuration options
52171 Roo.BorderLayout = function(container, config){
52172 config = config || {};
52173 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52174 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52175 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52176 var target = this.factory.validRegions[i];
52177 if(config[target]){
52178 this.addRegion(target, config[target]);
52183 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52185 * Creates and adds a new region if it doesn't already exist.
52186 * @param {String} target The target region key (north, south, east, west or center).
52187 * @param {Object} config The regions config object
52188 * @return {BorderLayoutRegion} The new region
52190 addRegion : function(target, config){
52191 if(!this.regions[target]){
52192 var r = this.factory.create(target, this, config);
52193 this.bindRegion(target, r);
52195 return this.regions[target];
52199 bindRegion : function(name, r){
52200 this.regions[name] = r;
52201 r.on("visibilitychange", this.layout, this);
52202 r.on("paneladded", this.layout, this);
52203 r.on("panelremoved", this.layout, this);
52204 r.on("invalidated", this.layout, this);
52205 r.on("resized", this.onRegionResized, this);
52206 r.on("collapsed", this.onRegionCollapsed, this);
52207 r.on("expanded", this.onRegionExpanded, this);
52211 * Performs a layout update.
52213 layout : function(){
52214 if(this.updating) {
52217 var size = this.getViewSize();
52218 var w = size.width;
52219 var h = size.height;
52224 //var x = 0, y = 0;
52226 var rs = this.regions;
52227 var north = rs["north"];
52228 var south = rs["south"];
52229 var west = rs["west"];
52230 var east = rs["east"];
52231 var center = rs["center"];
52232 //if(this.hideOnLayout){ // not supported anymore
52233 //c.el.setStyle("display", "none");
52235 if(north && north.isVisible()){
52236 var b = north.getBox();
52237 var m = north.getMargins();
52238 b.width = w - (m.left+m.right);
52241 centerY = b.height + b.y + m.bottom;
52242 centerH -= centerY;
52243 north.updateBox(this.safeBox(b));
52245 if(south && south.isVisible()){
52246 var b = south.getBox();
52247 var m = south.getMargins();
52248 b.width = w - (m.left+m.right);
52250 var totalHeight = (b.height + m.top + m.bottom);
52251 b.y = h - totalHeight + m.top;
52252 centerH -= totalHeight;
52253 south.updateBox(this.safeBox(b));
52255 if(west && west.isVisible()){
52256 var b = west.getBox();
52257 var m = west.getMargins();
52258 b.height = centerH - (m.top+m.bottom);
52260 b.y = centerY + m.top;
52261 var totalWidth = (b.width + m.left + m.right);
52262 centerX += totalWidth;
52263 centerW -= totalWidth;
52264 west.updateBox(this.safeBox(b));
52266 if(east && east.isVisible()){
52267 var b = east.getBox();
52268 var m = east.getMargins();
52269 b.height = centerH - (m.top+m.bottom);
52270 var totalWidth = (b.width + m.left + m.right);
52271 b.x = w - totalWidth + m.left;
52272 b.y = centerY + m.top;
52273 centerW -= totalWidth;
52274 east.updateBox(this.safeBox(b));
52277 var m = center.getMargins();
52279 x: centerX + m.left,
52280 y: centerY + m.top,
52281 width: centerW - (m.left+m.right),
52282 height: centerH - (m.top+m.bottom)
52284 //if(this.hideOnLayout){
52285 //center.el.setStyle("display", "block");
52287 center.updateBox(this.safeBox(centerBox));
52290 this.fireEvent("layout", this);
52294 safeBox : function(box){
52295 box.width = Math.max(0, box.width);
52296 box.height = Math.max(0, box.height);
52301 * Adds a ContentPanel (or subclass) to this layout.
52302 * @param {String} target The target region key (north, south, east, west or center).
52303 * @param {Roo.ContentPanel} panel The panel to add
52304 * @return {Roo.ContentPanel} The added panel
52306 add : function(target, panel){
52308 target = target.toLowerCase();
52309 return this.regions[target].add(panel);
52313 * Remove a ContentPanel (or subclass) to this layout.
52314 * @param {String} target The target region key (north, south, east, west or center).
52315 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52316 * @return {Roo.ContentPanel} The removed panel
52318 remove : function(target, panel){
52319 target = target.toLowerCase();
52320 return this.regions[target].remove(panel);
52324 * Searches all regions for a panel with the specified id
52325 * @param {String} panelId
52326 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52328 findPanel : function(panelId){
52329 var rs = this.regions;
52330 for(var target in rs){
52331 if(typeof rs[target] != "function"){
52332 var p = rs[target].getPanel(panelId);
52342 * Searches all regions for a panel with the specified id and activates (shows) it.
52343 * @param {String/ContentPanel} panelId The panels id or the panel itself
52344 * @return {Roo.ContentPanel} The shown panel or null
52346 showPanel : function(panelId) {
52347 var rs = this.regions;
52348 for(var target in rs){
52349 var r = rs[target];
52350 if(typeof r != "function"){
52351 if(r.hasPanel(panelId)){
52352 return r.showPanel(panelId);
52360 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52361 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52363 restoreState : function(provider){
52365 provider = Roo.state.Manager;
52367 var sm = new Roo.LayoutStateManager();
52368 sm.init(this, provider);
52372 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52373 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52374 * a valid ContentPanel config object. Example:
52376 // Create the main layout
52377 var layout = new Roo.BorderLayout('main-ct', {
52388 // Create and add multiple ContentPanels at once via configs
52391 id: 'source-files',
52393 title:'Ext Source Files',
52406 * @param {Object} regions An object containing ContentPanel configs by region name
52408 batchAdd : function(regions){
52409 this.beginUpdate();
52410 for(var rname in regions){
52411 var lr = this.regions[rname];
52413 this.addTypedPanels(lr, regions[rname]);
52420 addTypedPanels : function(lr, ps){
52421 if(typeof ps == 'string'){
52422 lr.add(new Roo.ContentPanel(ps));
52424 else if(ps instanceof Array){
52425 for(var i =0, len = ps.length; i < len; i++){
52426 this.addTypedPanels(lr, ps[i]);
52429 else if(!ps.events){ // raw config?
52431 delete ps.el; // prevent conflict
52432 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52434 else { // panel object assumed!
52439 * Adds a xtype elements to the layout.
52443 xtype : 'ContentPanel',
52450 xtype : 'NestedLayoutPanel',
52456 items : [ ... list of content panels or nested layout panels.. ]
52460 * @param {Object} cfg Xtype definition of item to add.
52462 addxtype : function(cfg)
52464 // basically accepts a pannel...
52465 // can accept a layout region..!?!?
52466 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52468 if (!cfg.xtype.match(/Panel$/)) {
52473 if (typeof(cfg.region) == 'undefined') {
52474 Roo.log("Failed to add Panel, region was not set");
52478 var region = cfg.region;
52484 xitems = cfg.items;
52491 case 'ContentPanel': // ContentPanel (el, cfg)
52492 case 'ScrollPanel': // ContentPanel (el, cfg)
52494 if(cfg.autoCreate) {
52495 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52497 var el = this.el.createChild();
52498 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52501 this.add(region, ret);
52505 case 'TreePanel': // our new panel!
52506 cfg.el = this.el.createChild();
52507 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52508 this.add(region, ret);
52511 case 'NestedLayoutPanel':
52512 // create a new Layout (which is a Border Layout...
52513 var el = this.el.createChild();
52514 var clayout = cfg.layout;
52516 clayout.items = clayout.items || [];
52517 // replace this exitems with the clayout ones..
52518 xitems = clayout.items;
52521 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52522 cfg.background = false;
52524 var layout = new Roo.BorderLayout(el, clayout);
52526 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52527 //console.log('adding nested layout panel ' + cfg.toSource());
52528 this.add(region, ret);
52529 nb = {}; /// find first...
52534 // needs grid and region
52536 //var el = this.getRegion(region).el.createChild();
52537 var el = this.el.createChild();
52538 // create the grid first...
52540 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52542 if (region == 'center' && this.active ) {
52543 cfg.background = false;
52545 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52547 this.add(region, ret);
52548 if (cfg.background) {
52549 ret.on('activate', function(gp) {
52550 if (!gp.grid.rendered) {
52565 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52567 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52568 this.add(region, ret);
52571 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52575 // GridPanel (grid, cfg)
52578 this.beginUpdate();
52582 Roo.each(xitems, function(i) {
52583 region = nb && i.region ? i.region : false;
52585 var add = ret.addxtype(i);
52588 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52589 if (!i.background) {
52590 abn[region] = nb[region] ;
52597 // make the last non-background panel active..
52598 //if (nb) { Roo.log(abn); }
52601 for(var r in abn) {
52602 region = this.getRegion(r);
52604 // tried using nb[r], but it does not work..
52606 region.showPanel(abn[r]);
52617 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52618 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52619 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52620 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52623 var CP = Roo.ContentPanel;
52625 var layout = Roo.BorderLayout.create({
52629 panels: [new CP("north", "North")]
52638 panels: [new CP("west", {title: "West"})]
52647 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52656 panels: [new CP("south", {title: "South", closable: true})]
52663 preferredTabWidth: 150,
52665 new CP("center1", {title: "Close Me", closable: true}),
52666 new CP("center2", {title: "Center Panel", closable: false})
52671 layout.getRegion("center").showPanel("center1");
52676 Roo.BorderLayout.create = function(config, targetEl){
52677 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52678 layout.beginUpdate();
52679 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52680 for(var j = 0, jlen = regions.length; j < jlen; j++){
52681 var lr = regions[j];
52682 if(layout.regions[lr] && config[lr].panels){
52683 var r = layout.regions[lr];
52684 var ps = config[lr].panels;
52685 layout.addTypedPanels(r, ps);
52688 layout.endUpdate();
52693 Roo.BorderLayout.RegionFactory = {
52695 validRegions : ["north","south","east","west","center"],
52698 create : function(target, mgr, config){
52699 target = target.toLowerCase();
52700 if(config.lightweight || config.basic){
52701 return new Roo.BasicLayoutRegion(mgr, config, target);
52705 return new Roo.NorthLayoutRegion(mgr, config);
52707 return new Roo.SouthLayoutRegion(mgr, config);
52709 return new Roo.EastLayoutRegion(mgr, config);
52711 return new Roo.WestLayoutRegion(mgr, config);
52713 return new Roo.CenterLayoutRegion(mgr, config);
52715 throw 'Layout region "'+target+'" not supported.';
52719 * Ext JS Library 1.1.1
52720 * Copyright(c) 2006-2007, Ext JS, LLC.
52722 * Originally Released Under LGPL - original licence link has changed is not relivant.
52725 * <script type="text/javascript">
52729 * @class Roo.BasicLayoutRegion
52730 * @extends Roo.util.Observable
52731 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52732 * and does not have a titlebar, tabs or any other features. All it does is size and position
52733 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52735 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52737 this.position = pos;
52740 * @scope Roo.BasicLayoutRegion
52744 * @event beforeremove
52745 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52746 * @param {Roo.LayoutRegion} this
52747 * @param {Roo.ContentPanel} panel The panel
52748 * @param {Object} e The cancel event object
52750 "beforeremove" : true,
52752 * @event invalidated
52753 * Fires when the layout for this region is changed.
52754 * @param {Roo.LayoutRegion} this
52756 "invalidated" : true,
52758 * @event visibilitychange
52759 * Fires when this region is shown or hidden
52760 * @param {Roo.LayoutRegion} this
52761 * @param {Boolean} visibility true or false
52763 "visibilitychange" : true,
52765 * @event paneladded
52766 * Fires when a panel is added.
52767 * @param {Roo.LayoutRegion} this
52768 * @param {Roo.ContentPanel} panel The panel
52770 "paneladded" : true,
52772 * @event panelremoved
52773 * Fires when a panel is removed.
52774 * @param {Roo.LayoutRegion} this
52775 * @param {Roo.ContentPanel} panel The panel
52777 "panelremoved" : true,
52779 * @event beforecollapse
52780 * Fires when this region before collapse.
52781 * @param {Roo.LayoutRegion} this
52783 "beforecollapse" : true,
52786 * Fires when this region is collapsed.
52787 * @param {Roo.LayoutRegion} this
52789 "collapsed" : true,
52792 * Fires when this region is expanded.
52793 * @param {Roo.LayoutRegion} this
52798 * Fires when this region is slid into view.
52799 * @param {Roo.LayoutRegion} this
52801 "slideshow" : true,
52804 * Fires when this region slides out of view.
52805 * @param {Roo.LayoutRegion} this
52807 "slidehide" : true,
52809 * @event panelactivated
52810 * Fires when a panel is activated.
52811 * @param {Roo.LayoutRegion} this
52812 * @param {Roo.ContentPanel} panel The activated panel
52814 "panelactivated" : true,
52817 * Fires when the user resizes this region.
52818 * @param {Roo.LayoutRegion} this
52819 * @param {Number} newSize The new size (width for east/west, height for north/south)
52823 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52824 this.panels = new Roo.util.MixedCollection();
52825 this.panels.getKey = this.getPanelId.createDelegate(this);
52827 this.activePanel = null;
52828 // ensure listeners are added...
52830 if (config.listeners || config.events) {
52831 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52832 listeners : config.listeners || {},
52833 events : config.events || {}
52837 if(skipConfig !== true){
52838 this.applyConfig(config);
52842 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52843 getPanelId : function(p){
52847 applyConfig : function(config){
52848 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52849 this.config = config;
52854 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
52855 * the width, for horizontal (north, south) the height.
52856 * @param {Number} newSize The new width or height
52858 resizeTo : function(newSize){
52859 var el = this.el ? this.el :
52860 (this.activePanel ? this.activePanel.getEl() : null);
52862 switch(this.position){
52865 el.setWidth(newSize);
52866 this.fireEvent("resized", this, newSize);
52870 el.setHeight(newSize);
52871 this.fireEvent("resized", this, newSize);
52877 getBox : function(){
52878 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
52881 getMargins : function(){
52882 return this.margins;
52885 updateBox : function(box){
52887 var el = this.activePanel.getEl();
52888 el.dom.style.left = box.x + "px";
52889 el.dom.style.top = box.y + "px";
52890 this.activePanel.setSize(box.width, box.height);
52894 * Returns the container element for this region.
52895 * @return {Roo.Element}
52897 getEl : function(){
52898 return this.activePanel;
52902 * Returns true if this region is currently visible.
52903 * @return {Boolean}
52905 isVisible : function(){
52906 return this.activePanel ? true : false;
52909 setActivePanel : function(panel){
52910 panel = this.getPanel(panel);
52911 if(this.activePanel && this.activePanel != panel){
52912 this.activePanel.setActiveState(false);
52913 this.activePanel.getEl().setLeftTop(-10000,-10000);
52915 this.activePanel = panel;
52916 panel.setActiveState(true);
52918 panel.setSize(this.box.width, this.box.height);
52920 this.fireEvent("panelactivated", this, panel);
52921 this.fireEvent("invalidated");
52925 * Show the specified panel.
52926 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
52927 * @return {Roo.ContentPanel} The shown panel or null
52929 showPanel : function(panel){
52930 if(panel = this.getPanel(panel)){
52931 this.setActivePanel(panel);
52937 * Get the active panel for this region.
52938 * @return {Roo.ContentPanel} The active panel or null
52940 getActivePanel : function(){
52941 return this.activePanel;
52945 * Add the passed ContentPanel(s)
52946 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52947 * @return {Roo.ContentPanel} The panel added (if only one was added)
52949 add : function(panel){
52950 if(arguments.length > 1){
52951 for(var i = 0, len = arguments.length; i < len; i++) {
52952 this.add(arguments[i]);
52956 if(this.hasPanel(panel)){
52957 this.showPanel(panel);
52960 var el = panel.getEl();
52961 if(el.dom.parentNode != this.mgr.el.dom){
52962 this.mgr.el.dom.appendChild(el.dom);
52964 if(panel.setRegion){
52965 panel.setRegion(this);
52967 this.panels.add(panel);
52968 el.setStyle("position", "absolute");
52969 if(!panel.background){
52970 this.setActivePanel(panel);
52971 if(this.config.initialSize && this.panels.getCount()==1){
52972 this.resizeTo(this.config.initialSize);
52975 this.fireEvent("paneladded", this, panel);
52980 * Returns true if the panel is in this region.
52981 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52982 * @return {Boolean}
52984 hasPanel : function(panel){
52985 if(typeof panel == "object"){ // must be panel obj
52986 panel = panel.getId();
52988 return this.getPanel(panel) ? true : false;
52992 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52993 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52994 * @param {Boolean} preservePanel Overrides the config preservePanel option
52995 * @return {Roo.ContentPanel} The panel that was removed
52997 remove : function(panel, preservePanel){
52998 panel = this.getPanel(panel);
53003 this.fireEvent("beforeremove", this, panel, e);
53004 if(e.cancel === true){
53007 var panelId = panel.getId();
53008 this.panels.removeKey(panelId);
53013 * Returns the panel specified or null if it's not in this region.
53014 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53015 * @return {Roo.ContentPanel}
53017 getPanel : function(id){
53018 if(typeof id == "object"){ // must be panel obj
53021 return this.panels.get(id);
53025 * Returns this regions position (north/south/east/west/center).
53028 getPosition: function(){
53029 return this.position;
53033 * Ext JS Library 1.1.1
53034 * Copyright(c) 2006-2007, Ext JS, LLC.
53036 * Originally Released Under LGPL - original licence link has changed is not relivant.
53039 * <script type="text/javascript">
53043 * @class Roo.LayoutRegion
53044 * @extends Roo.BasicLayoutRegion
53045 * This class represents a region in a layout manager.
53046 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
53047 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
53048 * @cfg {Boolean} floatable False to disable floating (defaults to true)
53049 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
53050 * @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})
53051 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
53052 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
53053 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
53054 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
53055 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
53056 * @cfg {String} title The title for the region (overrides panel titles)
53057 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
53058 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
53059 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
53060 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
53061 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
53062 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
53063 * the space available, similar to FireFox 1.5 tabs (defaults to false)
53064 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
53065 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
53066 * @cfg {Boolean} showPin True to show a pin button
53067 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
53068 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
53069 * @cfg {Boolean} disableTabTips True to disable tab tooltips
53070 * @cfg {Number} width For East/West panels
53071 * @cfg {Number} height For North/South panels
53072 * @cfg {Boolean} split To show the splitter
53073 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
53075 Roo.LayoutRegion = function(mgr, config, pos){
53076 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
53077 var dh = Roo.DomHelper;
53078 /** This region's container element
53079 * @type Roo.Element */
53080 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
53081 /** This region's title element
53082 * @type Roo.Element */
53084 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
53085 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
53086 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
53088 this.titleEl.enableDisplayMode();
53089 /** This region's title text element
53090 * @type HTMLElement */
53091 this.titleTextEl = this.titleEl.dom.firstChild;
53092 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53093 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53094 this.closeBtn.enableDisplayMode();
53095 this.closeBtn.on("click", this.closeClicked, this);
53096 this.closeBtn.hide();
53098 this.createBody(config);
53099 this.visible = true;
53100 this.collapsed = false;
53102 if(config.hideWhenEmpty){
53104 this.on("paneladded", this.validateVisibility, this);
53105 this.on("panelremoved", this.validateVisibility, this);
53107 this.applyConfig(config);
53110 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53112 createBody : function(){
53113 /** This region's body element
53114 * @type Roo.Element */
53115 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53118 applyConfig : function(c){
53119 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53120 var dh = Roo.DomHelper;
53121 if(c.titlebar !== false){
53122 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53123 this.collapseBtn.on("click", this.collapse, this);
53124 this.collapseBtn.enableDisplayMode();
53126 if(c.showPin === true || this.showPin){
53127 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53128 this.stickBtn.enableDisplayMode();
53129 this.stickBtn.on("click", this.expand, this);
53130 this.stickBtn.hide();
53133 /** This region's collapsed element
53134 * @type Roo.Element */
53135 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53136 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53138 if(c.floatable !== false){
53139 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53140 this.collapsedEl.on("click", this.collapseClick, this);
53143 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53144 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53145 id: "message", unselectable: "on", style:{"float":"left"}});
53146 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53148 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53149 this.expandBtn.on("click", this.expand, this);
53151 if(this.collapseBtn){
53152 this.collapseBtn.setVisible(c.collapsible == true);
53154 this.cmargins = c.cmargins || this.cmargins ||
53155 (this.position == "west" || this.position == "east" ?
53156 {top: 0, left: 2, right:2, bottom: 0} :
53157 {top: 2, left: 0, right:0, bottom: 2});
53158 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53159 this.bottomTabs = c.tabPosition != "top";
53160 this.autoScroll = c.autoScroll || false;
53161 if(this.autoScroll){
53162 this.bodyEl.setStyle("overflow", "auto");
53164 this.bodyEl.setStyle("overflow", "hidden");
53166 //if(c.titlebar !== false){
53167 if((!c.titlebar && !c.title) || c.titlebar === false){
53168 this.titleEl.hide();
53170 this.titleEl.show();
53172 this.titleTextEl.innerHTML = c.title;
53176 this.duration = c.duration || .30;
53177 this.slideDuration = c.slideDuration || .45;
53180 this.collapse(true);
53187 * Returns true if this region is currently visible.
53188 * @return {Boolean}
53190 isVisible : function(){
53191 return this.visible;
53195 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53196 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53198 setCollapsedTitle : function(title){
53199 title = title || " ";
53200 if(this.collapsedTitleTextEl){
53201 this.collapsedTitleTextEl.innerHTML = title;
53205 getBox : function(){
53207 if(!this.collapsed){
53208 b = this.el.getBox(false, true);
53210 b = this.collapsedEl.getBox(false, true);
53215 getMargins : function(){
53216 return this.collapsed ? this.cmargins : this.margins;
53219 highlight : function(){
53220 this.el.addClass("x-layout-panel-dragover");
53223 unhighlight : function(){
53224 this.el.removeClass("x-layout-panel-dragover");
53227 updateBox : function(box){
53229 if(!this.collapsed){
53230 this.el.dom.style.left = box.x + "px";
53231 this.el.dom.style.top = box.y + "px";
53232 this.updateBody(box.width, box.height);
53234 this.collapsedEl.dom.style.left = box.x + "px";
53235 this.collapsedEl.dom.style.top = box.y + "px";
53236 this.collapsedEl.setSize(box.width, box.height);
53239 this.tabs.autoSizeTabs();
53243 updateBody : function(w, h){
53245 this.el.setWidth(w);
53246 w -= this.el.getBorderWidth("rl");
53247 if(this.config.adjustments){
53248 w += this.config.adjustments[0];
53252 this.el.setHeight(h);
53253 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53254 h -= this.el.getBorderWidth("tb");
53255 if(this.config.adjustments){
53256 h += this.config.adjustments[1];
53258 this.bodyEl.setHeight(h);
53260 h = this.tabs.syncHeight(h);
53263 if(this.panelSize){
53264 w = w !== null ? w : this.panelSize.width;
53265 h = h !== null ? h : this.panelSize.height;
53267 if(this.activePanel){
53268 var el = this.activePanel.getEl();
53269 w = w !== null ? w : el.getWidth();
53270 h = h !== null ? h : el.getHeight();
53271 this.panelSize = {width: w, height: h};
53272 this.activePanel.setSize(w, h);
53274 if(Roo.isIE && this.tabs){
53275 this.tabs.el.repaint();
53280 * Returns the container element for this region.
53281 * @return {Roo.Element}
53283 getEl : function(){
53288 * Hides this region.
53291 if(!this.collapsed){
53292 this.el.dom.style.left = "-2000px";
53295 this.collapsedEl.dom.style.left = "-2000px";
53296 this.collapsedEl.hide();
53298 this.visible = false;
53299 this.fireEvent("visibilitychange", this, false);
53303 * Shows this region if it was previously hidden.
53306 if(!this.collapsed){
53309 this.collapsedEl.show();
53311 this.visible = true;
53312 this.fireEvent("visibilitychange", this, true);
53315 closeClicked : function(){
53316 if(this.activePanel){
53317 this.remove(this.activePanel);
53321 collapseClick : function(e){
53323 e.stopPropagation();
53326 e.stopPropagation();
53332 * Collapses this region.
53333 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53335 collapse : function(skipAnim, skipCheck){
53336 if(this.collapsed) {
53340 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53342 this.collapsed = true;
53344 this.split.el.hide();
53346 if(this.config.animate && skipAnim !== true){
53347 this.fireEvent("invalidated", this);
53348 this.animateCollapse();
53350 this.el.setLocation(-20000,-20000);
53352 this.collapsedEl.show();
53353 this.fireEvent("collapsed", this);
53354 this.fireEvent("invalidated", this);
53360 animateCollapse : function(){
53365 * Expands this region if it was previously collapsed.
53366 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53367 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53369 expand : function(e, skipAnim){
53371 e.stopPropagation();
53373 if(!this.collapsed || this.el.hasActiveFx()) {
53377 this.afterSlideIn();
53380 this.collapsed = false;
53381 if(this.config.animate && skipAnim !== true){
53382 this.animateExpand();
53386 this.split.el.show();
53388 this.collapsedEl.setLocation(-2000,-2000);
53389 this.collapsedEl.hide();
53390 this.fireEvent("invalidated", this);
53391 this.fireEvent("expanded", this);
53395 animateExpand : function(){
53399 initTabs : function()
53401 this.bodyEl.setStyle("overflow", "hidden");
53402 var ts = new Roo.TabPanel(
53405 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53406 disableTooltips: this.config.disableTabTips,
53407 toolbar : this.config.toolbar
53410 if(this.config.hideTabs){
53411 ts.stripWrap.setDisplayed(false);
53414 ts.resizeTabs = this.config.resizeTabs === true;
53415 ts.minTabWidth = this.config.minTabWidth || 40;
53416 ts.maxTabWidth = this.config.maxTabWidth || 250;
53417 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53418 ts.monitorResize = false;
53419 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53420 ts.bodyEl.addClass('x-layout-tabs-body');
53421 this.panels.each(this.initPanelAsTab, this);
53424 initPanelAsTab : function(panel){
53425 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53426 this.config.closeOnTab && panel.isClosable());
53427 if(panel.tabTip !== undefined){
53428 ti.setTooltip(panel.tabTip);
53430 ti.on("activate", function(){
53431 this.setActivePanel(panel);
53433 if(this.config.closeOnTab){
53434 ti.on("beforeclose", function(t, e){
53436 this.remove(panel);
53442 updatePanelTitle : function(panel, title){
53443 if(this.activePanel == panel){
53444 this.updateTitle(title);
53447 var ti = this.tabs.getTab(panel.getEl().id);
53449 if(panel.tabTip !== undefined){
53450 ti.setTooltip(panel.tabTip);
53455 updateTitle : function(title){
53456 if(this.titleTextEl && !this.config.title){
53457 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53461 setActivePanel : function(panel){
53462 panel = this.getPanel(panel);
53463 if(this.activePanel && this.activePanel != panel){
53464 this.activePanel.setActiveState(false);
53466 this.activePanel = panel;
53467 panel.setActiveState(true);
53468 if(this.panelSize){
53469 panel.setSize(this.panelSize.width, this.panelSize.height);
53472 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53474 this.updateTitle(panel.getTitle());
53476 this.fireEvent("invalidated", this);
53478 this.fireEvent("panelactivated", this, panel);
53482 * Shows the specified panel.
53483 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53484 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53486 showPanel : function(panel)
53488 panel = this.getPanel(panel);
53491 var tab = this.tabs.getTab(panel.getEl().id);
53492 if(tab.isHidden()){
53493 this.tabs.unhideTab(tab.id);
53497 this.setActivePanel(panel);
53504 * Get the active panel for this region.
53505 * @return {Roo.ContentPanel} The active panel or null
53507 getActivePanel : function(){
53508 return this.activePanel;
53511 validateVisibility : function(){
53512 if(this.panels.getCount() < 1){
53513 this.updateTitle(" ");
53514 this.closeBtn.hide();
53517 if(!this.isVisible()){
53524 * Adds the passed ContentPanel(s) to this region.
53525 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53526 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53528 add : function(panel){
53529 if(arguments.length > 1){
53530 for(var i = 0, len = arguments.length; i < len; i++) {
53531 this.add(arguments[i]);
53535 if(this.hasPanel(panel)){
53536 this.showPanel(panel);
53539 panel.setRegion(this);
53540 this.panels.add(panel);
53541 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53542 this.bodyEl.dom.appendChild(panel.getEl().dom);
53543 if(panel.background !== true){
53544 this.setActivePanel(panel);
53546 this.fireEvent("paneladded", this, panel);
53552 this.initPanelAsTab(panel);
53554 if(panel.background !== true){
53555 this.tabs.activate(panel.getEl().id);
53557 this.fireEvent("paneladded", this, panel);
53562 * Hides the tab for the specified panel.
53563 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53565 hidePanel : function(panel){
53566 if(this.tabs && (panel = this.getPanel(panel))){
53567 this.tabs.hideTab(panel.getEl().id);
53572 * Unhides the tab for a previously hidden panel.
53573 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53575 unhidePanel : function(panel){
53576 if(this.tabs && (panel = this.getPanel(panel))){
53577 this.tabs.unhideTab(panel.getEl().id);
53581 clearPanels : function(){
53582 while(this.panels.getCount() > 0){
53583 this.remove(this.panels.first());
53588 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53589 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53590 * @param {Boolean} preservePanel Overrides the config preservePanel option
53591 * @return {Roo.ContentPanel} The panel that was removed
53593 remove : function(panel, preservePanel){
53594 panel = this.getPanel(panel);
53599 this.fireEvent("beforeremove", this, panel, e);
53600 if(e.cancel === true){
53603 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53604 var panelId = panel.getId();
53605 this.panels.removeKey(panelId);
53607 document.body.appendChild(panel.getEl().dom);
53610 this.tabs.removeTab(panel.getEl().id);
53611 }else if (!preservePanel){
53612 this.bodyEl.dom.removeChild(panel.getEl().dom);
53614 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53615 var p = this.panels.first();
53616 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53617 tempEl.appendChild(p.getEl().dom);
53618 this.bodyEl.update("");
53619 this.bodyEl.dom.appendChild(p.getEl().dom);
53621 this.updateTitle(p.getTitle());
53623 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53624 this.setActivePanel(p);
53626 panel.setRegion(null);
53627 if(this.activePanel == panel){
53628 this.activePanel = null;
53630 if(this.config.autoDestroy !== false && preservePanel !== true){
53631 try{panel.destroy();}catch(e){}
53633 this.fireEvent("panelremoved", this, panel);
53638 * Returns the TabPanel component used by this region
53639 * @return {Roo.TabPanel}
53641 getTabs : function(){
53645 createTool : function(parentEl, className){
53646 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53647 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53648 btn.addClassOnOver("x-layout-tools-button-over");
53653 * Ext JS Library 1.1.1
53654 * Copyright(c) 2006-2007, Ext JS, LLC.
53656 * Originally Released Under LGPL - original licence link has changed is not relivant.
53659 * <script type="text/javascript">
53665 * @class Roo.SplitLayoutRegion
53666 * @extends Roo.LayoutRegion
53667 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53669 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53670 this.cursor = cursor;
53671 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53674 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53675 splitTip : "Drag to resize.",
53676 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53677 useSplitTips : false,
53679 applyConfig : function(config){
53680 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53683 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53684 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53685 /** The SplitBar for this region
53686 * @type Roo.SplitBar */
53687 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53688 this.split.on("moved", this.onSplitMove, this);
53689 this.split.useShim = config.useShim === true;
53690 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53691 if(this.useSplitTips){
53692 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53694 if(config.collapsible){
53695 this.split.el.on("dblclick", this.collapse, this);
53698 if(typeof config.minSize != "undefined"){
53699 this.split.minSize = config.minSize;
53701 if(typeof config.maxSize != "undefined"){
53702 this.split.maxSize = config.maxSize;
53704 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53705 this.hideSplitter();
53710 getHMaxSize : function(){
53711 var cmax = this.config.maxSize || 10000;
53712 var center = this.mgr.getRegion("center");
53713 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53716 getVMaxSize : function(){
53717 var cmax = this.config.maxSize || 10000;
53718 var center = this.mgr.getRegion("center");
53719 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53722 onSplitMove : function(split, newSize){
53723 this.fireEvent("resized", this, newSize);
53727 * Returns the {@link Roo.SplitBar} for this region.
53728 * @return {Roo.SplitBar}
53730 getSplitBar : function(){
53735 this.hideSplitter();
53736 Roo.SplitLayoutRegion.superclass.hide.call(this);
53739 hideSplitter : function(){
53741 this.split.el.setLocation(-2000,-2000);
53742 this.split.el.hide();
53748 this.split.el.show();
53750 Roo.SplitLayoutRegion.superclass.show.call(this);
53753 beforeSlide: function(){
53754 if(Roo.isGecko){// firefox overflow auto bug workaround
53755 this.bodyEl.clip();
53757 this.tabs.bodyEl.clip();
53759 if(this.activePanel){
53760 this.activePanel.getEl().clip();
53762 if(this.activePanel.beforeSlide){
53763 this.activePanel.beforeSlide();
53769 afterSlide : function(){
53770 if(Roo.isGecko){// firefox overflow auto bug workaround
53771 this.bodyEl.unclip();
53773 this.tabs.bodyEl.unclip();
53775 if(this.activePanel){
53776 this.activePanel.getEl().unclip();
53777 if(this.activePanel.afterSlide){
53778 this.activePanel.afterSlide();
53784 initAutoHide : function(){
53785 if(this.autoHide !== false){
53786 if(!this.autoHideHd){
53787 var st = new Roo.util.DelayedTask(this.slideIn, this);
53788 this.autoHideHd = {
53789 "mouseout": function(e){
53790 if(!e.within(this.el, true)){
53794 "mouseover" : function(e){
53800 this.el.on(this.autoHideHd);
53804 clearAutoHide : function(){
53805 if(this.autoHide !== false){
53806 this.el.un("mouseout", this.autoHideHd.mouseout);
53807 this.el.un("mouseover", this.autoHideHd.mouseover);
53811 clearMonitor : function(){
53812 Roo.get(document).un("click", this.slideInIf, this);
53815 // these names are backwards but not changed for compat
53816 slideOut : function(){
53817 if(this.isSlid || this.el.hasActiveFx()){
53820 this.isSlid = true;
53821 if(this.collapseBtn){
53822 this.collapseBtn.hide();
53824 this.closeBtnState = this.closeBtn.getStyle('display');
53825 this.closeBtn.hide();
53827 this.stickBtn.show();
53830 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53831 this.beforeSlide();
53832 this.el.setStyle("z-index", 10001);
53833 this.el.slideIn(this.getSlideAnchor(), {
53834 callback: function(){
53836 this.initAutoHide();
53837 Roo.get(document).on("click", this.slideInIf, this);
53838 this.fireEvent("slideshow", this);
53845 afterSlideIn : function(){
53846 this.clearAutoHide();
53847 this.isSlid = false;
53848 this.clearMonitor();
53849 this.el.setStyle("z-index", "");
53850 if(this.collapseBtn){
53851 this.collapseBtn.show();
53853 this.closeBtn.setStyle('display', this.closeBtnState);
53855 this.stickBtn.hide();
53857 this.fireEvent("slidehide", this);
53860 slideIn : function(cb){
53861 if(!this.isSlid || this.el.hasActiveFx()){
53865 this.isSlid = false;
53866 this.beforeSlide();
53867 this.el.slideOut(this.getSlideAnchor(), {
53868 callback: function(){
53869 this.el.setLeftTop(-10000, -10000);
53871 this.afterSlideIn();
53879 slideInIf : function(e){
53880 if(!e.within(this.el)){
53885 animateCollapse : function(){
53886 this.beforeSlide();
53887 this.el.setStyle("z-index", 20000);
53888 var anchor = this.getSlideAnchor();
53889 this.el.slideOut(anchor, {
53890 callback : function(){
53891 this.el.setStyle("z-index", "");
53892 this.collapsedEl.slideIn(anchor, {duration:.3});
53894 this.el.setLocation(-10000,-10000);
53896 this.fireEvent("collapsed", this);
53903 animateExpand : function(){
53904 this.beforeSlide();
53905 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
53906 this.el.setStyle("z-index", 20000);
53907 this.collapsedEl.hide({
53910 this.el.slideIn(this.getSlideAnchor(), {
53911 callback : function(){
53912 this.el.setStyle("z-index", "");
53915 this.split.el.show();
53917 this.fireEvent("invalidated", this);
53918 this.fireEvent("expanded", this);
53946 getAnchor : function(){
53947 return this.anchors[this.position];
53950 getCollapseAnchor : function(){
53951 return this.canchors[this.position];
53954 getSlideAnchor : function(){
53955 return this.sanchors[this.position];
53958 getAlignAdj : function(){
53959 var cm = this.cmargins;
53960 switch(this.position){
53976 getExpandAdj : function(){
53977 var c = this.collapsedEl, cm = this.cmargins;
53978 switch(this.position){
53980 return [-(cm.right+c.getWidth()+cm.left), 0];
53983 return [cm.right+c.getWidth()+cm.left, 0];
53986 return [0, -(cm.top+cm.bottom+c.getHeight())];
53989 return [0, cm.top+cm.bottom+c.getHeight()];
53995 * Ext JS Library 1.1.1
53996 * Copyright(c) 2006-2007, Ext JS, LLC.
53998 * Originally Released Under LGPL - original licence link has changed is not relivant.
54001 * <script type="text/javascript">
54004 * These classes are private internal classes
54006 Roo.CenterLayoutRegion = function(mgr, config){
54007 Roo.LayoutRegion.call(this, mgr, config, "center");
54008 this.visible = true;
54009 this.minWidth = config.minWidth || 20;
54010 this.minHeight = config.minHeight || 20;
54013 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
54015 // center panel can't be hidden
54019 // center panel can't be hidden
54022 getMinWidth: function(){
54023 return this.minWidth;
54026 getMinHeight: function(){
54027 return this.minHeight;
54032 Roo.NorthLayoutRegion = function(mgr, config){
54033 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
54035 this.split.placement = Roo.SplitBar.TOP;
54036 this.split.orientation = Roo.SplitBar.VERTICAL;
54037 this.split.el.addClass("x-layout-split-v");
54039 var size = config.initialSize || config.height;
54040 if(typeof size != "undefined"){
54041 this.el.setHeight(size);
54044 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
54045 orientation: Roo.SplitBar.VERTICAL,
54046 getBox : function(){
54047 if(this.collapsed){
54048 return this.collapsedEl.getBox();
54050 var box = this.el.getBox();
54052 box.height += this.split.el.getHeight();
54057 updateBox : function(box){
54058 if(this.split && !this.collapsed){
54059 box.height -= this.split.el.getHeight();
54060 this.split.el.setLeft(box.x);
54061 this.split.el.setTop(box.y+box.height);
54062 this.split.el.setWidth(box.width);
54064 if(this.collapsed){
54065 this.updateBody(box.width, null);
54067 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54071 Roo.SouthLayoutRegion = function(mgr, config){
54072 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
54074 this.split.placement = Roo.SplitBar.BOTTOM;
54075 this.split.orientation = Roo.SplitBar.VERTICAL;
54076 this.split.el.addClass("x-layout-split-v");
54078 var size = config.initialSize || config.height;
54079 if(typeof size != "undefined"){
54080 this.el.setHeight(size);
54083 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
54084 orientation: Roo.SplitBar.VERTICAL,
54085 getBox : function(){
54086 if(this.collapsed){
54087 return this.collapsedEl.getBox();
54089 var box = this.el.getBox();
54091 var sh = this.split.el.getHeight();
54098 updateBox : function(box){
54099 if(this.split && !this.collapsed){
54100 var sh = this.split.el.getHeight();
54103 this.split.el.setLeft(box.x);
54104 this.split.el.setTop(box.y-sh);
54105 this.split.el.setWidth(box.width);
54107 if(this.collapsed){
54108 this.updateBody(box.width, null);
54110 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54114 Roo.EastLayoutRegion = function(mgr, config){
54115 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54117 this.split.placement = Roo.SplitBar.RIGHT;
54118 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54119 this.split.el.addClass("x-layout-split-h");
54121 var size = config.initialSize || config.width;
54122 if(typeof size != "undefined"){
54123 this.el.setWidth(size);
54126 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54127 orientation: Roo.SplitBar.HORIZONTAL,
54128 getBox : function(){
54129 if(this.collapsed){
54130 return this.collapsedEl.getBox();
54132 var box = this.el.getBox();
54134 var sw = this.split.el.getWidth();
54141 updateBox : function(box){
54142 if(this.split && !this.collapsed){
54143 var sw = this.split.el.getWidth();
54145 this.split.el.setLeft(box.x);
54146 this.split.el.setTop(box.y);
54147 this.split.el.setHeight(box.height);
54150 if(this.collapsed){
54151 this.updateBody(null, box.height);
54153 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54157 Roo.WestLayoutRegion = function(mgr, config){
54158 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54160 this.split.placement = Roo.SplitBar.LEFT;
54161 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54162 this.split.el.addClass("x-layout-split-h");
54164 var size = config.initialSize || config.width;
54165 if(typeof size != "undefined"){
54166 this.el.setWidth(size);
54169 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
54170 orientation: Roo.SplitBar.HORIZONTAL,
54171 getBox : function(){
54172 if(this.collapsed){
54173 return this.collapsedEl.getBox();
54175 var box = this.el.getBox();
54177 box.width += this.split.el.getWidth();
54182 updateBox : function(box){
54183 if(this.split && !this.collapsed){
54184 var sw = this.split.el.getWidth();
54186 this.split.el.setLeft(box.x+box.width);
54187 this.split.el.setTop(box.y);
54188 this.split.el.setHeight(box.height);
54190 if(this.collapsed){
54191 this.updateBody(null, box.height);
54193 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54198 * Ext JS Library 1.1.1
54199 * Copyright(c) 2006-2007, Ext JS, LLC.
54201 * Originally Released Under LGPL - original licence link has changed is not relivant.
54204 * <script type="text/javascript">
54209 * Private internal class for reading and applying state
54211 Roo.LayoutStateManager = function(layout){
54212 // default empty state
54221 Roo.LayoutStateManager.prototype = {
54222 init : function(layout, provider){
54223 this.provider = provider;
54224 var state = provider.get(layout.id+"-layout-state");
54226 var wasUpdating = layout.isUpdating();
54228 layout.beginUpdate();
54230 for(var key in state){
54231 if(typeof state[key] != "function"){
54232 var rstate = state[key];
54233 var r = layout.getRegion(key);
54236 r.resizeTo(rstate.size);
54238 if(rstate.collapsed == true){
54241 r.expand(null, true);
54247 layout.endUpdate();
54249 this.state = state;
54251 this.layout = layout;
54252 layout.on("regionresized", this.onRegionResized, this);
54253 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54254 layout.on("regionexpanded", this.onRegionExpanded, this);
54257 storeState : function(){
54258 this.provider.set(this.layout.id+"-layout-state", this.state);
54261 onRegionResized : function(region, newSize){
54262 this.state[region.getPosition()].size = newSize;
54266 onRegionCollapsed : function(region){
54267 this.state[region.getPosition()].collapsed = true;
54271 onRegionExpanded : function(region){
54272 this.state[region.getPosition()].collapsed = false;
54277 * Ext JS Library 1.1.1
54278 * Copyright(c) 2006-2007, Ext JS, LLC.
54280 * Originally Released Under LGPL - original licence link has changed is not relivant.
54283 * <script type="text/javascript">
54286 * @class Roo.ContentPanel
54287 * @extends Roo.util.Observable
54288 * A basic ContentPanel element.
54289 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54290 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54291 * @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
54292 * @cfg {Boolean} closable True if the panel can be closed/removed
54293 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54294 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54295 * @cfg {Toolbar} toolbar A toolbar for this panel
54296 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54297 * @cfg {String} title The title for this panel
54298 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54299 * @cfg {String} url Calls {@link #setUrl} with this value
54300 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54301 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54302 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54303 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54304 * @cfg {String} style Extra style to add to the content panel
54307 * Create a new ContentPanel.
54308 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54309 * @param {String/Object} config A string to set only the title or a config object
54310 * @param {String} content (optional) Set the HTML content for this panel
54311 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54313 Roo.ContentPanel = function(el, config, content){
54317 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54321 if (config && config.parentLayout) {
54322 el = config.parentLayout.el.createChild();
54325 if(el.autoCreate){ // xtype is available if this is called from factory
54329 this.el = Roo.get(el);
54330 if(!this.el && config && config.autoCreate){
54331 if(typeof config.autoCreate == "object"){
54332 if(!config.autoCreate.id){
54333 config.autoCreate.id = config.id||el;
54335 this.el = Roo.DomHelper.append(document.body,
54336 config.autoCreate, true);
54338 this.el = Roo.DomHelper.append(document.body,
54339 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54344 this.closable = false;
54345 this.loaded = false;
54346 this.active = false;
54347 if(typeof config == "string"){
54348 this.title = config;
54350 Roo.apply(this, config);
54353 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54354 this.wrapEl = this.el.wrap();
54355 this.toolbar.container = this.el.insertSibling(false, 'before');
54356 this.toolbar = new Roo.Toolbar(this.toolbar);
54359 // xtype created footer. - not sure if will work as we normally have to render first..
54360 if (this.footer && !this.footer.el && this.footer.xtype) {
54361 if (!this.wrapEl) {
54362 this.wrapEl = this.el.wrap();
54365 this.footer.container = this.wrapEl.createChild();
54367 this.footer = Roo.factory(this.footer, Roo);
54372 this.resizeEl = Roo.get(this.resizeEl, true);
54374 this.resizeEl = this.el;
54376 // handle view.xtype
54384 * Fires when this panel is activated.
54385 * @param {Roo.ContentPanel} this
54389 * @event deactivate
54390 * Fires when this panel is activated.
54391 * @param {Roo.ContentPanel} this
54393 "deactivate" : true,
54397 * Fires when this panel is resized if fitToFrame is true.
54398 * @param {Roo.ContentPanel} this
54399 * @param {Number} width The width after any component adjustments
54400 * @param {Number} height The height after any component adjustments
54406 * Fires when this tab is created
54407 * @param {Roo.ContentPanel} this
54417 if(this.autoScroll){
54418 this.resizeEl.setStyle("overflow", "auto");
54420 // fix randome scrolling
54421 this.el.on('scroll', function() {
54422 Roo.log('fix random scolling');
54423 this.scrollTo('top',0);
54426 content = content || this.content;
54428 this.setContent(content);
54430 if(config && config.url){
54431 this.setUrl(this.url, this.params, this.loadOnce);
54436 Roo.ContentPanel.superclass.constructor.call(this);
54438 if (this.view && typeof(this.view.xtype) != 'undefined') {
54439 this.view.el = this.el.appendChild(document.createElement("div"));
54440 this.view = Roo.factory(this.view);
54441 this.view.render && this.view.render(false, '');
54445 this.fireEvent('render', this);
54448 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54450 setRegion : function(region){
54451 this.region = region;
54453 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54455 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54460 * Returns the toolbar for this Panel if one was configured.
54461 * @return {Roo.Toolbar}
54463 getToolbar : function(){
54464 return this.toolbar;
54467 setActiveState : function(active){
54468 this.active = active;
54470 this.fireEvent("deactivate", this);
54472 this.fireEvent("activate", this);
54476 * Updates this panel's element
54477 * @param {String} content The new content
54478 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54480 setContent : function(content, loadScripts){
54481 this.el.update(content, loadScripts);
54484 ignoreResize : function(w, h){
54485 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54488 this.lastSize = {width: w, height: h};
54493 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54494 * @return {Roo.UpdateManager} The UpdateManager
54496 getUpdateManager : function(){
54497 return this.el.getUpdateManager();
54500 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54501 * @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:
54504 url: "your-url.php",
54505 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54506 callback: yourFunction,
54507 scope: yourObject, //(optional scope)
54510 text: "Loading...",
54515 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54516 * 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.
54517 * @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}
54518 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54519 * @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.
54520 * @return {Roo.ContentPanel} this
54523 var um = this.el.getUpdateManager();
54524 um.update.apply(um, arguments);
54530 * 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.
54531 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54532 * @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)
54533 * @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)
54534 * @return {Roo.UpdateManager} The UpdateManager
54536 setUrl : function(url, params, loadOnce){
54537 if(this.refreshDelegate){
54538 this.removeListener("activate", this.refreshDelegate);
54540 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54541 this.on("activate", this.refreshDelegate);
54542 return this.el.getUpdateManager();
54545 _handleRefresh : function(url, params, loadOnce){
54546 if(!loadOnce || !this.loaded){
54547 var updater = this.el.getUpdateManager();
54548 updater.update(url, params, this._setLoaded.createDelegate(this));
54552 _setLoaded : function(){
54553 this.loaded = true;
54557 * Returns this panel's id
54560 getId : function(){
54565 * Returns this panel's element - used by regiosn to add.
54566 * @return {Roo.Element}
54568 getEl : function(){
54569 return this.wrapEl || this.el;
54572 adjustForComponents : function(width, height)
54574 //Roo.log('adjustForComponents ');
54575 if(this.resizeEl != this.el){
54576 width -= this.el.getFrameWidth('lr');
54577 height -= this.el.getFrameWidth('tb');
54580 var te = this.toolbar.getEl();
54581 height -= te.getHeight();
54582 te.setWidth(width);
54585 var te = this.footer.getEl();
54586 //Roo.log("footer:" + te.getHeight());
54588 height -= te.getHeight();
54589 te.setWidth(width);
54593 if(this.adjustments){
54594 width += this.adjustments[0];
54595 height += this.adjustments[1];
54597 return {"width": width, "height": height};
54600 setSize : function(width, height){
54601 if(this.fitToFrame && !this.ignoreResize(width, height)){
54602 if(this.fitContainer && this.resizeEl != this.el){
54603 this.el.setSize(width, height);
54605 var size = this.adjustForComponents(width, height);
54606 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54607 this.fireEvent('resize', this, size.width, size.height);
54612 * Returns this panel's title
54615 getTitle : function(){
54620 * Set this panel's title
54621 * @param {String} title
54623 setTitle : function(title){
54624 this.title = title;
54626 this.region.updatePanelTitle(this, title);
54631 * Returns true is this panel was configured to be closable
54632 * @return {Boolean}
54634 isClosable : function(){
54635 return this.closable;
54638 beforeSlide : function(){
54640 this.resizeEl.clip();
54643 afterSlide : function(){
54645 this.resizeEl.unclip();
54649 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54650 * Will fail silently if the {@link #setUrl} method has not been called.
54651 * This does not activate the panel, just updates its content.
54653 refresh : function(){
54654 if(this.refreshDelegate){
54655 this.loaded = false;
54656 this.refreshDelegate();
54661 * Destroys this panel
54663 destroy : function(){
54664 this.el.removeAllListeners();
54665 var tempEl = document.createElement("span");
54666 tempEl.appendChild(this.el.dom);
54667 tempEl.innerHTML = "";
54673 * form - if the content panel contains a form - this is a reference to it.
54674 * @type {Roo.form.Form}
54678 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54679 * This contains a reference to it.
54685 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54695 * @param {Object} cfg Xtype definition of item to add.
54698 addxtype : function(cfg) {
54700 if (cfg.xtype.match(/^Form$/)) {
54703 //if (this.footer) {
54704 // el = this.footer.container.insertSibling(false, 'before');
54706 el = this.el.createChild();
54709 this.form = new Roo.form.Form(cfg);
54712 if ( this.form.allItems.length) {
54713 this.form.render(el.dom);
54717 // should only have one of theses..
54718 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54719 // views.. should not be just added - used named prop 'view''
54721 cfg.el = this.el.appendChild(document.createElement("div"));
54724 var ret = new Roo.factory(cfg);
54726 ret.render && ret.render(false, ''); // render blank..
54735 * @class Roo.GridPanel
54736 * @extends Roo.ContentPanel
54738 * Create a new GridPanel.
54739 * @param {Roo.grid.Grid} grid The grid for this panel
54740 * @param {String/Object} config A string to set only the panel's title, or a config object
54742 Roo.GridPanel = function(grid, config){
54745 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54746 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54748 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54750 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54753 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54755 // xtype created footer. - not sure if will work as we normally have to render first..
54756 if (this.footer && !this.footer.el && this.footer.xtype) {
54758 this.footer.container = this.grid.getView().getFooterPanel(true);
54759 this.footer.dataSource = this.grid.dataSource;
54760 this.footer = Roo.factory(this.footer, Roo);
54764 grid.monitorWindowResize = false; // turn off autosizing
54765 grid.autoHeight = false;
54766 grid.autoWidth = false;
54768 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54771 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54772 getId : function(){
54773 return this.grid.id;
54777 * Returns the grid for this panel
54778 * @return {Roo.grid.Grid}
54780 getGrid : function(){
54784 setSize : function(width, height){
54785 if(!this.ignoreResize(width, height)){
54786 var grid = this.grid;
54787 var size = this.adjustForComponents(width, height);
54788 grid.getGridEl().setSize(size.width, size.height);
54793 beforeSlide : function(){
54794 this.grid.getView().scroller.clip();
54797 afterSlide : function(){
54798 this.grid.getView().scroller.unclip();
54801 destroy : function(){
54802 this.grid.destroy();
54804 Roo.GridPanel.superclass.destroy.call(this);
54810 * @class Roo.NestedLayoutPanel
54811 * @extends Roo.ContentPanel
54813 * Create a new NestedLayoutPanel.
54816 * @param {Roo.BorderLayout} layout The layout for this panel
54817 * @param {String/Object} config A string to set only the title or a config object
54819 Roo.NestedLayoutPanel = function(layout, config)
54821 // construct with only one argument..
54822 /* FIXME - implement nicer consturctors
54823 if (layout.layout) {
54825 layout = config.layout;
54826 delete config.layout;
54828 if (layout.xtype && !layout.getEl) {
54829 // then layout needs constructing..
54830 layout = Roo.factory(layout, Roo);
54835 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54837 layout.monitorWindowResize = false; // turn off autosizing
54838 this.layout = layout;
54839 this.layout.getEl().addClass("x-layout-nested-layout");
54846 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
54848 setSize : function(width, height){
54849 if(!this.ignoreResize(width, height)){
54850 var size = this.adjustForComponents(width, height);
54851 var el = this.layout.getEl();
54852 el.setSize(size.width, size.height);
54853 var touch = el.dom.offsetWidth;
54854 this.layout.layout();
54855 // ie requires a double layout on the first pass
54856 if(Roo.isIE && !this.initialized){
54857 this.initialized = true;
54858 this.layout.layout();
54863 // activate all subpanels if not currently active..
54865 setActiveState : function(active){
54866 this.active = active;
54868 this.fireEvent("deactivate", this);
54872 this.fireEvent("activate", this);
54873 // not sure if this should happen before or after..
54874 if (!this.layout) {
54875 return; // should not happen..
54878 for (var r in this.layout.regions) {
54879 reg = this.layout.getRegion(r);
54880 if (reg.getActivePanel()) {
54881 //reg.showPanel(reg.getActivePanel()); // force it to activate..
54882 reg.setActivePanel(reg.getActivePanel());
54885 if (!reg.panels.length) {
54888 reg.showPanel(reg.getPanel(0));
54897 * Returns the nested BorderLayout for this panel
54898 * @return {Roo.BorderLayout}
54900 getLayout : function(){
54901 return this.layout;
54905 * Adds a xtype elements to the layout of the nested panel
54909 xtype : 'ContentPanel',
54916 xtype : 'NestedLayoutPanel',
54922 items : [ ... list of content panels or nested layout panels.. ]
54926 * @param {Object} cfg Xtype definition of item to add.
54928 addxtype : function(cfg) {
54929 return this.layout.addxtype(cfg);
54934 Roo.ScrollPanel = function(el, config, content){
54935 config = config || {};
54936 config.fitToFrame = true;
54937 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
54939 this.el.dom.style.overflow = "hidden";
54940 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
54941 this.el.removeClass("x-layout-inactive-content");
54942 this.el.on("mousewheel", this.onWheel, this);
54944 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
54945 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
54946 up.unselectable(); down.unselectable();
54947 up.on("click", this.scrollUp, this);
54948 down.on("click", this.scrollDown, this);
54949 up.addClassOnOver("x-scroller-btn-over");
54950 down.addClassOnOver("x-scroller-btn-over");
54951 up.addClassOnClick("x-scroller-btn-click");
54952 down.addClassOnClick("x-scroller-btn-click");
54953 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
54955 this.resizeEl = this.el;
54956 this.el = wrap; this.up = up; this.down = down;
54959 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
54961 wheelIncrement : 5,
54962 scrollUp : function(){
54963 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
54966 scrollDown : function(){
54967 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
54970 afterScroll : function(){
54971 var el = this.resizeEl;
54972 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
54973 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54974 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54977 setSize : function(){
54978 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
54979 this.afterScroll();
54982 onWheel : function(e){
54983 var d = e.getWheelDelta();
54984 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
54985 this.afterScroll();
54989 setContent : function(content, loadScripts){
54990 this.resizeEl.update(content, loadScripts);
55004 * @class Roo.TreePanel
55005 * @extends Roo.ContentPanel
55007 * Create a new TreePanel. - defaults to fit/scoll contents.
55008 * @param {String/Object} config A string to set only the panel's title, or a config object
55009 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
55011 Roo.TreePanel = function(config){
55012 var el = config.el;
55013 var tree = config.tree;
55014 delete config.tree;
55015 delete config.el; // hopefull!
55017 // wrapper for IE7 strict & safari scroll issue
55019 var treeEl = el.createChild();
55020 config.resizeEl = treeEl;
55024 Roo.TreePanel.superclass.constructor.call(this, el, config);
55027 this.tree = new Roo.tree.TreePanel(treeEl , tree);
55028 //console.log(tree);
55029 this.on('activate', function()
55031 if (this.tree.rendered) {
55034 //console.log('render tree');
55035 this.tree.render();
55037 // this should not be needed.. - it's actually the 'el' that resizes?
55038 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
55040 //this.on('resize', function (cp, w, h) {
55041 // this.tree.innerCt.setWidth(w);
55042 // this.tree.innerCt.setHeight(h);
55043 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
55050 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
55067 * Ext JS Library 1.1.1
55068 * Copyright(c) 2006-2007, Ext JS, LLC.
55070 * Originally Released Under LGPL - original licence link has changed is not relivant.
55073 * <script type="text/javascript">
55078 * @class Roo.ReaderLayout
55079 * @extends Roo.BorderLayout
55080 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
55081 * center region containing two nested regions (a top one for a list view and one for item preview below),
55082 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
55083 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
55084 * expedites the setup of the overall layout and regions for this common application style.
55087 var reader = new Roo.ReaderLayout();
55088 var CP = Roo.ContentPanel; // shortcut for adding
55090 reader.beginUpdate();
55091 reader.add("north", new CP("north", "North"));
55092 reader.add("west", new CP("west", {title: "West"}));
55093 reader.add("east", new CP("east", {title: "East"}));
55095 reader.regions.listView.add(new CP("listView", "List"));
55096 reader.regions.preview.add(new CP("preview", "Preview"));
55097 reader.endUpdate();
55100 * Create a new ReaderLayout
55101 * @param {Object} config Configuration options
55102 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55103 * document.body if omitted)
55105 Roo.ReaderLayout = function(config, renderTo){
55106 var c = config || {size:{}};
55107 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55108 north: c.north !== false ? Roo.apply({
55112 }, c.north) : false,
55113 west: c.west !== false ? Roo.apply({
55121 margins:{left:5,right:0,bottom:5,top:5},
55122 cmargins:{left:5,right:5,bottom:5,top:5}
55123 }, c.west) : false,
55124 east: c.east !== false ? Roo.apply({
55132 margins:{left:0,right:5,bottom:5,top:5},
55133 cmargins:{left:5,right:5,bottom:5,top:5}
55134 }, c.east) : false,
55135 center: Roo.apply({
55136 tabPosition: 'top',
55140 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55144 this.el.addClass('x-reader');
55146 this.beginUpdate();
55148 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55149 south: c.preview !== false ? Roo.apply({
55156 cmargins:{top:5,left:0, right:0, bottom:0}
55157 }, c.preview) : false,
55158 center: Roo.apply({
55164 this.add('center', new Roo.NestedLayoutPanel(inner,
55165 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55169 this.regions.preview = inner.getRegion('south');
55170 this.regions.listView = inner.getRegion('center');
55173 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55175 * Ext JS Library 1.1.1
55176 * Copyright(c) 2006-2007, Ext JS, LLC.
55178 * Originally Released Under LGPL - original licence link has changed is not relivant.
55181 * <script type="text/javascript">
55185 * @class Roo.grid.Grid
55186 * @extends Roo.util.Observable
55187 * This class represents the primary interface of a component based grid control.
55188 * <br><br>Usage:<pre><code>
55189 var grid = new Roo.grid.Grid("my-container-id", {
55192 selModel: mySelectionModel,
55193 autoSizeColumns: true,
55194 monitorWindowResize: false,
55195 trackMouseOver: true
55200 * <b>Common Problems:</b><br/>
55201 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55202 * element will correct this<br/>
55203 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55204 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55205 * are unpredictable.<br/>
55206 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55207 * grid to calculate dimensions/offsets.<br/>
55209 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55210 * The container MUST have some type of size defined for the grid to fill. The container will be
55211 * automatically set to position relative if it isn't already.
55212 * @param {Object} config A config object that sets properties on this grid.
55214 Roo.grid.Grid = function(container, config){
55215 // initialize the container
55216 this.container = Roo.get(container);
55217 this.container.update("");
55218 this.container.setStyle("overflow", "hidden");
55219 this.container.addClass('x-grid-container');
55221 this.id = this.container.id;
55223 Roo.apply(this, config);
55224 // check and correct shorthanded configs
55226 this.dataSource = this.ds;
55230 this.colModel = this.cm;
55234 this.selModel = this.sm;
55238 if (this.selModel) {
55239 this.selModel = Roo.factory(this.selModel, Roo.grid);
55240 this.sm = this.selModel;
55241 this.sm.xmodule = this.xmodule || false;
55243 if (typeof(this.colModel.config) == 'undefined') {
55244 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55245 this.cm = this.colModel;
55246 this.cm.xmodule = this.xmodule || false;
55248 if (this.dataSource) {
55249 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55250 this.ds = this.dataSource;
55251 this.ds.xmodule = this.xmodule || false;
55258 this.container.setWidth(this.width);
55262 this.container.setHeight(this.height);
55269 * The raw click event for the entire grid.
55270 * @param {Roo.EventObject} e
55275 * The raw dblclick event for the entire grid.
55276 * @param {Roo.EventObject} e
55280 * @event contextmenu
55281 * The raw contextmenu event for the entire grid.
55282 * @param {Roo.EventObject} e
55284 "contextmenu" : true,
55287 * The raw mousedown event for the entire grid.
55288 * @param {Roo.EventObject} e
55290 "mousedown" : true,
55293 * The raw mouseup event for the entire grid.
55294 * @param {Roo.EventObject} e
55299 * The raw mouseover event for the entire grid.
55300 * @param {Roo.EventObject} e
55302 "mouseover" : true,
55305 * The raw mouseout event for the entire grid.
55306 * @param {Roo.EventObject} e
55311 * The raw keypress event for the entire grid.
55312 * @param {Roo.EventObject} e
55317 * The raw keydown event for the entire grid.
55318 * @param {Roo.EventObject} e
55326 * Fires when a cell is clicked
55327 * @param {Grid} this
55328 * @param {Number} rowIndex
55329 * @param {Number} columnIndex
55330 * @param {Roo.EventObject} e
55332 "cellclick" : true,
55334 * @event celldblclick
55335 * Fires when a cell is double clicked
55336 * @param {Grid} this
55337 * @param {Number} rowIndex
55338 * @param {Number} columnIndex
55339 * @param {Roo.EventObject} e
55341 "celldblclick" : true,
55344 * Fires when a row is clicked
55345 * @param {Grid} this
55346 * @param {Number} rowIndex
55347 * @param {Roo.EventObject} e
55351 * @event rowdblclick
55352 * Fires when a row is double clicked
55353 * @param {Grid} this
55354 * @param {Number} rowIndex
55355 * @param {Roo.EventObject} e
55357 "rowdblclick" : true,
55359 * @event headerclick
55360 * Fires when a header is clicked
55361 * @param {Grid} this
55362 * @param {Number} columnIndex
55363 * @param {Roo.EventObject} e
55365 "headerclick" : true,
55367 * @event headerdblclick
55368 * Fires when a header cell is double clicked
55369 * @param {Grid} this
55370 * @param {Number} columnIndex
55371 * @param {Roo.EventObject} e
55373 "headerdblclick" : true,
55375 * @event rowcontextmenu
55376 * Fires when a row is right clicked
55377 * @param {Grid} this
55378 * @param {Number} rowIndex
55379 * @param {Roo.EventObject} e
55381 "rowcontextmenu" : true,
55383 * @event cellcontextmenu
55384 * Fires when a cell is right clicked
55385 * @param {Grid} this
55386 * @param {Number} rowIndex
55387 * @param {Number} cellIndex
55388 * @param {Roo.EventObject} e
55390 "cellcontextmenu" : true,
55392 * @event headercontextmenu
55393 * Fires when a header is right clicked
55394 * @param {Grid} this
55395 * @param {Number} columnIndex
55396 * @param {Roo.EventObject} e
55398 "headercontextmenu" : true,
55400 * @event bodyscroll
55401 * Fires when the body element is scrolled
55402 * @param {Number} scrollLeft
55403 * @param {Number} scrollTop
55405 "bodyscroll" : true,
55407 * @event columnresize
55408 * Fires when the user resizes a column
55409 * @param {Number} columnIndex
55410 * @param {Number} newSize
55412 "columnresize" : true,
55414 * @event columnmove
55415 * Fires when the user moves a column
55416 * @param {Number} oldIndex
55417 * @param {Number} newIndex
55419 "columnmove" : true,
55422 * Fires when row(s) start being dragged
55423 * @param {Grid} this
55424 * @param {Roo.GridDD} dd The drag drop object
55425 * @param {event} e The raw browser event
55427 "startdrag" : true,
55430 * Fires when a drag operation is complete
55431 * @param {Grid} this
55432 * @param {Roo.GridDD} dd The drag drop object
55433 * @param {event} e The raw browser event
55438 * Fires when dragged row(s) are dropped on a valid DD target
55439 * @param {Grid} this
55440 * @param {Roo.GridDD} dd The drag drop object
55441 * @param {String} targetId The target drag drop object
55442 * @param {event} e The raw browser event
55447 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55448 * @param {Grid} this
55449 * @param {Roo.GridDD} dd The drag drop object
55450 * @param {String} targetId The target drag drop object
55451 * @param {event} e The raw browser event
55456 * Fires when the dragged row(s) first cross another DD target while being dragged
55457 * @param {Grid} this
55458 * @param {Roo.GridDD} dd The drag drop object
55459 * @param {String} targetId The target drag drop object
55460 * @param {event} e The raw browser event
55462 "dragenter" : true,
55465 * Fires when the dragged row(s) leave another DD target while being dragged
55466 * @param {Grid} this
55467 * @param {Roo.GridDD} dd The drag drop object
55468 * @param {String} targetId The target drag drop object
55469 * @param {event} e The raw browser event
55474 * Fires when a row is rendered, so you can change add a style to it.
55475 * @param {GridView} gridview The grid view
55476 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55482 * Fires when the grid is rendered
55483 * @param {Grid} grid
55488 Roo.grid.Grid.superclass.constructor.call(this);
55490 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55493 * @cfg {String} ddGroup - drag drop group.
55496 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
55500 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55502 minColumnWidth : 25,
55505 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55506 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55507 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55509 autoSizeColumns : false,
55512 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55514 autoSizeHeaders : true,
55517 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55519 monitorWindowResize : true,
55522 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55523 * rows measured to get a columns size. Default is 0 (all rows).
55525 maxRowsToMeasure : 0,
55528 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55530 trackMouseOver : true,
55533 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55536 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
55540 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55542 enableDragDrop : false,
55545 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55547 enableColumnMove : true,
55550 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55552 enableColumnHide : true,
55555 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55557 enableRowHeightSync : false,
55560 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55565 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55567 autoHeight : false,
55570 * @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.
55572 autoExpandColumn : false,
55575 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55578 autoExpandMin : 50,
55581 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55583 autoExpandMax : 1000,
55586 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55591 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55595 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55605 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55606 * of a fixed width. Default is false.
55609 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55614 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55615 * %0 is replaced with the number of selected rows.
55617 ddText : "{0} selected row{1}",
55621 * Called once after all setup has been completed and the grid is ready to be rendered.
55622 * @return {Roo.grid.Grid} this
55624 render : function()
55626 var c = this.container;
55627 // try to detect autoHeight/width mode
55628 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55629 this.autoHeight = true;
55631 var view = this.getView();
55634 c.on("click", this.onClick, this);
55635 c.on("dblclick", this.onDblClick, this);
55636 c.on("contextmenu", this.onContextMenu, this);
55637 c.on("keydown", this.onKeyDown, this);
55639 c.on("touchstart", this.onTouchStart, this);
55642 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55644 this.getSelectionModel().init(this);
55649 this.loadMask = new Roo.LoadMask(this.container,
55650 Roo.apply({store:this.dataSource}, this.loadMask));
55654 if (this.toolbar && this.toolbar.xtype) {
55655 this.toolbar.container = this.getView().getHeaderPanel(true);
55656 this.toolbar = new Roo.Toolbar(this.toolbar);
55658 if (this.footer && this.footer.xtype) {
55659 this.footer.dataSource = this.getDataSource();
55660 this.footer.container = this.getView().getFooterPanel(true);
55661 this.footer = Roo.factory(this.footer, Roo);
55663 if (this.dropTarget && this.dropTarget.xtype) {
55664 delete this.dropTarget.xtype;
55665 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55669 this.rendered = true;
55670 this.fireEvent('render', this);
55675 * Reconfigures the grid to use a different Store and Column Model.
55676 * The View will be bound to the new objects and refreshed.
55677 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55678 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55680 reconfigure : function(dataSource, colModel){
55682 this.loadMask.destroy();
55683 this.loadMask = new Roo.LoadMask(this.container,
55684 Roo.apply({store:dataSource}, this.loadMask));
55686 this.view.bind(dataSource, colModel);
55687 this.dataSource = dataSource;
55688 this.colModel = colModel;
55689 this.view.refresh(true);
55693 * Add's a column, default at the end..
55695 * @param {int} position to add (default end)
55696 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55698 addColumns : function(pos, ar)
55701 for (var i =0;i< ar.length;i++) {
55703 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55704 this.cm.lookup[cfg.id] = cfg;
55708 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55709 pos = this.cm.config.length; //this.cm.config.push(cfg);
55711 pos = Math.max(0,pos);
55714 this.cm.config.splice.apply(this.cm.config, ar);
55718 this.view.generateRules(this.cm);
55719 this.view.refresh(true);
55727 onKeyDown : function(e){
55728 this.fireEvent("keydown", e);
55732 * Destroy this grid.
55733 * @param {Boolean} removeEl True to remove the element
55735 destroy : function(removeEl, keepListeners){
55737 this.loadMask.destroy();
55739 var c = this.container;
55740 c.removeAllListeners();
55741 this.view.destroy();
55742 this.colModel.purgeListeners();
55743 if(!keepListeners){
55744 this.purgeListeners();
55747 if(removeEl === true){
55753 processEvent : function(name, e){
55754 // does this fire select???
55755 //Roo.log('grid:processEvent ' + name);
55757 if (name != 'touchstart' ) {
55758 this.fireEvent(name, e);
55761 var t = e.getTarget();
55763 var header = v.findHeaderIndex(t);
55764 if(header !== false){
55765 var ename = name == 'touchstart' ? 'click' : name;
55767 this.fireEvent("header" + ename, this, header, e);
55769 var row = v.findRowIndex(t);
55770 var cell = v.findCellIndex(t);
55771 if (name == 'touchstart') {
55772 // first touch is always a click.
55773 // hopefull this happens after selection is updated.?
55776 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55777 var cs = this.selModel.getSelectedCell();
55778 if (row == cs[0] && cell == cs[1]){
55782 if (typeof(this.selModel.getSelections) != 'undefined') {
55783 var cs = this.selModel.getSelections();
55784 var ds = this.dataSource;
55785 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55796 this.fireEvent("row" + name, this, row, e);
55797 if(cell !== false){
55798 this.fireEvent("cell" + name, this, row, cell, e);
55805 onClick : function(e){
55806 this.processEvent("click", e);
55809 onTouchStart : function(e){
55810 this.processEvent("touchstart", e);
55814 onContextMenu : function(e, t){
55815 this.processEvent("contextmenu", e);
55819 onDblClick : function(e){
55820 this.processEvent("dblclick", e);
55824 walkCells : function(row, col, step, fn, scope){
55825 var cm = this.colModel, clen = cm.getColumnCount();
55826 var ds = this.dataSource, rlen = ds.getCount(), first = true;
55838 if(fn.call(scope || this, row, col, cm) === true){
55856 if(fn.call(scope || this, row, col, cm) === true){
55868 getSelections : function(){
55869 return this.selModel.getSelections();
55873 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
55874 * but if manual update is required this method will initiate it.
55876 autoSize : function(){
55878 this.view.layout();
55879 if(this.view.adjustForScroll){
55880 this.view.adjustForScroll();
55886 * Returns the grid's underlying element.
55887 * @return {Element} The element
55889 getGridEl : function(){
55890 return this.container;
55893 // private for compatibility, overridden by editor grid
55894 stopEditing : function(){},
55897 * Returns the grid's SelectionModel.
55898 * @return {SelectionModel}
55900 getSelectionModel : function(){
55901 if(!this.selModel){
55902 this.selModel = new Roo.grid.RowSelectionModel();
55904 return this.selModel;
55908 * Returns the grid's DataSource.
55909 * @return {DataSource}
55911 getDataSource : function(){
55912 return this.dataSource;
55916 * Returns the grid's ColumnModel.
55917 * @return {ColumnModel}
55919 getColumnModel : function(){
55920 return this.colModel;
55924 * Returns the grid's GridView object.
55925 * @return {GridView}
55927 getView : function(){
55929 this.view = new Roo.grid.GridView(this.viewConfig);
55930 this.relayEvents(this.view, [
55931 "beforerowremoved", "beforerowsinserted",
55932 "beforerefresh", "rowremoved",
55933 "rowsinserted", "rowupdated" ,"refresh"
55939 * Called to get grid's drag proxy text, by default returns this.ddText.
55940 * Override this to put something different in the dragged text.
55943 getDragDropText : function(){
55944 var count = this.selModel.getCount();
55945 return String.format(this.ddText, count, count == 1 ? '' : 's');
55950 * Ext JS Library 1.1.1
55951 * Copyright(c) 2006-2007, Ext JS, LLC.
55953 * Originally Released Under LGPL - original licence link has changed is not relivant.
55956 * <script type="text/javascript">
55959 Roo.grid.AbstractGridView = function(){
55963 "beforerowremoved" : true,
55964 "beforerowsinserted" : true,
55965 "beforerefresh" : true,
55966 "rowremoved" : true,
55967 "rowsinserted" : true,
55968 "rowupdated" : true,
55971 Roo.grid.AbstractGridView.superclass.constructor.call(this);
55974 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
55975 rowClass : "x-grid-row",
55976 cellClass : "x-grid-cell",
55977 tdClass : "x-grid-td",
55978 hdClass : "x-grid-hd",
55979 splitClass : "x-grid-hd-split",
55981 init: function(grid){
55983 var cid = this.grid.getGridEl().id;
55984 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
55985 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
55986 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
55987 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
55990 getColumnRenderers : function(){
55991 var renderers = [];
55992 var cm = this.grid.colModel;
55993 var colCount = cm.getColumnCount();
55994 for(var i = 0; i < colCount; i++){
55995 renderers[i] = cm.getRenderer(i);
56000 getColumnIds : function(){
56002 var cm = this.grid.colModel;
56003 var colCount = cm.getColumnCount();
56004 for(var i = 0; i < colCount; i++){
56005 ids[i] = cm.getColumnId(i);
56010 getDataIndexes : function(){
56011 if(!this.indexMap){
56012 this.indexMap = this.buildIndexMap();
56014 return this.indexMap.colToData;
56017 getColumnIndexByDataIndex : function(dataIndex){
56018 if(!this.indexMap){
56019 this.indexMap = this.buildIndexMap();
56021 return this.indexMap.dataToCol[dataIndex];
56025 * Set a css style for a column dynamically.
56026 * @param {Number} colIndex The index of the column
56027 * @param {String} name The css property name
56028 * @param {String} value The css value
56030 setCSSStyle : function(colIndex, name, value){
56031 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
56032 Roo.util.CSS.updateRule(selector, name, value);
56035 generateRules : function(cm){
56036 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
56037 Roo.util.CSS.removeStyleSheet(rulesId);
56038 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56039 var cid = cm.getColumnId(i);
56040 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
56041 this.tdSelector, cid, " {\n}\n",
56042 this.hdSelector, cid, " {\n}\n",
56043 this.splitSelector, cid, " {\n}\n");
56045 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56049 * Ext JS Library 1.1.1
56050 * Copyright(c) 2006-2007, Ext JS, LLC.
56052 * Originally Released Under LGPL - original licence link has changed is not relivant.
56055 * <script type="text/javascript">
56059 // This is a support class used internally by the Grid components
56060 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
56062 this.view = grid.getView();
56063 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56064 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
56066 this.setHandleElId(Roo.id(hd));
56067 this.setOuterHandleElId(Roo.id(hd2));
56069 this.scroll = false;
56071 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
56073 getDragData : function(e){
56074 var t = Roo.lib.Event.getTarget(e);
56075 var h = this.view.findHeaderCell(t);
56077 return {ddel: h.firstChild, header:h};
56082 onInitDrag : function(e){
56083 this.view.headersDisabled = true;
56084 var clone = this.dragData.ddel.cloneNode(true);
56085 clone.id = Roo.id();
56086 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
56087 this.proxy.update(clone);
56091 afterValidDrop : function(){
56093 setTimeout(function(){
56094 v.headersDisabled = false;
56098 afterInvalidDrop : function(){
56100 setTimeout(function(){
56101 v.headersDisabled = false;
56107 * Ext JS Library 1.1.1
56108 * Copyright(c) 2006-2007, Ext JS, LLC.
56110 * Originally Released Under LGPL - original licence link has changed is not relivant.
56113 * <script type="text/javascript">
56116 // This is a support class used internally by the Grid components
56117 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56119 this.view = grid.getView();
56120 // split the proxies so they don't interfere with mouse events
56121 this.proxyTop = Roo.DomHelper.append(document.body, {
56122 cls:"col-move-top", html:" "
56124 this.proxyBottom = Roo.DomHelper.append(document.body, {
56125 cls:"col-move-bottom", html:" "
56127 this.proxyTop.hide = this.proxyBottom.hide = function(){
56128 this.setLeftTop(-100,-100);
56129 this.setStyle("visibility", "hidden");
56131 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56132 // temporarily disabled
56133 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56134 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56136 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56137 proxyOffsets : [-4, -9],
56138 fly: Roo.Element.fly,
56140 getTargetFromEvent : function(e){
56141 var t = Roo.lib.Event.getTarget(e);
56142 var cindex = this.view.findCellIndex(t);
56143 if(cindex !== false){
56144 return this.view.getHeaderCell(cindex);
56149 nextVisible : function(h){
56150 var v = this.view, cm = this.grid.colModel;
56153 if(!cm.isHidden(v.getCellIndex(h))){
56161 prevVisible : function(h){
56162 var v = this.view, cm = this.grid.colModel;
56165 if(!cm.isHidden(v.getCellIndex(h))){
56173 positionIndicator : function(h, n, e){
56174 var x = Roo.lib.Event.getPageX(e);
56175 var r = Roo.lib.Dom.getRegion(n.firstChild);
56176 var px, pt, py = r.top + this.proxyOffsets[1];
56177 if((r.right - x) <= (r.right-r.left)/2){
56178 px = r.right+this.view.borderWidth;
56184 var oldIndex = this.view.getCellIndex(h);
56185 var newIndex = this.view.getCellIndex(n);
56187 if(this.grid.colModel.isFixed(newIndex)){
56191 var locked = this.grid.colModel.isLocked(newIndex);
56196 if(oldIndex < newIndex){
56199 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56202 px += this.proxyOffsets[0];
56203 this.proxyTop.setLeftTop(px, py);
56204 this.proxyTop.show();
56205 if(!this.bottomOffset){
56206 this.bottomOffset = this.view.mainHd.getHeight();
56208 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56209 this.proxyBottom.show();
56213 onNodeEnter : function(n, dd, e, data){
56214 if(data.header != n){
56215 this.positionIndicator(data.header, n, e);
56219 onNodeOver : function(n, dd, e, data){
56220 var result = false;
56221 if(data.header != n){
56222 result = this.positionIndicator(data.header, n, e);
56225 this.proxyTop.hide();
56226 this.proxyBottom.hide();
56228 return result ? this.dropAllowed : this.dropNotAllowed;
56231 onNodeOut : function(n, dd, e, data){
56232 this.proxyTop.hide();
56233 this.proxyBottom.hide();
56236 onNodeDrop : function(n, dd, e, data){
56237 var h = data.header;
56239 var cm = this.grid.colModel;
56240 var x = Roo.lib.Event.getPageX(e);
56241 var r = Roo.lib.Dom.getRegion(n.firstChild);
56242 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56243 var oldIndex = this.view.getCellIndex(h);
56244 var newIndex = this.view.getCellIndex(n);
56245 var locked = cm.isLocked(newIndex);
56249 if(oldIndex < newIndex){
56252 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56255 cm.setLocked(oldIndex, locked, true);
56256 cm.moveColumn(oldIndex, newIndex);
56257 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56265 * Ext JS Library 1.1.1
56266 * Copyright(c) 2006-2007, Ext JS, LLC.
56268 * Originally Released Under LGPL - original licence link has changed is not relivant.
56271 * <script type="text/javascript">
56275 * @class Roo.grid.GridView
56276 * @extends Roo.util.Observable
56279 * @param {Object} config
56281 Roo.grid.GridView = function(config){
56282 Roo.grid.GridView.superclass.constructor.call(this);
56285 Roo.apply(this, config);
56288 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56290 unselectable : 'unselectable="on"',
56291 unselectableCls : 'x-unselectable',
56294 rowClass : "x-grid-row",
56296 cellClass : "x-grid-col",
56298 tdClass : "x-grid-td",
56300 hdClass : "x-grid-hd",
56302 splitClass : "x-grid-split",
56304 sortClasses : ["sort-asc", "sort-desc"],
56306 enableMoveAnim : false,
56310 dh : Roo.DomHelper,
56312 fly : Roo.Element.fly,
56314 css : Roo.util.CSS,
56320 scrollIncrement : 22,
56322 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56324 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56326 bind : function(ds, cm){
56328 this.ds.un("load", this.onLoad, this);
56329 this.ds.un("datachanged", this.onDataChange, this);
56330 this.ds.un("add", this.onAdd, this);
56331 this.ds.un("remove", this.onRemove, this);
56332 this.ds.un("update", this.onUpdate, this);
56333 this.ds.un("clear", this.onClear, this);
56336 ds.on("load", this.onLoad, this);
56337 ds.on("datachanged", this.onDataChange, this);
56338 ds.on("add", this.onAdd, this);
56339 ds.on("remove", this.onRemove, this);
56340 ds.on("update", this.onUpdate, this);
56341 ds.on("clear", this.onClear, this);
56346 this.cm.un("widthchange", this.onColWidthChange, this);
56347 this.cm.un("headerchange", this.onHeaderChange, this);
56348 this.cm.un("hiddenchange", this.onHiddenChange, this);
56349 this.cm.un("columnmoved", this.onColumnMove, this);
56350 this.cm.un("columnlockchange", this.onColumnLock, this);
56353 this.generateRules(cm);
56354 cm.on("widthchange", this.onColWidthChange, this);
56355 cm.on("headerchange", this.onHeaderChange, this);
56356 cm.on("hiddenchange", this.onHiddenChange, this);
56357 cm.on("columnmoved", this.onColumnMove, this);
56358 cm.on("columnlockchange", this.onColumnLock, this);
56363 init: function(grid){
56364 Roo.grid.GridView.superclass.init.call(this, grid);
56366 this.bind(grid.dataSource, grid.colModel);
56368 grid.on("headerclick", this.handleHeaderClick, this);
56370 if(grid.trackMouseOver){
56371 grid.on("mouseover", this.onRowOver, this);
56372 grid.on("mouseout", this.onRowOut, this);
56374 grid.cancelTextSelection = function(){};
56375 this.gridId = grid.id;
56377 var tpls = this.templates || {};
56380 tpls.master = new Roo.Template(
56381 '<div class="x-grid" hidefocus="true">',
56382 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56383 '<div class="x-grid-topbar"></div>',
56384 '<div class="x-grid-scroller"><div></div></div>',
56385 '<div class="x-grid-locked">',
56386 '<div class="x-grid-header">{lockedHeader}</div>',
56387 '<div class="x-grid-body">{lockedBody}</div>',
56389 '<div class="x-grid-viewport">',
56390 '<div class="x-grid-header">{header}</div>',
56391 '<div class="x-grid-body">{body}</div>',
56393 '<div class="x-grid-bottombar"></div>',
56395 '<div class="x-grid-resize-proxy"> </div>',
56398 tpls.master.disableformats = true;
56402 tpls.header = new Roo.Template(
56403 '<table border="0" cellspacing="0" cellpadding="0">',
56404 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56407 tpls.header.disableformats = true;
56409 tpls.header.compile();
56412 tpls.hcell = new Roo.Template(
56413 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56414 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56417 tpls.hcell.disableFormats = true;
56419 tpls.hcell.compile();
56422 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56423 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56424 tpls.hsplit.disableFormats = true;
56426 tpls.hsplit.compile();
56429 tpls.body = new Roo.Template(
56430 '<table border="0" cellspacing="0" cellpadding="0">',
56431 "<tbody>{rows}</tbody>",
56434 tpls.body.disableFormats = true;
56436 tpls.body.compile();
56439 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56440 tpls.row.disableFormats = true;
56442 tpls.row.compile();
56445 tpls.cell = new Roo.Template(
56446 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56447 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56448 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56451 tpls.cell.disableFormats = true;
56453 tpls.cell.compile();
56455 this.templates = tpls;
56458 // remap these for backwards compat
56459 onColWidthChange : function(){
56460 this.updateColumns.apply(this, arguments);
56462 onHeaderChange : function(){
56463 this.updateHeaders.apply(this, arguments);
56465 onHiddenChange : function(){
56466 this.handleHiddenChange.apply(this, arguments);
56468 onColumnMove : function(){
56469 this.handleColumnMove.apply(this, arguments);
56471 onColumnLock : function(){
56472 this.handleLockChange.apply(this, arguments);
56475 onDataChange : function(){
56477 this.updateHeaderSortState();
56480 onClear : function(){
56484 onUpdate : function(ds, record){
56485 this.refreshRow(record);
56488 refreshRow : function(record){
56489 var ds = this.ds, index;
56490 if(typeof record == 'number'){
56492 record = ds.getAt(index);
56494 index = ds.indexOf(record);
56496 this.insertRows(ds, index, index, true);
56497 this.onRemove(ds, record, index+1, true);
56498 this.syncRowHeights(index, index);
56500 this.fireEvent("rowupdated", this, index, record);
56503 onAdd : function(ds, records, index){
56504 this.insertRows(ds, index, index + (records.length-1));
56507 onRemove : function(ds, record, index, isUpdate){
56508 if(isUpdate !== true){
56509 this.fireEvent("beforerowremoved", this, index, record);
56511 var bt = this.getBodyTable(), lt = this.getLockedTable();
56512 if(bt.rows[index]){
56513 bt.firstChild.removeChild(bt.rows[index]);
56515 if(lt.rows[index]){
56516 lt.firstChild.removeChild(lt.rows[index]);
56518 if(isUpdate !== true){
56519 this.stripeRows(index);
56520 this.syncRowHeights(index, index);
56522 this.fireEvent("rowremoved", this, index, record);
56526 onLoad : function(){
56527 this.scrollToTop();
56531 * Scrolls the grid to the top
56533 scrollToTop : function(){
56535 this.scroller.dom.scrollTop = 0;
56541 * Gets a panel in the header of the grid that can be used for toolbars etc.
56542 * After modifying the contents of this panel a call to grid.autoSize() may be
56543 * required to register any changes in size.
56544 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56545 * @return Roo.Element
56547 getHeaderPanel : function(doShow){
56549 this.headerPanel.show();
56551 return this.headerPanel;
56555 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56556 * After modifying the contents of this panel a call to grid.autoSize() may be
56557 * required to register any changes in size.
56558 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56559 * @return Roo.Element
56561 getFooterPanel : function(doShow){
56563 this.footerPanel.show();
56565 return this.footerPanel;
56568 initElements : function(){
56569 var E = Roo.Element;
56570 var el = this.grid.getGridEl().dom.firstChild;
56571 var cs = el.childNodes;
56573 this.el = new E(el);
56575 this.focusEl = new E(el.firstChild);
56576 this.focusEl.swallowEvent("click", true);
56578 this.headerPanel = new E(cs[1]);
56579 this.headerPanel.enableDisplayMode("block");
56581 this.scroller = new E(cs[2]);
56582 this.scrollSizer = new E(this.scroller.dom.firstChild);
56584 this.lockedWrap = new E(cs[3]);
56585 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56586 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56588 this.mainWrap = new E(cs[4]);
56589 this.mainHd = new E(this.mainWrap.dom.firstChild);
56590 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56592 this.footerPanel = new E(cs[5]);
56593 this.footerPanel.enableDisplayMode("block");
56595 this.resizeProxy = new E(cs[6]);
56597 this.headerSelector = String.format(
56598 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56599 this.lockedHd.id, this.mainHd.id
56602 this.splitterSelector = String.format(
56603 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56604 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56607 idToCssName : function(s)
56609 return s.replace(/[^a-z0-9]+/ig, '-');
56612 getHeaderCell : function(index){
56613 return Roo.DomQuery.select(this.headerSelector)[index];
56616 getHeaderCellMeasure : function(index){
56617 return this.getHeaderCell(index).firstChild;
56620 getHeaderCellText : function(index){
56621 return this.getHeaderCell(index).firstChild.firstChild;
56624 getLockedTable : function(){
56625 return this.lockedBody.dom.firstChild;
56628 getBodyTable : function(){
56629 return this.mainBody.dom.firstChild;
56632 getLockedRow : function(index){
56633 return this.getLockedTable().rows[index];
56636 getRow : function(index){
56637 return this.getBodyTable().rows[index];
56640 getRowComposite : function(index){
56642 this.rowEl = new Roo.CompositeElementLite();
56644 var els = [], lrow, mrow;
56645 if(lrow = this.getLockedRow(index)){
56648 if(mrow = this.getRow(index)){
56651 this.rowEl.elements = els;
56655 * Gets the 'td' of the cell
56657 * @param {Integer} rowIndex row to select
56658 * @param {Integer} colIndex column to select
56662 getCell : function(rowIndex, colIndex){
56663 var locked = this.cm.getLockedCount();
56665 if(colIndex < locked){
56666 source = this.lockedBody.dom.firstChild;
56668 source = this.mainBody.dom.firstChild;
56669 colIndex -= locked;
56671 return source.rows[rowIndex].childNodes[colIndex];
56674 getCellText : function(rowIndex, colIndex){
56675 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56678 getCellBox : function(cell){
56679 var b = this.fly(cell).getBox();
56680 if(Roo.isOpera){ // opera fails to report the Y
56681 b.y = cell.offsetTop + this.mainBody.getY();
56686 getCellIndex : function(cell){
56687 var id = String(cell.className).match(this.cellRE);
56689 return parseInt(id[1], 10);
56694 findHeaderIndex : function(n){
56695 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56696 return r ? this.getCellIndex(r) : false;
56699 findHeaderCell : function(n){
56700 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56701 return r ? r : false;
56704 findRowIndex : function(n){
56708 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56709 return r ? r.rowIndex : false;
56712 findCellIndex : function(node){
56713 var stop = this.el.dom;
56714 while(node && node != stop){
56715 if(this.findRE.test(node.className)){
56716 return this.getCellIndex(node);
56718 node = node.parentNode;
56723 getColumnId : function(index){
56724 return this.cm.getColumnId(index);
56727 getSplitters : function()
56729 if(this.splitterSelector){
56730 return Roo.DomQuery.select(this.splitterSelector);
56736 getSplitter : function(index){
56737 return this.getSplitters()[index];
56740 onRowOver : function(e, t){
56742 if((row = this.findRowIndex(t)) !== false){
56743 this.getRowComposite(row).addClass("x-grid-row-over");
56747 onRowOut : function(e, t){
56749 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56750 this.getRowComposite(row).removeClass("x-grid-row-over");
56754 renderHeaders : function(){
56756 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56757 var cb = [], lb = [], sb = [], lsb = [], p = {};
56758 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56759 p.cellId = "x-grid-hd-0-" + i;
56760 p.splitId = "x-grid-csplit-0-" + i;
56761 p.id = cm.getColumnId(i);
56762 p.value = cm.getColumnHeader(i) || "";
56763 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56764 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56765 if(!cm.isLocked(i)){
56766 cb[cb.length] = ct.apply(p);
56767 sb[sb.length] = st.apply(p);
56769 lb[lb.length] = ct.apply(p);
56770 lsb[lsb.length] = st.apply(p);
56773 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56774 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56777 updateHeaders : function(){
56778 var html = this.renderHeaders();
56779 this.lockedHd.update(html[0]);
56780 this.mainHd.update(html[1]);
56784 * Focuses the specified row.
56785 * @param {Number} row The row index
56787 focusRow : function(row)
56789 //Roo.log('GridView.focusRow');
56790 var x = this.scroller.dom.scrollLeft;
56791 this.focusCell(row, 0, false);
56792 this.scroller.dom.scrollLeft = x;
56796 * Focuses the specified cell.
56797 * @param {Number} row The row index
56798 * @param {Number} col The column index
56799 * @param {Boolean} hscroll false to disable horizontal scrolling
56801 focusCell : function(row, col, hscroll)
56803 //Roo.log('GridView.focusCell');
56804 var el = this.ensureVisible(row, col, hscroll);
56805 this.focusEl.alignTo(el, "tl-tl");
56807 this.focusEl.focus();
56809 this.focusEl.focus.defer(1, this.focusEl);
56814 * Scrolls the specified cell into view
56815 * @param {Number} row The row index
56816 * @param {Number} col The column index
56817 * @param {Boolean} hscroll false to disable horizontal scrolling
56819 ensureVisible : function(row, col, hscroll)
56821 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56822 //return null; //disable for testing.
56823 if(typeof row != "number"){
56824 row = row.rowIndex;
56826 if(row < 0 && row >= this.ds.getCount()){
56829 col = (col !== undefined ? col : 0);
56830 var cm = this.grid.colModel;
56831 while(cm.isHidden(col)){
56835 var el = this.getCell(row, col);
56839 var c = this.scroller.dom;
56841 var ctop = parseInt(el.offsetTop, 10);
56842 var cleft = parseInt(el.offsetLeft, 10);
56843 var cbot = ctop + el.offsetHeight;
56844 var cright = cleft + el.offsetWidth;
56846 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
56847 var stop = parseInt(c.scrollTop, 10);
56848 var sleft = parseInt(c.scrollLeft, 10);
56849 var sbot = stop + ch;
56850 var sright = sleft + c.clientWidth;
56852 Roo.log('GridView.ensureVisible:' +
56854 ' c.clientHeight:' + c.clientHeight +
56855 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
56863 c.scrollTop = ctop;
56864 //Roo.log("set scrolltop to ctop DISABLE?");
56865 }else if(cbot > sbot){
56866 //Roo.log("set scrolltop to cbot-ch");
56867 c.scrollTop = cbot-ch;
56870 if(hscroll !== false){
56872 c.scrollLeft = cleft;
56873 }else if(cright > sright){
56874 c.scrollLeft = cright-c.clientWidth;
56881 updateColumns : function(){
56882 this.grid.stopEditing();
56883 var cm = this.grid.colModel, colIds = this.getColumnIds();
56884 //var totalWidth = cm.getTotalWidth();
56886 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56887 //if(cm.isHidden(i)) continue;
56888 var w = cm.getColumnWidth(i);
56889 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56890 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56892 this.updateSplitters();
56895 generateRules : function(cm){
56896 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
56897 Roo.util.CSS.removeStyleSheet(rulesId);
56898 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56899 var cid = cm.getColumnId(i);
56901 if(cm.config[i].align){
56902 align = 'text-align:'+cm.config[i].align+';';
56905 if(cm.isHidden(i)){
56906 hidden = 'display:none;';
56908 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
56910 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
56911 this.hdSelector, cid, " {\n", align, width, "}\n",
56912 this.tdSelector, cid, " {\n",hidden,"\n}\n",
56913 this.splitSelector, cid, " {\n", hidden , "\n}\n");
56915 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56918 updateSplitters : function(){
56919 var cm = this.cm, s = this.getSplitters();
56920 if(s){ // splitters not created yet
56921 var pos = 0, locked = true;
56922 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56923 if(cm.isHidden(i)) {
56926 var w = cm.getColumnWidth(i); // make sure it's a number
56927 if(!cm.isLocked(i) && locked){
56932 s[i].style.left = (pos-this.splitOffset) + "px";
56937 handleHiddenChange : function(colModel, colIndex, hidden){
56939 this.hideColumn(colIndex);
56941 this.unhideColumn(colIndex);
56945 hideColumn : function(colIndex){
56946 var cid = this.getColumnId(colIndex);
56947 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
56948 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
56950 this.updateHeaders();
56952 this.updateSplitters();
56956 unhideColumn : function(colIndex){
56957 var cid = this.getColumnId(colIndex);
56958 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
56959 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
56962 this.updateHeaders();
56964 this.updateSplitters();
56968 insertRows : function(dm, firstRow, lastRow, isUpdate){
56969 if(firstRow == 0 && lastRow == dm.getCount()-1){
56973 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
56975 var s = this.getScrollState();
56976 var markup = this.renderRows(firstRow, lastRow);
56977 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
56978 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
56979 this.restoreScroll(s);
56981 this.fireEvent("rowsinserted", this, firstRow, lastRow);
56982 this.syncRowHeights(firstRow, lastRow);
56983 this.stripeRows(firstRow);
56989 bufferRows : function(markup, target, index){
56990 var before = null, trows = target.rows, tbody = target.tBodies[0];
56991 if(index < trows.length){
56992 before = trows[index];
56994 var b = document.createElement("div");
56995 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
56996 var rows = b.firstChild.rows;
56997 for(var i = 0, len = rows.length; i < len; i++){
56999 tbody.insertBefore(rows[0], before);
57001 tbody.appendChild(rows[0]);
57008 deleteRows : function(dm, firstRow, lastRow){
57009 if(dm.getRowCount()<1){
57010 this.fireEvent("beforerefresh", this);
57011 this.mainBody.update("");
57012 this.lockedBody.update("");
57013 this.fireEvent("refresh", this);
57015 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
57016 var bt = this.getBodyTable();
57017 var tbody = bt.firstChild;
57018 var rows = bt.rows;
57019 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
57020 tbody.removeChild(rows[firstRow]);
57022 this.stripeRows(firstRow);
57023 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
57027 updateRows : function(dataSource, firstRow, lastRow){
57028 var s = this.getScrollState();
57030 this.restoreScroll(s);
57033 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
57037 this.updateHeaderSortState();
57040 getScrollState : function(){
57042 var sb = this.scroller.dom;
57043 return {left: sb.scrollLeft, top: sb.scrollTop};
57046 stripeRows : function(startRow){
57047 if(!this.grid.stripeRows || this.ds.getCount() < 1){
57050 startRow = startRow || 0;
57051 var rows = this.getBodyTable().rows;
57052 var lrows = this.getLockedTable().rows;
57053 var cls = ' x-grid-row-alt ';
57054 for(var i = startRow, len = rows.length; i < len; i++){
57055 var row = rows[i], lrow = lrows[i];
57056 var isAlt = ((i+1) % 2 == 0);
57057 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
57058 if(isAlt == hasAlt){
57062 row.className += " x-grid-row-alt";
57064 row.className = row.className.replace("x-grid-row-alt", "");
57067 lrow.className = row.className;
57072 restoreScroll : function(state){
57073 //Roo.log('GridView.restoreScroll');
57074 var sb = this.scroller.dom;
57075 sb.scrollLeft = state.left;
57076 sb.scrollTop = state.top;
57080 syncScroll : function(){
57081 //Roo.log('GridView.syncScroll');
57082 var sb = this.scroller.dom;
57083 var sh = this.mainHd.dom;
57084 var bs = this.mainBody.dom;
57085 var lv = this.lockedBody.dom;
57086 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
57087 lv.scrollTop = bs.scrollTop = sb.scrollTop;
57090 handleScroll : function(e){
57092 var sb = this.scroller.dom;
57093 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
57097 handleWheel : function(e){
57098 var d = e.getWheelDelta();
57099 this.scroller.dom.scrollTop -= d*22;
57100 // set this here to prevent jumpy scrolling on large tables
57101 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
57105 renderRows : function(startRow, endRow){
57106 // pull in all the crap needed to render rows
57107 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
57108 var colCount = cm.getColumnCount();
57110 if(ds.getCount() < 1){
57114 // build a map for all the columns
57116 for(var i = 0; i < colCount; i++){
57117 var name = cm.getDataIndex(i);
57119 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57120 renderer : cm.getRenderer(i),
57121 id : cm.getColumnId(i),
57122 locked : cm.isLocked(i),
57123 has_editor : cm.isCellEditable(i)
57127 startRow = startRow || 0;
57128 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57130 // records to render
57131 var rs = ds.getRange(startRow, endRow);
57133 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57136 // As much as I hate to duplicate code, this was branched because FireFox really hates
57137 // [].join("") on strings. The performance difference was substantial enough to
57138 // branch this function
57139 doRender : Roo.isGecko ?
57140 function(cs, rs, ds, startRow, colCount, stripe){
57141 var ts = this.templates, ct = ts.cell, rt = ts.row;
57143 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57145 var hasListener = this.grid.hasListener('rowclass');
57147 for(var j = 0, len = rs.length; j < len; j++){
57148 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57149 for(var i = 0; i < colCount; i++){
57151 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57153 p.css = p.attr = "";
57154 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57155 if(p.value == undefined || p.value === "") {
57156 p.value = " ";
57159 p.css += ' x-grid-editable-cell';
57161 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57162 p.css += ' x-grid-dirty-cell';
57164 var markup = ct.apply(p);
57172 if(stripe && ((rowIndex+1) % 2 == 0)){
57173 alt.push("x-grid-row-alt")
57176 alt.push( " x-grid-dirty-row");
57179 if(this.getRowClass){
57180 alt.push(this.getRowClass(r, rowIndex));
57186 rowIndex : rowIndex,
57189 this.grid.fireEvent('rowclass', this, rowcfg);
57190 alt.push(rowcfg.rowClass);
57192 rp.alt = alt.join(" ");
57193 lbuf+= rt.apply(rp);
57195 buf+= rt.apply(rp);
57197 return [lbuf, buf];
57199 function(cs, rs, ds, startRow, colCount, stripe){
57200 var ts = this.templates, ct = ts.cell, rt = ts.row;
57202 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57203 var hasListener = this.grid.hasListener('rowclass');
57206 for(var j = 0, len = rs.length; j < len; j++){
57207 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57208 for(var i = 0; i < colCount; i++){
57210 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57212 p.css = p.attr = "";
57213 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57214 if(p.value == undefined || p.value === "") {
57215 p.value = " ";
57219 p.css += ' x-grid-editable-cell';
57221 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57222 p.css += ' x-grid-dirty-cell'
57225 var markup = ct.apply(p);
57227 cb[cb.length] = markup;
57229 lcb[lcb.length] = markup;
57233 if(stripe && ((rowIndex+1) % 2 == 0)){
57234 alt.push( "x-grid-row-alt");
57237 alt.push(" x-grid-dirty-row");
57240 if(this.getRowClass){
57241 alt.push( this.getRowClass(r, rowIndex));
57247 rowIndex : rowIndex,
57250 this.grid.fireEvent('rowclass', this, rowcfg);
57251 alt.push(rowcfg.rowClass);
57254 rp.alt = alt.join(" ");
57255 rp.cells = lcb.join("");
57256 lbuf[lbuf.length] = rt.apply(rp);
57257 rp.cells = cb.join("");
57258 buf[buf.length] = rt.apply(rp);
57260 return [lbuf.join(""), buf.join("")];
57263 renderBody : function(){
57264 var markup = this.renderRows();
57265 var bt = this.templates.body;
57266 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57270 * Refreshes the grid
57271 * @param {Boolean} headersToo
57273 refresh : function(headersToo){
57274 this.fireEvent("beforerefresh", this);
57275 this.grid.stopEditing();
57276 var result = this.renderBody();
57277 this.lockedBody.update(result[0]);
57278 this.mainBody.update(result[1]);
57279 if(headersToo === true){
57280 this.updateHeaders();
57281 this.updateColumns();
57282 this.updateSplitters();
57283 this.updateHeaderSortState();
57285 this.syncRowHeights();
57287 this.fireEvent("refresh", this);
57290 handleColumnMove : function(cm, oldIndex, newIndex){
57291 this.indexMap = null;
57292 var s = this.getScrollState();
57293 this.refresh(true);
57294 this.restoreScroll(s);
57295 this.afterMove(newIndex);
57298 afterMove : function(colIndex){
57299 if(this.enableMoveAnim && Roo.enableFx){
57300 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57302 // if multisort - fix sortOrder, and reload..
57303 if (this.grid.dataSource.multiSort) {
57304 // the we can call sort again..
57305 var dm = this.grid.dataSource;
57306 var cm = this.grid.colModel;
57308 for(var i = 0; i < cm.config.length; i++ ) {
57310 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57311 continue; // dont' bother, it's not in sort list or being set.
57314 so.push(cm.config[i].dataIndex);
57317 dm.load(dm.lastOptions);
57324 updateCell : function(dm, rowIndex, dataIndex){
57325 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57326 if(typeof colIndex == "undefined"){ // not present in grid
57329 var cm = this.grid.colModel;
57330 var cell = this.getCell(rowIndex, colIndex);
57331 var cellText = this.getCellText(rowIndex, colIndex);
57334 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57335 id : cm.getColumnId(colIndex),
57336 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57338 var renderer = cm.getRenderer(colIndex);
57339 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57340 if(typeof val == "undefined" || val === "") {
57343 cellText.innerHTML = val;
57344 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57345 this.syncRowHeights(rowIndex, rowIndex);
57348 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57350 if(this.grid.autoSizeHeaders){
57351 var h = this.getHeaderCellMeasure(colIndex);
57352 maxWidth = Math.max(maxWidth, h.scrollWidth);
57355 if(this.cm.isLocked(colIndex)){
57356 tb = this.getLockedTable();
57359 tb = this.getBodyTable();
57360 index = colIndex - this.cm.getLockedCount();
57363 var rows = tb.rows;
57364 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57365 for(var i = 0; i < stopIndex; i++){
57366 var cell = rows[i].childNodes[index].firstChild;
57367 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57370 return maxWidth + /*margin for error in IE*/ 5;
57373 * Autofit a column to its content.
57374 * @param {Number} colIndex
57375 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57377 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57378 if(this.cm.isHidden(colIndex)){
57379 return; // can't calc a hidden column
57382 var cid = this.cm.getColumnId(colIndex);
57383 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57384 if(this.grid.autoSizeHeaders){
57385 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57388 var newWidth = this.calcColumnWidth(colIndex);
57389 this.cm.setColumnWidth(colIndex,
57390 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57391 if(!suppressEvent){
57392 this.grid.fireEvent("columnresize", colIndex, newWidth);
57397 * Autofits all columns to their content and then expands to fit any extra space in the grid
57399 autoSizeColumns : function(){
57400 var cm = this.grid.colModel;
57401 var colCount = cm.getColumnCount();
57402 for(var i = 0; i < colCount; i++){
57403 this.autoSizeColumn(i, true, true);
57405 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57408 this.updateColumns();
57414 * Autofits all columns to the grid's width proportionate with their current size
57415 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57417 fitColumns : function(reserveScrollSpace){
57418 var cm = this.grid.colModel;
57419 var colCount = cm.getColumnCount();
57423 for (i = 0; i < colCount; i++){
57424 if(!cm.isHidden(i) && !cm.isFixed(i)){
57425 w = cm.getColumnWidth(i);
57431 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57432 if(reserveScrollSpace){
57435 var frac = (avail - cm.getTotalWidth())/width;
57436 while (cols.length){
57439 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57441 this.updateColumns();
57445 onRowSelect : function(rowIndex){
57446 var row = this.getRowComposite(rowIndex);
57447 row.addClass("x-grid-row-selected");
57450 onRowDeselect : function(rowIndex){
57451 var row = this.getRowComposite(rowIndex);
57452 row.removeClass("x-grid-row-selected");
57455 onCellSelect : function(row, col){
57456 var cell = this.getCell(row, col);
57458 Roo.fly(cell).addClass("x-grid-cell-selected");
57462 onCellDeselect : function(row, col){
57463 var cell = this.getCell(row, col);
57465 Roo.fly(cell).removeClass("x-grid-cell-selected");
57469 updateHeaderSortState : function(){
57471 // sort state can be single { field: xxx, direction : yyy}
57472 // or { xxx=>ASC , yyy : DESC ..... }
57475 if (!this.ds.multiSort) {
57476 var state = this.ds.getSortState();
57480 mstate[state.field] = state.direction;
57481 // FIXME... - this is not used here.. but might be elsewhere..
57482 this.sortState = state;
57485 mstate = this.ds.sortToggle;
57487 //remove existing sort classes..
57489 var sc = this.sortClasses;
57490 var hds = this.el.select(this.headerSelector).removeClass(sc);
57492 for(var f in mstate) {
57494 var sortColumn = this.cm.findColumnIndex(f);
57496 if(sortColumn != -1){
57497 var sortDir = mstate[f];
57498 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57507 handleHeaderClick : function(g, index,e){
57509 Roo.log("header click");
57512 // touch events on header are handled by context
57513 this.handleHdCtx(g,index,e);
57518 if(this.headersDisabled){
57521 var dm = g.dataSource, cm = g.colModel;
57522 if(!cm.isSortable(index)){
57527 if (dm.multiSort) {
57528 // update the sortOrder
57530 for(var i = 0; i < cm.config.length; i++ ) {
57532 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57533 continue; // dont' bother, it's not in sort list or being set.
57536 so.push(cm.config[i].dataIndex);
57542 dm.sort(cm.getDataIndex(index));
57546 destroy : function(){
57548 this.colMenu.removeAll();
57549 Roo.menu.MenuMgr.unregister(this.colMenu);
57550 this.colMenu.getEl().remove();
57551 delete this.colMenu;
57554 this.hmenu.removeAll();
57555 Roo.menu.MenuMgr.unregister(this.hmenu);
57556 this.hmenu.getEl().remove();
57559 if(this.grid.enableColumnMove){
57560 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57562 for(var dd in dds){
57563 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57564 var elid = dds[dd].dragElId;
57566 Roo.get(elid).remove();
57567 } else if(dds[dd].config.isTarget){
57568 dds[dd].proxyTop.remove();
57569 dds[dd].proxyBottom.remove();
57572 if(Roo.dd.DDM.locationCache[dd]){
57573 delete Roo.dd.DDM.locationCache[dd];
57576 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57579 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57580 this.bind(null, null);
57581 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57584 handleLockChange : function(){
57585 this.refresh(true);
57588 onDenyColumnLock : function(){
57592 onDenyColumnHide : function(){
57596 handleHdMenuClick : function(item){
57597 var index = this.hdCtxIndex;
57598 var cm = this.cm, ds = this.ds;
57601 ds.sort(cm.getDataIndex(index), "ASC");
57604 ds.sort(cm.getDataIndex(index), "DESC");
57607 var lc = cm.getLockedCount();
57608 if(cm.getColumnCount(true) <= lc+1){
57609 this.onDenyColumnLock();
57613 cm.setLocked(index, true, true);
57614 cm.moveColumn(index, lc);
57615 this.grid.fireEvent("columnmove", index, lc);
57617 cm.setLocked(index, true);
57621 var lc = cm.getLockedCount();
57622 if((lc-1) != index){
57623 cm.setLocked(index, false, true);
57624 cm.moveColumn(index, lc-1);
57625 this.grid.fireEvent("columnmove", index, lc-1);
57627 cm.setLocked(index, false);
57630 case 'wider': // used to expand cols on touch..
57632 var cw = cm.getColumnWidth(index);
57633 cw += (item.id == 'wider' ? 1 : -1) * 50;
57634 cw = Math.max(0, cw);
57635 cw = Math.min(cw,4000);
57636 cm.setColumnWidth(index, cw);
57640 index = cm.getIndexById(item.id.substr(4));
57642 if(item.checked && cm.getColumnCount(true) <= 1){
57643 this.onDenyColumnHide();
57646 cm.setHidden(index, item.checked);
57652 beforeColMenuShow : function(){
57653 var cm = this.cm, colCount = cm.getColumnCount();
57654 this.colMenu.removeAll();
57655 for(var i = 0; i < colCount; i++){
57656 this.colMenu.add(new Roo.menu.CheckItem({
57657 id: "col-"+cm.getColumnId(i),
57658 text: cm.getColumnHeader(i),
57659 checked: !cm.isHidden(i),
57665 handleHdCtx : function(g, index, e){
57667 var hd = this.getHeaderCell(index);
57668 this.hdCtxIndex = index;
57669 var ms = this.hmenu.items, cm = this.cm;
57670 ms.get("asc").setDisabled(!cm.isSortable(index));
57671 ms.get("desc").setDisabled(!cm.isSortable(index));
57672 if(this.grid.enableColLock !== false){
57673 ms.get("lock").setDisabled(cm.isLocked(index));
57674 ms.get("unlock").setDisabled(!cm.isLocked(index));
57676 this.hmenu.show(hd, "tl-bl");
57679 handleHdOver : function(e){
57680 var hd = this.findHeaderCell(e.getTarget());
57681 if(hd && !this.headersDisabled){
57682 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57683 this.fly(hd).addClass("x-grid-hd-over");
57688 handleHdOut : function(e){
57689 var hd = this.findHeaderCell(e.getTarget());
57691 this.fly(hd).removeClass("x-grid-hd-over");
57695 handleSplitDblClick : function(e, t){
57696 var i = this.getCellIndex(t);
57697 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57698 this.autoSizeColumn(i, true);
57703 render : function(){
57706 var colCount = cm.getColumnCount();
57708 if(this.grid.monitorWindowResize === true){
57709 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57711 var header = this.renderHeaders();
57712 var body = this.templates.body.apply({rows:""});
57713 var html = this.templates.master.apply({
57716 lockedHeader: header[0],
57720 //this.updateColumns();
57722 this.grid.getGridEl().dom.innerHTML = html;
57724 this.initElements();
57726 // a kludge to fix the random scolling effect in webkit
57727 this.el.on("scroll", function() {
57728 this.el.dom.scrollTop=0; // hopefully not recursive..
57731 this.scroller.on("scroll", this.handleScroll, this);
57732 this.lockedBody.on("mousewheel", this.handleWheel, this);
57733 this.mainBody.on("mousewheel", this.handleWheel, this);
57735 this.mainHd.on("mouseover", this.handleHdOver, this);
57736 this.mainHd.on("mouseout", this.handleHdOut, this);
57737 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57738 {delegate: "."+this.splitClass});
57740 this.lockedHd.on("mouseover", this.handleHdOver, this);
57741 this.lockedHd.on("mouseout", this.handleHdOut, this);
57742 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57743 {delegate: "."+this.splitClass});
57745 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57746 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57749 this.updateSplitters();
57751 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57752 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57753 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57756 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57757 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57759 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57760 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57762 if(this.grid.enableColLock !== false){
57763 this.hmenu.add('-',
57764 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57765 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57769 this.hmenu.add('-',
57770 {id:"wider", text: this.columnsWiderText},
57771 {id:"narrow", text: this.columnsNarrowText }
57777 if(this.grid.enableColumnHide !== false){
57779 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57780 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57781 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57783 this.hmenu.add('-',
57784 {id:"columns", text: this.columnsText, menu: this.colMenu}
57787 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57789 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57792 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57793 this.dd = new Roo.grid.GridDragZone(this.grid, {
57794 ddGroup : this.grid.ddGroup || 'GridDD'
57800 for(var i = 0; i < colCount; i++){
57801 if(cm.isHidden(i)){
57802 this.hideColumn(i);
57804 if(cm.config[i].align){
57805 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57806 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57810 this.updateHeaderSortState();
57812 this.beforeInitialResize();
57815 // two part rendering gives faster view to the user
57816 this.renderPhase2.defer(1, this);
57819 renderPhase2 : function(){
57820 // render the rows now
57822 if(this.grid.autoSizeColumns){
57823 this.autoSizeColumns();
57827 beforeInitialResize : function(){
57831 onColumnSplitterMoved : function(i, w){
57832 this.userResized = true;
57833 var cm = this.grid.colModel;
57834 cm.setColumnWidth(i, w, true);
57835 var cid = cm.getColumnId(i);
57836 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57837 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57838 this.updateSplitters();
57840 this.grid.fireEvent("columnresize", i, w);
57843 syncRowHeights : function(startIndex, endIndex){
57844 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
57845 startIndex = startIndex || 0;
57846 var mrows = this.getBodyTable().rows;
57847 var lrows = this.getLockedTable().rows;
57848 var len = mrows.length-1;
57849 endIndex = Math.min(endIndex || len, len);
57850 for(var i = startIndex; i <= endIndex; i++){
57851 var m = mrows[i], l = lrows[i];
57852 var h = Math.max(m.offsetHeight, l.offsetHeight);
57853 m.style.height = l.style.height = h + "px";
57858 layout : function(initialRender, is2ndPass)
57861 var auto = g.autoHeight;
57862 var scrollOffset = 16;
57863 var c = g.getGridEl(), cm = this.cm,
57864 expandCol = g.autoExpandColumn,
57866 //c.beginMeasure();
57868 if(!c.dom.offsetWidth){ // display:none?
57870 this.lockedWrap.show();
57871 this.mainWrap.show();
57876 var hasLock = this.cm.isLocked(0);
57878 var tbh = this.headerPanel.getHeight();
57879 var bbh = this.footerPanel.getHeight();
57882 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
57883 var newHeight = ch + c.getBorderWidth("tb");
57885 newHeight = Math.min(g.maxHeight, newHeight);
57887 c.setHeight(newHeight);
57891 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
57894 var s = this.scroller;
57896 var csize = c.getSize(true);
57898 this.el.setSize(csize.width, csize.height);
57900 this.headerPanel.setWidth(csize.width);
57901 this.footerPanel.setWidth(csize.width);
57903 var hdHeight = this.mainHd.getHeight();
57904 var vw = csize.width;
57905 var vh = csize.height - (tbh + bbh);
57909 var bt = this.getBodyTable();
57911 if(cm.getLockedCount() == cm.config.length){
57912 bt = this.getLockedTable();
57915 var ltWidth = hasLock ?
57916 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
57918 var scrollHeight = bt.offsetHeight;
57919 var scrollWidth = ltWidth + bt.offsetWidth;
57920 var vscroll = false, hscroll = false;
57922 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
57924 var lw = this.lockedWrap, mw = this.mainWrap;
57925 var lb = this.lockedBody, mb = this.mainBody;
57927 setTimeout(function(){
57928 var t = s.dom.offsetTop;
57929 var w = s.dom.clientWidth,
57930 h = s.dom.clientHeight;
57933 lw.setSize(ltWidth, h);
57935 mw.setLeftTop(ltWidth, t);
57936 mw.setSize(w-ltWidth, h);
57938 lb.setHeight(h-hdHeight);
57939 mb.setHeight(h-hdHeight);
57941 if(is2ndPass !== true && !gv.userResized && expandCol){
57942 // high speed resize without full column calculation
57944 var ci = cm.getIndexById(expandCol);
57946 ci = cm.findColumnIndex(expandCol);
57948 ci = Math.max(0, ci); // make sure it's got at least the first col.
57949 var expandId = cm.getColumnId(ci);
57950 var tw = cm.getTotalWidth(false);
57951 var currentWidth = cm.getColumnWidth(ci);
57952 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
57953 if(currentWidth != cw){
57954 cm.setColumnWidth(ci, cw, true);
57955 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57956 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57957 gv.updateSplitters();
57958 gv.layout(false, true);
57970 onWindowResize : function(){
57971 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
57977 appendFooter : function(parentEl){
57981 sortAscText : "Sort Ascending",
57982 sortDescText : "Sort Descending",
57983 lockText : "Lock Column",
57984 unlockText : "Unlock Column",
57985 columnsText : "Columns",
57987 columnsWiderText : "Wider",
57988 columnsNarrowText : "Thinner"
57992 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
57993 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
57994 this.proxy.el.addClass('x-grid3-col-dd');
57997 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
57998 handleMouseDown : function(e){
58002 callHandleMouseDown : function(e){
58003 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
58008 * Ext JS Library 1.1.1
58009 * Copyright(c) 2006-2007, Ext JS, LLC.
58011 * Originally Released Under LGPL - original licence link has changed is not relivant.
58014 * <script type="text/javascript">
58018 // This is a support class used internally by the Grid components
58019 Roo.grid.SplitDragZone = function(grid, hd, hd2){
58021 this.view = grid.getView();
58022 this.proxy = this.view.resizeProxy;
58023 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
58024 "gridSplitters" + this.grid.getGridEl().id, {
58025 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
58027 this.setHandleElId(Roo.id(hd));
58028 this.setOuterHandleElId(Roo.id(hd2));
58029 this.scroll = false;
58031 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
58032 fly: Roo.Element.fly,
58034 b4StartDrag : function(x, y){
58035 this.view.headersDisabled = true;
58036 this.proxy.setHeight(this.view.mainWrap.getHeight());
58037 var w = this.cm.getColumnWidth(this.cellIndex);
58038 var minw = Math.max(w-this.grid.minColumnWidth, 0);
58039 this.resetConstraints();
58040 this.setXConstraint(minw, 1000);
58041 this.setYConstraint(0, 0);
58042 this.minX = x - minw;
58043 this.maxX = x + 1000;
58045 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
58049 handleMouseDown : function(e){
58050 ev = Roo.EventObject.setEvent(e);
58051 var t = this.fly(ev.getTarget());
58052 if(t.hasClass("x-grid-split")){
58053 this.cellIndex = this.view.getCellIndex(t.dom);
58054 this.split = t.dom;
58055 this.cm = this.grid.colModel;
58056 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
58057 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
58062 endDrag : function(e){
58063 this.view.headersDisabled = false;
58064 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
58065 var diff = endX - this.startPos;
58066 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
58069 autoOffset : function(){
58070 this.setDelta(0,0);
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">
58084 // This is a support class used internally by the Grid components
58085 Roo.grid.GridDragZone = function(grid, config){
58086 this.view = grid.getView();
58087 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
58088 if(this.view.lockedBody){
58089 this.setHandleElId(Roo.id(this.view.mainBody.dom));
58090 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
58092 this.scroll = false;
58094 this.ddel = document.createElement('div');
58095 this.ddel.className = 'x-grid-dd-wrap';
58098 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
58099 ddGroup : "GridDD",
58101 getDragData : function(e){
58102 var t = Roo.lib.Event.getTarget(e);
58103 var rowIndex = this.view.findRowIndex(t);
58104 var sm = this.grid.selModel;
58106 //Roo.log(rowIndex);
58108 if (sm.getSelectedCell) {
58109 // cell selection..
58110 if (!sm.getSelectedCell()) {
58113 if (rowIndex != sm.getSelectedCell()[0]) {
58118 if (sm.getSelections && sm.getSelections().length < 1) {
58123 // before it used to all dragging of unseleted... - now we dont do that.
58124 if(rowIndex !== false){
58129 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58131 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58134 if (e.hasModifier()){
58135 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58138 Roo.log("getDragData");
58143 rowIndex: rowIndex,
58144 selections: sm.getSelections ? sm.getSelections() : (
58145 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
58152 onInitDrag : function(e){
58153 var data = this.dragData;
58154 this.ddel.innerHTML = this.grid.getDragDropText();
58155 this.proxy.update(this.ddel);
58156 // fire start drag?
58159 afterRepair : function(){
58160 this.dragging = false;
58163 getRepairXY : function(e, data){
58167 onEndDrag : function(data, e){
58171 onValidDrop : function(dd, e, id){
58176 beforeInvalidDrop : function(e, id){
58181 * Ext JS Library 1.1.1
58182 * Copyright(c) 2006-2007, Ext JS, LLC.
58184 * Originally Released Under LGPL - original licence link has changed is not relivant.
58187 * <script type="text/javascript">
58192 * @class Roo.grid.ColumnModel
58193 * @extends Roo.util.Observable
58194 * This is the default implementation of a ColumnModel used by the Grid. It defines
58195 * the columns in the grid.
58198 var colModel = new Roo.grid.ColumnModel([
58199 {header: "Ticker", width: 60, sortable: true, locked: true},
58200 {header: "Company Name", width: 150, sortable: true},
58201 {header: "Market Cap.", width: 100, sortable: true},
58202 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58203 {header: "Employees", width: 100, sortable: true, resizable: false}
58208 * The config options listed for this class are options which may appear in each
58209 * individual column definition.
58210 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58212 * @param {Object} config An Array of column config objects. See this class's
58213 * config objects for details.
58215 Roo.grid.ColumnModel = function(config){
58217 * The config passed into the constructor
58219 this.config = config;
58222 // if no id, create one
58223 // if the column does not have a dataIndex mapping,
58224 // map it to the order it is in the config
58225 for(var i = 0, len = config.length; i < len; i++){
58227 if(typeof c.dataIndex == "undefined"){
58230 if(typeof c.renderer == "string"){
58231 c.renderer = Roo.util.Format[c.renderer];
58233 if(typeof c.id == "undefined"){
58236 if(c.editor && c.editor.xtype){
58237 c.editor = Roo.factory(c.editor, Roo.grid);
58239 if(c.editor && c.editor.isFormField){
58240 c.editor = new Roo.grid.GridEditor(c.editor);
58242 this.lookup[c.id] = c;
58246 * The width of columns which have no width specified (defaults to 100)
58249 this.defaultWidth = 100;
58252 * Default sortable of columns which have no sortable specified (defaults to false)
58255 this.defaultSortable = false;
58259 * @event widthchange
58260 * Fires when the width of a column changes.
58261 * @param {ColumnModel} this
58262 * @param {Number} columnIndex The column index
58263 * @param {Number} newWidth The new width
58265 "widthchange": true,
58267 * @event headerchange
58268 * Fires when the text of a header changes.
58269 * @param {ColumnModel} this
58270 * @param {Number} columnIndex The column index
58271 * @param {Number} newText The new header text
58273 "headerchange": true,
58275 * @event hiddenchange
58276 * Fires when a column is hidden or "unhidden".
58277 * @param {ColumnModel} this
58278 * @param {Number} columnIndex The column index
58279 * @param {Boolean} hidden true if hidden, false otherwise
58281 "hiddenchange": true,
58283 * @event columnmoved
58284 * Fires when a column is moved.
58285 * @param {ColumnModel} this
58286 * @param {Number} oldIndex
58287 * @param {Number} newIndex
58289 "columnmoved" : true,
58291 * @event columlockchange
58292 * Fires when a column's locked state is changed
58293 * @param {ColumnModel} this
58294 * @param {Number} colIndex
58295 * @param {Boolean} locked true if locked
58297 "columnlockchange" : true
58299 Roo.grid.ColumnModel.superclass.constructor.call(this);
58301 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58303 * @cfg {String} header The header text to display in the Grid view.
58306 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58307 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58308 * specified, the column's index is used as an index into the Record's data Array.
58311 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58312 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58315 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58316 * Defaults to the value of the {@link #defaultSortable} property.
58317 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58320 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58323 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58326 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58329 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58332 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58333 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58334 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58335 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58338 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58341 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58344 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58347 * @cfg {String} cursor (Optional)
58350 * @cfg {String} tooltip (Optional)
58353 * @cfg {Number} xs (Optional)
58356 * @cfg {Number} sm (Optional)
58359 * @cfg {Number} md (Optional)
58362 * @cfg {Number} lg (Optional)
58365 * Returns the id of the column at the specified index.
58366 * @param {Number} index The column index
58367 * @return {String} the id
58369 getColumnId : function(index){
58370 return this.config[index].id;
58374 * Returns the column for a specified id.
58375 * @param {String} id The column id
58376 * @return {Object} the column
58378 getColumnById : function(id){
58379 return this.lookup[id];
58384 * Returns the column for a specified dataIndex.
58385 * @param {String} dataIndex The column dataIndex
58386 * @return {Object|Boolean} the column or false if not found
58388 getColumnByDataIndex: function(dataIndex){
58389 var index = this.findColumnIndex(dataIndex);
58390 return index > -1 ? this.config[index] : false;
58394 * Returns the index for a specified column id.
58395 * @param {String} id The column id
58396 * @return {Number} the index, or -1 if not found
58398 getIndexById : function(id){
58399 for(var i = 0, len = this.config.length; i < len; i++){
58400 if(this.config[i].id == id){
58408 * Returns the index for a specified column dataIndex.
58409 * @param {String} dataIndex The column dataIndex
58410 * @return {Number} the index, or -1 if not found
58413 findColumnIndex : function(dataIndex){
58414 for(var i = 0, len = this.config.length; i < len; i++){
58415 if(this.config[i].dataIndex == dataIndex){
58423 moveColumn : function(oldIndex, newIndex){
58424 var c = this.config[oldIndex];
58425 this.config.splice(oldIndex, 1);
58426 this.config.splice(newIndex, 0, c);
58427 this.dataMap = null;
58428 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58431 isLocked : function(colIndex){
58432 return this.config[colIndex].locked === true;
58435 setLocked : function(colIndex, value, suppressEvent){
58436 if(this.isLocked(colIndex) == value){
58439 this.config[colIndex].locked = value;
58440 if(!suppressEvent){
58441 this.fireEvent("columnlockchange", this, colIndex, value);
58445 getTotalLockedWidth : function(){
58446 var totalWidth = 0;
58447 for(var i = 0; i < this.config.length; i++){
58448 if(this.isLocked(i) && !this.isHidden(i)){
58449 this.totalWidth += this.getColumnWidth(i);
58455 getLockedCount : function(){
58456 for(var i = 0, len = this.config.length; i < len; i++){
58457 if(!this.isLocked(i)){
58462 return this.config.length;
58466 * Returns the number of columns.
58469 getColumnCount : function(visibleOnly){
58470 if(visibleOnly === true){
58472 for(var i = 0, len = this.config.length; i < len; i++){
58473 if(!this.isHidden(i)){
58479 return this.config.length;
58483 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58484 * @param {Function} fn
58485 * @param {Object} scope (optional)
58486 * @return {Array} result
58488 getColumnsBy : function(fn, scope){
58490 for(var i = 0, len = this.config.length; i < len; i++){
58491 var c = this.config[i];
58492 if(fn.call(scope||this, c, i) === true){
58500 * Returns true if the specified column is sortable.
58501 * @param {Number} col The column index
58502 * @return {Boolean}
58504 isSortable : function(col){
58505 if(typeof this.config[col].sortable == "undefined"){
58506 return this.defaultSortable;
58508 return this.config[col].sortable;
58512 * Returns the rendering (formatting) function defined for the column.
58513 * @param {Number} col The column index.
58514 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58516 getRenderer : function(col){
58517 if(!this.config[col].renderer){
58518 return Roo.grid.ColumnModel.defaultRenderer;
58520 return this.config[col].renderer;
58524 * Sets the rendering (formatting) function for a column.
58525 * @param {Number} col The column index
58526 * @param {Function} fn The function to use to process the cell's raw data
58527 * to return HTML markup for the grid view. The render function is called with
58528 * the following parameters:<ul>
58529 * <li>Data value.</li>
58530 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58531 * <li>css A CSS style string to apply to the table cell.</li>
58532 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58533 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58534 * <li>Row index</li>
58535 * <li>Column index</li>
58536 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58538 setRenderer : function(col, fn){
58539 this.config[col].renderer = fn;
58543 * Returns the width for the specified column.
58544 * @param {Number} col The column index
58547 getColumnWidth : function(col){
58548 return this.config[col].width * 1 || this.defaultWidth;
58552 * Sets the width for a column.
58553 * @param {Number} col The column index
58554 * @param {Number} width The new width
58556 setColumnWidth : function(col, width, suppressEvent){
58557 this.config[col].width = width;
58558 this.totalWidth = null;
58559 if(!suppressEvent){
58560 this.fireEvent("widthchange", this, col, width);
58565 * Returns the total width of all columns.
58566 * @param {Boolean} includeHidden True to include hidden column widths
58569 getTotalWidth : function(includeHidden){
58570 if(!this.totalWidth){
58571 this.totalWidth = 0;
58572 for(var i = 0, len = this.config.length; i < len; i++){
58573 if(includeHidden || !this.isHidden(i)){
58574 this.totalWidth += this.getColumnWidth(i);
58578 return this.totalWidth;
58582 * Returns the header for the specified column.
58583 * @param {Number} col The column index
58586 getColumnHeader : function(col){
58587 return this.config[col].header;
58591 * Sets the header for a column.
58592 * @param {Number} col The column index
58593 * @param {String} header The new header
58595 setColumnHeader : function(col, header){
58596 this.config[col].header = header;
58597 this.fireEvent("headerchange", this, col, header);
58601 * Returns the tooltip for the specified column.
58602 * @param {Number} col The column index
58605 getColumnTooltip : function(col){
58606 return this.config[col].tooltip;
58609 * Sets the tooltip for a column.
58610 * @param {Number} col The column index
58611 * @param {String} tooltip The new tooltip
58613 setColumnTooltip : function(col, tooltip){
58614 this.config[col].tooltip = tooltip;
58618 * Returns the dataIndex for the specified column.
58619 * @param {Number} col The column index
58622 getDataIndex : function(col){
58623 return this.config[col].dataIndex;
58627 * Sets the dataIndex for a column.
58628 * @param {Number} col The column index
58629 * @param {Number} dataIndex The new dataIndex
58631 setDataIndex : function(col, dataIndex){
58632 this.config[col].dataIndex = dataIndex;
58638 * Returns true if the cell is editable.
58639 * @param {Number} colIndex The column index
58640 * @param {Number} rowIndex The row index - this is nto actually used..?
58641 * @return {Boolean}
58643 isCellEditable : function(colIndex, rowIndex){
58644 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58648 * Returns the editor defined for the cell/column.
58649 * return false or null to disable editing.
58650 * @param {Number} colIndex The column index
58651 * @param {Number} rowIndex The row index
58654 getCellEditor : function(colIndex, rowIndex){
58655 return this.config[colIndex].editor;
58659 * Sets if a column is editable.
58660 * @param {Number} col The column index
58661 * @param {Boolean} editable True if the column is editable
58663 setEditable : function(col, editable){
58664 this.config[col].editable = editable;
58669 * Returns true if the column is hidden.
58670 * @param {Number} colIndex The column index
58671 * @return {Boolean}
58673 isHidden : function(colIndex){
58674 return this.config[colIndex].hidden;
58679 * Returns true if the column width cannot be changed
58681 isFixed : function(colIndex){
58682 return this.config[colIndex].fixed;
58686 * Returns true if the column can be resized
58687 * @return {Boolean}
58689 isResizable : function(colIndex){
58690 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58693 * Sets if a column is hidden.
58694 * @param {Number} colIndex The column index
58695 * @param {Boolean} hidden True if the column is hidden
58697 setHidden : function(colIndex, hidden){
58698 this.config[colIndex].hidden = hidden;
58699 this.totalWidth = null;
58700 this.fireEvent("hiddenchange", this, colIndex, hidden);
58704 * Sets the editor for a column.
58705 * @param {Number} col The column index
58706 * @param {Object} editor The editor object
58708 setEditor : function(col, editor){
58709 this.config[col].editor = editor;
58713 Roo.grid.ColumnModel.defaultRenderer = function(value)
58715 if(typeof value == "object") {
58718 if(typeof value == "string" && value.length < 1){
58722 return String.format("{0}", value);
58725 // Alias for backwards compatibility
58726 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
58729 * Ext JS Library 1.1.1
58730 * Copyright(c) 2006-2007, Ext JS, LLC.
58732 * Originally Released Under LGPL - original licence link has changed is not relivant.
58735 * <script type="text/javascript">
58739 * @class Roo.grid.AbstractSelectionModel
58740 * @extends Roo.util.Observable
58741 * Abstract base class for grid SelectionModels. It provides the interface that should be
58742 * implemented by descendant classes. This class should not be directly instantiated.
58745 Roo.grid.AbstractSelectionModel = function(){
58746 this.locked = false;
58747 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
58750 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
58751 /** @ignore Called by the grid automatically. Do not call directly. */
58752 init : function(grid){
58758 * Locks the selections.
58761 this.locked = true;
58765 * Unlocks the selections.
58767 unlock : function(){
58768 this.locked = false;
58772 * Returns true if the selections are locked.
58773 * @return {Boolean}
58775 isLocked : function(){
58776 return this.locked;
58780 * Ext JS Library 1.1.1
58781 * Copyright(c) 2006-2007, Ext JS, LLC.
58783 * Originally Released Under LGPL - original licence link has changed is not relivant.
58786 * <script type="text/javascript">
58789 * @extends Roo.grid.AbstractSelectionModel
58790 * @class Roo.grid.RowSelectionModel
58791 * The default SelectionModel used by {@link Roo.grid.Grid}.
58792 * It supports multiple selections and keyboard selection/navigation.
58794 * @param {Object} config
58796 Roo.grid.RowSelectionModel = function(config){
58797 Roo.apply(this, config);
58798 this.selections = new Roo.util.MixedCollection(false, function(o){
58803 this.lastActive = false;
58807 * @event selectionchange
58808 * Fires when the selection changes
58809 * @param {SelectionModel} this
58811 "selectionchange" : true,
58813 * @event afterselectionchange
58814 * Fires after the selection changes (eg. by key press or clicking)
58815 * @param {SelectionModel} this
58817 "afterselectionchange" : true,
58819 * @event beforerowselect
58820 * Fires when a row is selected being selected, return false to cancel.
58821 * @param {SelectionModel} this
58822 * @param {Number} rowIndex The selected index
58823 * @param {Boolean} keepExisting False if other selections will be cleared
58825 "beforerowselect" : true,
58828 * Fires when a row is selected.
58829 * @param {SelectionModel} this
58830 * @param {Number} rowIndex The selected index
58831 * @param {Roo.data.Record} r The record
58833 "rowselect" : true,
58835 * @event rowdeselect
58836 * Fires when a row is deselected.
58837 * @param {SelectionModel} this
58838 * @param {Number} rowIndex The selected index
58840 "rowdeselect" : true
58842 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
58843 this.locked = false;
58846 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
58848 * @cfg {Boolean} singleSelect
58849 * True to allow selection of only one row at a time (defaults to false)
58851 singleSelect : false,
58854 initEvents : function(){
58856 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
58857 this.grid.on("mousedown", this.handleMouseDown, this);
58858 }else{ // allow click to work like normal
58859 this.grid.on("rowclick", this.handleDragableRowClick, this);
58862 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
58863 "up" : function(e){
58865 this.selectPrevious(e.shiftKey);
58866 }else if(this.last !== false && this.lastActive !== false){
58867 var last = this.last;
58868 this.selectRange(this.last, this.lastActive-1);
58869 this.grid.getView().focusRow(this.lastActive);
58870 if(last !== false){
58874 this.selectFirstRow();
58876 this.fireEvent("afterselectionchange", this);
58878 "down" : function(e){
58880 this.selectNext(e.shiftKey);
58881 }else if(this.last !== false && this.lastActive !== false){
58882 var last = this.last;
58883 this.selectRange(this.last, this.lastActive+1);
58884 this.grid.getView().focusRow(this.lastActive);
58885 if(last !== false){
58889 this.selectFirstRow();
58891 this.fireEvent("afterselectionchange", this);
58896 var view = this.grid.view;
58897 view.on("refresh", this.onRefresh, this);
58898 view.on("rowupdated", this.onRowUpdated, this);
58899 view.on("rowremoved", this.onRemove, this);
58903 onRefresh : function(){
58904 var ds = this.grid.dataSource, i, v = this.grid.view;
58905 var s = this.selections;
58906 s.each(function(r){
58907 if((i = ds.indexOfId(r.id)) != -1){
58909 s.add(ds.getAt(i)); // updating the selection relate data
58917 onRemove : function(v, index, r){
58918 this.selections.remove(r);
58922 onRowUpdated : function(v, index, r){
58923 if(this.isSelected(r)){
58924 v.onRowSelect(index);
58930 * @param {Array} records The records to select
58931 * @param {Boolean} keepExisting (optional) True to keep existing selections
58933 selectRecords : function(records, keepExisting){
58935 this.clearSelections();
58937 var ds = this.grid.dataSource;
58938 for(var i = 0, len = records.length; i < len; i++){
58939 this.selectRow(ds.indexOf(records[i]), true);
58944 * Gets the number of selected rows.
58947 getCount : function(){
58948 return this.selections.length;
58952 * Selects the first row in the grid.
58954 selectFirstRow : function(){
58959 * Select the last row.
58960 * @param {Boolean} keepExisting (optional) True to keep existing selections
58962 selectLastRow : function(keepExisting){
58963 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
58967 * Selects the row immediately following the last selected row.
58968 * @param {Boolean} keepExisting (optional) True to keep existing selections
58970 selectNext : function(keepExisting){
58971 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
58972 this.selectRow(this.last+1, keepExisting);
58973 this.grid.getView().focusRow(this.last);
58978 * Selects the row that precedes the last selected row.
58979 * @param {Boolean} keepExisting (optional) True to keep existing selections
58981 selectPrevious : function(keepExisting){
58983 this.selectRow(this.last-1, keepExisting);
58984 this.grid.getView().focusRow(this.last);
58989 * Returns the selected records
58990 * @return {Array} Array of selected records
58992 getSelections : function(){
58993 return [].concat(this.selections.items);
58997 * Returns the first selected record.
59000 getSelected : function(){
59001 return this.selections.itemAt(0);
59006 * Clears all selections.
59008 clearSelections : function(fast){
59013 var ds = this.grid.dataSource;
59014 var s = this.selections;
59015 s.each(function(r){
59016 this.deselectRow(ds.indexOfId(r.id));
59020 this.selections.clear();
59027 * Selects all rows.
59029 selectAll : function(){
59033 this.selections.clear();
59034 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
59035 this.selectRow(i, true);
59040 * Returns True if there is a selection.
59041 * @return {Boolean}
59043 hasSelection : function(){
59044 return this.selections.length > 0;
59048 * Returns True if the specified row is selected.
59049 * @param {Number/Record} record The record or index of the record to check
59050 * @return {Boolean}
59052 isSelected : function(index){
59053 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
59054 return (r && this.selections.key(r.id) ? true : false);
59058 * Returns True if the specified record id is selected.
59059 * @param {String} id The id of record to check
59060 * @return {Boolean}
59062 isIdSelected : function(id){
59063 return (this.selections.key(id) ? true : false);
59067 handleMouseDown : function(e, t){
59068 var view = this.grid.getView(), rowIndex;
59069 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
59072 if(e.shiftKey && this.last !== false){
59073 var last = this.last;
59074 this.selectRange(last, rowIndex, e.ctrlKey);
59075 this.last = last; // reset the last
59076 view.focusRow(rowIndex);
59078 var isSelected = this.isSelected(rowIndex);
59079 if(e.button !== 0 && isSelected){
59080 view.focusRow(rowIndex);
59081 }else if(e.ctrlKey && isSelected){
59082 this.deselectRow(rowIndex);
59083 }else if(!isSelected){
59084 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
59085 view.focusRow(rowIndex);
59088 this.fireEvent("afterselectionchange", this);
59091 handleDragableRowClick : function(grid, rowIndex, e)
59093 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
59094 this.selectRow(rowIndex, false);
59095 grid.view.focusRow(rowIndex);
59096 this.fireEvent("afterselectionchange", this);
59101 * Selects multiple rows.
59102 * @param {Array} rows Array of the indexes of the row to select
59103 * @param {Boolean} keepExisting (optional) True to keep existing selections
59105 selectRows : function(rows, keepExisting){
59107 this.clearSelections();
59109 for(var i = 0, len = rows.length; i < len; i++){
59110 this.selectRow(rows[i], true);
59115 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59116 * @param {Number} startRow The index of the first row in the range
59117 * @param {Number} endRow The index of the last row in the range
59118 * @param {Boolean} keepExisting (optional) True to retain existing selections
59120 selectRange : function(startRow, endRow, keepExisting){
59125 this.clearSelections();
59127 if(startRow <= endRow){
59128 for(var i = startRow; i <= endRow; i++){
59129 this.selectRow(i, true);
59132 for(var i = startRow; i >= endRow; i--){
59133 this.selectRow(i, true);
59139 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59140 * @param {Number} startRow The index of the first row in the range
59141 * @param {Number} endRow The index of the last row in the range
59143 deselectRange : function(startRow, endRow, preventViewNotify){
59147 for(var i = startRow; i <= endRow; i++){
59148 this.deselectRow(i, preventViewNotify);
59154 * @param {Number} row The index of the row to select
59155 * @param {Boolean} keepExisting (optional) True to keep existing selections
59157 selectRow : function(index, keepExisting, preventViewNotify){
59158 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
59161 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59162 if(!keepExisting || this.singleSelect){
59163 this.clearSelections();
59165 var r = this.grid.dataSource.getAt(index);
59166 this.selections.add(r);
59167 this.last = this.lastActive = index;
59168 if(!preventViewNotify){
59169 this.grid.getView().onRowSelect(index);
59171 this.fireEvent("rowselect", this, index, r);
59172 this.fireEvent("selectionchange", this);
59178 * @param {Number} row The index of the row to deselect
59180 deselectRow : function(index, preventViewNotify){
59184 if(this.last == index){
59187 if(this.lastActive == index){
59188 this.lastActive = false;
59190 var r = this.grid.dataSource.getAt(index);
59191 this.selections.remove(r);
59192 if(!preventViewNotify){
59193 this.grid.getView().onRowDeselect(index);
59195 this.fireEvent("rowdeselect", this, index);
59196 this.fireEvent("selectionchange", this);
59200 restoreLast : function(){
59202 this.last = this._last;
59207 acceptsNav : function(row, col, cm){
59208 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59212 onEditorKey : function(field, e){
59213 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59218 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59220 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59222 }else if(k == e.ENTER && !e.ctrlKey){
59226 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59228 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59230 }else if(k == e.ESC){
59234 g.startEditing(newCell[0], newCell[1]);
59239 * Ext JS Library 1.1.1
59240 * Copyright(c) 2006-2007, Ext JS, LLC.
59242 * Originally Released Under LGPL - original licence link has changed is not relivant.
59245 * <script type="text/javascript">
59248 * @class Roo.grid.CellSelectionModel
59249 * @extends Roo.grid.AbstractSelectionModel
59250 * This class provides the basic implementation for cell selection in a grid.
59252 * @param {Object} config The object containing the configuration of this model.
59253 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59255 Roo.grid.CellSelectionModel = function(config){
59256 Roo.apply(this, config);
59258 this.selection = null;
59262 * @event beforerowselect
59263 * Fires before a cell is selected.
59264 * @param {SelectionModel} this
59265 * @param {Number} rowIndex The selected row index
59266 * @param {Number} colIndex The selected cell index
59268 "beforecellselect" : true,
59270 * @event cellselect
59271 * Fires when a cell is selected.
59272 * @param {SelectionModel} this
59273 * @param {Number} rowIndex The selected row index
59274 * @param {Number} colIndex The selected cell index
59276 "cellselect" : true,
59278 * @event selectionchange
59279 * Fires when the active selection changes.
59280 * @param {SelectionModel} this
59281 * @param {Object} selection null for no selection or an object (o) with two properties
59283 <li>o.record: the record object for the row the selection is in</li>
59284 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59287 "selectionchange" : true,
59290 * Fires when the tab (or enter) was pressed on the last editable cell
59291 * You can use this to trigger add new row.
59292 * @param {SelectionModel} this
59296 * @event beforeeditnext
59297 * Fires before the next editable sell is made active
59298 * You can use this to skip to another cell or fire the tabend
59299 * if you set cell to false
59300 * @param {Object} eventdata object : { cell : [ row, col ] }
59302 "beforeeditnext" : true
59304 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59307 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59309 enter_is_tab: false,
59312 initEvents : function(){
59313 this.grid.on("mousedown", this.handleMouseDown, this);
59314 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59315 var view = this.grid.view;
59316 view.on("refresh", this.onViewChange, this);
59317 view.on("rowupdated", this.onRowUpdated, this);
59318 view.on("beforerowremoved", this.clearSelections, this);
59319 view.on("beforerowsinserted", this.clearSelections, this);
59320 if(this.grid.isEditor){
59321 this.grid.on("beforeedit", this.beforeEdit, this);
59326 beforeEdit : function(e){
59327 this.select(e.row, e.column, false, true, e.record);
59331 onRowUpdated : function(v, index, r){
59332 if(this.selection && this.selection.record == r){
59333 v.onCellSelect(index, this.selection.cell[1]);
59338 onViewChange : function(){
59339 this.clearSelections(true);
59343 * Returns the currently selected cell,.
59344 * @return {Array} The selected cell (row, column) or null if none selected.
59346 getSelectedCell : function(){
59347 return this.selection ? this.selection.cell : null;
59351 * Clears all selections.
59352 * @param {Boolean} true to prevent the gridview from being notified about the change.
59354 clearSelections : function(preventNotify){
59355 var s = this.selection;
59357 if(preventNotify !== true){
59358 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59360 this.selection = null;
59361 this.fireEvent("selectionchange", this, null);
59366 * Returns true if there is a selection.
59367 * @return {Boolean}
59369 hasSelection : function(){
59370 return this.selection ? true : false;
59374 handleMouseDown : function(e, t){
59375 var v = this.grid.getView();
59376 if(this.isLocked()){
59379 var row = v.findRowIndex(t);
59380 var cell = v.findCellIndex(t);
59381 if(row !== false && cell !== false){
59382 this.select(row, cell);
59388 * @param {Number} rowIndex
59389 * @param {Number} collIndex
59391 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59392 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59393 this.clearSelections();
59394 r = r || this.grid.dataSource.getAt(rowIndex);
59397 cell : [rowIndex, colIndex]
59399 if(!preventViewNotify){
59400 var v = this.grid.getView();
59401 v.onCellSelect(rowIndex, colIndex);
59402 if(preventFocus !== true){
59403 v.focusCell(rowIndex, colIndex);
59406 this.fireEvent("cellselect", this, rowIndex, colIndex);
59407 this.fireEvent("selectionchange", this, this.selection);
59412 isSelectable : function(rowIndex, colIndex, cm){
59413 return !cm.isHidden(colIndex);
59417 handleKeyDown : function(e){
59418 //Roo.log('Cell Sel Model handleKeyDown');
59419 if(!e.isNavKeyPress()){
59422 var g = this.grid, s = this.selection;
59425 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59427 this.select(cell[0], cell[1]);
59432 var walk = function(row, col, step){
59433 return g.walkCells(row, col, step, sm.isSelectable, sm);
59435 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59442 // handled by onEditorKey
59443 if (g.isEditor && g.editing) {
59447 newCell = walk(r, c-1, -1);
59449 newCell = walk(r, c+1, 1);
59454 newCell = walk(r+1, c, 1);
59458 newCell = walk(r-1, c, -1);
59462 newCell = walk(r, c+1, 1);
59466 newCell = walk(r, c-1, -1);
59471 if(g.isEditor && !g.editing){
59472 g.startEditing(r, c);
59481 this.select(newCell[0], newCell[1]);
59487 acceptsNav : function(row, col, cm){
59488 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59492 * @param {Number} field (not used) - as it's normally used as a listener
59493 * @param {Number} e - event - fake it by using
59495 * var e = Roo.EventObjectImpl.prototype;
59496 * e.keyCode = e.TAB
59500 onEditorKey : function(field, e){
59502 var k = e.getKey(),
59505 ed = g.activeEditor,
59507 ///Roo.log('onEditorKey' + k);
59510 if (this.enter_is_tab && k == e.ENTER) {
59516 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59518 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59524 } else if(k == e.ENTER && !e.ctrlKey){
59527 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59529 } else if(k == e.ESC){
59534 var ecall = { cell : newCell, forward : forward };
59535 this.fireEvent('beforeeditnext', ecall );
59536 newCell = ecall.cell;
59537 forward = ecall.forward;
59541 //Roo.log('next cell after edit');
59542 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59543 } else if (forward) {
59544 // tabbed past last
59545 this.fireEvent.defer(100, this, ['tabend',this]);
59550 * Ext JS Library 1.1.1
59551 * Copyright(c) 2006-2007, Ext JS, LLC.
59553 * Originally Released Under LGPL - original licence link has changed is not relivant.
59556 * <script type="text/javascript">
59560 * @class Roo.grid.EditorGrid
59561 * @extends Roo.grid.Grid
59562 * Class for creating and editable grid.
59563 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59564 * The container MUST have some type of size defined for the grid to fill. The container will be
59565 * automatically set to position relative if it isn't already.
59566 * @param {Object} dataSource The data model to bind to
59567 * @param {Object} colModel The column model with info about this grid's columns
59569 Roo.grid.EditorGrid = function(container, config){
59570 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59571 this.getGridEl().addClass("xedit-grid");
59573 if(!this.selModel){
59574 this.selModel = new Roo.grid.CellSelectionModel();
59577 this.activeEditor = null;
59581 * @event beforeedit
59582 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59583 * <ul style="padding:5px;padding-left:16px;">
59584 * <li>grid - This grid</li>
59585 * <li>record - The record being edited</li>
59586 * <li>field - The field name being edited</li>
59587 * <li>value - The value for the field being edited.</li>
59588 * <li>row - The grid row index</li>
59589 * <li>column - The grid column index</li>
59590 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59592 * @param {Object} e An edit event (see above for description)
59594 "beforeedit" : true,
59597 * Fires after a cell is edited. <br />
59598 * <ul style="padding:5px;padding-left:16px;">
59599 * <li>grid - This grid</li>
59600 * <li>record - The record being edited</li>
59601 * <li>field - The field name being edited</li>
59602 * <li>value - The value being set</li>
59603 * <li>originalValue - The original value for the field, before the edit.</li>
59604 * <li>row - The grid row index</li>
59605 * <li>column - The grid column index</li>
59607 * @param {Object} e An edit event (see above for description)
59609 "afteredit" : true,
59611 * @event validateedit
59612 * Fires after a cell is edited, but before the value is set in the record.
59613 * You can use this to modify the value being set in the field, Return false
59614 * to cancel the change. The edit event object has the following properties <br />
59615 * <ul style="padding:5px;padding-left:16px;">
59616 * <li>editor - This editor</li>
59617 * <li>grid - This grid</li>
59618 * <li>record - The record being edited</li>
59619 * <li>field - The field name being edited</li>
59620 * <li>value - The value being set</li>
59621 * <li>originalValue - The original value for the field, before the edit.</li>
59622 * <li>row - The grid row index</li>
59623 * <li>column - The grid column index</li>
59624 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59626 * @param {Object} e An edit event (see above for description)
59628 "validateedit" : true
59630 this.on("bodyscroll", this.stopEditing, this);
59631 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59634 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59636 * @cfg {Number} clicksToEdit
59637 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59644 trackMouseOver: false, // causes very odd FF errors
59646 onCellDblClick : function(g, row, col){
59647 this.startEditing(row, col);
59650 onEditComplete : function(ed, value, startValue){
59651 this.editing = false;
59652 this.activeEditor = null;
59653 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59655 var field = this.colModel.getDataIndex(ed.col);
59660 originalValue: startValue,
59667 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59670 if(String(value) !== String(startValue)){
59672 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59673 r.set(field, e.value);
59674 // if we are dealing with a combo box..
59675 // then we also set the 'name' colum to be the displayField
59676 if (ed.field.displayField && ed.field.name) {
59677 r.set(ed.field.name, ed.field.el.dom.value);
59680 delete e.cancel; //?? why!!!
59681 this.fireEvent("afteredit", e);
59684 this.fireEvent("afteredit", e); // always fire it!
59686 this.view.focusCell(ed.row, ed.col);
59690 * Starts editing the specified for the specified row/column
59691 * @param {Number} rowIndex
59692 * @param {Number} colIndex
59694 startEditing : function(row, col){
59695 this.stopEditing();
59696 if(this.colModel.isCellEditable(col, row)){
59697 this.view.ensureVisible(row, col, true);
59699 var r = this.dataSource.getAt(row);
59700 var field = this.colModel.getDataIndex(col);
59701 var cell = Roo.get(this.view.getCell(row,col));
59706 value: r.data[field],
59711 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59712 this.editing = true;
59713 var ed = this.colModel.getCellEditor(col, row);
59719 ed.render(ed.parentEl || document.body);
59725 (function(){ // complex but required for focus issues in safari, ie and opera
59729 ed.on("complete", this.onEditComplete, this, {single: true});
59730 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
59731 this.activeEditor = ed;
59732 var v = r.data[field];
59733 ed.startEdit(this.view.getCell(row, col), v);
59734 // combo's with 'displayField and name set
59735 if (ed.field.displayField && ed.field.name) {
59736 ed.field.el.dom.value = r.data[ed.field.name];
59740 }).defer(50, this);
59746 * Stops any active editing
59748 stopEditing : function(){
59749 if(this.activeEditor){
59750 this.activeEditor.completeEdit();
59752 this.activeEditor = null;
59756 * Called to get grid's drag proxy text, by default returns this.ddText.
59759 getDragDropText : function(){
59760 var count = this.selModel.getSelectedCell() ? 1 : 0;
59761 return String.format(this.ddText, count, count == 1 ? '' : 's');
59766 * Ext JS Library 1.1.1
59767 * Copyright(c) 2006-2007, Ext JS, LLC.
59769 * Originally Released Under LGPL - original licence link has changed is not relivant.
59772 * <script type="text/javascript">
59775 // private - not really -- you end up using it !
59776 // This is a support class used internally by the Grid components
59779 * @class Roo.grid.GridEditor
59780 * @extends Roo.Editor
59781 * Class for creating and editable grid elements.
59782 * @param {Object} config any settings (must include field)
59784 Roo.grid.GridEditor = function(field, config){
59785 if (!config && field.field) {
59787 field = Roo.factory(config.field, Roo.form);
59789 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
59790 field.monitorTab = false;
59793 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
59796 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
59799 alignment: "tl-tl",
59802 cls: "x-small-editor x-grid-editor",
59807 * Ext JS Library 1.1.1
59808 * Copyright(c) 2006-2007, Ext JS, LLC.
59810 * Originally Released Under LGPL - original licence link has changed is not relivant.
59813 * <script type="text/javascript">
59818 Roo.grid.PropertyRecord = Roo.data.Record.create([
59819 {name:'name',type:'string'}, 'value'
59823 Roo.grid.PropertyStore = function(grid, source){
59825 this.store = new Roo.data.Store({
59826 recordType : Roo.grid.PropertyRecord
59828 this.store.on('update', this.onUpdate, this);
59830 this.setSource(source);
59832 Roo.grid.PropertyStore.superclass.constructor.call(this);
59837 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
59838 setSource : function(o){
59840 this.store.removeAll();
59843 if(this.isEditableValue(o[k])){
59844 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
59847 this.store.loadRecords({records: data}, {}, true);
59850 onUpdate : function(ds, record, type){
59851 if(type == Roo.data.Record.EDIT){
59852 var v = record.data['value'];
59853 var oldValue = record.modified['value'];
59854 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
59855 this.source[record.id] = v;
59857 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
59864 getProperty : function(row){
59865 return this.store.getAt(row);
59868 isEditableValue: function(val){
59869 if(val && val instanceof Date){
59871 }else if(typeof val == 'object' || typeof val == 'function'){
59877 setValue : function(prop, value){
59878 this.source[prop] = value;
59879 this.store.getById(prop).set('value', value);
59882 getSource : function(){
59883 return this.source;
59887 Roo.grid.PropertyColumnModel = function(grid, store){
59890 g.PropertyColumnModel.superclass.constructor.call(this, [
59891 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
59892 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
59894 this.store = store;
59895 this.bselect = Roo.DomHelper.append(document.body, {
59896 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
59897 {tag: 'option', value: 'true', html: 'true'},
59898 {tag: 'option', value: 'false', html: 'false'}
59901 Roo.id(this.bselect);
59904 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
59905 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
59906 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
59907 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
59908 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
59910 this.renderCellDelegate = this.renderCell.createDelegate(this);
59911 this.renderPropDelegate = this.renderProp.createDelegate(this);
59914 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
59918 valueText : 'Value',
59920 dateFormat : 'm/j/Y',
59923 renderDate : function(dateVal){
59924 return dateVal.dateFormat(this.dateFormat);
59927 renderBool : function(bVal){
59928 return bVal ? 'true' : 'false';
59931 isCellEditable : function(colIndex, rowIndex){
59932 return colIndex == 1;
59935 getRenderer : function(col){
59937 this.renderCellDelegate : this.renderPropDelegate;
59940 renderProp : function(v){
59941 return this.getPropertyName(v);
59944 renderCell : function(val){
59946 if(val instanceof Date){
59947 rv = this.renderDate(val);
59948 }else if(typeof val == 'boolean'){
59949 rv = this.renderBool(val);
59951 return Roo.util.Format.htmlEncode(rv);
59954 getPropertyName : function(name){
59955 var pn = this.grid.propertyNames;
59956 return pn && pn[name] ? pn[name] : name;
59959 getCellEditor : function(colIndex, rowIndex){
59960 var p = this.store.getProperty(rowIndex);
59961 var n = p.data['name'], val = p.data['value'];
59963 if(typeof(this.grid.customEditors[n]) == 'string'){
59964 return this.editors[this.grid.customEditors[n]];
59966 if(typeof(this.grid.customEditors[n]) != 'undefined'){
59967 return this.grid.customEditors[n];
59969 if(val instanceof Date){
59970 return this.editors['date'];
59971 }else if(typeof val == 'number'){
59972 return this.editors['number'];
59973 }else if(typeof val == 'boolean'){
59974 return this.editors['boolean'];
59976 return this.editors['string'];
59982 * @class Roo.grid.PropertyGrid
59983 * @extends Roo.grid.EditorGrid
59984 * This class represents the interface of a component based property grid control.
59985 * <br><br>Usage:<pre><code>
59986 var grid = new Roo.grid.PropertyGrid("my-container-id", {
59994 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59995 * The container MUST have some type of size defined for the grid to fill. The container will be
59996 * automatically set to position relative if it isn't already.
59997 * @param {Object} config A config object that sets properties on this grid.
59999 Roo.grid.PropertyGrid = function(container, config){
60000 config = config || {};
60001 var store = new Roo.grid.PropertyStore(this);
60002 this.store = store;
60003 var cm = new Roo.grid.PropertyColumnModel(this, store);
60004 store.store.sort('name', 'ASC');
60005 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
60008 enableColLock:false,
60009 enableColumnMove:false,
60011 trackMouseOver: false,
60014 this.getGridEl().addClass('x-props-grid');
60015 this.lastEditRow = null;
60016 this.on('columnresize', this.onColumnResize, this);
60019 * @event beforepropertychange
60020 * Fires before a property changes (return false to stop?)
60021 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60022 * @param {String} id Record Id
60023 * @param {String} newval New Value
60024 * @param {String} oldval Old Value
60026 "beforepropertychange": true,
60028 * @event propertychange
60029 * Fires after a property changes
60030 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60031 * @param {String} id Record Id
60032 * @param {String} newval New Value
60033 * @param {String} oldval Old Value
60035 "propertychange": true
60037 this.customEditors = this.customEditors || {};
60039 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
60042 * @cfg {Object} customEditors map of colnames=> custom editors.
60043 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
60044 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
60045 * false disables editing of the field.
60049 * @cfg {Object} propertyNames map of property Names to their displayed value
60052 render : function(){
60053 Roo.grid.PropertyGrid.superclass.render.call(this);
60054 this.autoSize.defer(100, this);
60057 autoSize : function(){
60058 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
60060 this.view.fitColumns();
60064 onColumnResize : function(){
60065 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
60069 * Sets the data for the Grid
60070 * accepts a Key => Value object of all the elements avaiable.
60071 * @param {Object} data to appear in grid.
60073 setSource : function(source){
60074 this.store.setSource(source);
60078 * Gets all the data from the grid.
60079 * @return {Object} data data stored in grid
60081 getSource : function(){
60082 return this.store.getSource();
60091 * @class Roo.grid.Calendar
60092 * @extends Roo.util.Grid
60093 * This class extends the Grid to provide a calendar widget
60094 * <br><br>Usage:<pre><code>
60095 var grid = new Roo.grid.Calendar("my-container-id", {
60098 selModel: mySelectionModel,
60099 autoSizeColumns: true,
60100 monitorWindowResize: false,
60101 trackMouseOver: true
60102 eventstore : real data store..
60108 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60109 * The container MUST have some type of size defined for the grid to fill. The container will be
60110 * automatically set to position relative if it isn't already.
60111 * @param {Object} config A config object that sets properties on this grid.
60113 Roo.grid.Calendar = function(container, config){
60114 // initialize the container
60115 this.container = Roo.get(container);
60116 this.container.update("");
60117 this.container.setStyle("overflow", "hidden");
60118 this.container.addClass('x-grid-container');
60120 this.id = this.container.id;
60122 Roo.apply(this, config);
60123 // check and correct shorthanded configs
60127 for (var r = 0;r < 6;r++) {
60130 for (var c =0;c < 7;c++) {
60134 if (this.eventStore) {
60135 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60136 this.eventStore.on('load',this.onLoad, this);
60137 this.eventStore.on('beforeload',this.clearEvents, this);
60141 this.dataSource = new Roo.data.Store({
60142 proxy: new Roo.data.MemoryProxy(rows),
60143 reader: new Roo.data.ArrayReader({}, [
60144 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60147 this.dataSource.load();
60148 this.ds = this.dataSource;
60149 this.ds.xmodule = this.xmodule || false;
60152 var cellRender = function(v,x,r)
60154 return String.format(
60155 '<div class="fc-day fc-widget-content"><div>' +
60156 '<div class="fc-event-container"></div>' +
60157 '<div class="fc-day-number">{0}</div>'+
60159 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60160 '</div></div>', v);
60165 this.colModel = new Roo.grid.ColumnModel( [
60167 xtype: 'ColumnModel',
60169 dataIndex : 'weekday0',
60171 renderer : cellRender
60174 xtype: 'ColumnModel',
60176 dataIndex : 'weekday1',
60178 renderer : cellRender
60181 xtype: 'ColumnModel',
60183 dataIndex : 'weekday2',
60184 header : 'Tuesday',
60185 renderer : cellRender
60188 xtype: 'ColumnModel',
60190 dataIndex : 'weekday3',
60191 header : 'Wednesday',
60192 renderer : cellRender
60195 xtype: 'ColumnModel',
60197 dataIndex : 'weekday4',
60198 header : 'Thursday',
60199 renderer : cellRender
60202 xtype: 'ColumnModel',
60204 dataIndex : 'weekday5',
60206 renderer : cellRender
60209 xtype: 'ColumnModel',
60211 dataIndex : 'weekday6',
60212 header : 'Saturday',
60213 renderer : cellRender
60216 this.cm = this.colModel;
60217 this.cm.xmodule = this.xmodule || false;
60221 //this.selModel = new Roo.grid.CellSelectionModel();
60222 //this.sm = this.selModel;
60223 //this.selModel.init(this);
60227 this.container.setWidth(this.width);
60231 this.container.setHeight(this.height);
60238 * The raw click event for the entire grid.
60239 * @param {Roo.EventObject} e
60244 * The raw dblclick event for the entire grid.
60245 * @param {Roo.EventObject} e
60249 * @event contextmenu
60250 * The raw contextmenu event for the entire grid.
60251 * @param {Roo.EventObject} e
60253 "contextmenu" : true,
60256 * The raw mousedown event for the entire grid.
60257 * @param {Roo.EventObject} e
60259 "mousedown" : true,
60262 * The raw mouseup event for the entire grid.
60263 * @param {Roo.EventObject} e
60268 * The raw mouseover event for the entire grid.
60269 * @param {Roo.EventObject} e
60271 "mouseover" : true,
60274 * The raw mouseout event for the entire grid.
60275 * @param {Roo.EventObject} e
60280 * The raw keypress event for the entire grid.
60281 * @param {Roo.EventObject} e
60286 * The raw keydown event for the entire grid.
60287 * @param {Roo.EventObject} e
60295 * Fires when a cell is clicked
60296 * @param {Grid} this
60297 * @param {Number} rowIndex
60298 * @param {Number} columnIndex
60299 * @param {Roo.EventObject} e
60301 "cellclick" : true,
60303 * @event celldblclick
60304 * Fires when a cell is double clicked
60305 * @param {Grid} this
60306 * @param {Number} rowIndex
60307 * @param {Number} columnIndex
60308 * @param {Roo.EventObject} e
60310 "celldblclick" : true,
60313 * Fires when a row is clicked
60314 * @param {Grid} this
60315 * @param {Number} rowIndex
60316 * @param {Roo.EventObject} e
60320 * @event rowdblclick
60321 * Fires when a row is double clicked
60322 * @param {Grid} this
60323 * @param {Number} rowIndex
60324 * @param {Roo.EventObject} e
60326 "rowdblclick" : true,
60328 * @event headerclick
60329 * Fires when a header is clicked
60330 * @param {Grid} this
60331 * @param {Number} columnIndex
60332 * @param {Roo.EventObject} e
60334 "headerclick" : true,
60336 * @event headerdblclick
60337 * Fires when a header cell is double clicked
60338 * @param {Grid} this
60339 * @param {Number} columnIndex
60340 * @param {Roo.EventObject} e
60342 "headerdblclick" : true,
60344 * @event rowcontextmenu
60345 * Fires when a row is right clicked
60346 * @param {Grid} this
60347 * @param {Number} rowIndex
60348 * @param {Roo.EventObject} e
60350 "rowcontextmenu" : true,
60352 * @event cellcontextmenu
60353 * Fires when a cell is right clicked
60354 * @param {Grid} this
60355 * @param {Number} rowIndex
60356 * @param {Number} cellIndex
60357 * @param {Roo.EventObject} e
60359 "cellcontextmenu" : true,
60361 * @event headercontextmenu
60362 * Fires when a header is right clicked
60363 * @param {Grid} this
60364 * @param {Number} columnIndex
60365 * @param {Roo.EventObject} e
60367 "headercontextmenu" : true,
60369 * @event bodyscroll
60370 * Fires when the body element is scrolled
60371 * @param {Number} scrollLeft
60372 * @param {Number} scrollTop
60374 "bodyscroll" : true,
60376 * @event columnresize
60377 * Fires when the user resizes a column
60378 * @param {Number} columnIndex
60379 * @param {Number} newSize
60381 "columnresize" : true,
60383 * @event columnmove
60384 * Fires when the user moves a column
60385 * @param {Number} oldIndex
60386 * @param {Number} newIndex
60388 "columnmove" : true,
60391 * Fires when row(s) start being dragged
60392 * @param {Grid} this
60393 * @param {Roo.GridDD} dd The drag drop object
60394 * @param {event} e The raw browser event
60396 "startdrag" : true,
60399 * Fires when a drag operation is complete
60400 * @param {Grid} this
60401 * @param {Roo.GridDD} dd The drag drop object
60402 * @param {event} e The raw browser event
60407 * Fires when dragged row(s) are dropped on a valid DD target
60408 * @param {Grid} this
60409 * @param {Roo.GridDD} dd The drag drop object
60410 * @param {String} targetId The target drag drop object
60411 * @param {event} e The raw browser event
60416 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60417 * @param {Grid} this
60418 * @param {Roo.GridDD} dd The drag drop object
60419 * @param {String} targetId The target drag drop object
60420 * @param {event} e The raw browser event
60425 * Fires when the dragged row(s) first cross another DD target while being dragged
60426 * @param {Grid} this
60427 * @param {Roo.GridDD} dd The drag drop object
60428 * @param {String} targetId The target drag drop object
60429 * @param {event} e The raw browser event
60431 "dragenter" : true,
60434 * Fires when the dragged row(s) leave another DD target while being dragged
60435 * @param {Grid} this
60436 * @param {Roo.GridDD} dd The drag drop object
60437 * @param {String} targetId The target drag drop object
60438 * @param {event} e The raw browser event
60443 * Fires when a row is rendered, so you can change add a style to it.
60444 * @param {GridView} gridview The grid view
60445 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60451 * Fires when the grid is rendered
60452 * @param {Grid} grid
60457 * Fires when a date is selected
60458 * @param {DatePicker} this
60459 * @param {Date} date The selected date
60463 * @event monthchange
60464 * Fires when the displayed month changes
60465 * @param {DatePicker} this
60466 * @param {Date} date The selected month
60468 'monthchange': true,
60470 * @event evententer
60471 * Fires when mouse over an event
60472 * @param {Calendar} this
60473 * @param {event} Event
60475 'evententer': true,
60477 * @event eventleave
60478 * Fires when the mouse leaves an
60479 * @param {Calendar} this
60482 'eventleave': true,
60484 * @event eventclick
60485 * Fires when the mouse click an
60486 * @param {Calendar} this
60489 'eventclick': true,
60491 * @event eventrender
60492 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60493 * @param {Calendar} this
60494 * @param {data} data to be modified
60496 'eventrender': true
60500 Roo.grid.Grid.superclass.constructor.call(this);
60501 this.on('render', function() {
60502 this.view.el.addClass('x-grid-cal');
60504 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60508 if (!Roo.grid.Calendar.style) {
60509 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60512 '.x-grid-cal .x-grid-col' : {
60513 height: 'auto !important',
60514 'vertical-align': 'top'
60516 '.x-grid-cal .fc-event-hori' : {
60527 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60529 * @cfg {Store} eventStore The store that loads events.
60534 activeDate : false,
60537 monitorWindowResize : false,
60540 resizeColumns : function() {
60541 var col = (this.view.el.getWidth() / 7) - 3;
60542 // loop through cols, and setWidth
60543 for(var i =0 ; i < 7 ; i++){
60544 this.cm.setColumnWidth(i, col);
60547 setDate :function(date) {
60549 Roo.log('setDate?');
60551 this.resizeColumns();
60552 var vd = this.activeDate;
60553 this.activeDate = date;
60554 // if(vd && this.el){
60555 // var t = date.getTime();
60556 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60557 // Roo.log('using add remove');
60559 // this.fireEvent('monthchange', this, date);
60561 // this.cells.removeClass("fc-state-highlight");
60562 // this.cells.each(function(c){
60563 // if(c.dateValue == t){
60564 // c.addClass("fc-state-highlight");
60565 // setTimeout(function(){
60566 // try{c.dom.firstChild.focus();}catch(e){}
60576 var days = date.getDaysInMonth();
60578 var firstOfMonth = date.getFirstDateOfMonth();
60579 var startingPos = firstOfMonth.getDay()-this.startDay;
60581 if(startingPos < this.startDay){
60585 var pm = date.add(Date.MONTH, -1);
60586 var prevStart = pm.getDaysInMonth()-startingPos;
60590 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60592 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60593 //this.cells.addClassOnOver('fc-state-hover');
60595 var cells = this.cells.elements;
60596 var textEls = this.textNodes;
60598 //Roo.each(cells, function(cell){
60599 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60602 days += startingPos;
60604 // convert everything to numbers so it's fast
60605 var day = 86400000;
60606 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60609 //Roo.log(prevStart);
60611 var today = new Date().clearTime().getTime();
60612 var sel = date.clearTime().getTime();
60613 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60614 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60615 var ddMatch = this.disabledDatesRE;
60616 var ddText = this.disabledDatesText;
60617 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60618 var ddaysText = this.disabledDaysText;
60619 var format = this.format;
60621 var setCellClass = function(cal, cell){
60623 //Roo.log('set Cell Class');
60625 var t = d.getTime();
60630 cell.dateValue = t;
60632 cell.className += " fc-today";
60633 cell.className += " fc-state-highlight";
60634 cell.title = cal.todayText;
60637 // disable highlight in other month..
60638 cell.className += " fc-state-highlight";
60643 //cell.className = " fc-state-disabled";
60644 cell.title = cal.minText;
60648 //cell.className = " fc-state-disabled";
60649 cell.title = cal.maxText;
60653 if(ddays.indexOf(d.getDay()) != -1){
60654 // cell.title = ddaysText;
60655 // cell.className = " fc-state-disabled";
60658 if(ddMatch && format){
60659 var fvalue = d.dateFormat(format);
60660 if(ddMatch.test(fvalue)){
60661 cell.title = ddText.replace("%0", fvalue);
60662 cell.className = " fc-state-disabled";
60666 if (!cell.initialClassName) {
60667 cell.initialClassName = cell.dom.className;
60670 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60675 for(; i < startingPos; i++) {
60676 cells[i].dayName = (++prevStart);
60677 Roo.log(textEls[i]);
60678 d.setDate(d.getDate()+1);
60680 //cells[i].className = "fc-past fc-other-month";
60681 setCellClass(this, cells[i]);
60686 for(; i < days; i++){
60687 intDay = i - startingPos + 1;
60688 cells[i].dayName = (intDay);
60689 d.setDate(d.getDate()+1);
60691 cells[i].className = ''; // "x-date-active";
60692 setCellClass(this, cells[i]);
60696 for(; i < 42; i++) {
60697 //textEls[i].innerHTML = (++extraDays);
60699 d.setDate(d.getDate()+1);
60700 cells[i].dayName = (++extraDays);
60701 cells[i].className = "fc-future fc-other-month";
60702 setCellClass(this, cells[i]);
60705 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60707 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60709 // this will cause all the cells to mis
60712 for (var r = 0;r < 6;r++) {
60713 for (var c =0;c < 7;c++) {
60714 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60718 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60719 for(i=0;i<cells.length;i++) {
60721 this.cells.elements[i].dayName = cells[i].dayName ;
60722 this.cells.elements[i].className = cells[i].className;
60723 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
60724 this.cells.elements[i].title = cells[i].title ;
60725 this.cells.elements[i].dateValue = cells[i].dateValue ;
60731 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
60732 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
60734 ////if(totalRows != 6){
60735 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
60736 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
60739 this.fireEvent('monthchange', this, date);
60744 * Returns the grid's SelectionModel.
60745 * @return {SelectionModel}
60747 getSelectionModel : function(){
60748 if(!this.selModel){
60749 this.selModel = new Roo.grid.CellSelectionModel();
60751 return this.selModel;
60755 this.eventStore.load()
60761 findCell : function(dt) {
60762 dt = dt.clearTime().getTime();
60764 this.cells.each(function(c){
60765 //Roo.log("check " +c.dateValue + '?=' + dt);
60766 if(c.dateValue == dt){
60776 findCells : function(rec) {
60777 var s = rec.data.start_dt.clone().clearTime().getTime();
60779 var e= rec.data.end_dt.clone().clearTime().getTime();
60782 this.cells.each(function(c){
60783 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
60785 if(c.dateValue > e){
60788 if(c.dateValue < s){
60797 findBestRow: function(cells)
60801 for (var i =0 ; i < cells.length;i++) {
60802 ret = Math.max(cells[i].rows || 0,ret);
60809 addItem : function(rec)
60811 // look for vertical location slot in
60812 var cells = this.findCells(rec);
60814 rec.row = this.findBestRow(cells);
60816 // work out the location.
60820 for(var i =0; i < cells.length; i++) {
60828 if (crow.start.getY() == cells[i].getY()) {
60830 crow.end = cells[i];
60846 for (var i = 0; i < cells.length;i++) {
60847 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
60854 clearEvents: function() {
60856 if (!this.eventStore.getCount()) {
60859 // reset number of rows in cells.
60860 Roo.each(this.cells.elements, function(c){
60864 this.eventStore.each(function(e) {
60865 this.clearEvent(e);
60870 clearEvent : function(ev)
60873 Roo.each(ev.els, function(el) {
60874 el.un('mouseenter' ,this.onEventEnter, this);
60875 el.un('mouseleave' ,this.onEventLeave, this);
60883 renderEvent : function(ev,ctr) {
60885 ctr = this.view.el.select('.fc-event-container',true).first();
60889 this.clearEvent(ev);
60895 var cells = ev.cells;
60896 var rows = ev.rows;
60897 this.fireEvent('eventrender', this, ev);
60899 for(var i =0; i < rows.length; i++) {
60903 cls += ' fc-event-start';
60905 if ((i+1) == rows.length) {
60906 cls += ' fc-event-end';
60909 //Roo.log(ev.data);
60910 // how many rows should it span..
60911 var cg = this.eventTmpl.append(ctr,Roo.apply({
60914 }, ev.data) , true);
60917 cg.on('mouseenter' ,this.onEventEnter, this, ev);
60918 cg.on('mouseleave' ,this.onEventLeave, this, ev);
60919 cg.on('click', this.onEventClick, this, ev);
60923 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
60924 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
60927 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
60928 cg.setWidth(ebox.right - sbox.x -2);
60932 renderEvents: function()
60934 // first make sure there is enough space..
60936 if (!this.eventTmpl) {
60937 this.eventTmpl = new Roo.Template(
60938 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
60939 '<div class="fc-event-inner">' +
60940 '<span class="fc-event-time">{time}</span>' +
60941 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
60943 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
60951 this.cells.each(function(c) {
60952 //Roo.log(c.select('.fc-day-content div',true).first());
60953 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
60956 var ctr = this.view.el.select('.fc-event-container',true).first();
60959 this.eventStore.each(function(ev){
60961 this.renderEvent(ev);
60965 this.view.layout();
60969 onEventEnter: function (e, el,event,d) {
60970 this.fireEvent('evententer', this, el, event);
60973 onEventLeave: function (e, el,event,d) {
60974 this.fireEvent('eventleave', this, el, event);
60977 onEventClick: function (e, el,event,d) {
60978 this.fireEvent('eventclick', this, el, event);
60981 onMonthChange: function () {
60985 onLoad: function () {
60987 //Roo.log('calendar onload');
60989 if(this.eventStore.getCount() > 0){
60993 this.eventStore.each(function(d){
60998 if (typeof(add.end_dt) == 'undefined') {
60999 Roo.log("Missing End time in calendar data: ");
61003 if (typeof(add.start_dt) == 'undefined') {
61004 Roo.log("Missing Start time in calendar data: ");
61008 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
61009 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
61010 add.id = add.id || d.id;
61011 add.title = add.title || '??';
61019 this.renderEvents();
61029 render : function ()
61033 if (!this.view.el.hasClass('course-timesheet')) {
61034 this.view.el.addClass('course-timesheet');
61036 if (this.tsStyle) {
61041 Roo.log(_this.grid.view.el.getWidth());
61044 this.tsStyle = Roo.util.CSS.createStyleSheet({
61045 '.course-timesheet .x-grid-row' : {
61048 '.x-grid-row td' : {
61049 'vertical-align' : 0
61051 '.course-edit-link' : {
61053 'text-overflow' : 'ellipsis',
61054 'overflow' : 'hidden',
61055 'white-space' : 'nowrap',
61056 'cursor' : 'pointer'
61061 '.de-act-sup-link' : {
61062 'color' : 'purple',
61063 'text-decoration' : 'line-through'
61067 'text-decoration' : 'line-through'
61069 '.course-timesheet .course-highlight' : {
61070 'border-top-style': 'dashed !important',
61071 'border-bottom-bottom': 'dashed !important'
61073 '.course-timesheet .course-item' : {
61074 'font-family' : 'tahoma, arial, helvetica',
61075 'font-size' : '11px',
61076 'overflow' : 'hidden',
61077 'padding-left' : '10px',
61078 'padding-right' : '10px',
61079 'padding-top' : '10px'
61087 monitorWindowResize : false,
61088 cellrenderer : function(v,x,r)
61093 xtype: 'CellSelectionModel',
61100 beforeload : function (_self, options)
61102 options.params = options.params || {};
61103 options.params._month = _this.monthField.getValue();
61104 options.params.limit = 9999;
61105 options.params['sort'] = 'when_dt';
61106 options.params['dir'] = 'ASC';
61107 this.proxy.loadResponse = this.loadResponse;
61109 //this.addColumns();
61111 load : function (_self, records, options)
61113 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
61114 // if you click on the translation.. you can edit it...
61115 var el = Roo.get(this);
61116 var id = el.dom.getAttribute('data-id');
61117 var d = el.dom.getAttribute('data-date');
61118 var t = el.dom.getAttribute('data-time');
61119 //var id = this.child('span').dom.textContent;
61122 Pman.Dialog.CourseCalendar.show({
61126 productitem_active : id ? 1 : 0
61128 _this.grid.ds.load({});
61133 _this.panel.fireEvent('resize', [ '', '' ]);
61136 loadResponse : function(o, success, response){
61137 // this is overridden on before load..
61139 Roo.log("our code?");
61140 //Roo.log(success);
61141 //Roo.log(response)
61142 delete this.activeRequest;
61144 this.fireEvent("loadexception", this, o, response);
61145 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61150 result = o.reader.read(response);
61152 Roo.log("load exception?");
61153 this.fireEvent("loadexception", this, o, response, e);
61154 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61157 Roo.log("ready...");
61158 // loop through result.records;
61159 // and set this.tdate[date] = [] << array of records..
61161 Roo.each(result.records, function(r){
61163 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61164 _this.tdata[r.data.when_dt.format('j')] = [];
61166 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61169 //Roo.log(_this.tdata);
61171 result.records = [];
61172 result.totalRecords = 6;
61174 // let's generate some duumy records for the rows.
61175 //var st = _this.dateField.getValue();
61177 // work out monday..
61178 //st = st.add(Date.DAY, -1 * st.format('w'));
61180 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61182 var firstOfMonth = date.getFirstDayOfMonth();
61183 var days = date.getDaysInMonth();
61185 var firstAdded = false;
61186 for (var i = 0; i < result.totalRecords ; i++) {
61187 //var d= st.add(Date.DAY, i);
61190 for(var w = 0 ; w < 7 ; w++){
61191 if(!firstAdded && firstOfMonth != w){
61198 var dd = (d > 0 && d < 10) ? "0"+d : d;
61199 row['weekday'+w] = String.format(
61200 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61201 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61203 date.format('Y-m-')+dd
61206 if(typeof(_this.tdata[d]) != 'undefined'){
61207 Roo.each(_this.tdata[d], function(r){
61211 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61212 if(r.parent_id*1>0){
61213 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61216 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61217 deactive = 'de-act-link';
61220 row['weekday'+w] += String.format(
61221 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61223 r.product_id_name, //1
61224 r.when_dt.format('h:ia'), //2
61234 // only do this if something added..
61236 result.records.push(_this.grid.dataSource.reader.newRow(row));
61240 // push it twice. (second one with an hour..
61244 this.fireEvent("load", this, o, o.request.arg);
61245 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61247 sortInfo : {field: 'when_dt', direction : 'ASC' },
61249 xtype: 'HttpProxy',
61252 url : baseURL + '/Roo/Shop_course.php'
61255 xtype: 'JsonReader',
61272 'name': 'parent_id',
61276 'name': 'product_id',
61280 'name': 'productitem_id',
61298 click : function (_self, e)
61300 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61301 sd.setMonth(sd.getMonth()-1);
61302 _this.monthField.setValue(sd.format('Y-m-d'));
61303 _this.grid.ds.load({});
61309 xtype: 'Separator',
61313 xtype: 'MonthField',
61316 render : function (_self)
61318 _this.monthField = _self;
61319 // _this.monthField.set today
61321 select : function (combo, date)
61323 _this.grid.ds.load({});
61326 value : (function() { return new Date(); })()
61329 xtype: 'Separator',
61335 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61345 click : function (_self, e)
61347 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61348 sd.setMonth(sd.getMonth()+1);
61349 _this.monthField.setValue(sd.format('Y-m-d'));
61350 _this.grid.ds.load({});
61363 * Ext JS Library 1.1.1
61364 * Copyright(c) 2006-2007, Ext JS, LLC.
61366 * Originally Released Under LGPL - original licence link has changed is not relivant.
61369 * <script type="text/javascript">
61373 * @class Roo.LoadMask
61374 * A simple utility class for generically masking elements while loading data. If the element being masked has
61375 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61376 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61377 * element's UpdateManager load indicator and will be destroyed after the initial load.
61379 * Create a new LoadMask
61380 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61381 * @param {Object} config The config object
61383 Roo.LoadMask = function(el, config){
61384 this.el = Roo.get(el);
61385 Roo.apply(this, config);
61387 this.store.on('beforeload', this.onBeforeLoad, this);
61388 this.store.on('load', this.onLoad, this);
61389 this.store.on('loadexception', this.onLoadException, this);
61390 this.removeMask = false;
61392 var um = this.el.getUpdateManager();
61393 um.showLoadIndicator = false; // disable the default indicator
61394 um.on('beforeupdate', this.onBeforeLoad, this);
61395 um.on('update', this.onLoad, this);
61396 um.on('failure', this.onLoad, this);
61397 this.removeMask = true;
61401 Roo.LoadMask.prototype = {
61403 * @cfg {Boolean} removeMask
61404 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61405 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61408 * @cfg {String} msg
61409 * The text to display in a centered loading message box (defaults to 'Loading...')
61411 msg : 'Loading...',
61413 * @cfg {String} msgCls
61414 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61416 msgCls : 'x-mask-loading',
61419 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61425 * Disables the mask to prevent it from being displayed
61427 disable : function(){
61428 this.disabled = true;
61432 * Enables the mask so that it can be displayed
61434 enable : function(){
61435 this.disabled = false;
61438 onLoadException : function()
61440 Roo.log(arguments);
61442 if (typeof(arguments[3]) != 'undefined') {
61443 Roo.MessageBox.alert("Error loading",arguments[3]);
61447 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61448 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61455 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61458 onLoad : function()
61460 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61464 onBeforeLoad : function(){
61465 if(!this.disabled){
61466 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61471 destroy : function(){
61473 this.store.un('beforeload', this.onBeforeLoad, this);
61474 this.store.un('load', this.onLoad, this);
61475 this.store.un('loadexception', this.onLoadException, this);
61477 var um = this.el.getUpdateManager();
61478 um.un('beforeupdate', this.onBeforeLoad, this);
61479 um.un('update', this.onLoad, this);
61480 um.un('failure', this.onLoad, this);
61485 * Ext JS Library 1.1.1
61486 * Copyright(c) 2006-2007, Ext JS, LLC.
61488 * Originally Released Under LGPL - original licence link has changed is not relivant.
61491 * <script type="text/javascript">
61496 * @class Roo.XTemplate
61497 * @extends Roo.Template
61498 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61500 var t = new Roo.XTemplate(
61501 '<select name="{name}">',
61502 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61506 // then append, applying the master template values
61509 * Supported features:
61514 {a_variable} - output encoded.
61515 {a_variable.format:("Y-m-d")} - call a method on the variable
61516 {a_variable:raw} - unencoded output
61517 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61518 {a_variable:this.method_on_template(...)} - call a method on the template object.
61523 <tpl for="a_variable or condition.."></tpl>
61524 <tpl if="a_variable or condition"></tpl>
61525 <tpl exec="some javascript"></tpl>
61526 <tpl name="named_template"></tpl> (experimental)
61528 <tpl for="."></tpl> - just iterate the property..
61529 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61533 Roo.XTemplate = function()
61535 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61542 Roo.extend(Roo.XTemplate, Roo.Template, {
61545 * The various sub templates
61550 * basic tag replacing syntax
61553 * // you can fake an object call by doing this
61557 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61560 * compile the template
61562 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61565 compile: function()
61569 s = ['<tpl>', s, '</tpl>'].join('');
61571 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61572 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61573 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61574 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61575 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61580 while(true == !!(m = s.match(re))){
61581 var forMatch = m[0].match(nameRe),
61582 ifMatch = m[0].match(ifRe),
61583 execMatch = m[0].match(execRe),
61584 namedMatch = m[0].match(namedRe),
61589 name = forMatch && forMatch[1] ? forMatch[1] : '';
61592 // if - puts fn into test..
61593 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61595 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61600 // exec - calls a function... returns empty if true is returned.
61601 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61603 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61611 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61612 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61613 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61616 var uid = namedMatch ? namedMatch[1] : id;
61620 id: namedMatch ? namedMatch[1] : id,
61627 s = s.replace(m[0], '');
61629 s = s.replace(m[0], '{xtpl'+ id + '}');
61634 for(var i = tpls.length-1; i >= 0; --i){
61635 this.compileTpl(tpls[i]);
61636 this.tpls[tpls[i].id] = tpls[i];
61638 this.master = tpls[tpls.length-1];
61642 * same as applyTemplate, except it's done to one of the subTemplates
61643 * when using named templates, you can do:
61645 * var str = pl.applySubTemplate('your-name', values);
61648 * @param {Number} id of the template
61649 * @param {Object} values to apply to template
61650 * @param {Object} parent (normaly the instance of this object)
61652 applySubTemplate : function(id, values, parent)
61656 var t = this.tpls[id];
61660 if(t.test && !t.test.call(this, values, parent)){
61664 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61665 Roo.log(e.toString());
61671 if(t.exec && t.exec.call(this, values, parent)){
61675 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61676 Roo.log(e.toString());
61681 var vs = t.target ? t.target.call(this, values, parent) : values;
61682 parent = t.target ? values : parent;
61683 if(t.target && vs instanceof Array){
61685 for(var i = 0, len = vs.length; i < len; i++){
61686 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61688 return buf.join('');
61690 return t.compiled.call(this, vs, parent);
61692 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61693 Roo.log(e.toString());
61694 Roo.log(t.compiled);
61699 compileTpl : function(tpl)
61701 var fm = Roo.util.Format;
61702 var useF = this.disableFormats !== true;
61703 var sep = Roo.isGecko ? "+" : ",";
61704 var undef = function(str) {
61705 Roo.log("Property not found :" + str);
61709 var fn = function(m, name, format, args)
61711 //Roo.log(arguments);
61712 args = args ? args.replace(/\\'/g,"'") : args;
61713 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61714 if (typeof(format) == 'undefined') {
61715 format= 'htmlEncode';
61717 if (format == 'raw' ) {
61721 if(name.substr(0, 4) == 'xtpl'){
61722 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
61725 // build an array of options to determine if value is undefined..
61727 // basically get 'xxxx.yyyy' then do
61728 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
61729 // (function () { Roo.log("Property not found"); return ''; })() :
61734 Roo.each(name.split('.'), function(st) {
61735 lookfor += (lookfor.length ? '.': '') + st;
61736 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
61739 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
61742 if(format && useF){
61744 args = args ? ',' + args : "";
61746 if(format.substr(0, 5) != "this."){
61747 format = "fm." + format + '(';
61749 format = 'this.call("'+ format.substr(5) + '", ';
61753 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
61757 // called with xxyx.yuu:(test,test)
61759 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
61761 // raw.. - :raw modifier..
61762 return "'"+ sep + udef_st + name + ")"+sep+"'";
61766 // branched to use + in gecko and [].join() in others
61768 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
61769 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
61772 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
61773 body.push(tpl.body.replace(/(\r\n|\n)/g,
61774 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
61775 body.push("'].join('');};};");
61776 body = body.join('');
61779 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
61781 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
61787 applyTemplate : function(values){
61788 return this.master.compiled.call(this, values, {});
61789 //var s = this.subs;
61792 apply : function(){
61793 return this.applyTemplate.apply(this, arguments);
61798 Roo.XTemplate.from = function(el){
61799 el = Roo.getDom(el);
61800 return new Roo.XTemplate(el.value || el.innerHTML);