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 if (this.dom instanceof SVGElement) {
7679 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
7681 this.dom.className = this.dom.className + " " + className;
7689 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7690 * @param {String/Array} className The CSS class to add, or an array of classes
7691 * @return {Roo.Element} this
7693 radioClass : function(className){
7694 var siblings = this.dom.parentNode.childNodes;
7695 for(var i = 0; i < siblings.length; i++) {
7696 var s = siblings[i];
7697 if(s.nodeType == 1){
7698 Roo.get(s).removeClass(className);
7701 this.addClass(className);
7706 * Removes one or more CSS classes from the element.
7707 * @param {String/Array} className The CSS class to remove, or an array of classes
7708 * @return {Roo.Element} this
7710 removeClass : function(className){
7712 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
7713 if(!className || !cn){
7716 if(className instanceof Array){
7717 for(var i = 0, len = className.length; i < len; i++) {
7718 this.removeClass(className[i]);
7721 if(this.hasClass(className)){
7722 var re = this.classReCache[className];
7724 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7725 this.classReCache[className] = re;
7727 if (this.dom instanceof SVGElement) {
7728 this.dom.className.baseVal = cn.replace(re, " ");
7730 this.dom.className = cn.replace(re, " ");
7741 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7742 * @param {String} className The CSS class to toggle
7743 * @return {Roo.Element} this
7745 toggleClass : function(className){
7746 if(this.hasClass(className)){
7747 this.removeClass(className);
7749 this.addClass(className);
7755 * Checks if the specified CSS class exists on this element's DOM node.
7756 * @param {String} className The CSS class to check for
7757 * @return {Boolean} True if the class exists, else false
7759 hasClass : function(className){
7760 if (this.dom instanceof SVGElement) {
7761 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
7763 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7767 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7768 * @param {String} oldClassName The CSS class to replace
7769 * @param {String} newClassName The replacement CSS class
7770 * @return {Roo.Element} this
7772 replaceClass : function(oldClassName, newClassName){
7773 this.removeClass(oldClassName);
7774 this.addClass(newClassName);
7779 * Returns an object with properties matching the styles requested.
7780 * For example, el.getStyles('color', 'font-size', 'width') might return
7781 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7782 * @param {String} style1 A style name
7783 * @param {String} style2 A style name
7784 * @param {String} etc.
7785 * @return {Object} The style object
7787 getStyles : function(){
7788 var a = arguments, len = a.length, r = {};
7789 for(var i = 0; i < len; i++){
7790 r[a[i]] = this.getStyle(a[i]);
7796 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7797 * @param {String} property The style property whose value is returned.
7798 * @return {String} The current value of the style property for this element.
7800 getStyle : function(){
7801 return view && view.getComputedStyle ?
7803 var el = this.dom, v, cs, camel;
7804 if(prop == 'float'){
7807 if(el.style && (v = el.style[prop])){
7810 if(cs = view.getComputedStyle(el, "")){
7811 if(!(camel = propCache[prop])){
7812 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7819 var el = this.dom, v, cs, camel;
7820 if(prop == 'opacity'){
7821 if(typeof el.style.filter == 'string'){
7822 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7824 var fv = parseFloat(m[1]);
7826 return fv ? fv / 100 : 0;
7831 }else if(prop == 'float'){
7832 prop = "styleFloat";
7834 if(!(camel = propCache[prop])){
7835 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7837 if(v = el.style[camel]){
7840 if(cs = el.currentStyle){
7848 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7849 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7850 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7851 * @return {Roo.Element} this
7853 setStyle : function(prop, value){
7854 if(typeof prop == "string"){
7856 if (prop == 'float') {
7857 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7862 if(!(camel = propCache[prop])){
7863 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7866 if(camel == 'opacity') {
7867 this.setOpacity(value);
7869 this.dom.style[camel] = value;
7872 for(var style in prop){
7873 if(typeof prop[style] != "function"){
7874 this.setStyle(style, prop[style]);
7882 * More flexible version of {@link #setStyle} for setting style properties.
7883 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7884 * a function which returns such a specification.
7885 * @return {Roo.Element} this
7887 applyStyles : function(style){
7888 Roo.DomHelper.applyStyles(this.dom, style);
7893 * 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).
7894 * @return {Number} The X position of the element
7897 return D.getX(this.dom);
7901 * 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).
7902 * @return {Number} The Y position of the element
7905 return D.getY(this.dom);
7909 * 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).
7910 * @return {Array} The XY position of the element
7913 return D.getXY(this.dom);
7917 * 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).
7918 * @param {Number} The X position of the element
7919 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7920 * @return {Roo.Element} this
7922 setX : function(x, animate){
7924 D.setX(this.dom, x);
7926 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7932 * 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).
7933 * @param {Number} The Y position of the element
7934 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7935 * @return {Roo.Element} this
7937 setY : function(y, animate){
7939 D.setY(this.dom, y);
7941 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7947 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7948 * @param {String} left The left CSS property value
7949 * @return {Roo.Element} this
7951 setLeft : function(left){
7952 this.setStyle("left", this.addUnits(left));
7957 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7958 * @param {String} top The top CSS property value
7959 * @return {Roo.Element} this
7961 setTop : function(top){
7962 this.setStyle("top", this.addUnits(top));
7967 * Sets the element's CSS right style.
7968 * @param {String} right The right CSS property value
7969 * @return {Roo.Element} this
7971 setRight : function(right){
7972 this.setStyle("right", this.addUnits(right));
7977 * Sets the element's CSS bottom style.
7978 * @param {String} bottom The bottom CSS property value
7979 * @return {Roo.Element} this
7981 setBottom : function(bottom){
7982 this.setStyle("bottom", this.addUnits(bottom));
7987 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7988 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7989 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7990 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7991 * @return {Roo.Element} this
7993 setXY : function(pos, animate){
7995 D.setXY(this.dom, pos);
7997 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8003 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8004 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8005 * @param {Number} x X value for new position (coordinates are page-based)
8006 * @param {Number} y Y value for new position (coordinates are page-based)
8007 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8008 * @return {Roo.Element} this
8010 setLocation : function(x, y, animate){
8011 this.setXY([x, y], this.preanim(arguments, 2));
8016 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8017 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8018 * @param {Number} x X value for new position (coordinates are page-based)
8019 * @param {Number} y Y value for new position (coordinates are page-based)
8020 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8021 * @return {Roo.Element} this
8023 moveTo : function(x, y, animate){
8024 this.setXY([x, y], this.preanim(arguments, 2));
8029 * Returns the region of the given element.
8030 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8031 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8033 getRegion : function(){
8034 return D.getRegion(this.dom);
8038 * Returns the offset height of the element
8039 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8040 * @return {Number} The element's height
8042 getHeight : function(contentHeight){
8043 var h = this.dom.offsetHeight || 0;
8044 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8048 * Returns the offset width of the element
8049 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8050 * @return {Number} The element's width
8052 getWidth : function(contentWidth){
8053 var w = this.dom.offsetWidth || 0;
8054 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8058 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8059 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8060 * if a height has not been set using CSS.
8063 getComputedHeight : function(){
8064 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8066 h = parseInt(this.getStyle('height'), 10) || 0;
8067 if(!this.isBorderBox()){
8068 h += this.getFrameWidth('tb');
8075 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8076 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8077 * if a width has not been set using CSS.
8080 getComputedWidth : function(){
8081 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8083 w = parseInt(this.getStyle('width'), 10) || 0;
8084 if(!this.isBorderBox()){
8085 w += this.getFrameWidth('lr');
8092 * Returns the size of the element.
8093 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8094 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8096 getSize : function(contentSize){
8097 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8101 * Returns the width and height of the viewport.
8102 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8104 getViewSize : function(){
8105 var d = this.dom, doc = document, aw = 0, ah = 0;
8106 if(d == doc || d == doc.body){
8107 return {width : D.getViewWidth(), height: D.getViewHeight()};
8110 width : d.clientWidth,
8111 height: d.clientHeight
8117 * Returns the value of the "value" attribute
8118 * @param {Boolean} asNumber true to parse the value as a number
8119 * @return {String/Number}
8121 getValue : function(asNumber){
8122 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8126 adjustWidth : function(width){
8127 if(typeof width == "number"){
8128 if(this.autoBoxAdjust && !this.isBorderBox()){
8129 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8139 adjustHeight : function(height){
8140 if(typeof height == "number"){
8141 if(this.autoBoxAdjust && !this.isBorderBox()){
8142 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8152 * Set the width of the element
8153 * @param {Number} width The new width
8154 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8155 * @return {Roo.Element} this
8157 setWidth : function(width, animate){
8158 width = this.adjustWidth(width);
8160 this.dom.style.width = this.addUnits(width);
8162 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8168 * Set the height of the element
8169 * @param {Number} height The new height
8170 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8171 * @return {Roo.Element} this
8173 setHeight : function(height, animate){
8174 height = this.adjustHeight(height);
8176 this.dom.style.height = this.addUnits(height);
8178 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8184 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8185 * @param {Number} width The new width
8186 * @param {Number} height The new height
8187 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8188 * @return {Roo.Element} this
8190 setSize : function(width, height, animate){
8191 if(typeof width == "object"){ // in case of object from getSize()
8192 height = width.height; width = width.width;
8194 width = this.adjustWidth(width); height = this.adjustHeight(height);
8196 this.dom.style.width = this.addUnits(width);
8197 this.dom.style.height = this.addUnits(height);
8199 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8205 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8206 * @param {Number} x X value for new position (coordinates are page-based)
8207 * @param {Number} y Y value for new position (coordinates are page-based)
8208 * @param {Number} width The new width
8209 * @param {Number} height The new height
8210 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8211 * @return {Roo.Element} this
8213 setBounds : function(x, y, width, height, animate){
8215 this.setSize(width, height);
8216 this.setLocation(x, y);
8218 width = this.adjustWidth(width); height = this.adjustHeight(height);
8219 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8220 this.preanim(arguments, 4), 'motion');
8226 * 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.
8227 * @param {Roo.lib.Region} region The region to fill
8228 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8229 * @return {Roo.Element} this
8231 setRegion : function(region, animate){
8232 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8237 * Appends an event handler
8239 * @param {String} eventName The type of event to append
8240 * @param {Function} fn The method the event invokes
8241 * @param {Object} scope (optional) The scope (this object) of the fn
8242 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8244 addListener : function(eventName, fn, scope, options){
8246 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8248 if (eventName == 'dblclick') {
8249 this.addListener('touchstart', this.onTapHandler, this);
8253 onTapHandler : function(event)
8255 if(!this.tapedTwice) {
8256 this.tapedTwice = true;
8258 setTimeout( function() {
8259 s.tapedTwice = false;
8263 event.preventDefault();
8264 var revent = new MouseEvent('dblclick', {
8270 this.dom.dispatchEvent(revent);
8271 //action on double tap goes below
8276 * Removes an event handler from this element
8277 * @param {String} eventName the type of event to remove
8278 * @param {Function} fn the method the event invokes
8279 * @return {Roo.Element} this
8281 removeListener : function(eventName, fn){
8282 Roo.EventManager.removeListener(this.dom, eventName, fn);
8287 * Removes all previous added listeners from this element
8288 * @return {Roo.Element} this
8290 removeAllListeners : function(){
8291 E.purgeElement(this.dom);
8295 relayEvent : function(eventName, observable){
8296 this.on(eventName, function(e){
8297 observable.fireEvent(eventName, e);
8302 * Set the opacity of the element
8303 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8304 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8305 * @return {Roo.Element} this
8307 setOpacity : function(opacity, animate){
8309 var s = this.dom.style;
8312 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8313 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8315 s.opacity = opacity;
8318 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8324 * Gets the left X coordinate
8325 * @param {Boolean} local True to get the local css position instead of page coordinate
8328 getLeft : function(local){
8332 return parseInt(this.getStyle("left"), 10) || 0;
8337 * Gets the right X coordinate of the element (element X position + element width)
8338 * @param {Boolean} local True to get the local css position instead of page coordinate
8341 getRight : function(local){
8343 return this.getX() + this.getWidth();
8345 return (this.getLeft(true) + this.getWidth()) || 0;
8350 * Gets the top Y coordinate
8351 * @param {Boolean} local True to get the local css position instead of page coordinate
8354 getTop : function(local) {
8358 return parseInt(this.getStyle("top"), 10) || 0;
8363 * Gets the bottom Y coordinate of the element (element Y position + element height)
8364 * @param {Boolean} local True to get the local css position instead of page coordinate
8367 getBottom : function(local){
8369 return this.getY() + this.getHeight();
8371 return (this.getTop(true) + this.getHeight()) || 0;
8376 * Initializes positioning on this element. If a desired position is not passed, it will make the
8377 * the element positioned relative IF it is not already positioned.
8378 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8379 * @param {Number} zIndex (optional) The zIndex to apply
8380 * @param {Number} x (optional) Set the page X position
8381 * @param {Number} y (optional) Set the page Y position
8383 position : function(pos, zIndex, x, y){
8385 if(this.getStyle('position') == 'static'){
8386 this.setStyle('position', 'relative');
8389 this.setStyle("position", pos);
8392 this.setStyle("z-index", zIndex);
8394 if(x !== undefined && y !== undefined){
8396 }else if(x !== undefined){
8398 }else if(y !== undefined){
8404 * Clear positioning back to the default when the document was loaded
8405 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8406 * @return {Roo.Element} this
8408 clearPositioning : function(value){
8416 "position" : "static"
8422 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8423 * snapshot before performing an update and then restoring the element.
8426 getPositioning : function(){
8427 var l = this.getStyle("left");
8428 var t = this.getStyle("top");
8430 "position" : this.getStyle("position"),
8432 "right" : l ? "" : this.getStyle("right"),
8434 "bottom" : t ? "" : this.getStyle("bottom"),
8435 "z-index" : this.getStyle("z-index")
8440 * Gets the width of the border(s) for the specified side(s)
8441 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8442 * passing lr would get the border (l)eft width + the border (r)ight width.
8443 * @return {Number} The width of the sides passed added together
8445 getBorderWidth : function(side){
8446 return this.addStyles(side, El.borders);
8450 * Gets the width of the padding(s) for the specified side(s)
8451 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8452 * passing lr would get the padding (l)eft + the padding (r)ight.
8453 * @return {Number} The padding of the sides passed added together
8455 getPadding : function(side){
8456 return this.addStyles(side, El.paddings);
8460 * Set positioning with an object returned by getPositioning().
8461 * @param {Object} posCfg
8462 * @return {Roo.Element} this
8464 setPositioning : function(pc){
8465 this.applyStyles(pc);
8466 if(pc.right == "auto"){
8467 this.dom.style.right = "";
8469 if(pc.bottom == "auto"){
8470 this.dom.style.bottom = "";
8476 fixDisplay : function(){
8477 if(this.getStyle("display") == "none"){
8478 this.setStyle("visibility", "hidden");
8479 this.setStyle("display", this.originalDisplay); // first try reverting to default
8480 if(this.getStyle("display") == "none"){ // if that fails, default to block
8481 this.setStyle("display", "block");
8487 * Quick set left and top adding default units
8488 * @param {String} left The left CSS property value
8489 * @param {String} top The top CSS property value
8490 * @return {Roo.Element} this
8492 setLeftTop : function(left, top){
8493 this.dom.style.left = this.addUnits(left);
8494 this.dom.style.top = this.addUnits(top);
8499 * Move this element relative to its current position.
8500 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8501 * @param {Number} distance How far to move the element in pixels
8502 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8503 * @return {Roo.Element} this
8505 move : function(direction, distance, animate){
8506 var xy = this.getXY();
8507 direction = direction.toLowerCase();
8511 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8515 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8520 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8525 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8532 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8533 * @return {Roo.Element} this
8536 if(!this.isClipped){
8537 this.isClipped = true;
8538 this.originalClip = {
8539 "o": this.getStyle("overflow"),
8540 "x": this.getStyle("overflow-x"),
8541 "y": this.getStyle("overflow-y")
8543 this.setStyle("overflow", "hidden");
8544 this.setStyle("overflow-x", "hidden");
8545 this.setStyle("overflow-y", "hidden");
8551 * Return clipping (overflow) to original clipping before clip() was called
8552 * @return {Roo.Element} this
8554 unclip : function(){
8556 this.isClipped = false;
8557 var o = this.originalClip;
8558 if(o.o){this.setStyle("overflow", o.o);}
8559 if(o.x){this.setStyle("overflow-x", o.x);}
8560 if(o.y){this.setStyle("overflow-y", o.y);}
8567 * Gets the x,y coordinates specified by the anchor position on the element.
8568 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8569 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8570 * {width: (target width), height: (target height)} (defaults to the element's current size)
8571 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8572 * @return {Array} [x, y] An array containing the element's x and y coordinates
8574 getAnchorXY : function(anchor, local, s){
8575 //Passing a different size is useful for pre-calculating anchors,
8576 //especially for anchored animations that change the el size.
8578 var w, h, vp = false;
8581 if(d == document.body || d == document){
8583 w = D.getViewWidth(); h = D.getViewHeight();
8585 w = this.getWidth(); h = this.getHeight();
8588 w = s.width; h = s.height;
8590 var x = 0, y = 0, r = Math.round;
8591 switch((anchor || "tl").toLowerCase()){
8633 var sc = this.getScroll();
8634 return [x + sc.left, y + sc.top];
8636 //Add the element's offset xy
8637 var o = this.getXY();
8638 return [x+o[0], y+o[1]];
8642 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8643 * supported position values.
8644 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8645 * @param {String} position The position to align to.
8646 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8647 * @return {Array} [x, y]
8649 getAlignToXY : function(el, p, o)
8654 throw "Element.alignTo with an element that doesn't exist";
8656 var c = false; //constrain to viewport
8657 var p1 = "", p2 = "";
8664 }else if(p.indexOf("-") == -1){
8667 p = p.toLowerCase();
8668 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8670 throw "Element.alignTo with an invalid alignment " + p;
8672 p1 = m[1]; p2 = m[2]; c = !!m[3];
8674 //Subtract the aligned el's internal xy from the target's offset xy
8675 //plus custom offset to get the aligned el's new offset xy
8676 var a1 = this.getAnchorXY(p1, true);
8677 var a2 = el.getAnchorXY(p2, false);
8678 var x = a2[0] - a1[0] + o[0];
8679 var y = a2[1] - a1[1] + o[1];
8681 //constrain the aligned el to viewport if necessary
8682 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8683 // 5px of margin for ie
8684 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8686 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8687 //perpendicular to the vp border, allow the aligned el to slide on that border,
8688 //otherwise swap the aligned el to the opposite border of the target.
8689 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8690 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8691 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8692 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8695 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8696 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8698 if((x+w) > dw + scrollX){
8699 x = swapX ? r.left-w : dw+scrollX-w;
8702 x = swapX ? r.right : scrollX;
8704 if((y+h) > dh + scrollY){
8705 y = swapY ? r.top-h : dh+scrollY-h;
8708 y = swapY ? r.bottom : scrollY;
8715 getConstrainToXY : function(){
8716 var os = {top:0, left:0, bottom:0, right: 0};
8718 return function(el, local, offsets, proposedXY){
8720 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8722 var vw, vh, vx = 0, vy = 0;
8723 if(el.dom == document.body || el.dom == document){
8724 vw = Roo.lib.Dom.getViewWidth();
8725 vh = Roo.lib.Dom.getViewHeight();
8727 vw = el.dom.clientWidth;
8728 vh = el.dom.clientHeight;
8730 var vxy = el.getXY();
8736 var s = el.getScroll();
8738 vx += offsets.left + s.left;
8739 vy += offsets.top + s.top;
8741 vw -= offsets.right;
8742 vh -= offsets.bottom;
8747 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8748 var x = xy[0], y = xy[1];
8749 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8751 // only move it if it needs it
8754 // first validate right/bottom
8763 // then make sure top/left isn't negative
8772 return moved ? [x, y] : false;
8777 adjustForConstraints : function(xy, parent, offsets){
8778 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8782 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8783 * document it aligns it to the viewport.
8784 * The position parameter is optional, and can be specified in any one of the following formats:
8786 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8787 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8788 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8789 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8790 * <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
8791 * element's anchor point, and the second value is used as the target's anchor point.</li>
8793 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8794 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8795 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8796 * that specified in order to enforce the viewport constraints.
8797 * Following are all of the supported anchor positions:
8800 ----- -----------------------------
8801 tl The top left corner (default)
8802 t The center of the top edge
8803 tr The top right corner
8804 l The center of the left edge
8805 c In the center of the element
8806 r The center of the right edge
8807 bl The bottom left corner
8808 b The center of the bottom edge
8809 br The bottom right corner
8813 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8814 el.alignTo("other-el");
8816 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8817 el.alignTo("other-el", "tr?");
8819 // align the bottom right corner of el with the center left edge of other-el
8820 el.alignTo("other-el", "br-l?");
8822 // align the center of el with the bottom left corner of other-el and
8823 // adjust the x position by -6 pixels (and the y position by 0)
8824 el.alignTo("other-el", "c-bl", [-6, 0]);
8826 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8827 * @param {String} position The position to align to.
8828 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8829 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8830 * @return {Roo.Element} this
8832 alignTo : function(element, position, offsets, animate){
8833 var xy = this.getAlignToXY(element, position, offsets);
8834 this.setXY(xy, this.preanim(arguments, 3));
8839 * Anchors an element to another element and realigns it when the window is resized.
8840 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8841 * @param {String} position The position to align to.
8842 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8843 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8844 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8845 * is a number, it is used as the buffer delay (defaults to 50ms).
8846 * @param {Function} callback The function to call after the animation finishes
8847 * @return {Roo.Element} this
8849 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8850 var action = function(){
8851 this.alignTo(el, alignment, offsets, animate);
8852 Roo.callback(callback, this);
8854 Roo.EventManager.onWindowResize(action, this);
8855 var tm = typeof monitorScroll;
8856 if(tm != 'undefined'){
8857 Roo.EventManager.on(window, 'scroll', action, this,
8858 {buffer: tm == 'number' ? monitorScroll : 50});
8860 action.call(this); // align immediately
8864 * Clears any opacity settings from this element. Required in some cases for IE.
8865 * @return {Roo.Element} this
8867 clearOpacity : function(){
8868 if (window.ActiveXObject) {
8869 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8870 this.dom.style.filter = "";
8873 this.dom.style.opacity = "";
8874 this.dom.style["-moz-opacity"] = "";
8875 this.dom.style["-khtml-opacity"] = "";
8881 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8882 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8883 * @return {Roo.Element} this
8885 hide : function(animate){
8886 this.setVisible(false, this.preanim(arguments, 0));
8891 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8892 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8893 * @return {Roo.Element} this
8895 show : function(animate){
8896 this.setVisible(true, this.preanim(arguments, 0));
8901 * @private Test if size has a unit, otherwise appends the default
8903 addUnits : function(size){
8904 return Roo.Element.addUnits(size, this.defaultUnit);
8908 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8909 * @return {Roo.Element} this
8911 beginMeasure : function(){
8913 if(el.offsetWidth || el.offsetHeight){
8914 return this; // offsets work already
8917 var p = this.dom, b = document.body; // start with this element
8918 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8919 var pe = Roo.get(p);
8920 if(pe.getStyle('display') == 'none'){
8921 changed.push({el: p, visibility: pe.getStyle("visibility")});
8922 p.style.visibility = "hidden";
8923 p.style.display = "block";
8927 this._measureChanged = changed;
8933 * Restores displays to before beginMeasure was called
8934 * @return {Roo.Element} this
8936 endMeasure : function(){
8937 var changed = this._measureChanged;
8939 for(var i = 0, len = changed.length; i < len; i++) {
8941 r.el.style.visibility = r.visibility;
8942 r.el.style.display = "none";
8944 this._measureChanged = null;
8950 * Update the innerHTML of this element, optionally searching for and processing scripts
8951 * @param {String} html The new HTML
8952 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8953 * @param {Function} callback For async script loading you can be noticed when the update completes
8954 * @return {Roo.Element} this
8956 update : function(html, loadScripts, callback){
8957 if(typeof html == "undefined"){
8960 if(loadScripts !== true){
8961 this.dom.innerHTML = html;
8962 if(typeof callback == "function"){
8970 html += '<span id="' + id + '"></span>';
8972 E.onAvailable(id, function(){
8973 var hd = document.getElementsByTagName("head")[0];
8974 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8975 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8976 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8979 while(match = re.exec(html)){
8980 var attrs = match[1];
8981 var srcMatch = attrs ? attrs.match(srcRe) : false;
8982 if(srcMatch && srcMatch[2]){
8983 var s = document.createElement("script");
8984 s.src = srcMatch[2];
8985 var typeMatch = attrs.match(typeRe);
8986 if(typeMatch && typeMatch[2]){
8987 s.type = typeMatch[2];
8990 }else if(match[2] && match[2].length > 0){
8991 if(window.execScript) {
8992 window.execScript(match[2]);
9000 window.eval(match[2]);
9004 var el = document.getElementById(id);
9005 if(el){el.parentNode.removeChild(el);}
9006 if(typeof callback == "function"){
9010 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9015 * Direct access to the UpdateManager update() method (takes the same parameters).
9016 * @param {String/Function} url The url for this request or a function to call to get the url
9017 * @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}
9018 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9019 * @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.
9020 * @return {Roo.Element} this
9023 var um = this.getUpdateManager();
9024 um.update.apply(um, arguments);
9029 * Gets this element's UpdateManager
9030 * @return {Roo.UpdateManager} The UpdateManager
9032 getUpdateManager : function(){
9033 if(!this.updateManager){
9034 this.updateManager = new Roo.UpdateManager(this);
9036 return this.updateManager;
9040 * Disables text selection for this element (normalized across browsers)
9041 * @return {Roo.Element} this
9043 unselectable : function(){
9044 this.dom.unselectable = "on";
9045 this.swallowEvent("selectstart", true);
9046 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9047 this.addClass("x-unselectable");
9052 * Calculates the x, y to center this element on the screen
9053 * @return {Array} The x, y values [x, y]
9055 getCenterXY : function(){
9056 return this.getAlignToXY(document, 'c-c');
9060 * Centers the Element in either the viewport, or another Element.
9061 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9063 center : function(centerIn){
9064 this.alignTo(centerIn || document, 'c-c');
9069 * Tests various css rules/browsers to determine if this element uses a border box
9072 isBorderBox : function(){
9073 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9077 * Return a box {x, y, width, height} that can be used to set another elements
9078 * size/location to match this element.
9079 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9080 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9081 * @return {Object} box An object in the format {x, y, width, height}
9083 getBox : function(contentBox, local){
9088 var left = parseInt(this.getStyle("left"), 10) || 0;
9089 var top = parseInt(this.getStyle("top"), 10) || 0;
9092 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9094 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9096 var l = this.getBorderWidth("l")+this.getPadding("l");
9097 var r = this.getBorderWidth("r")+this.getPadding("r");
9098 var t = this.getBorderWidth("t")+this.getPadding("t");
9099 var b = this.getBorderWidth("b")+this.getPadding("b");
9100 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)};
9102 bx.right = bx.x + bx.width;
9103 bx.bottom = bx.y + bx.height;
9108 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9109 for more information about the sides.
9110 * @param {String} sides
9113 getFrameWidth : function(sides, onlyContentBox){
9114 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9118 * 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.
9119 * @param {Object} box The box to fill {x, y, width, height}
9120 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9121 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9122 * @return {Roo.Element} this
9124 setBox : function(box, adjust, animate){
9125 var w = box.width, h = box.height;
9126 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9127 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9128 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9130 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9135 * Forces the browser to repaint this element
9136 * @return {Roo.Element} this
9138 repaint : function(){
9140 this.addClass("x-repaint");
9141 setTimeout(function(){
9142 Roo.get(dom).removeClass("x-repaint");
9148 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9149 * then it returns the calculated width of the sides (see getPadding)
9150 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9151 * @return {Object/Number}
9153 getMargins : function(side){
9156 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9157 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9158 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9159 right: parseInt(this.getStyle("margin-right"), 10) || 0
9162 return this.addStyles(side, El.margins);
9167 addStyles : function(sides, styles){
9169 for(var i = 0, len = sides.length; i < len; i++){
9170 v = this.getStyle(styles[sides.charAt(i)]);
9172 w = parseInt(v, 10);
9180 * Creates a proxy element of this element
9181 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9182 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9183 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9184 * @return {Roo.Element} The new proxy element
9186 createProxy : function(config, renderTo, matchBox){
9188 renderTo = Roo.getDom(renderTo);
9190 renderTo = document.body;
9192 config = typeof config == "object" ?
9193 config : {tag : "div", cls: config};
9194 var proxy = Roo.DomHelper.append(renderTo, config, true);
9196 proxy.setBox(this.getBox());
9202 * Puts a mask over this element to disable user interaction. Requires core.css.
9203 * This method can only be applied to elements which accept child nodes.
9204 * @param {String} msg (optional) A message to display in the mask
9205 * @param {String} msgCls (optional) A css class to apply to the msg element
9206 * @return {Element} The mask element
9208 mask : function(msg, msgCls)
9210 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9211 this.setStyle("position", "relative");
9214 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9217 this.addClass("x-masked");
9218 this._mask.setDisplayed(true);
9223 while (dom && dom.style) {
9224 if (!isNaN(parseInt(dom.style.zIndex))) {
9225 z = Math.max(z, parseInt(dom.style.zIndex));
9227 dom = dom.parentNode;
9229 // if we are masking the body - then it hides everything..
9230 if (this.dom == document.body) {
9232 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9233 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9236 if(typeof msg == 'string'){
9238 this._maskMsg = Roo.DomHelper.append(this.dom, {
9239 cls: "roo-el-mask-msg",
9243 cls: 'fa fa-spinner fa-spin'
9251 var mm = this._maskMsg;
9252 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9253 if (mm.dom.lastChild) { // weird IE issue?
9254 mm.dom.lastChild.innerHTML = msg;
9256 mm.setDisplayed(true);
9258 mm.setStyle('z-index', z + 102);
9260 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9261 this._mask.setHeight(this.getHeight());
9263 this._mask.setStyle('z-index', z + 100);
9269 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9270 * it is cached for reuse.
9272 unmask : function(removeEl){
9274 if(removeEl === true){
9275 this._mask.remove();
9278 this._maskMsg.remove();
9279 delete this._maskMsg;
9282 this._mask.setDisplayed(false);
9284 this._maskMsg.setDisplayed(false);
9288 this.removeClass("x-masked");
9292 * Returns true if this element is masked
9295 isMasked : function(){
9296 return this._mask && this._mask.isVisible();
9300 * Creates an iframe shim for this element to keep selects and other windowed objects from
9302 * @return {Roo.Element} The new shim element
9304 createShim : function(){
9305 var el = document.createElement('iframe');
9306 el.frameBorder = 'no';
9307 el.className = 'roo-shim';
9308 if(Roo.isIE && Roo.isSecure){
9309 el.src = Roo.SSL_SECURE_URL;
9311 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9312 shim.autoBoxAdjust = false;
9317 * Removes this element from the DOM and deletes it from the cache
9319 remove : function(){
9320 if(this.dom.parentNode){
9321 this.dom.parentNode.removeChild(this.dom);
9323 delete El.cache[this.dom.id];
9327 * Sets up event handlers to add and remove a css class when the mouse is over this element
9328 * @param {String} className
9329 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9330 * mouseout events for children elements
9331 * @return {Roo.Element} this
9333 addClassOnOver : function(className, preventFlicker){
9334 this.on("mouseover", function(){
9335 Roo.fly(this, '_internal').addClass(className);
9337 var removeFn = function(e){
9338 if(preventFlicker !== true || !e.within(this, true)){
9339 Roo.fly(this, '_internal').removeClass(className);
9342 this.on("mouseout", removeFn, this.dom);
9347 * Sets up event handlers to add and remove a css class when this element has the focus
9348 * @param {String} className
9349 * @return {Roo.Element} this
9351 addClassOnFocus : function(className){
9352 this.on("focus", function(){
9353 Roo.fly(this, '_internal').addClass(className);
9355 this.on("blur", function(){
9356 Roo.fly(this, '_internal').removeClass(className);
9361 * 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)
9362 * @param {String} className
9363 * @return {Roo.Element} this
9365 addClassOnClick : function(className){
9367 this.on("mousedown", function(){
9368 Roo.fly(dom, '_internal').addClass(className);
9369 var d = Roo.get(document);
9370 var fn = function(){
9371 Roo.fly(dom, '_internal').removeClass(className);
9372 d.removeListener("mouseup", fn);
9374 d.on("mouseup", fn);
9380 * Stops the specified event from bubbling and optionally prevents the default action
9381 * @param {String} eventName
9382 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9383 * @return {Roo.Element} this
9385 swallowEvent : function(eventName, preventDefault){
9386 var fn = function(e){
9387 e.stopPropagation();
9392 if(eventName instanceof Array){
9393 for(var i = 0, len = eventName.length; i < len; i++){
9394 this.on(eventName[i], fn);
9398 this.on(eventName, fn);
9405 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9408 * Sizes this element to its parent element's dimensions performing
9409 * neccessary box adjustments.
9410 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9411 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9412 * @return {Roo.Element} this
9414 fitToParent : function(monitorResize, targetParent) {
9415 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9416 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9417 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9420 var p = Roo.get(targetParent || this.dom.parentNode);
9421 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9422 if (monitorResize === true) {
9423 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9424 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9430 * Gets the next sibling, skipping text nodes
9431 * @return {HTMLElement} The next sibling or null
9433 getNextSibling : function(){
9434 var n = this.dom.nextSibling;
9435 while(n && n.nodeType != 1){
9442 * Gets the previous sibling, skipping text nodes
9443 * @return {HTMLElement} The previous sibling or null
9445 getPrevSibling : function(){
9446 var n = this.dom.previousSibling;
9447 while(n && n.nodeType != 1){
9448 n = n.previousSibling;
9455 * Appends the passed element(s) to this element
9456 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9457 * @return {Roo.Element} this
9459 appendChild: function(el){
9466 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9467 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9468 * automatically generated with the specified attributes.
9469 * @param {HTMLElement} insertBefore (optional) a child element of this element
9470 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9471 * @return {Roo.Element} The new child element
9473 createChild: function(config, insertBefore, returnDom){
9474 config = config || {tag:'div'};
9476 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9478 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9482 * Appends this element to the passed element
9483 * @param {String/HTMLElement/Element} el The new parent element
9484 * @return {Roo.Element} this
9486 appendTo: function(el){
9487 el = Roo.getDom(el);
9488 el.appendChild(this.dom);
9493 * Inserts this element before the passed element in the DOM
9494 * @param {String/HTMLElement/Element} el The element to insert before
9495 * @return {Roo.Element} this
9497 insertBefore: function(el){
9498 el = Roo.getDom(el);
9499 el.parentNode.insertBefore(this.dom, el);
9504 * Inserts this element after the passed element in the DOM
9505 * @param {String/HTMLElement/Element} el The element to insert after
9506 * @return {Roo.Element} this
9508 insertAfter: function(el){
9509 el = Roo.getDom(el);
9510 el.parentNode.insertBefore(this.dom, el.nextSibling);
9515 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9516 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9517 * @return {Roo.Element} The new child
9519 insertFirst: function(el, returnDom){
9521 if(typeof el == 'object' && !el.nodeType){ // dh config
9522 return this.createChild(el, this.dom.firstChild, returnDom);
9524 el = Roo.getDom(el);
9525 this.dom.insertBefore(el, this.dom.firstChild);
9526 return !returnDom ? Roo.get(el) : el;
9531 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9532 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9533 * @param {String} where (optional) 'before' or 'after' defaults to before
9534 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9535 * @return {Roo.Element} the inserted Element
9537 insertSibling: function(el, where, returnDom){
9538 where = where ? where.toLowerCase() : 'before';
9540 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9542 if(typeof el == 'object' && !el.nodeType){ // dh config
9543 if(where == 'after' && !this.dom.nextSibling){
9544 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9546 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9550 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9551 where == 'before' ? this.dom : this.dom.nextSibling);
9560 * Creates and wraps this element with another element
9561 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9562 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9563 * @return {HTMLElement/Element} The newly created wrapper element
9565 wrap: function(config, returnDom){
9567 config = {tag: "div"};
9569 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9570 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9575 * Replaces the passed element with this element
9576 * @param {String/HTMLElement/Element} el The element to replace
9577 * @return {Roo.Element} this
9579 replace: function(el){
9581 this.insertBefore(el);
9587 * Inserts an html fragment into this element
9588 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9589 * @param {String} html The HTML fragment
9590 * @param {Boolean} returnEl True to return an Roo.Element
9591 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9593 insertHtml : function(where, html, returnEl){
9594 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9595 return returnEl ? Roo.get(el) : el;
9599 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9600 * @param {Object} o The object with the attributes
9601 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9602 * @return {Roo.Element} this
9604 set : function(o, useSet){
9606 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9608 if(attr == "style" || typeof o[attr] == "function") { continue; }
9610 el.className = o["cls"];
9613 el.setAttribute(attr, o[attr]);
9620 Roo.DomHelper.applyStyles(el, o.style);
9626 * Convenience method for constructing a KeyMap
9627 * @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:
9628 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9629 * @param {Function} fn The function to call
9630 * @param {Object} scope (optional) The scope of the function
9631 * @return {Roo.KeyMap} The KeyMap created
9633 addKeyListener : function(key, fn, scope){
9635 if(typeof key != "object" || key instanceof Array){
9651 return new Roo.KeyMap(this, config);
9655 * Creates a KeyMap for this element
9656 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9657 * @return {Roo.KeyMap} The KeyMap created
9659 addKeyMap : function(config){
9660 return new Roo.KeyMap(this, config);
9664 * Returns true if this element is scrollable.
9667 isScrollable : function(){
9669 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9673 * 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().
9674 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9675 * @param {Number} value The new scroll value
9676 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9677 * @return {Element} this
9680 scrollTo : function(side, value, animate){
9681 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9683 this.dom[prop] = value;
9685 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9686 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9692 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9693 * within this element's scrollable range.
9694 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9695 * @param {Number} distance How far to scroll the element in pixels
9696 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9697 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9698 * was scrolled as far as it could go.
9700 scroll : function(direction, distance, animate){
9701 if(!this.isScrollable()){
9705 var l = el.scrollLeft, t = el.scrollTop;
9706 var w = el.scrollWidth, h = el.scrollHeight;
9707 var cw = el.clientWidth, ch = el.clientHeight;
9708 direction = direction.toLowerCase();
9709 var scrolled = false;
9710 var a = this.preanim(arguments, 2);
9715 var v = Math.min(l + distance, w-cw);
9716 this.scrollTo("left", v, a);
9723 var v = Math.max(l - distance, 0);
9724 this.scrollTo("left", v, a);
9732 var v = Math.max(t - distance, 0);
9733 this.scrollTo("top", v, a);
9741 var v = Math.min(t + distance, h-ch);
9742 this.scrollTo("top", v, a);
9751 * Translates the passed page coordinates into left/top css values for this element
9752 * @param {Number/Array} x The page x or an array containing [x, y]
9753 * @param {Number} y The page y
9754 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9756 translatePoints : function(x, y){
9757 if(typeof x == 'object' || x instanceof Array){
9760 var p = this.getStyle('position');
9761 var o = this.getXY();
9763 var l = parseInt(this.getStyle('left'), 10);
9764 var t = parseInt(this.getStyle('top'), 10);
9767 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9770 t = (p == "relative") ? 0 : this.dom.offsetTop;
9773 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9777 * Returns the current scroll position of the element.
9778 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9780 getScroll : function(){
9781 var d = this.dom, doc = document;
9782 if(d == doc || d == doc.body){
9783 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9784 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9785 return {left: l, top: t};
9787 return {left: d.scrollLeft, top: d.scrollTop};
9792 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9793 * are convert to standard 6 digit hex color.
9794 * @param {String} attr The css attribute
9795 * @param {String} defaultValue The default value to use when a valid color isn't found
9796 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9799 getColor : function(attr, defaultValue, prefix){
9800 var v = this.getStyle(attr);
9801 if(!v || v == "transparent" || v == "inherit") {
9802 return defaultValue;
9804 var color = typeof prefix == "undefined" ? "#" : prefix;
9805 if(v.substr(0, 4) == "rgb("){
9806 var rvs = v.slice(4, v.length -1).split(",");
9807 for(var i = 0; i < 3; i++){
9808 var h = parseInt(rvs[i]).toString(16);
9815 if(v.substr(0, 1) == "#"){
9817 for(var i = 1; i < 4; i++){
9818 var c = v.charAt(i);
9821 }else if(v.length == 7){
9822 color += v.substr(1);
9826 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9830 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9831 * gradient background, rounded corners and a 4-way shadow.
9832 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9833 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9834 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9835 * @return {Roo.Element} this
9837 boxWrap : function(cls){
9838 cls = cls || 'x-box';
9839 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9840 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9845 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9846 * @param {String} namespace The namespace in which to look for the attribute
9847 * @param {String} name The attribute name
9848 * @return {String} The attribute value
9850 getAttributeNS : Roo.isIE ? function(ns, name){
9852 var type = typeof d[ns+":"+name];
9853 if(type != 'undefined' && type != 'unknown'){
9854 return d[ns+":"+name];
9857 } : function(ns, name){
9859 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9864 * Sets or Returns the value the dom attribute value
9865 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9866 * @param {String} value (optional) The value to set the attribute to
9867 * @return {String} The attribute value
9869 attr : function(name){
9870 if (arguments.length > 1) {
9871 this.dom.setAttribute(name, arguments[1]);
9872 return arguments[1];
9874 if (typeof(name) == 'object') {
9875 for(var i in name) {
9876 this.attr(i, name[i]);
9882 if (!this.dom.hasAttribute(name)) {
9885 return this.dom.getAttribute(name);
9892 var ep = El.prototype;
9895 * Appends an event handler (Shorthand for addListener)
9896 * @param {String} eventName The type of event to append
9897 * @param {Function} fn The method the event invokes
9898 * @param {Object} scope (optional) The scope (this object) of the fn
9899 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9902 ep.on = ep.addListener;
9904 ep.mon = ep.addListener;
9907 * Removes an event handler from this element (shorthand for removeListener)
9908 * @param {String} eventName the type of event to remove
9909 * @param {Function} fn the method the event invokes
9910 * @return {Roo.Element} this
9913 ep.un = ep.removeListener;
9916 * true to automatically adjust width and height settings for box-model issues (default to true)
9918 ep.autoBoxAdjust = true;
9921 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9924 El.addUnits = function(v, defaultUnit){
9925 if(v === "" || v == "auto"){
9928 if(v === undefined){
9931 if(typeof v == "number" || !El.unitPattern.test(v)){
9932 return v + (defaultUnit || 'px');
9937 // special markup used throughout Roo when box wrapping elements
9938 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>';
9940 * Visibility mode constant - Use visibility to hide element
9946 * Visibility mode constant - Use display to hide element
9952 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9953 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9954 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9966 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9967 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9968 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9969 * @return {Element} The Element object
9972 El.get = function(el){
9974 if(!el){ return null; }
9975 if(typeof el == "string"){ // element id
9976 if(!(elm = document.getElementById(el))){
9979 if(ex = El.cache[el]){
9982 ex = El.cache[el] = new El(elm);
9985 }else if(el.tagName){ // dom element
9989 if(ex = El.cache[id]){
9992 ex = El.cache[id] = new El(el);
9995 }else if(el instanceof El){
9997 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9998 // catch case where it hasn't been appended
9999 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10002 }else if(el.isComposite){
10004 }else if(el instanceof Array){
10005 return El.select(el);
10006 }else if(el == document){
10007 // create a bogus element object representing the document object
10009 var f = function(){};
10010 f.prototype = El.prototype;
10012 docEl.dom = document;
10020 El.uncache = function(el){
10021 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10023 delete El.cache[a[i].id || a[i]];
10029 // Garbage collection - uncache elements/purge listeners on orphaned elements
10030 // so we don't hold a reference and cause the browser to retain them
10031 El.garbageCollect = function(){
10032 if(!Roo.enableGarbageCollector){
10033 clearInterval(El.collectorThread);
10036 for(var eid in El.cache){
10037 var el = El.cache[eid], d = el.dom;
10038 // -------------------------------------------------------
10039 // Determining what is garbage:
10040 // -------------------------------------------------------
10042 // dom node is null, definitely garbage
10043 // -------------------------------------------------------
10045 // no parentNode == direct orphan, definitely garbage
10046 // -------------------------------------------------------
10047 // !d.offsetParent && !document.getElementById(eid)
10048 // display none elements have no offsetParent so we will
10049 // also try to look it up by it's id. However, check
10050 // offsetParent first so we don't do unneeded lookups.
10051 // This enables collection of elements that are not orphans
10052 // directly, but somewhere up the line they have an orphan
10054 // -------------------------------------------------------
10055 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10056 delete El.cache[eid];
10057 if(d && Roo.enableListenerCollection){
10063 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10067 El.Flyweight = function(dom){
10070 El.Flyweight.prototype = El.prototype;
10072 El._flyweights = {};
10074 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10075 * the dom node can be overwritten by other code.
10076 * @param {String/HTMLElement} el The dom node or id
10077 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10078 * prevent conflicts (e.g. internally Roo uses "_internal")
10080 * @return {Element} The shared Element object
10082 El.fly = function(el, named){
10083 named = named || '_global';
10084 el = Roo.getDom(el);
10088 if(!El._flyweights[named]){
10089 El._flyweights[named] = new El.Flyweight();
10091 El._flyweights[named].dom = el;
10092 return El._flyweights[named];
10096 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10097 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10098 * Shorthand of {@link Roo.Element#get}
10099 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10100 * @return {Element} The Element object
10106 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10107 * the dom node can be overwritten by other code.
10108 * Shorthand of {@link Roo.Element#fly}
10109 * @param {String/HTMLElement} el The dom node or id
10110 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10111 * prevent conflicts (e.g. internally Roo uses "_internal")
10113 * @return {Element} The shared Element object
10119 // speedy lookup for elements never to box adjust
10120 var noBoxAdjust = Roo.isStrict ? {
10123 input:1, select:1, textarea:1
10125 if(Roo.isIE || Roo.isGecko){
10126 noBoxAdjust['button'] = 1;
10130 Roo.EventManager.on(window, 'unload', function(){
10132 delete El._flyweights;
10140 Roo.Element.selectorFunction = Roo.DomQuery.select;
10143 Roo.Element.select = function(selector, unique, root){
10145 if(typeof selector == "string"){
10146 els = Roo.Element.selectorFunction(selector, root);
10147 }else if(selector.length !== undefined){
10150 throw "Invalid selector";
10152 if(unique === true){
10153 return new Roo.CompositeElement(els);
10155 return new Roo.CompositeElementLite(els);
10159 * Selects elements based on the passed CSS selector to enable working on them as 1.
10160 * @param {String/Array} selector The CSS selector or an array of elements
10161 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10162 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10163 * @return {CompositeElementLite/CompositeElement}
10167 Roo.select = Roo.Element.select;
10184 * Ext JS Library 1.1.1
10185 * Copyright(c) 2006-2007, Ext JS, LLC.
10187 * Originally Released Under LGPL - original licence link has changed is not relivant.
10190 * <script type="text/javascript">
10195 //Notifies Element that fx methods are available
10196 Roo.enableFx = true;
10200 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10201 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10202 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10203 * Element effects to work.</p><br/>
10205 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10206 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10207 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10208 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10209 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10210 * expected results and should be done with care.</p><br/>
10212 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10213 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10216 ----- -----------------------------
10217 tl The top left corner
10218 t The center of the top edge
10219 tr The top right corner
10220 l The center of the left edge
10221 r The center of the right edge
10222 bl The bottom left corner
10223 b The center of the bottom edge
10224 br The bottom right corner
10226 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10227 * below are common options that can be passed to any Fx method.</b>
10228 * @cfg {Function} callback A function called when the effect is finished
10229 * @cfg {Object} scope The scope of the effect function
10230 * @cfg {String} easing A valid Easing value for the effect
10231 * @cfg {String} afterCls A css class to apply after the effect
10232 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10233 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10234 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10235 * effects that end with the element being visually hidden, ignored otherwise)
10236 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10237 * a function which returns such a specification that will be applied to the Element after the effect finishes
10238 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10239 * @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
10240 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10244 * Slides the element into view. An anchor point can be optionally passed to set the point of
10245 * origin for the slide effect. This function automatically handles wrapping the element with
10246 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10249 // default: slide the element in from the top
10252 // custom: slide the element in from the right with a 2-second duration
10253 el.slideIn('r', { duration: 2 });
10255 // common config options shown with default values
10261 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10262 * @param {Object} options (optional) Object literal with any of the Fx config options
10263 * @return {Roo.Element} The Element
10265 slideIn : function(anchor, o){
10266 var el = this.getFxEl();
10269 el.queueFx(o, function(){
10271 anchor = anchor || "t";
10273 // fix display to visibility
10276 // restore values after effect
10277 var r = this.getFxRestore();
10278 var b = this.getBox();
10279 // fixed size for slide
10283 var wrap = this.fxWrap(r.pos, o, "hidden");
10285 var st = this.dom.style;
10286 st.visibility = "visible";
10287 st.position = "absolute";
10289 // clear out temp styles after slide and unwrap
10290 var after = function(){
10291 el.fxUnwrap(wrap, r.pos, o);
10292 st.width = r.width;
10293 st.height = r.height;
10296 // time to calc the positions
10297 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10299 switch(anchor.toLowerCase()){
10301 wrap.setSize(b.width, 0);
10302 st.left = st.bottom = "0";
10306 wrap.setSize(0, b.height);
10307 st.right = st.top = "0";
10311 wrap.setSize(0, b.height);
10312 wrap.setX(b.right);
10313 st.left = st.top = "0";
10314 a = {width: bw, points: pt};
10317 wrap.setSize(b.width, 0);
10318 wrap.setY(b.bottom);
10319 st.left = st.top = "0";
10320 a = {height: bh, points: pt};
10323 wrap.setSize(0, 0);
10324 st.right = st.bottom = "0";
10325 a = {width: bw, height: bh};
10328 wrap.setSize(0, 0);
10329 wrap.setY(b.y+b.height);
10330 st.right = st.top = "0";
10331 a = {width: bw, height: bh, points: pt};
10334 wrap.setSize(0, 0);
10335 wrap.setXY([b.right, b.bottom]);
10336 st.left = st.top = "0";
10337 a = {width: bw, height: bh, points: pt};
10340 wrap.setSize(0, 0);
10341 wrap.setX(b.x+b.width);
10342 st.left = st.bottom = "0";
10343 a = {width: bw, height: bh, points: pt};
10346 this.dom.style.visibility = "visible";
10349 arguments.callee.anim = wrap.fxanim(a,
10359 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10360 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10361 * 'hidden') but block elements will still take up space in the document. The element must be removed
10362 * from the DOM using the 'remove' config option if desired. This function automatically handles
10363 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10366 // default: slide the element out to the top
10369 // custom: slide the element out to the right with a 2-second duration
10370 el.slideOut('r', { duration: 2 });
10372 // common config options shown with default values
10380 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10381 * @param {Object} options (optional) Object literal with any of the Fx config options
10382 * @return {Roo.Element} The Element
10384 slideOut : function(anchor, o){
10385 var el = this.getFxEl();
10388 el.queueFx(o, function(){
10390 anchor = anchor || "t";
10392 // restore values after effect
10393 var r = this.getFxRestore();
10395 var b = this.getBox();
10396 // fixed size for slide
10400 var wrap = this.fxWrap(r.pos, o, "visible");
10402 var st = this.dom.style;
10403 st.visibility = "visible";
10404 st.position = "absolute";
10408 var after = function(){
10410 el.setDisplayed(false);
10415 el.fxUnwrap(wrap, r.pos, o);
10417 st.width = r.width;
10418 st.height = r.height;
10423 var a, zero = {to: 0};
10424 switch(anchor.toLowerCase()){
10426 st.left = st.bottom = "0";
10427 a = {height: zero};
10430 st.right = st.top = "0";
10434 st.left = st.top = "0";
10435 a = {width: zero, points: {to:[b.right, b.y]}};
10438 st.left = st.top = "0";
10439 a = {height: zero, points: {to:[b.x, b.bottom]}};
10442 st.right = st.bottom = "0";
10443 a = {width: zero, height: zero};
10446 st.right = st.top = "0";
10447 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10450 st.left = st.top = "0";
10451 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10454 st.left = st.bottom = "0";
10455 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10459 arguments.callee.anim = wrap.fxanim(a,
10469 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10470 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10471 * The element must be removed from the DOM using the 'remove' config option if desired.
10477 // common config options shown with default values
10485 * @param {Object} options (optional) Object literal with any of the Fx config options
10486 * @return {Roo.Element} The Element
10488 puff : function(o){
10489 var el = this.getFxEl();
10492 el.queueFx(o, function(){
10493 this.clearOpacity();
10496 // restore values after effect
10497 var r = this.getFxRestore();
10498 var st = this.dom.style;
10500 var after = function(){
10502 el.setDisplayed(false);
10509 el.setPositioning(r.pos);
10510 st.width = r.width;
10511 st.height = r.height;
10516 var width = this.getWidth();
10517 var height = this.getHeight();
10519 arguments.callee.anim = this.fxanim({
10520 width : {to: this.adjustWidth(width * 2)},
10521 height : {to: this.adjustHeight(height * 2)},
10522 points : {by: [-(width * .5), -(height * .5)]},
10524 fontSize: {to:200, unit: "%"}
10535 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10536 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10537 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10543 // all config options shown with default values
10551 * @param {Object} options (optional) Object literal with any of the Fx config options
10552 * @return {Roo.Element} The Element
10554 switchOff : function(o){
10555 var el = this.getFxEl();
10558 el.queueFx(o, function(){
10559 this.clearOpacity();
10562 // restore values after effect
10563 var r = this.getFxRestore();
10564 var st = this.dom.style;
10566 var after = function(){
10568 el.setDisplayed(false);
10574 el.setPositioning(r.pos);
10575 st.width = r.width;
10576 st.height = r.height;
10581 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10582 this.clearOpacity();
10586 points:{by:[0, this.getHeight() * .5]}
10587 }, o, 'motion', 0.3, 'easeIn', after);
10588 }).defer(100, this);
10595 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10596 * changed using the "attr" config option) and then fading back to the original color. If no original
10597 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10600 // default: highlight background to yellow
10603 // custom: highlight foreground text to blue for 2 seconds
10604 el.highlight("0000ff", { attr: 'color', duration: 2 });
10606 // common config options shown with default values
10607 el.highlight("ffff9c", {
10608 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10609 endColor: (current color) or "ffffff",
10614 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10615 * @param {Object} options (optional) Object literal with any of the Fx config options
10616 * @return {Roo.Element} The Element
10618 highlight : function(color, o){
10619 var el = this.getFxEl();
10622 el.queueFx(o, function(){
10623 color = color || "ffff9c";
10624 attr = o.attr || "backgroundColor";
10626 this.clearOpacity();
10629 var origColor = this.getColor(attr);
10630 var restoreColor = this.dom.style[attr];
10631 endColor = (o.endColor || origColor) || "ffffff";
10633 var after = function(){
10634 el.dom.style[attr] = restoreColor;
10639 a[attr] = {from: color, to: endColor};
10640 arguments.callee.anim = this.fxanim(a,
10650 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10653 // default: a single light blue ripple
10656 // custom: 3 red ripples lasting 3 seconds total
10657 el.frame("ff0000", 3, { duration: 3 });
10659 // common config options shown with default values
10660 el.frame("C3DAF9", 1, {
10661 duration: 1 //duration of entire animation (not each individual ripple)
10662 // Note: Easing is not configurable and will be ignored if included
10665 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10666 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10667 * @param {Object} options (optional) Object literal with any of the Fx config options
10668 * @return {Roo.Element} The Element
10670 frame : function(color, count, o){
10671 var el = this.getFxEl();
10674 el.queueFx(o, function(){
10675 color = color || "#C3DAF9";
10676 if(color.length == 6){
10677 color = "#" + color;
10679 count = count || 1;
10680 duration = o.duration || 1;
10683 var b = this.getBox();
10684 var animFn = function(){
10685 var proxy = this.createProxy({
10688 visbility:"hidden",
10689 position:"absolute",
10690 "z-index":"35000", // yee haw
10691 border:"0px solid " + color
10694 var scale = Roo.isBorderBox ? 2 : 1;
10696 top:{from:b.y, to:b.y - 20},
10697 left:{from:b.x, to:b.x - 20},
10698 borderWidth:{from:0, to:10},
10699 opacity:{from:1, to:0},
10700 height:{from:b.height, to:(b.height + (20*scale))},
10701 width:{from:b.width, to:(b.width + (20*scale))}
10702 }, duration, function(){
10706 animFn.defer((duration/2)*1000, this);
10717 * Creates a pause before any subsequent queued effects begin. If there are
10718 * no effects queued after the pause it will have no effect.
10723 * @param {Number} seconds The length of time to pause (in seconds)
10724 * @return {Roo.Element} The Element
10726 pause : function(seconds){
10727 var el = this.getFxEl();
10730 el.queueFx(o, function(){
10731 setTimeout(function(){
10733 }, seconds * 1000);
10739 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10740 * using the "endOpacity" config option.
10743 // default: fade in from opacity 0 to 100%
10746 // custom: fade in from opacity 0 to 75% over 2 seconds
10747 el.fadeIn({ endOpacity: .75, duration: 2});
10749 // common config options shown with default values
10751 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10756 * @param {Object} options (optional) Object literal with any of the Fx config options
10757 * @return {Roo.Element} The Element
10759 fadeIn : function(o){
10760 var el = this.getFxEl();
10762 el.queueFx(o, function(){
10763 this.setOpacity(0);
10765 this.dom.style.visibility = 'visible';
10766 var to = o.endOpacity || 1;
10767 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10768 o, null, .5, "easeOut", function(){
10770 this.clearOpacity();
10779 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10780 * using the "endOpacity" config option.
10783 // default: fade out from the element's current opacity to 0
10786 // custom: fade out from the element's current opacity to 25% over 2 seconds
10787 el.fadeOut({ endOpacity: .25, duration: 2});
10789 // common config options shown with default values
10791 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10798 * @param {Object} options (optional) Object literal with any of the Fx config options
10799 * @return {Roo.Element} The Element
10801 fadeOut : function(o){
10802 var el = this.getFxEl();
10804 el.queueFx(o, function(){
10805 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10806 o, null, .5, "easeOut", function(){
10807 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10808 this.dom.style.display = "none";
10810 this.dom.style.visibility = "hidden";
10812 this.clearOpacity();
10820 * Animates the transition of an element's dimensions from a starting height/width
10821 * to an ending height/width.
10824 // change height and width to 100x100 pixels
10825 el.scale(100, 100);
10827 // common config options shown with default values. The height and width will default to
10828 // the element's existing values if passed as null.
10831 [element's height], {
10836 * @param {Number} width The new width (pass undefined to keep the original width)
10837 * @param {Number} height The new height (pass undefined to keep the original height)
10838 * @param {Object} options (optional) Object literal with any of the Fx config options
10839 * @return {Roo.Element} The Element
10841 scale : function(w, h, o){
10842 this.shift(Roo.apply({}, o, {
10850 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10851 * Any of these properties not specified in the config object will not be changed. This effect
10852 * requires that at least one new dimension, position or opacity setting must be passed in on
10853 * the config object in order for the function to have any effect.
10856 // slide the element horizontally to x position 200 while changing the height and opacity
10857 el.shift({ x: 200, height: 50, opacity: .8 });
10859 // common config options shown with default values.
10861 width: [element's width],
10862 height: [element's height],
10863 x: [element's x position],
10864 y: [element's y position],
10865 opacity: [element's opacity],
10870 * @param {Object} options Object literal with any of the Fx config options
10871 * @return {Roo.Element} The Element
10873 shift : function(o){
10874 var el = this.getFxEl();
10876 el.queueFx(o, function(){
10877 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10878 if(w !== undefined){
10879 a.width = {to: this.adjustWidth(w)};
10881 if(h !== undefined){
10882 a.height = {to: this.adjustHeight(h)};
10884 if(x !== undefined || y !== undefined){
10886 x !== undefined ? x : this.getX(),
10887 y !== undefined ? y : this.getY()
10890 if(op !== undefined){
10891 a.opacity = {to: op};
10893 if(o.xy !== undefined){
10894 a.points = {to: o.xy};
10896 arguments.callee.anim = this.fxanim(a,
10897 o, 'motion', .35, "easeOut", function(){
10905 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10906 * ending point of the effect.
10909 // default: slide the element downward while fading out
10912 // custom: slide the element out to the right with a 2-second duration
10913 el.ghost('r', { duration: 2 });
10915 // common config options shown with default values
10923 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10924 * @param {Object} options (optional) Object literal with any of the Fx config options
10925 * @return {Roo.Element} The Element
10927 ghost : function(anchor, o){
10928 var el = this.getFxEl();
10931 el.queueFx(o, function(){
10932 anchor = anchor || "b";
10934 // restore values after effect
10935 var r = this.getFxRestore();
10936 var w = this.getWidth(),
10937 h = this.getHeight();
10939 var st = this.dom.style;
10941 var after = function(){
10943 el.setDisplayed(false);
10949 el.setPositioning(r.pos);
10950 st.width = r.width;
10951 st.height = r.height;
10956 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10957 switch(anchor.toLowerCase()){
10984 arguments.callee.anim = this.fxanim(a,
10994 * Ensures that all effects queued after syncFx is called on the element are
10995 * run concurrently. This is the opposite of {@link #sequenceFx}.
10996 * @return {Roo.Element} The Element
10998 syncFx : function(){
10999 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11008 * Ensures that all effects queued after sequenceFx is called on the element are
11009 * run in sequence. This is the opposite of {@link #syncFx}.
11010 * @return {Roo.Element} The Element
11012 sequenceFx : function(){
11013 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11015 concurrent : false,
11022 nextFx : function(){
11023 var ef = this.fxQueue[0];
11030 * Returns true if the element has any effects actively running or queued, else returns false.
11031 * @return {Boolean} True if element has active effects, else false
11033 hasActiveFx : function(){
11034 return this.fxQueue && this.fxQueue[0];
11038 * Stops any running effects and clears the element's internal effects queue if it contains
11039 * any additional effects that haven't started yet.
11040 * @return {Roo.Element} The Element
11042 stopFx : function(){
11043 if(this.hasActiveFx()){
11044 var cur = this.fxQueue[0];
11045 if(cur && cur.anim && cur.anim.isAnimated()){
11046 this.fxQueue = [cur]; // clear out others
11047 cur.anim.stop(true);
11054 beforeFx : function(o){
11055 if(this.hasActiveFx() && !o.concurrent){
11066 * Returns true if the element is currently blocking so that no other effect can be queued
11067 * until this effect is finished, else returns false if blocking is not set. This is commonly
11068 * used to ensure that an effect initiated by a user action runs to completion prior to the
11069 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11070 * @return {Boolean} True if blocking, else false
11072 hasFxBlock : function(){
11073 var q = this.fxQueue;
11074 return q && q[0] && q[0].block;
11078 queueFx : function(o, fn){
11082 if(!this.hasFxBlock()){
11083 Roo.applyIf(o, this.fxDefaults);
11085 var run = this.beforeFx(o);
11086 fn.block = o.block;
11087 this.fxQueue.push(fn);
11099 fxWrap : function(pos, o, vis){
11101 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11104 wrapXY = this.getXY();
11106 var div = document.createElement("div");
11107 div.style.visibility = vis;
11108 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11109 wrap.setPositioning(pos);
11110 if(wrap.getStyle("position") == "static"){
11111 wrap.position("relative");
11113 this.clearPositioning('auto');
11115 wrap.dom.appendChild(this.dom);
11117 wrap.setXY(wrapXY);
11124 fxUnwrap : function(wrap, pos, o){
11125 this.clearPositioning();
11126 this.setPositioning(pos);
11128 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11134 getFxRestore : function(){
11135 var st = this.dom.style;
11136 return {pos: this.getPositioning(), width: st.width, height : st.height};
11140 afterFx : function(o){
11142 this.applyStyles(o.afterStyle);
11145 this.addClass(o.afterCls);
11147 if(o.remove === true){
11150 Roo.callback(o.callback, o.scope, [this]);
11152 this.fxQueue.shift();
11158 getFxEl : function(){ // support for composite element fx
11159 return Roo.get(this.dom);
11163 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11164 animType = animType || 'run';
11166 var anim = Roo.lib.Anim[animType](
11168 (opt.duration || defaultDur) || .35,
11169 (opt.easing || defaultEase) || 'easeOut',
11171 Roo.callback(cb, this);
11180 // backwords compat
11181 Roo.Fx.resize = Roo.Fx.scale;
11183 //When included, Roo.Fx is automatically applied to Element so that all basic
11184 //effects are available directly via the Element API
11185 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11187 * Ext JS Library 1.1.1
11188 * Copyright(c) 2006-2007, Ext JS, LLC.
11190 * Originally Released Under LGPL - original licence link has changed is not relivant.
11193 * <script type="text/javascript">
11198 * @class Roo.CompositeElement
11199 * Standard composite class. Creates a Roo.Element for every element in the collection.
11201 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11202 * actions will be performed on all the elements in this collection.</b>
11204 * All methods return <i>this</i> and can be chained.
11206 var els = Roo.select("#some-el div.some-class", true);
11207 // or select directly from an existing element
11208 var el = Roo.get('some-el');
11209 el.select('div.some-class', true);
11211 els.setWidth(100); // all elements become 100 width
11212 els.hide(true); // all elements fade out and hide
11214 els.setWidth(100).hide(true);
11217 Roo.CompositeElement = function(els){
11218 this.elements = [];
11219 this.addElements(els);
11221 Roo.CompositeElement.prototype = {
11223 addElements : function(els){
11227 if(typeof els == "string"){
11228 els = Roo.Element.selectorFunction(els);
11230 var yels = this.elements;
11231 var index = yels.length-1;
11232 for(var i = 0, len = els.length; i < len; i++) {
11233 yels[++index] = Roo.get(els[i]);
11239 * Clears this composite and adds the elements returned by the passed selector.
11240 * @param {String/Array} els A string CSS selector, an array of elements or an element
11241 * @return {CompositeElement} this
11243 fill : function(els){
11244 this.elements = [];
11250 * Filters this composite to only elements that match the passed selector.
11251 * @param {String} selector A string CSS selector
11252 * @param {Boolean} inverse return inverse filter (not matches)
11253 * @return {CompositeElement} this
11255 filter : function(selector, inverse){
11257 inverse = inverse || false;
11258 this.each(function(el){
11259 var match = inverse ? !el.is(selector) : el.is(selector);
11261 els[els.length] = el.dom;
11268 invoke : function(fn, args){
11269 var els = this.elements;
11270 for(var i = 0, len = els.length; i < len; i++) {
11271 Roo.Element.prototype[fn].apply(els[i], args);
11276 * Adds elements to this composite.
11277 * @param {String/Array} els A string CSS selector, an array of elements or an element
11278 * @return {CompositeElement} this
11280 add : function(els){
11281 if(typeof els == "string"){
11282 this.addElements(Roo.Element.selectorFunction(els));
11283 }else if(els.length !== undefined){
11284 this.addElements(els);
11286 this.addElements([els]);
11291 * Calls the passed function passing (el, this, index) for each element in this composite.
11292 * @param {Function} fn The function to call
11293 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11294 * @return {CompositeElement} this
11296 each : function(fn, scope){
11297 var els = this.elements;
11298 for(var i = 0, len = els.length; i < len; i++){
11299 if(fn.call(scope || els[i], els[i], this, i) === false) {
11307 * Returns the Element object at the specified index
11308 * @param {Number} index
11309 * @return {Roo.Element}
11311 item : function(index){
11312 return this.elements[index] || null;
11316 * Returns the first Element
11317 * @return {Roo.Element}
11319 first : function(){
11320 return this.item(0);
11324 * Returns the last Element
11325 * @return {Roo.Element}
11328 return this.item(this.elements.length-1);
11332 * Returns the number of elements in this composite
11335 getCount : function(){
11336 return this.elements.length;
11340 * Returns true if this composite contains the passed element
11343 contains : function(el){
11344 return this.indexOf(el) !== -1;
11348 * Returns true if this composite contains the passed element
11351 indexOf : function(el){
11352 return this.elements.indexOf(Roo.get(el));
11357 * Removes the specified element(s).
11358 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11359 * or an array of any of those.
11360 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11361 * @return {CompositeElement} this
11363 removeElement : function(el, removeDom){
11364 if(el instanceof Array){
11365 for(var i = 0, len = el.length; i < len; i++){
11366 this.removeElement(el[i]);
11370 var index = typeof el == 'number' ? el : this.indexOf(el);
11373 var d = this.elements[index];
11377 d.parentNode.removeChild(d);
11380 this.elements.splice(index, 1);
11386 * Replaces the specified element with the passed element.
11387 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11389 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11390 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11391 * @return {CompositeElement} this
11393 replaceElement : function(el, replacement, domReplace){
11394 var index = typeof el == 'number' ? el : this.indexOf(el);
11397 this.elements[index].replaceWith(replacement);
11399 this.elements.splice(index, 1, Roo.get(replacement))
11406 * Removes all elements.
11408 clear : function(){
11409 this.elements = [];
11413 Roo.CompositeElement.createCall = function(proto, fnName){
11414 if(!proto[fnName]){
11415 proto[fnName] = function(){
11416 return this.invoke(fnName, arguments);
11420 for(var fnName in Roo.Element.prototype){
11421 if(typeof Roo.Element.prototype[fnName] == "function"){
11422 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11428 * Ext JS Library 1.1.1
11429 * Copyright(c) 2006-2007, Ext JS, LLC.
11431 * Originally Released Under LGPL - original licence link has changed is not relivant.
11434 * <script type="text/javascript">
11438 * @class Roo.CompositeElementLite
11439 * @extends Roo.CompositeElement
11440 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11442 var els = Roo.select("#some-el div.some-class");
11443 // or select directly from an existing element
11444 var el = Roo.get('some-el');
11445 el.select('div.some-class');
11447 els.setWidth(100); // all elements become 100 width
11448 els.hide(true); // all elements fade out and hide
11450 els.setWidth(100).hide(true);
11451 </code></pre><br><br>
11452 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11453 * actions will be performed on all the elements in this collection.</b>
11455 Roo.CompositeElementLite = function(els){
11456 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11457 this.el = new Roo.Element.Flyweight();
11459 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11460 addElements : function(els){
11462 if(els instanceof Array){
11463 this.elements = this.elements.concat(els);
11465 var yels = this.elements;
11466 var index = yels.length-1;
11467 for(var i = 0, len = els.length; i < len; i++) {
11468 yels[++index] = els[i];
11474 invoke : function(fn, args){
11475 var els = this.elements;
11477 for(var i = 0, len = els.length; i < len; i++) {
11479 Roo.Element.prototype[fn].apply(el, args);
11484 * Returns a flyweight Element of the dom element object at the specified index
11485 * @param {Number} index
11486 * @return {Roo.Element}
11488 item : function(index){
11489 if(!this.elements[index]){
11492 this.el.dom = this.elements[index];
11496 // fixes scope with flyweight
11497 addListener : function(eventName, handler, scope, opt){
11498 var els = this.elements;
11499 for(var i = 0, len = els.length; i < len; i++) {
11500 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11506 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11507 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11508 * a reference to the dom node, use el.dom.</b>
11509 * @param {Function} fn The function to call
11510 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11511 * @return {CompositeElement} this
11513 each : function(fn, scope){
11514 var els = this.elements;
11516 for(var i = 0, len = els.length; i < len; i++){
11518 if(fn.call(scope || el, el, this, i) === false){
11525 indexOf : function(el){
11526 return this.elements.indexOf(Roo.getDom(el));
11529 replaceElement : function(el, replacement, domReplace){
11530 var index = typeof el == 'number' ? el : this.indexOf(el);
11532 replacement = Roo.getDom(replacement);
11534 var d = this.elements[index];
11535 d.parentNode.insertBefore(replacement, d);
11536 d.parentNode.removeChild(d);
11538 this.elements.splice(index, 1, replacement);
11543 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11547 * Ext JS Library 1.1.1
11548 * Copyright(c) 2006-2007, Ext JS, LLC.
11550 * Originally Released Under LGPL - original licence link has changed is not relivant.
11553 * <script type="text/javascript">
11559 * @class Roo.data.Connection
11560 * @extends Roo.util.Observable
11561 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11562 * either to a configured URL, or to a URL specified at request time.
11564 * Requests made by this class are asynchronous, and will return immediately. No data from
11565 * the server will be available to the statement immediately following the {@link #request} call.
11566 * To process returned data, use a callback in the request options object, or an event listener.
11568 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11569 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11570 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11571 * property and, if present, the IFRAME's XML document as the responseXML property.
11573 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11574 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11575 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11576 * standard DOM methods.
11578 * @param {Object} config a configuration object.
11580 Roo.data.Connection = function(config){
11581 Roo.apply(this, config);
11584 * @event beforerequest
11585 * Fires before a network request is made to retrieve a data object.
11586 * @param {Connection} conn This Connection object.
11587 * @param {Object} options The options config object passed to the {@link #request} method.
11589 "beforerequest" : true,
11591 * @event requestcomplete
11592 * Fires if the request was successfully completed.
11593 * @param {Connection} conn This Connection object.
11594 * @param {Object} response The XHR object containing the response data.
11595 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11596 * @param {Object} options The options config object passed to the {@link #request} method.
11598 "requestcomplete" : true,
11600 * @event requestexception
11601 * Fires if an error HTTP status was returned from the server.
11602 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11603 * @param {Connection} conn This Connection object.
11604 * @param {Object} response The XHR object containing the response data.
11605 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11606 * @param {Object} options The options config object passed to the {@link #request} method.
11608 "requestexception" : true
11610 Roo.data.Connection.superclass.constructor.call(this);
11613 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11615 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11618 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11619 * extra parameters to each request made by this object. (defaults to undefined)
11622 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11623 * to each request made by this object. (defaults to undefined)
11626 * @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)
11629 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11633 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11639 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11642 disableCaching: true,
11645 * Sends an HTTP request to a remote server.
11646 * @param {Object} options An object which may contain the following properties:<ul>
11647 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11648 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11649 * request, a url encoded string or a function to call to get either.</li>
11650 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11651 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11652 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11653 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11654 * <li>options {Object} The parameter to the request call.</li>
11655 * <li>success {Boolean} True if the request succeeded.</li>
11656 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11658 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11659 * The callback is passed the following parameters:<ul>
11660 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11661 * <li>options {Object} The parameter to the request call.</li>
11663 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11664 * The callback is passed the following parameters:<ul>
11665 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11666 * <li>options {Object} The parameter to the request call.</li>
11668 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11669 * for the callback function. Defaults to the browser window.</li>
11670 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11671 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11672 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11673 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11674 * params for the post data. Any params will be appended to the URL.</li>
11675 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11677 * @return {Number} transactionId
11679 request : function(o){
11680 if(this.fireEvent("beforerequest", this, o) !== false){
11683 if(typeof p == "function"){
11684 p = p.call(o.scope||window, o);
11686 if(typeof p == "object"){
11687 p = Roo.urlEncode(o.params);
11689 if(this.extraParams){
11690 var extras = Roo.urlEncode(this.extraParams);
11691 p = p ? (p + '&' + extras) : extras;
11694 var url = o.url || this.url;
11695 if(typeof url == 'function'){
11696 url = url.call(o.scope||window, o);
11700 var form = Roo.getDom(o.form);
11701 url = url || form.action;
11703 var enctype = form.getAttribute("enctype");
11706 return this.doFormDataUpload(o, url);
11709 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11710 return this.doFormUpload(o, p, url);
11712 var f = Roo.lib.Ajax.serializeForm(form);
11713 p = p ? (p + '&' + f) : f;
11716 if (!o.form && o.formData) {
11717 o.formData = o.formData === true ? new FormData() : o.formData;
11718 for (var k in o.params) {
11719 o.formData.append(k,o.params[k]);
11722 return this.doFormDataUpload(o, url);
11726 var hs = o.headers;
11727 if(this.defaultHeaders){
11728 hs = Roo.apply(hs || {}, this.defaultHeaders);
11735 success: this.handleResponse,
11736 failure: this.handleFailure,
11738 argument: {options: o},
11739 timeout : o.timeout || this.timeout
11742 var method = o.method||this.method||(p ? "POST" : "GET");
11744 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11745 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11748 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11752 }else if(this.autoAbort !== false){
11756 if((method == 'GET' && p) || o.xmlData){
11757 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11760 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11761 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11762 Roo.lib.Ajax.useDefaultHeader == true;
11763 return this.transId;
11765 Roo.callback(o.callback, o.scope, [o, null, null]);
11771 * Determine whether this object has a request outstanding.
11772 * @param {Number} transactionId (Optional) defaults to the last transaction
11773 * @return {Boolean} True if there is an outstanding request.
11775 isLoading : function(transId){
11777 return Roo.lib.Ajax.isCallInProgress(transId);
11779 return this.transId ? true : false;
11784 * Aborts any outstanding request.
11785 * @param {Number} transactionId (Optional) defaults to the last transaction
11787 abort : function(transId){
11788 if(transId || this.isLoading()){
11789 Roo.lib.Ajax.abort(transId || this.transId);
11794 handleResponse : function(response){
11795 this.transId = false;
11796 var options = response.argument.options;
11797 response.argument = options ? options.argument : null;
11798 this.fireEvent("requestcomplete", this, response, options);
11799 Roo.callback(options.success, options.scope, [response, options]);
11800 Roo.callback(options.callback, options.scope, [options, true, response]);
11804 handleFailure : function(response, e){
11805 this.transId = false;
11806 var options = response.argument.options;
11807 response.argument = options ? options.argument : null;
11808 this.fireEvent("requestexception", this, response, options, e);
11809 Roo.callback(options.failure, options.scope, [response, options]);
11810 Roo.callback(options.callback, options.scope, [options, false, response]);
11814 doFormUpload : function(o, ps, url){
11816 var frame = document.createElement('iframe');
11819 frame.className = 'x-hidden';
11821 frame.src = Roo.SSL_SECURE_URL;
11823 document.body.appendChild(frame);
11826 document.frames[id].name = id;
11829 var form = Roo.getDom(o.form);
11831 form.method = 'POST';
11832 form.enctype = form.encoding = 'multipart/form-data';
11838 if(ps){ // add dynamic params
11840 ps = Roo.urlDecode(ps, false);
11842 if(ps.hasOwnProperty(k)){
11843 hd = document.createElement('input');
11844 hd.type = 'hidden';
11847 form.appendChild(hd);
11854 var r = { // bogus response object
11859 r.argument = o ? o.argument : null;
11864 doc = frame.contentWindow.document;
11866 doc = (frame.contentDocument || window.frames[id].document);
11868 if(doc && doc.body){
11869 r.responseText = doc.body.innerHTML;
11871 if(doc && doc.XMLDocument){
11872 r.responseXML = doc.XMLDocument;
11874 r.responseXML = doc;
11881 Roo.EventManager.removeListener(frame, 'load', cb, this);
11883 this.fireEvent("requestcomplete", this, r, o);
11884 Roo.callback(o.success, o.scope, [r, o]);
11885 Roo.callback(o.callback, o.scope, [o, true, r]);
11887 setTimeout(function(){document.body.removeChild(frame);}, 100);
11890 Roo.EventManager.on(frame, 'load', cb, this);
11893 if(hiddens){ // remove dynamic params
11894 for(var i = 0, len = hiddens.length; i < len; i++){
11895 form.removeChild(hiddens[i]);
11899 // this is a 'formdata version???'
11902 doFormDataUpload : function(o, url)
11906 var form = Roo.getDom(o.form);
11907 form.enctype = form.encoding = 'multipart/form-data';
11908 formData = o.formData === true ? new FormData(form) : o.formData;
11910 formData = o.formData === true ? new FormData() : o.formData;
11915 success: this.handleResponse,
11916 failure: this.handleFailure,
11918 argument: {options: o},
11919 timeout : o.timeout || this.timeout
11922 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11926 }else if(this.autoAbort !== false){
11930 //Roo.lib.Ajax.defaultPostHeader = null;
11931 Roo.lib.Ajax.useDefaultHeader = false;
11932 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11933 Roo.lib.Ajax.useDefaultHeader = true;
11941 * Ext JS Library 1.1.1
11942 * Copyright(c) 2006-2007, Ext JS, LLC.
11944 * Originally Released Under LGPL - original licence link has changed is not relivant.
11947 * <script type="text/javascript">
11951 * Global Ajax request class.
11954 * @extends Roo.data.Connection
11957 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11958 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11959 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11960 * @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)
11961 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11962 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11963 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11965 Roo.Ajax = new Roo.data.Connection({
11974 * Serialize the passed form into a url encoded string
11976 * @param {String/HTMLElement} form
11979 serializeForm : function(form){
11980 return Roo.lib.Ajax.serializeForm(form);
11984 * Ext JS Library 1.1.1
11985 * Copyright(c) 2006-2007, Ext JS, LLC.
11987 * Originally Released Under LGPL - original licence link has changed is not relivant.
11990 * <script type="text/javascript">
11995 * @class Roo.UpdateManager
11996 * @extends Roo.util.Observable
11997 * Provides AJAX-style update for Element object.<br><br>
12000 * // Get it from a Roo.Element object
12001 * var el = Roo.get("foo");
12002 * var mgr = el.getUpdateManager();
12003 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
12005 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12007 * // or directly (returns the same UpdateManager instance)
12008 * var mgr = new Roo.UpdateManager("myElementId");
12009 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12010 * mgr.on("update", myFcnNeedsToKnow);
12012 // short handed call directly from the element object
12013 Roo.get("foo").load({
12017 text: "Loading Foo..."
12021 * Create new UpdateManager directly.
12022 * @param {String/HTMLElement/Roo.Element} el The element to update
12023 * @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).
12025 Roo.UpdateManager = function(el, forceNew){
12027 if(!forceNew && el.updateManager){
12028 return el.updateManager;
12031 * The Element object
12032 * @type Roo.Element
12036 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12039 this.defaultUrl = null;
12043 * @event beforeupdate
12044 * Fired before an update is made, return false from your handler and the update is cancelled.
12045 * @param {Roo.Element} el
12046 * @param {String/Object/Function} url
12047 * @param {String/Object} params
12049 "beforeupdate": true,
12052 * Fired after successful update is made.
12053 * @param {Roo.Element} el
12054 * @param {Object} oResponseObject The response Object
12059 * Fired on update failure.
12060 * @param {Roo.Element} el
12061 * @param {Object} oResponseObject The response Object
12065 var d = Roo.UpdateManager.defaults;
12067 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12070 this.sslBlankUrl = d.sslBlankUrl;
12072 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12075 this.disableCaching = d.disableCaching;
12077 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12080 this.indicatorText = d.indicatorText;
12082 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12085 this.showLoadIndicator = d.showLoadIndicator;
12087 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12090 this.timeout = d.timeout;
12093 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12096 this.loadScripts = d.loadScripts;
12099 * Transaction object of current executing transaction
12101 this.transaction = null;
12106 this.autoRefreshProcId = null;
12108 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12111 this.refreshDelegate = this.refresh.createDelegate(this);
12113 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12116 this.updateDelegate = this.update.createDelegate(this);
12118 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12121 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12125 this.successDelegate = this.processSuccess.createDelegate(this);
12129 this.failureDelegate = this.processFailure.createDelegate(this);
12131 if(!this.renderer){
12133 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12135 this.renderer = new Roo.UpdateManager.BasicRenderer();
12138 Roo.UpdateManager.superclass.constructor.call(this);
12141 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12143 * Get the Element this UpdateManager is bound to
12144 * @return {Roo.Element} The element
12146 getEl : function(){
12150 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12151 * @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:
12154 url: "your-url.php",<br/>
12155 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12156 callback: yourFunction,<br/>
12157 scope: yourObject, //(optional scope) <br/>
12158 discardUrl: false, <br/>
12159 nocache: false,<br/>
12160 text: "Loading...",<br/>
12162 scripts: false<br/>
12165 * The only required property is url. The optional properties nocache, text and scripts
12166 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12167 * @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}
12168 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12169 * @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.
12171 update : function(url, params, callback, discardUrl){
12172 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12173 var method = this.method,
12175 if(typeof url == "object"){ // must be config object
12178 params = params || cfg.params;
12179 callback = callback || cfg.callback;
12180 discardUrl = discardUrl || cfg.discardUrl;
12181 if(callback && cfg.scope){
12182 callback = callback.createDelegate(cfg.scope);
12184 if(typeof cfg.method != "undefined"){method = cfg.method;};
12185 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12186 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12187 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12188 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12190 this.showLoading();
12192 this.defaultUrl = url;
12194 if(typeof url == "function"){
12195 url = url.call(this);
12198 method = method || (params ? "POST" : "GET");
12199 if(method == "GET"){
12200 url = this.prepareUrl(url);
12203 var o = Roo.apply(cfg ||{}, {
12206 success: this.successDelegate,
12207 failure: this.failureDelegate,
12208 callback: undefined,
12209 timeout: (this.timeout*1000),
12210 argument: {"url": url, "form": null, "callback": callback, "params": params}
12212 Roo.log("updated manager called with timeout of " + o.timeout);
12213 this.transaction = Roo.Ajax.request(o);
12218 * 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.
12219 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12220 * @param {String/HTMLElement} form The form Id or form element
12221 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12222 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12223 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12225 formUpdate : function(form, url, reset, callback){
12226 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12227 if(typeof url == "function"){
12228 url = url.call(this);
12230 form = Roo.getDom(form);
12231 this.transaction = Roo.Ajax.request({
12234 success: this.successDelegate,
12235 failure: this.failureDelegate,
12236 timeout: (this.timeout*1000),
12237 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12239 this.showLoading.defer(1, this);
12244 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12245 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12247 refresh : function(callback){
12248 if(this.defaultUrl == null){
12251 this.update(this.defaultUrl, null, callback, true);
12255 * Set this element to auto refresh.
12256 * @param {Number} interval How often to update (in seconds).
12257 * @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)
12258 * @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}
12259 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12260 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12262 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12264 this.update(url || this.defaultUrl, params, callback, true);
12266 if(this.autoRefreshProcId){
12267 clearInterval(this.autoRefreshProcId);
12269 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12273 * Stop auto refresh on this element.
12275 stopAutoRefresh : function(){
12276 if(this.autoRefreshProcId){
12277 clearInterval(this.autoRefreshProcId);
12278 delete this.autoRefreshProcId;
12282 isAutoRefreshing : function(){
12283 return this.autoRefreshProcId ? true : false;
12286 * Called to update the element to "Loading" state. Override to perform custom action.
12288 showLoading : function(){
12289 if(this.showLoadIndicator){
12290 this.el.update(this.indicatorText);
12295 * Adds unique parameter to query string if disableCaching = true
12298 prepareUrl : function(url){
12299 if(this.disableCaching){
12300 var append = "_dc=" + (new Date().getTime());
12301 if(url.indexOf("?") !== -1){
12302 url += "&" + append;
12304 url += "?" + append;
12313 processSuccess : function(response){
12314 this.transaction = null;
12315 if(response.argument.form && response.argument.reset){
12316 try{ // put in try/catch since some older FF releases had problems with this
12317 response.argument.form.reset();
12320 if(this.loadScripts){
12321 this.renderer.render(this.el, response, this,
12322 this.updateComplete.createDelegate(this, [response]));
12324 this.renderer.render(this.el, response, this);
12325 this.updateComplete(response);
12329 updateComplete : function(response){
12330 this.fireEvent("update", this.el, response);
12331 if(typeof response.argument.callback == "function"){
12332 response.argument.callback(this.el, true, response);
12339 processFailure : function(response){
12340 this.transaction = null;
12341 this.fireEvent("failure", this.el, response);
12342 if(typeof response.argument.callback == "function"){
12343 response.argument.callback(this.el, false, response);
12348 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12349 * @param {Object} renderer The object implementing the render() method
12351 setRenderer : function(renderer){
12352 this.renderer = renderer;
12355 getRenderer : function(){
12356 return this.renderer;
12360 * Set the defaultUrl used for updates
12361 * @param {String/Function} defaultUrl The url or a function to call to get the url
12363 setDefaultUrl : function(defaultUrl){
12364 this.defaultUrl = defaultUrl;
12368 * Aborts the executing transaction
12370 abort : function(){
12371 if(this.transaction){
12372 Roo.Ajax.abort(this.transaction);
12377 * Returns true if an update is in progress
12378 * @return {Boolean}
12380 isUpdating : function(){
12381 if(this.transaction){
12382 return Roo.Ajax.isLoading(this.transaction);
12389 * @class Roo.UpdateManager.defaults
12390 * @static (not really - but it helps the doc tool)
12391 * The defaults collection enables customizing the default properties of UpdateManager
12393 Roo.UpdateManager.defaults = {
12395 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12401 * True to process scripts by default (Defaults to false).
12404 loadScripts : false,
12407 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12410 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12412 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12415 disableCaching : false,
12417 * Whether to show indicatorText when loading (Defaults to true).
12420 showLoadIndicator : true,
12422 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12425 indicatorText : '<div class="loading-indicator">Loading...</div>'
12429 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12431 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12432 * @param {String/HTMLElement/Roo.Element} el The element to update
12433 * @param {String} url The url
12434 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12435 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12438 * @member Roo.UpdateManager
12440 Roo.UpdateManager.updateElement = function(el, url, params, options){
12441 var um = Roo.get(el, true).getUpdateManager();
12442 Roo.apply(um, options);
12443 um.update(url, params, options ? options.callback : null);
12445 // alias for backwards compat
12446 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12448 * @class Roo.UpdateManager.BasicRenderer
12449 * Default Content renderer. Updates the elements innerHTML with the responseText.
12451 Roo.UpdateManager.BasicRenderer = function(){};
12453 Roo.UpdateManager.BasicRenderer.prototype = {
12455 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12456 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12457 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12458 * @param {Roo.Element} el The element being rendered
12459 * @param {Object} response The YUI Connect response object
12460 * @param {UpdateManager} updateManager The calling update manager
12461 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12463 render : function(el, response, updateManager, callback){
12464 el.update(response.responseText, updateManager.loadScripts, callback);
12470 * (c)) Alan Knowles
12476 * @class Roo.DomTemplate
12477 * @extends Roo.Template
12478 * An effort at a dom based template engine..
12480 * Similar to XTemplate, except it uses dom parsing to create the template..
12482 * Supported features:
12487 {a_variable} - output encoded.
12488 {a_variable.format:("Y-m-d")} - call a method on the variable
12489 {a_variable:raw} - unencoded output
12490 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12491 {a_variable:this.method_on_template(...)} - call a method on the template object.
12496 <div roo-for="a_variable or condition.."></div>
12497 <div roo-if="a_variable or condition"></div>
12498 <div roo-exec="some javascript"></div>
12499 <div roo-name="named_template"></div>
12504 Roo.DomTemplate = function()
12506 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12513 Roo.extend(Roo.DomTemplate, Roo.Template, {
12515 * id counter for sub templates.
12519 * flag to indicate if dom parser is inside a pre,
12520 * it will strip whitespace if not.
12525 * The various sub templates
12533 * basic tag replacing syntax
12536 * // you can fake an object call by doing this
12540 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12541 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12543 iterChild : function (node, method) {
12545 var oldPre = this.inPre;
12546 if (node.tagName == 'PRE') {
12549 for( var i = 0; i < node.childNodes.length; i++) {
12550 method.call(this, node.childNodes[i]);
12552 this.inPre = oldPre;
12558 * compile the template
12560 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12563 compile: function()
12567 // covert the html into DOM...
12571 doc = document.implementation.createHTMLDocument("");
12572 doc.documentElement.innerHTML = this.html ;
12573 div = doc.documentElement;
12575 // old IE... - nasty -- it causes all sorts of issues.. with
12576 // images getting pulled from server..
12577 div = document.createElement('div');
12578 div.innerHTML = this.html;
12580 //doc.documentElement.innerHTML = htmlBody
12586 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12588 var tpls = this.tpls;
12590 // create a top level template from the snippet..
12592 //Roo.log(div.innerHTML);
12599 body : div.innerHTML,
12612 Roo.each(tpls, function(tp){
12613 this.compileTpl(tp);
12614 this.tpls[tp.id] = tp;
12617 this.master = tpls[0];
12623 compileNode : function(node, istop) {
12628 // skip anything not a tag..
12629 if (node.nodeType != 1) {
12630 if (node.nodeType == 3 && !this.inPre) {
12631 // reduce white space..
12632 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12655 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12656 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12657 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12658 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12664 // just itterate children..
12665 this.iterChild(node,this.compileNode);
12668 tpl.uid = this.id++;
12669 tpl.value = node.getAttribute('roo-' + tpl.attr);
12670 node.removeAttribute('roo-'+ tpl.attr);
12671 if (tpl.attr != 'name') {
12672 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12673 node.parentNode.replaceChild(placeholder, node);
12676 var placeholder = document.createElement('span');
12677 placeholder.className = 'roo-tpl-' + tpl.value;
12678 node.parentNode.replaceChild(placeholder, node);
12681 // parent now sees '{domtplXXXX}
12682 this.iterChild(node,this.compileNode);
12684 // we should now have node body...
12685 var div = document.createElement('div');
12686 div.appendChild(node);
12688 // this has the unfortunate side effect of converting tagged attributes
12689 // eg. href="{...}" into %7C...%7D
12690 // this has been fixed by searching for those combo's although it's a bit hacky..
12693 tpl.body = div.innerHTML;
12700 switch (tpl.value) {
12701 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12702 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12703 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12708 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12712 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12716 tpl.id = tpl.value; // replace non characters???
12722 this.tpls.push(tpl);
12732 * Compile a segment of the template into a 'sub-template'
12738 compileTpl : function(tpl)
12740 var fm = Roo.util.Format;
12741 var useF = this.disableFormats !== true;
12743 var sep = Roo.isGecko ? "+\n" : ",\n";
12745 var undef = function(str) {
12746 Roo.debug && Roo.log("Property not found :" + str);
12750 //Roo.log(tpl.body);
12754 var fn = function(m, lbrace, name, format, args)
12757 //Roo.log(arguments);
12758 args = args ? args.replace(/\\'/g,"'") : args;
12759 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12760 if (typeof(format) == 'undefined') {
12761 format = 'htmlEncode';
12763 if (format == 'raw' ) {
12767 if(name.substr(0, 6) == 'domtpl'){
12768 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12771 // build an array of options to determine if value is undefined..
12773 // basically get 'xxxx.yyyy' then do
12774 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12775 // (function () { Roo.log("Property not found"); return ''; })() :
12780 Roo.each(name.split('.'), function(st) {
12781 lookfor += (lookfor.length ? '.': '') + st;
12782 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12785 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12788 if(format && useF){
12790 args = args ? ',' + args : "";
12792 if(format.substr(0, 5) != "this."){
12793 format = "fm." + format + '(';
12795 format = 'this.call("'+ format.substr(5) + '", ';
12799 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12802 if (args && args.length) {
12803 // called with xxyx.yuu:(test,test)
12805 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12807 // raw.. - :raw modifier..
12808 return "'"+ sep + udef_st + name + ")"+sep+"'";
12812 // branched to use + in gecko and [].join() in others
12814 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12815 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12818 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12819 body.push(tpl.body.replace(/(\r\n|\n)/g,
12820 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12821 body.push("'].join('');};};");
12822 body = body.join('');
12825 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12827 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12834 * same as applyTemplate, except it's done to one of the subTemplates
12835 * when using named templates, you can do:
12837 * var str = pl.applySubTemplate('your-name', values);
12840 * @param {Number} id of the template
12841 * @param {Object} values to apply to template
12842 * @param {Object} parent (normaly the instance of this object)
12844 applySubTemplate : function(id, values, parent)
12848 var t = this.tpls[id];
12852 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12853 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12857 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12864 if(t.execCall && t.execCall.call(this, values, parent)){
12868 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12874 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12875 parent = t.target ? values : parent;
12876 if(t.forCall && vs instanceof Array){
12878 for(var i = 0, len = vs.length; i < len; i++){
12880 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12882 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12884 //Roo.log(t.compiled);
12888 return buf.join('');
12891 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12896 return t.compiled.call(this, vs, parent);
12898 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12900 //Roo.log(t.compiled);
12908 applyTemplate : function(values){
12909 return this.master.compiled.call(this, values, {});
12910 //var s = this.subs;
12913 apply : function(){
12914 return this.applyTemplate.apply(this, arguments);
12919 Roo.DomTemplate.from = function(el){
12920 el = Roo.getDom(el);
12921 return new Roo.Domtemplate(el.value || el.innerHTML);
12924 * Ext JS Library 1.1.1
12925 * Copyright(c) 2006-2007, Ext JS, LLC.
12927 * Originally Released Under LGPL - original licence link has changed is not relivant.
12930 * <script type="text/javascript">
12934 * @class Roo.util.DelayedTask
12935 * Provides a convenient method of performing setTimeout where a new
12936 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12937 * You can use this class to buffer
12938 * the keypress events for a certain number of milliseconds, and perform only if they stop
12939 * for that amount of time.
12940 * @constructor The parameters to this constructor serve as defaults and are not required.
12941 * @param {Function} fn (optional) The default function to timeout
12942 * @param {Object} scope (optional) The default scope of that timeout
12943 * @param {Array} args (optional) The default Array of arguments
12945 Roo.util.DelayedTask = function(fn, scope, args){
12946 var id = null, d, t;
12948 var call = function(){
12949 var now = new Date().getTime();
12953 fn.apply(scope, args || []);
12957 * Cancels any pending timeout and queues a new one
12958 * @param {Number} delay The milliseconds to delay
12959 * @param {Function} newFn (optional) Overrides function passed to constructor
12960 * @param {Object} newScope (optional) Overrides scope passed to constructor
12961 * @param {Array} newArgs (optional) Overrides args passed to constructor
12963 this.delay = function(delay, newFn, newScope, newArgs){
12964 if(id && delay != d){
12968 t = new Date().getTime();
12970 scope = newScope || scope;
12971 args = newArgs || args;
12973 id = setInterval(call, d);
12978 * Cancel the last queued timeout
12980 this.cancel = function(){
12988 * Ext JS Library 1.1.1
12989 * Copyright(c) 2006-2007, Ext JS, LLC.
12991 * Originally Released Under LGPL - original licence link has changed is not relivant.
12994 * <script type="text/javascript">
12998 Roo.util.TaskRunner = function(interval){
12999 interval = interval || 10;
13000 var tasks = [], removeQueue = [];
13002 var running = false;
13004 var stopThread = function(){
13010 var startThread = function(){
13013 id = setInterval(runTasks, interval);
13017 var removeTask = function(task){
13018 removeQueue.push(task);
13024 var runTasks = function(){
13025 if(removeQueue.length > 0){
13026 for(var i = 0, len = removeQueue.length; i < len; i++){
13027 tasks.remove(removeQueue[i]);
13030 if(tasks.length < 1){
13035 var now = new Date().getTime();
13036 for(var i = 0, len = tasks.length; i < len; ++i){
13038 var itime = now - t.taskRunTime;
13039 if(t.interval <= itime){
13040 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13041 t.taskRunTime = now;
13042 if(rt === false || t.taskRunCount === t.repeat){
13047 if(t.duration && t.duration <= (now - t.taskStartTime)){
13054 * Queues a new task.
13055 * @param {Object} task
13057 this.start = function(task){
13059 task.taskStartTime = new Date().getTime();
13060 task.taskRunTime = 0;
13061 task.taskRunCount = 0;
13066 this.stop = function(task){
13071 this.stopAll = function(){
13073 for(var i = 0, len = tasks.length; i < len; i++){
13074 if(tasks[i].onStop){
13083 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13085 * Ext JS Library 1.1.1
13086 * Copyright(c) 2006-2007, Ext JS, LLC.
13088 * Originally Released Under LGPL - original licence link has changed is not relivant.
13091 * <script type="text/javascript">
13096 * @class Roo.util.MixedCollection
13097 * @extends Roo.util.Observable
13098 * A Collection class that maintains both numeric indexes and keys and exposes events.
13100 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13101 * collection (defaults to false)
13102 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13103 * and return the key value for that item. This is used when available to look up the key on items that
13104 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13105 * equivalent to providing an implementation for the {@link #getKey} method.
13107 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13115 * Fires when the collection is cleared.
13120 * Fires when an item is added to the collection.
13121 * @param {Number} index The index at which the item was added.
13122 * @param {Object} o The item added.
13123 * @param {String} key The key associated with the added item.
13128 * Fires when an item is replaced in the collection.
13129 * @param {String} key he key associated with the new added.
13130 * @param {Object} old The item being replaced.
13131 * @param {Object} new The new item.
13136 * Fires when an item is removed from the collection.
13137 * @param {Object} o The item being removed.
13138 * @param {String} key (optional) The key associated with the removed item.
13143 this.allowFunctions = allowFunctions === true;
13145 this.getKey = keyFn;
13147 Roo.util.MixedCollection.superclass.constructor.call(this);
13150 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13151 allowFunctions : false,
13154 * Adds an item to the collection.
13155 * @param {String} key The key to associate with the item
13156 * @param {Object} o The item to add.
13157 * @return {Object} The item added.
13159 add : function(key, o){
13160 if(arguments.length == 1){
13162 key = this.getKey(o);
13164 if(typeof key == "undefined" || key === null){
13166 this.items.push(o);
13167 this.keys.push(null);
13169 var old = this.map[key];
13171 return this.replace(key, o);
13174 this.items.push(o);
13176 this.keys.push(key);
13178 this.fireEvent("add", this.length-1, o, key);
13183 * MixedCollection has a generic way to fetch keys if you implement getKey.
13186 var mc = new Roo.util.MixedCollection();
13187 mc.add(someEl.dom.id, someEl);
13188 mc.add(otherEl.dom.id, otherEl);
13192 var mc = new Roo.util.MixedCollection();
13193 mc.getKey = function(el){
13199 // or via the constructor
13200 var mc = new Roo.util.MixedCollection(false, function(el){
13206 * @param o {Object} The item for which to find the key.
13207 * @return {Object} The key for the passed item.
13209 getKey : function(o){
13214 * Replaces an item in the collection.
13215 * @param {String} key The key associated with the item to replace, or the item to replace.
13216 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13217 * @return {Object} The new item.
13219 replace : function(key, o){
13220 if(arguments.length == 1){
13222 key = this.getKey(o);
13224 var old = this.item(key);
13225 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13226 return this.add(key, o);
13228 var index = this.indexOfKey(key);
13229 this.items[index] = o;
13231 this.fireEvent("replace", key, old, o);
13236 * Adds all elements of an Array or an Object to the collection.
13237 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13238 * an Array of values, each of which are added to the collection.
13240 addAll : function(objs){
13241 if(arguments.length > 1 || objs instanceof Array){
13242 var args = arguments.length > 1 ? arguments : objs;
13243 for(var i = 0, len = args.length; i < len; i++){
13247 for(var key in objs){
13248 if(this.allowFunctions || typeof objs[key] != "function"){
13249 this.add(key, objs[key]);
13256 * Executes the specified function once for every item in the collection, passing each
13257 * item as the first and only parameter. returning false from the function will stop the iteration.
13258 * @param {Function} fn The function to execute for each item.
13259 * @param {Object} scope (optional) The scope in which to execute the function.
13261 each : function(fn, scope){
13262 var items = [].concat(this.items); // each safe for removal
13263 for(var i = 0, len = items.length; i < len; i++){
13264 if(fn.call(scope || items[i], items[i], i, len) === false){
13271 * Executes the specified function once for every key in the collection, passing each
13272 * key, and its associated item as the first two parameters.
13273 * @param {Function} fn The function to execute for each item.
13274 * @param {Object} scope (optional) The scope in which to execute the function.
13276 eachKey : function(fn, scope){
13277 for(var i = 0, len = this.keys.length; i < len; i++){
13278 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13283 * Returns the first item in the collection which elicits a true return value from the
13284 * passed selection function.
13285 * @param {Function} fn The selection function to execute for each item.
13286 * @param {Object} scope (optional) The scope in which to execute the function.
13287 * @return {Object} The first item in the collection which returned true from the selection function.
13289 find : function(fn, scope){
13290 for(var i = 0, len = this.items.length; i < len; i++){
13291 if(fn.call(scope || window, this.items[i], this.keys[i])){
13292 return this.items[i];
13299 * Inserts an item at the specified index in the collection.
13300 * @param {Number} index The index to insert the item at.
13301 * @param {String} key The key to associate with the new item, or the item itself.
13302 * @param {Object} o (optional) If the second parameter was a key, the new item.
13303 * @return {Object} The item inserted.
13305 insert : function(index, key, o){
13306 if(arguments.length == 2){
13308 key = this.getKey(o);
13310 if(index >= this.length){
13311 return this.add(key, o);
13314 this.items.splice(index, 0, o);
13315 if(typeof key != "undefined" && key != null){
13318 this.keys.splice(index, 0, key);
13319 this.fireEvent("add", index, o, key);
13324 * Removed an item from the collection.
13325 * @param {Object} o The item to remove.
13326 * @return {Object} The item removed.
13328 remove : function(o){
13329 return this.removeAt(this.indexOf(o));
13333 * Remove an item from a specified index in the collection.
13334 * @param {Number} index The index within the collection of the item to remove.
13336 removeAt : function(index){
13337 if(index < this.length && index >= 0){
13339 var o = this.items[index];
13340 this.items.splice(index, 1);
13341 var key = this.keys[index];
13342 if(typeof key != "undefined"){
13343 delete this.map[key];
13345 this.keys.splice(index, 1);
13346 this.fireEvent("remove", o, key);
13351 * Removed an item associated with the passed key fom the collection.
13352 * @param {String} key The key of the item to remove.
13354 removeKey : function(key){
13355 return this.removeAt(this.indexOfKey(key));
13359 * Returns the number of items in the collection.
13360 * @return {Number} the number of items in the collection.
13362 getCount : function(){
13363 return this.length;
13367 * Returns index within the collection of the passed Object.
13368 * @param {Object} o The item to find the index of.
13369 * @return {Number} index of the item.
13371 indexOf : function(o){
13372 if(!this.items.indexOf){
13373 for(var i = 0, len = this.items.length; i < len; i++){
13374 if(this.items[i] == o) {
13380 return this.items.indexOf(o);
13385 * Returns index within the collection of the passed key.
13386 * @param {String} key The key to find the index of.
13387 * @return {Number} index of the key.
13389 indexOfKey : function(key){
13390 if(!this.keys.indexOf){
13391 for(var i = 0, len = this.keys.length; i < len; i++){
13392 if(this.keys[i] == key) {
13398 return this.keys.indexOf(key);
13403 * Returns the item associated with the passed key OR index. Key has priority over index.
13404 * @param {String/Number} key The key or index of the item.
13405 * @return {Object} The item associated with the passed key.
13407 item : function(key){
13408 if (key === 'length') {
13411 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13412 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13416 * Returns the item at the specified index.
13417 * @param {Number} index The index of the item.
13420 itemAt : function(index){
13421 return this.items[index];
13425 * Returns the item associated with the passed key.
13426 * @param {String/Number} key The key of the item.
13427 * @return {Object} The item associated with the passed key.
13429 key : function(key){
13430 return this.map[key];
13434 * Returns true if the collection contains the passed Object as an item.
13435 * @param {Object} o The Object to look for in the collection.
13436 * @return {Boolean} True if the collection contains the Object as an item.
13438 contains : function(o){
13439 return this.indexOf(o) != -1;
13443 * Returns true if the collection contains the passed Object as a key.
13444 * @param {String} key The key to look for in the collection.
13445 * @return {Boolean} True if the collection contains the Object as a key.
13447 containsKey : function(key){
13448 return typeof this.map[key] != "undefined";
13452 * Removes all items from the collection.
13454 clear : function(){
13459 this.fireEvent("clear");
13463 * Returns the first item in the collection.
13464 * @return {Object} the first item in the collection..
13466 first : function(){
13467 return this.items[0];
13471 * Returns the last item in the collection.
13472 * @return {Object} the last item in the collection..
13475 return this.items[this.length-1];
13478 _sort : function(property, dir, fn){
13479 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13480 fn = fn || function(a, b){
13483 var c = [], k = this.keys, items = this.items;
13484 for(var i = 0, len = items.length; i < len; i++){
13485 c[c.length] = {key: k[i], value: items[i], index: i};
13487 c.sort(function(a, b){
13488 var v = fn(a[property], b[property]) * dsc;
13490 v = (a.index < b.index ? -1 : 1);
13494 for(var i = 0, len = c.length; i < len; i++){
13495 items[i] = c[i].value;
13498 this.fireEvent("sort", this);
13502 * Sorts this collection with the passed comparison function
13503 * @param {String} direction (optional) "ASC" or "DESC"
13504 * @param {Function} fn (optional) comparison function
13506 sort : function(dir, fn){
13507 this._sort("value", dir, fn);
13511 * Sorts this collection by keys
13512 * @param {String} direction (optional) "ASC" or "DESC"
13513 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13515 keySort : function(dir, fn){
13516 this._sort("key", dir, fn || function(a, b){
13517 return String(a).toUpperCase()-String(b).toUpperCase();
13522 * Returns a range of items in this collection
13523 * @param {Number} startIndex (optional) defaults to 0
13524 * @param {Number} endIndex (optional) default to the last item
13525 * @return {Array} An array of items
13527 getRange : function(start, end){
13528 var items = this.items;
13529 if(items.length < 1){
13532 start = start || 0;
13533 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13536 for(var i = start; i <= end; i++) {
13537 r[r.length] = items[i];
13540 for(var i = start; i >= end; i--) {
13541 r[r.length] = items[i];
13548 * Filter the <i>objects</i> in this collection by a specific property.
13549 * Returns a new collection that has been filtered.
13550 * @param {String} property A property on your objects
13551 * @param {String/RegExp} value Either string that the property values
13552 * should start with or a RegExp to test against the property
13553 * @return {MixedCollection} The new filtered collection
13555 filter : function(property, value){
13556 if(!value.exec){ // not a regex
13557 value = String(value);
13558 if(value.length == 0){
13559 return this.clone();
13561 value = new RegExp("^" + Roo.escapeRe(value), "i");
13563 return this.filterBy(function(o){
13564 return o && value.test(o[property]);
13569 * Filter by a function. * Returns a new collection that has been filtered.
13570 * The passed function will be called with each
13571 * object in the collection. If the function returns true, the value is included
13572 * otherwise it is filtered.
13573 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13574 * @param {Object} scope (optional) The scope of the function (defaults to this)
13575 * @return {MixedCollection} The new filtered collection
13577 filterBy : function(fn, scope){
13578 var r = new Roo.util.MixedCollection();
13579 r.getKey = this.getKey;
13580 var k = this.keys, it = this.items;
13581 for(var i = 0, len = it.length; i < len; i++){
13582 if(fn.call(scope||this, it[i], k[i])){
13583 r.add(k[i], it[i]);
13590 * Creates a duplicate of this collection
13591 * @return {MixedCollection}
13593 clone : function(){
13594 var r = new Roo.util.MixedCollection();
13595 var k = this.keys, it = this.items;
13596 for(var i = 0, len = it.length; i < len; i++){
13597 r.add(k[i], it[i]);
13599 r.getKey = this.getKey;
13604 * Returns the item associated with the passed key or index.
13606 * @param {String/Number} key The key or index of the item.
13607 * @return {Object} The item associated with the passed key.
13609 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13611 * Ext JS Library 1.1.1
13612 * Copyright(c) 2006-2007, Ext JS, LLC.
13614 * Originally Released Under LGPL - original licence link has changed is not relivant.
13617 * <script type="text/javascript">
13620 * @class Roo.util.JSON
13621 * Modified version of Douglas Crockford"s json.js that doesn"t
13622 * mess with the Object prototype
13623 * http://www.json.org/js.html
13626 Roo.util.JSON = new (function(){
13627 var useHasOwn = {}.hasOwnProperty ? true : false;
13629 // crashes Safari in some instances
13630 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13632 var pad = function(n) {
13633 return n < 10 ? "0" + n : n;
13646 var encodeString = function(s){
13647 if (/["\\\x00-\x1f]/.test(s)) {
13648 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13653 c = b.charCodeAt();
13655 Math.floor(c / 16).toString(16) +
13656 (c % 16).toString(16);
13659 return '"' + s + '"';
13662 var encodeArray = function(o){
13663 var a = ["["], b, i, l = o.length, v;
13664 for (i = 0; i < l; i += 1) {
13666 switch (typeof v) {
13675 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13683 var encodeDate = function(o){
13684 return '"' + o.getFullYear() + "-" +
13685 pad(o.getMonth() + 1) + "-" +
13686 pad(o.getDate()) + "T" +
13687 pad(o.getHours()) + ":" +
13688 pad(o.getMinutes()) + ":" +
13689 pad(o.getSeconds()) + '"';
13693 * Encodes an Object, Array or other value
13694 * @param {Mixed} o The variable to encode
13695 * @return {String} The JSON string
13697 this.encode = function(o)
13699 // should this be extended to fully wrap stringify..
13701 if(typeof o == "undefined" || o === null){
13703 }else if(o instanceof Array){
13704 return encodeArray(o);
13705 }else if(o instanceof Date){
13706 return encodeDate(o);
13707 }else if(typeof o == "string"){
13708 return encodeString(o);
13709 }else if(typeof o == "number"){
13710 return isFinite(o) ? String(o) : "null";
13711 }else if(typeof o == "boolean"){
13714 var a = ["{"], b, i, v;
13716 if(!useHasOwn || o.hasOwnProperty(i)) {
13718 switch (typeof v) {
13727 a.push(this.encode(i), ":",
13728 v === null ? "null" : this.encode(v));
13739 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13740 * @param {String} json The JSON string
13741 * @return {Object} The resulting object
13743 this.decode = function(json){
13745 return /** eval:var:json */ eval("(" + json + ')');
13749 * Shorthand for {@link Roo.util.JSON#encode}
13750 * @member Roo encode
13752 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13754 * Shorthand for {@link Roo.util.JSON#decode}
13755 * @member Roo decode
13757 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13760 * Ext JS Library 1.1.1
13761 * Copyright(c) 2006-2007, Ext JS, LLC.
13763 * Originally Released Under LGPL - original licence link has changed is not relivant.
13766 * <script type="text/javascript">
13770 * @class Roo.util.Format
13771 * Reusable data formatting functions
13774 Roo.util.Format = function(){
13775 var trimRe = /^\s+|\s+$/g;
13778 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13779 * @param {String} value The string to truncate
13780 * @param {Number} length The maximum length to allow before truncating
13781 * @return {String} The converted text
13783 ellipsis : function(value, len){
13784 if(value && value.length > len){
13785 return value.substr(0, len-3)+"...";
13791 * Checks a reference and converts it to empty string if it is undefined
13792 * @param {Mixed} value Reference to check
13793 * @return {Mixed} Empty string if converted, otherwise the original value
13795 undef : function(value){
13796 return typeof value != "undefined" ? value : "";
13800 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13801 * @param {String} value The string to encode
13802 * @return {String} The encoded text
13804 htmlEncode : function(value){
13805 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13809 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13810 * @param {String} value The string to decode
13811 * @return {String} The decoded text
13813 htmlDecode : function(value){
13814 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13818 * Trims any whitespace from either side of a string
13819 * @param {String} value The text to trim
13820 * @return {String} The trimmed text
13822 trim : function(value){
13823 return String(value).replace(trimRe, "");
13827 * Returns a substring from within an original string
13828 * @param {String} value The original text
13829 * @param {Number} start The start index of the substring
13830 * @param {Number} length The length of the substring
13831 * @return {String} The substring
13833 substr : function(value, start, length){
13834 return String(value).substr(start, length);
13838 * Converts a string to all lower case letters
13839 * @param {String} value The text to convert
13840 * @return {String} The converted text
13842 lowercase : function(value){
13843 return String(value).toLowerCase();
13847 * Converts a string to all upper case letters
13848 * @param {String} value The text to convert
13849 * @return {String} The converted text
13851 uppercase : function(value){
13852 return String(value).toUpperCase();
13856 * Converts the first character only of a string to upper case
13857 * @param {String} value The text to convert
13858 * @return {String} The converted text
13860 capitalize : function(value){
13861 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13865 call : function(value, fn){
13866 if(arguments.length > 2){
13867 var args = Array.prototype.slice.call(arguments, 2);
13868 args.unshift(value);
13870 return /** eval:var:value */ eval(fn).apply(window, args);
13872 /** eval:var:value */
13873 return /** eval:var:value */ eval(fn).call(window, value);
13879 * safer version of Math.toFixed..??/
13880 * @param {Number/String} value The numeric value to format
13881 * @param {Number/String} value Decimal places
13882 * @return {String} The formatted currency string
13884 toFixed : function(v, n)
13886 // why not use to fixed - precision is buggered???
13888 return Math.round(v-0);
13890 var fact = Math.pow(10,n+1);
13891 v = (Math.round((v-0)*fact))/fact;
13892 var z = (''+fact).substring(2);
13893 if (v == Math.floor(v)) {
13894 return Math.floor(v) + '.' + z;
13897 // now just padd decimals..
13898 var ps = String(v).split('.');
13899 var fd = (ps[1] + z);
13900 var r = fd.substring(0,n);
13901 var rm = fd.substring(n);
13903 return ps[0] + '.' + r;
13905 r*=1; // turn it into a number;
13907 if (String(r).length != n) {
13910 r = String(r).substring(1); // chop the end off.
13913 return ps[0] + '.' + r;
13918 * Format a number as US currency
13919 * @param {Number/String} value The numeric value to format
13920 * @return {String} The formatted currency string
13922 usMoney : function(v){
13923 return '$' + Roo.util.Format.number(v);
13928 * eventually this should probably emulate php's number_format
13929 * @param {Number/String} value The numeric value to format
13930 * @param {Number} decimals number of decimal places
13931 * @param {String} delimiter for thousands (default comma)
13932 * @return {String} The formatted currency string
13934 number : function(v, decimals, thousandsDelimiter)
13936 // multiply and round.
13937 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13938 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13940 var mul = Math.pow(10, decimals);
13941 var zero = String(mul).substring(1);
13942 v = (Math.round((v-0)*mul))/mul;
13944 // if it's '0' number.. then
13946 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13948 var ps = v.split('.');
13951 var r = /(\d+)(\d{3})/;
13954 if(thousandsDelimiter.length != 0) {
13955 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
13960 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13961 // does not have decimals
13962 (decimals ? ('.' + zero) : '');
13965 return whole + sub ;
13969 * Parse a value into a formatted date using the specified format pattern.
13970 * @param {Mixed} value The value to format
13971 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13972 * @return {String} The formatted date string
13974 date : function(v, format){
13978 if(!(v instanceof Date)){
13979 v = new Date(Date.parse(v));
13981 return v.dateFormat(format || Roo.util.Format.defaults.date);
13985 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13986 * @param {String} format Any valid date format string
13987 * @return {Function} The date formatting function
13989 dateRenderer : function(format){
13990 return function(v){
13991 return Roo.util.Format.date(v, format);
13996 stripTagsRE : /<\/?[^>]+>/gi,
13999 * Strips all HTML tags
14000 * @param {Mixed} value The text from which to strip tags
14001 * @return {String} The stripped text
14003 stripTags : function(v){
14004 return !v ? v : String(v).replace(this.stripTagsRE, "");
14008 * Size in Mb,Gb etc.
14009 * @param {Number} value The number to be formated
14010 * @param {number} decimals how many decimal places
14011 * @return {String} the formated string
14013 size : function(value, decimals)
14015 var sizes = ['b', 'k', 'M', 'G', 'T'];
14019 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14020 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
14027 Roo.util.Format.defaults = {
14031 * Ext JS Library 1.1.1
14032 * Copyright(c) 2006-2007, Ext JS, LLC.
14034 * Originally Released Under LGPL - original licence link has changed is not relivant.
14037 * <script type="text/javascript">
14044 * @class Roo.MasterTemplate
14045 * @extends Roo.Template
14046 * Provides a template that can have child templates. The syntax is:
14048 var t = new Roo.MasterTemplate(
14049 '<select name="{name}">',
14050 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14053 t.add('options', {value: 'foo', text: 'bar'});
14054 // or you can add multiple child elements in one shot
14055 t.addAll('options', [
14056 {value: 'foo', text: 'bar'},
14057 {value: 'foo2', text: 'bar2'},
14058 {value: 'foo3', text: 'bar3'}
14060 // then append, applying the master template values
14061 t.append('my-form', {name: 'my-select'});
14063 * A name attribute for the child template is not required if you have only one child
14064 * template or you want to refer to them by index.
14066 Roo.MasterTemplate = function(){
14067 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14068 this.originalHtml = this.html;
14070 var m, re = this.subTemplateRe;
14073 while(m = re.exec(this.html)){
14074 var name = m[1], content = m[2];
14079 tpl : new Roo.Template(content)
14082 st[name] = st[subIndex];
14084 st[subIndex].tpl.compile();
14085 st[subIndex].tpl.call = this.call.createDelegate(this);
14088 this.subCount = subIndex;
14091 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14093 * The regular expression used to match sub templates
14097 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14100 * Applies the passed values to a child template.
14101 * @param {String/Number} name (optional) The name or index of the child template
14102 * @param {Array/Object} values The values to be applied to the template
14103 * @return {MasterTemplate} this
14105 add : function(name, values){
14106 if(arguments.length == 1){
14107 values = arguments[0];
14110 var s = this.subs[name];
14111 s.buffer[s.buffer.length] = s.tpl.apply(values);
14116 * Applies all the passed values to a child template.
14117 * @param {String/Number} name (optional) The name or index of the child template
14118 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14119 * @param {Boolean} reset (optional) True to reset the template first
14120 * @return {MasterTemplate} this
14122 fill : function(name, values, reset){
14124 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14132 for(var i = 0, len = values.length; i < len; i++){
14133 this.add(name, values[i]);
14139 * Resets the template for reuse
14140 * @return {MasterTemplate} this
14142 reset : function(){
14144 for(var i = 0; i < this.subCount; i++){
14150 applyTemplate : function(values){
14152 var replaceIndex = -1;
14153 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14154 return s[++replaceIndex].buffer.join("");
14156 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14159 apply : function(){
14160 return this.applyTemplate.apply(this, arguments);
14163 compile : function(){return this;}
14167 * Alias for fill().
14170 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14172 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14173 * var tpl = Roo.MasterTemplate.from('element-id');
14174 * @param {String/HTMLElement} el
14175 * @param {Object} config
14178 Roo.MasterTemplate.from = function(el, config){
14179 el = Roo.getDom(el);
14180 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14183 * Ext JS Library 1.1.1
14184 * Copyright(c) 2006-2007, Ext JS, LLC.
14186 * Originally Released Under LGPL - original licence link has changed is not relivant.
14189 * <script type="text/javascript">
14194 * @class Roo.util.CSS
14195 * Utility class for manipulating CSS rules
14198 Roo.util.CSS = function(){
14200 var doc = document;
14202 var camelRe = /(-[a-z])/gi;
14203 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14207 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14208 * tag and appended to the HEAD of the document.
14209 * @param {String|Object} cssText The text containing the css rules
14210 * @param {String} id An id to add to the stylesheet for later removal
14211 * @return {StyleSheet}
14213 createStyleSheet : function(cssText, id){
14215 var head = doc.getElementsByTagName("head")[0];
14216 var nrules = doc.createElement("style");
14217 nrules.setAttribute("type", "text/css");
14219 nrules.setAttribute("id", id);
14221 if (typeof(cssText) != 'string') {
14222 // support object maps..
14223 // not sure if this a good idea..
14224 // perhaps it should be merged with the general css handling
14225 // and handle js style props.
14226 var cssTextNew = [];
14227 for(var n in cssText) {
14229 for(var k in cssText[n]) {
14230 citems.push( k + ' : ' +cssText[n][k] + ';' );
14232 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14235 cssText = cssTextNew.join("\n");
14241 head.appendChild(nrules);
14242 ss = nrules.styleSheet;
14243 ss.cssText = cssText;
14246 nrules.appendChild(doc.createTextNode(cssText));
14248 nrules.cssText = cssText;
14250 head.appendChild(nrules);
14251 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14253 this.cacheStyleSheet(ss);
14258 * Removes a style or link tag by id
14259 * @param {String} id The id of the tag
14261 removeStyleSheet : function(id){
14262 var existing = doc.getElementById(id);
14264 existing.parentNode.removeChild(existing);
14269 * Dynamically swaps an existing stylesheet reference for a new one
14270 * @param {String} id The id of an existing link tag to remove
14271 * @param {String} url The href of the new stylesheet to include
14273 swapStyleSheet : function(id, url){
14274 this.removeStyleSheet(id);
14275 var ss = doc.createElement("link");
14276 ss.setAttribute("rel", "stylesheet");
14277 ss.setAttribute("type", "text/css");
14278 ss.setAttribute("id", id);
14279 ss.setAttribute("href", url);
14280 doc.getElementsByTagName("head")[0].appendChild(ss);
14284 * Refresh the rule cache if you have dynamically added stylesheets
14285 * @return {Object} An object (hash) of rules indexed by selector
14287 refreshCache : function(){
14288 return this.getRules(true);
14292 cacheStyleSheet : function(stylesheet){
14296 try{// try catch for cross domain access issue
14297 var ssRules = stylesheet.cssRules || stylesheet.rules;
14298 for(var j = ssRules.length-1; j >= 0; --j){
14299 rules[ssRules[j].selectorText] = ssRules[j];
14305 * Gets all css rules for the document
14306 * @param {Boolean} refreshCache true to refresh the internal cache
14307 * @return {Object} An object (hash) of rules indexed by selector
14309 getRules : function(refreshCache){
14310 if(rules == null || refreshCache){
14312 var ds = doc.styleSheets;
14313 for(var i =0, len = ds.length; i < len; i++){
14315 this.cacheStyleSheet(ds[i]);
14323 * Gets an an individual CSS rule by selector(s)
14324 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14325 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14326 * @return {CSSRule} The CSS rule or null if one is not found
14328 getRule : function(selector, refreshCache){
14329 var rs = this.getRules(refreshCache);
14330 if(!(selector instanceof Array)){
14331 return rs[selector];
14333 for(var i = 0; i < selector.length; i++){
14334 if(rs[selector[i]]){
14335 return rs[selector[i]];
14343 * Updates a rule property
14344 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14345 * @param {String} property The css property
14346 * @param {String} value The new value for the property
14347 * @return {Boolean} true If a rule was found and updated
14349 updateRule : function(selector, property, value){
14350 if(!(selector instanceof Array)){
14351 var rule = this.getRule(selector);
14353 rule.style[property.replace(camelRe, camelFn)] = value;
14357 for(var i = 0; i < selector.length; i++){
14358 if(this.updateRule(selector[i], property, value)){
14368 * Ext JS Library 1.1.1
14369 * Copyright(c) 2006-2007, Ext JS, LLC.
14371 * Originally Released Under LGPL - original licence link has changed is not relivant.
14374 * <script type="text/javascript">
14380 * @class Roo.util.ClickRepeater
14381 * @extends Roo.util.Observable
14383 * A wrapper class which can be applied to any element. Fires a "click" event while the
14384 * mouse is pressed. The interval between firings may be specified in the config but
14385 * defaults to 10 milliseconds.
14387 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14389 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14390 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14391 * Similar to an autorepeat key delay.
14392 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14393 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14394 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14395 * "interval" and "delay" are ignored. "immediate" is honored.
14396 * @cfg {Boolean} preventDefault True to prevent the default click event
14397 * @cfg {Boolean} stopDefault True to stop the default click event
14400 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14401 * 2007-02-02 jvs Renamed to ClickRepeater
14402 * 2007-02-03 jvs Modifications for FF Mac and Safari
14405 * @param {String/HTMLElement/Element} el The element to listen on
14406 * @param {Object} config
14408 Roo.util.ClickRepeater = function(el, config)
14410 this.el = Roo.get(el);
14411 this.el.unselectable();
14413 Roo.apply(this, config);
14418 * Fires when the mouse button is depressed.
14419 * @param {Roo.util.ClickRepeater} this
14421 "mousedown" : true,
14424 * Fires on a specified interval during the time the element is pressed.
14425 * @param {Roo.util.ClickRepeater} this
14430 * Fires when the mouse key is released.
14431 * @param {Roo.util.ClickRepeater} this
14436 this.el.on("mousedown", this.handleMouseDown, this);
14437 if(this.preventDefault || this.stopDefault){
14438 this.el.on("click", function(e){
14439 if(this.preventDefault){
14440 e.preventDefault();
14442 if(this.stopDefault){
14448 // allow inline handler
14450 this.on("click", this.handler, this.scope || this);
14453 Roo.util.ClickRepeater.superclass.constructor.call(this);
14456 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14459 preventDefault : true,
14460 stopDefault : false,
14464 handleMouseDown : function(){
14465 clearTimeout(this.timer);
14467 if(this.pressClass){
14468 this.el.addClass(this.pressClass);
14470 this.mousedownTime = new Date();
14472 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14473 this.el.on("mouseout", this.handleMouseOut, this);
14475 this.fireEvent("mousedown", this);
14476 this.fireEvent("click", this);
14478 this.timer = this.click.defer(this.delay || this.interval, this);
14482 click : function(){
14483 this.fireEvent("click", this);
14484 this.timer = this.click.defer(this.getInterval(), this);
14488 getInterval: function(){
14489 if(!this.accelerate){
14490 return this.interval;
14492 var pressTime = this.mousedownTime.getElapsed();
14493 if(pressTime < 500){
14495 }else if(pressTime < 1700){
14497 }else if(pressTime < 2600){
14499 }else if(pressTime < 3500){
14501 }else if(pressTime < 4400){
14503 }else if(pressTime < 5300){
14505 }else if(pressTime < 6200){
14513 handleMouseOut : function(){
14514 clearTimeout(this.timer);
14515 if(this.pressClass){
14516 this.el.removeClass(this.pressClass);
14518 this.el.on("mouseover", this.handleMouseReturn, this);
14522 handleMouseReturn : function(){
14523 this.el.un("mouseover", this.handleMouseReturn);
14524 if(this.pressClass){
14525 this.el.addClass(this.pressClass);
14531 handleMouseUp : function(){
14532 clearTimeout(this.timer);
14533 this.el.un("mouseover", this.handleMouseReturn);
14534 this.el.un("mouseout", this.handleMouseOut);
14535 Roo.get(document).un("mouseup", this.handleMouseUp);
14536 this.el.removeClass(this.pressClass);
14537 this.fireEvent("mouseup", this);
14540 * @class Roo.util.Clipboard
14546 Roo.util.Clipboard = {
14548 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
14549 * @param {String} text to copy to clipboard
14551 write : function(text) {
14552 // navigator clipboard api needs a secure context (https)
14553 if (navigator.clipboard && window.isSecureContext) {
14554 // navigator clipboard api method'
14555 navigator.clipboard.writeText(text);
14558 // text area method
14559 var ta = document.createElement("textarea");
14561 // make the textarea out of viewport
14562 ta.style.position = "fixed";
14563 ta.style.left = "-999999px";
14564 ta.style.top = "-999999px";
14565 document.body.appendChild(ta);
14568 document.execCommand('copy');
14578 * Ext JS Library 1.1.1
14579 * Copyright(c) 2006-2007, Ext JS, LLC.
14581 * Originally Released Under LGPL - original licence link has changed is not relivant.
14584 * <script type="text/javascript">
14589 * @class Roo.KeyNav
14590 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14591 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14592 * way to implement custom navigation schemes for any UI component.</p>
14593 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14594 * pageUp, pageDown, del, home, end. Usage:</p>
14596 var nav = new Roo.KeyNav("my-element", {
14597 "left" : function(e){
14598 this.moveLeft(e.ctrlKey);
14600 "right" : function(e){
14601 this.moveRight(e.ctrlKey);
14603 "enter" : function(e){
14610 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14611 * @param {Object} config The config
14613 Roo.KeyNav = function(el, config){
14614 this.el = Roo.get(el);
14615 Roo.apply(this, config);
14616 if(!this.disabled){
14617 this.disabled = true;
14622 Roo.KeyNav.prototype = {
14624 * @cfg {Boolean} disabled
14625 * True to disable this KeyNav instance (defaults to false)
14629 * @cfg {String} defaultEventAction
14630 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14631 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14632 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14634 defaultEventAction: "stopEvent",
14636 * @cfg {Boolean} forceKeyDown
14637 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14638 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14639 * handle keydown instead of keypress.
14641 forceKeyDown : false,
14644 prepareEvent : function(e){
14645 var k = e.getKey();
14646 var h = this.keyToHandler[k];
14647 //if(h && this[h]){
14648 // e.stopPropagation();
14650 if(Roo.isSafari && h && k >= 37 && k <= 40){
14656 relay : function(e){
14657 var k = e.getKey();
14658 var h = this.keyToHandler[k];
14660 if(this.doRelay(e, this[h], h) !== true){
14661 e[this.defaultEventAction]();
14667 doRelay : function(e, h, hname){
14668 return h.call(this.scope || this, e);
14671 // possible handlers
14685 // quick lookup hash
14702 * Enable this KeyNav
14704 enable: function(){
14706 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14707 // the EventObject will normalize Safari automatically
14708 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14709 this.el.on("keydown", this.relay, this);
14711 this.el.on("keydown", this.prepareEvent, this);
14712 this.el.on("keypress", this.relay, this);
14714 this.disabled = false;
14719 * Disable this KeyNav
14721 disable: function(){
14722 if(!this.disabled){
14723 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14724 this.el.un("keydown", this.relay);
14726 this.el.un("keydown", this.prepareEvent);
14727 this.el.un("keypress", this.relay);
14729 this.disabled = true;
14734 * Ext JS Library 1.1.1
14735 * Copyright(c) 2006-2007, Ext JS, LLC.
14737 * Originally Released Under LGPL - original licence link has changed is not relivant.
14740 * <script type="text/javascript">
14745 * @class Roo.KeyMap
14746 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14747 * The constructor accepts the same config object as defined by {@link #addBinding}.
14748 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14749 * combination it will call the function with this signature (if the match is a multi-key
14750 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14751 * A KeyMap can also handle a string representation of keys.<br />
14754 // map one key by key code
14755 var map = new Roo.KeyMap("my-element", {
14756 key: 13, // or Roo.EventObject.ENTER
14761 // map multiple keys to one action by string
14762 var map = new Roo.KeyMap("my-element", {
14768 // map multiple keys to multiple actions by strings and array of codes
14769 var map = new Roo.KeyMap("my-element", [
14772 fn: function(){ alert("Return was pressed"); }
14775 fn: function(){ alert('a, b or c was pressed'); }
14780 fn: function(){ alert('Control + shift + tab was pressed.'); }
14784 * <b>Note: A KeyMap starts enabled</b>
14786 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14787 * @param {Object} config The config (see {@link #addBinding})
14788 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14790 Roo.KeyMap = function(el, config, eventName){
14791 this.el = Roo.get(el);
14792 this.eventName = eventName || "keydown";
14793 this.bindings = [];
14795 this.addBinding(config);
14800 Roo.KeyMap.prototype = {
14802 * True to stop the event from bubbling and prevent the default browser action if the
14803 * key was handled by the KeyMap (defaults to false)
14809 * Add a new binding to this KeyMap. The following config object properties are supported:
14811 Property Type Description
14812 ---------- --------------- ----------------------------------------------------------------------
14813 key String/Array A single keycode or an array of keycodes to handle
14814 shift Boolean True to handle key only when shift is pressed (defaults to false)
14815 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14816 alt Boolean True to handle key only when alt is pressed (defaults to false)
14817 fn Function The function to call when KeyMap finds the expected key combination
14818 scope Object The scope of the callback function
14824 var map = new Roo.KeyMap(document, {
14825 key: Roo.EventObject.ENTER,
14830 //Add a new binding to the existing KeyMap later
14838 * @param {Object/Array} config A single KeyMap config or an array of configs
14840 addBinding : function(config){
14841 if(config instanceof Array){
14842 for(var i = 0, len = config.length; i < len; i++){
14843 this.addBinding(config[i]);
14847 var keyCode = config.key,
14848 shift = config.shift,
14849 ctrl = config.ctrl,
14852 scope = config.scope;
14853 if(typeof keyCode == "string"){
14855 var keyString = keyCode.toUpperCase();
14856 for(var j = 0, len = keyString.length; j < len; j++){
14857 ks.push(keyString.charCodeAt(j));
14861 var keyArray = keyCode instanceof Array;
14862 var handler = function(e){
14863 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14864 var k = e.getKey();
14866 for(var i = 0, len = keyCode.length; i < len; i++){
14867 if(keyCode[i] == k){
14868 if(this.stopEvent){
14871 fn.call(scope || window, k, e);
14877 if(this.stopEvent){
14880 fn.call(scope || window, k, e);
14885 this.bindings.push(handler);
14889 * Shorthand for adding a single key listener
14890 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14891 * following options:
14892 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14893 * @param {Function} fn The function to call
14894 * @param {Object} scope (optional) The scope of the function
14896 on : function(key, fn, scope){
14897 var keyCode, shift, ctrl, alt;
14898 if(typeof key == "object" && !(key instanceof Array)){
14917 handleKeyDown : function(e){
14918 if(this.enabled){ //just in case
14919 var b = this.bindings;
14920 for(var i = 0, len = b.length; i < len; i++){
14921 b[i].call(this, e);
14927 * Returns true if this KeyMap is enabled
14928 * @return {Boolean}
14930 isEnabled : function(){
14931 return this.enabled;
14935 * Enables this KeyMap
14937 enable: function(){
14939 this.el.on(this.eventName, this.handleKeyDown, this);
14940 this.enabled = true;
14945 * Disable this KeyMap
14947 disable: function(){
14949 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14950 this.enabled = false;
14955 * Ext JS Library 1.1.1
14956 * Copyright(c) 2006-2007, Ext JS, LLC.
14958 * Originally Released Under LGPL - original licence link has changed is not relivant.
14961 * <script type="text/javascript">
14966 * @class Roo.util.TextMetrics
14967 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14968 * wide, in pixels, a given block of text will be.
14971 Roo.util.TextMetrics = function(){
14975 * Measures the size of the specified text
14976 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14977 * that can affect the size of the rendered text
14978 * @param {String} text The text to measure
14979 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14980 * in order to accurately measure the text height
14981 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14983 measure : function(el, text, fixedWidth){
14985 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14988 shared.setFixedWidth(fixedWidth || 'auto');
14989 return shared.getSize(text);
14993 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14994 * the overhead of multiple calls to initialize the style properties on each measurement.
14995 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14996 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14997 * in order to accurately measure the text height
14998 * @return {Roo.util.TextMetrics.Instance} instance The new instance
15000 createInstance : function(el, fixedWidth){
15001 return Roo.util.TextMetrics.Instance(el, fixedWidth);
15008 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
15009 var ml = new Roo.Element(document.createElement('div'));
15010 document.body.appendChild(ml.dom);
15011 ml.position('absolute');
15012 ml.setLeftTop(-1000, -1000);
15016 ml.setWidth(fixedWidth);
15021 * Returns the size of the specified text based on the internal element's style and width properties
15022 * @memberOf Roo.util.TextMetrics.Instance#
15023 * @param {String} text The text to measure
15024 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15026 getSize : function(text){
15028 var s = ml.getSize();
15034 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15035 * that can affect the size of the rendered text
15036 * @memberOf Roo.util.TextMetrics.Instance#
15037 * @param {String/HTMLElement} el The element, dom node or id
15039 bind : function(el){
15041 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15046 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15047 * to set a fixed width in order to accurately measure the text height.
15048 * @memberOf Roo.util.TextMetrics.Instance#
15049 * @param {Number} width The width to set on the element
15051 setFixedWidth : function(width){
15052 ml.setWidth(width);
15056 * Returns the measured width of the specified text
15057 * @memberOf Roo.util.TextMetrics.Instance#
15058 * @param {String} text The text to measure
15059 * @return {Number} width The width in pixels
15061 getWidth : function(text){
15062 ml.dom.style.width = 'auto';
15063 return this.getSize(text).width;
15067 * Returns the measured height of the specified text. For multiline text, be sure to call
15068 * {@link #setFixedWidth} if necessary.
15069 * @memberOf Roo.util.TextMetrics.Instance#
15070 * @param {String} text The text to measure
15071 * @return {Number} height The height in pixels
15073 getHeight : function(text){
15074 return this.getSize(text).height;
15078 instance.bind(bindTo);
15083 // backwards compat
15084 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15086 * Ext JS Library 1.1.1
15087 * Copyright(c) 2006-2007, Ext JS, LLC.
15089 * Originally Released Under LGPL - original licence link has changed is not relivant.
15092 * <script type="text/javascript">
15096 * @class Roo.state.Provider
15097 * Abstract base class for state provider implementations. This class provides methods
15098 * for encoding and decoding <b>typed</b> variables including dates and defines the
15099 * Provider interface.
15101 Roo.state.Provider = function(){
15103 * @event statechange
15104 * Fires when a state change occurs.
15105 * @param {Provider} this This state provider
15106 * @param {String} key The state key which was changed
15107 * @param {String} value The encoded value for the state
15110 "statechange": true
15113 Roo.state.Provider.superclass.constructor.call(this);
15115 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15117 * Returns the current value for a key
15118 * @param {String} name The key name
15119 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15120 * @return {Mixed} The state data
15122 get : function(name, defaultValue){
15123 return typeof this.state[name] == "undefined" ?
15124 defaultValue : this.state[name];
15128 * Clears a value from the state
15129 * @param {String} name The key name
15131 clear : function(name){
15132 delete this.state[name];
15133 this.fireEvent("statechange", this, name, null);
15137 * Sets the value for a key
15138 * @param {String} name The key name
15139 * @param {Mixed} value The value to set
15141 set : function(name, value){
15142 this.state[name] = value;
15143 this.fireEvent("statechange", this, name, value);
15147 * Decodes a string previously encoded with {@link #encodeValue}.
15148 * @param {String} value The value to decode
15149 * @return {Mixed} The decoded value
15151 decodeValue : function(cookie){
15152 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15153 var matches = re.exec(unescape(cookie));
15154 if(!matches || !matches[1]) {
15155 return; // non state cookie
15157 var type = matches[1];
15158 var v = matches[2];
15161 return parseFloat(v);
15163 return new Date(Date.parse(v));
15168 var values = v.split("^");
15169 for(var i = 0, len = values.length; i < len; i++){
15170 all.push(this.decodeValue(values[i]));
15175 var values = v.split("^");
15176 for(var i = 0, len = values.length; i < len; i++){
15177 var kv = values[i].split("=");
15178 all[kv[0]] = this.decodeValue(kv[1]);
15187 * Encodes a value including type information. Decode with {@link #decodeValue}.
15188 * @param {Mixed} value The value to encode
15189 * @return {String} The encoded value
15191 encodeValue : function(v){
15193 if(typeof v == "number"){
15195 }else if(typeof v == "boolean"){
15196 enc = "b:" + (v ? "1" : "0");
15197 }else if(v instanceof Date){
15198 enc = "d:" + v.toGMTString();
15199 }else if(v instanceof Array){
15201 for(var i = 0, len = v.length; i < len; i++){
15202 flat += this.encodeValue(v[i]);
15208 }else if(typeof v == "object"){
15211 if(typeof v[key] != "function"){
15212 flat += key + "=" + this.encodeValue(v[key]) + "^";
15215 enc = "o:" + flat.substring(0, flat.length-1);
15219 return escape(enc);
15225 * Ext JS Library 1.1.1
15226 * Copyright(c) 2006-2007, Ext JS, LLC.
15228 * Originally Released Under LGPL - original licence link has changed is not relivant.
15231 * <script type="text/javascript">
15234 * @class Roo.state.Manager
15235 * This is the global state manager. By default all components that are "state aware" check this class
15236 * for state information if you don't pass them a custom state provider. In order for this class
15237 * to be useful, it must be initialized with a provider when your application initializes.
15239 // in your initialization function
15241 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15243 // supposed you have a {@link Roo.BorderLayout}
15244 var layout = new Roo.BorderLayout(...);
15245 layout.restoreState();
15246 // or a {Roo.BasicDialog}
15247 var dialog = new Roo.BasicDialog(...);
15248 dialog.restoreState();
15252 Roo.state.Manager = function(){
15253 var provider = new Roo.state.Provider();
15257 * Configures the default state provider for your application
15258 * @param {Provider} stateProvider The state provider to set
15260 setProvider : function(stateProvider){
15261 provider = stateProvider;
15265 * Returns the current value for a key
15266 * @param {String} name The key name
15267 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15268 * @return {Mixed} The state data
15270 get : function(key, defaultValue){
15271 return provider.get(key, defaultValue);
15275 * Sets the value for a key
15276 * @param {String} name The key name
15277 * @param {Mixed} value The state data
15279 set : function(key, value){
15280 provider.set(key, value);
15284 * Clears a value from the state
15285 * @param {String} name The key name
15287 clear : function(key){
15288 provider.clear(key);
15292 * Gets the currently configured state provider
15293 * @return {Provider} The state provider
15295 getProvider : function(){
15302 * Ext JS Library 1.1.1
15303 * Copyright(c) 2006-2007, Ext JS, LLC.
15305 * Originally Released Under LGPL - original licence link has changed is not relivant.
15308 * <script type="text/javascript">
15311 * @class Roo.state.CookieProvider
15312 * @extends Roo.state.Provider
15313 * The default Provider implementation which saves state via cookies.
15316 var cp = new Roo.state.CookieProvider({
15318 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15319 domain: "roojs.com"
15321 Roo.state.Manager.setProvider(cp);
15323 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15324 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15325 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15326 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15327 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15328 * domain the page is running on including the 'www' like 'www.roojs.com')
15329 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15331 * Create a new CookieProvider
15332 * @param {Object} config The configuration object
15334 Roo.state.CookieProvider = function(config){
15335 Roo.state.CookieProvider.superclass.constructor.call(this);
15337 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15338 this.domain = null;
15339 this.secure = false;
15340 Roo.apply(this, config);
15341 this.state = this.readCookies();
15344 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15346 set : function(name, value){
15347 if(typeof value == "undefined" || value === null){
15351 this.setCookie(name, value);
15352 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15356 clear : function(name){
15357 this.clearCookie(name);
15358 Roo.state.CookieProvider.superclass.clear.call(this, name);
15362 readCookies : function(){
15364 var c = document.cookie + ";";
15365 var re = /\s?(.*?)=(.*?);/g;
15367 while((matches = re.exec(c)) != null){
15368 var name = matches[1];
15369 var value = matches[2];
15370 if(name && name.substring(0,3) == "ys-"){
15371 cookies[name.substr(3)] = this.decodeValue(value);
15378 setCookie : function(name, value){
15379 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15380 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15381 ((this.path == null) ? "" : ("; path=" + this.path)) +
15382 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15383 ((this.secure == true) ? "; secure" : "");
15387 clearCookie : function(name){
15388 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15389 ((this.path == null) ? "" : ("; path=" + this.path)) +
15390 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15391 ((this.secure == true) ? "; secure" : "");
15395 * Ext JS Library 1.1.1
15396 * Copyright(c) 2006-2007, Ext JS, LLC.
15398 * Originally Released Under LGPL - original licence link has changed is not relivant.
15401 * <script type="text/javascript">
15406 * @class Roo.ComponentMgr
15407 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15410 Roo.ComponentMgr = function(){
15411 var all = new Roo.util.MixedCollection();
15415 * Registers a component.
15416 * @param {Roo.Component} c The component
15418 register : function(c){
15423 * Unregisters a component.
15424 * @param {Roo.Component} c The component
15426 unregister : function(c){
15431 * Returns a component by id
15432 * @param {String} id The component id
15434 get : function(id){
15435 return all.get(id);
15439 * Registers a function that will be called when a specified component is added to ComponentMgr
15440 * @param {String} id The component id
15441 * @param {Funtction} fn The callback function
15442 * @param {Object} scope The scope of the callback
15444 onAvailable : function(id, fn, scope){
15445 all.on("add", function(index, o){
15447 fn.call(scope || o, o);
15448 all.un("add", fn, scope);
15455 * Ext JS Library 1.1.1
15456 * Copyright(c) 2006-2007, Ext JS, LLC.
15458 * Originally Released Under LGPL - original licence link has changed is not relivant.
15461 * <script type="text/javascript">
15465 * @class Roo.Component
15466 * @extends Roo.util.Observable
15467 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15468 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15469 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15470 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15471 * All visual components (widgets) that require rendering into a layout should subclass Component.
15473 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15474 * 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
15475 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15477 Roo.Component = function(config){
15478 config = config || {};
15479 if(config.tagName || config.dom || typeof config == "string"){ // element object
15480 config = {el: config, id: config.id || config};
15482 this.initialConfig = config;
15484 Roo.apply(this, config);
15488 * Fires after the component is disabled.
15489 * @param {Roo.Component} this
15494 * Fires after the component is enabled.
15495 * @param {Roo.Component} this
15499 * @event beforeshow
15500 * Fires before the component is shown. Return false to stop the show.
15501 * @param {Roo.Component} this
15506 * Fires after the component is shown.
15507 * @param {Roo.Component} this
15511 * @event beforehide
15512 * Fires before the component is hidden. Return false to stop the hide.
15513 * @param {Roo.Component} this
15518 * Fires after the component is hidden.
15519 * @param {Roo.Component} this
15523 * @event beforerender
15524 * Fires before the component is rendered. Return false to stop the render.
15525 * @param {Roo.Component} this
15527 beforerender : true,
15530 * Fires after the component is rendered.
15531 * @param {Roo.Component} this
15535 * @event beforedestroy
15536 * Fires before the component is destroyed. Return false to stop the destroy.
15537 * @param {Roo.Component} this
15539 beforedestroy : true,
15542 * Fires after the component is destroyed.
15543 * @param {Roo.Component} this
15548 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15550 Roo.ComponentMgr.register(this);
15551 Roo.Component.superclass.constructor.call(this);
15552 this.initComponent();
15553 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15554 this.render(this.renderTo);
15555 delete this.renderTo;
15560 Roo.Component.AUTO_ID = 1000;
15562 Roo.extend(Roo.Component, Roo.util.Observable, {
15564 * @scope Roo.Component.prototype
15566 * true if this component is hidden. Read-only.
15571 * true if this component is disabled. Read-only.
15576 * true if this component has been rendered. Read-only.
15580 /** @cfg {String} disableClass
15581 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15583 disabledClass : "x-item-disabled",
15584 /** @cfg {Boolean} allowDomMove
15585 * Whether the component can move the Dom node when rendering (defaults to true).
15587 allowDomMove : true,
15588 /** @cfg {String} hideMode (display|visibility)
15589 * How this component should hidden. Supported values are
15590 * "visibility" (css visibility), "offsets" (negative offset position) and
15591 * "display" (css display) - defaults to "display".
15593 hideMode: 'display',
15596 ctype : "Roo.Component",
15599 * @cfg {String} actionMode
15600 * which property holds the element that used for hide() / show() / disable() / enable()
15601 * default is 'el' for forms you probably want to set this to fieldEl
15606 getActionEl : function(){
15607 return this[this.actionMode];
15610 initComponent : Roo.emptyFn,
15612 * If this is a lazy rendering component, render it to its container element.
15613 * @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.
15615 render : function(container, position){
15621 if(this.fireEvent("beforerender", this) === false){
15625 if(!container && this.el){
15626 this.el = Roo.get(this.el);
15627 container = this.el.dom.parentNode;
15628 this.allowDomMove = false;
15630 this.container = Roo.get(container);
15631 this.rendered = true;
15632 if(position !== undefined){
15633 if(typeof position == 'number'){
15634 position = this.container.dom.childNodes[position];
15636 position = Roo.getDom(position);
15639 this.onRender(this.container, position || null);
15641 this.el.addClass(this.cls);
15645 this.el.applyStyles(this.style);
15648 this.fireEvent("render", this);
15649 this.afterRender(this.container);
15662 // default function is not really useful
15663 onRender : function(ct, position){
15665 this.el = Roo.get(this.el);
15666 if(this.allowDomMove !== false){
15667 ct.dom.insertBefore(this.el.dom, position);
15673 getAutoCreate : function(){
15674 var cfg = typeof this.autoCreate == "object" ?
15675 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15676 if(this.id && !cfg.id){
15683 afterRender : Roo.emptyFn,
15686 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15687 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15689 destroy : function(){
15690 if(this.fireEvent("beforedestroy", this) !== false){
15691 this.purgeListeners();
15692 this.beforeDestroy();
15694 this.el.removeAllListeners();
15696 if(this.actionMode == "container"){
15697 this.container.remove();
15701 Roo.ComponentMgr.unregister(this);
15702 this.fireEvent("destroy", this);
15707 beforeDestroy : function(){
15712 onDestroy : function(){
15717 * Returns the underlying {@link Roo.Element}.
15718 * @return {Roo.Element} The element
15720 getEl : function(){
15725 * Returns the id of this component.
15728 getId : function(){
15733 * Try to focus this component.
15734 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15735 * @return {Roo.Component} this
15737 focus : function(selectText){
15740 if(selectText === true){
15741 this.el.dom.select();
15756 * Disable this component.
15757 * @return {Roo.Component} this
15759 disable : function(){
15763 this.disabled = true;
15764 this.fireEvent("disable", this);
15769 onDisable : function(){
15770 this.getActionEl().addClass(this.disabledClass);
15771 this.el.dom.disabled = true;
15775 * Enable this component.
15776 * @return {Roo.Component} this
15778 enable : function(){
15782 this.disabled = false;
15783 this.fireEvent("enable", this);
15788 onEnable : function(){
15789 this.getActionEl().removeClass(this.disabledClass);
15790 this.el.dom.disabled = false;
15794 * Convenience function for setting disabled/enabled by boolean.
15795 * @param {Boolean} disabled
15797 setDisabled : function(disabled){
15798 this[disabled ? "disable" : "enable"]();
15802 * Show this component.
15803 * @return {Roo.Component} this
15806 if(this.fireEvent("beforeshow", this) !== false){
15807 this.hidden = false;
15811 this.fireEvent("show", this);
15817 onShow : function(){
15818 var ae = this.getActionEl();
15819 if(this.hideMode == 'visibility'){
15820 ae.dom.style.visibility = "visible";
15821 }else if(this.hideMode == 'offsets'){
15822 ae.removeClass('x-hidden');
15824 ae.dom.style.display = "";
15829 * Hide this component.
15830 * @return {Roo.Component} this
15833 if(this.fireEvent("beforehide", this) !== false){
15834 this.hidden = true;
15838 this.fireEvent("hide", this);
15844 onHide : function(){
15845 var ae = this.getActionEl();
15846 if(this.hideMode == 'visibility'){
15847 ae.dom.style.visibility = "hidden";
15848 }else if(this.hideMode == 'offsets'){
15849 ae.addClass('x-hidden');
15851 ae.dom.style.display = "none";
15856 * Convenience function to hide or show this component by boolean.
15857 * @param {Boolean} visible True to show, false to hide
15858 * @return {Roo.Component} this
15860 setVisible: function(visible){
15870 * Returns true if this component is visible.
15872 isVisible : function(){
15873 return this.getActionEl().isVisible();
15876 cloneConfig : function(overrides){
15877 overrides = overrides || {};
15878 var id = overrides.id || Roo.id();
15879 var cfg = Roo.applyIf(overrides, this.initialConfig);
15880 cfg.id = id; // prevent dup id
15881 return new this.constructor(cfg);
15885 * Ext JS Library 1.1.1
15886 * Copyright(c) 2006-2007, Ext JS, LLC.
15888 * Originally Released Under LGPL - original licence link has changed is not relivant.
15891 * <script type="text/javascript">
15895 * @class Roo.BoxComponent
15896 * @extends Roo.Component
15897 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15898 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15899 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15900 * layout containers.
15902 * @param {Roo.Element/String/Object} config The configuration options.
15904 Roo.BoxComponent = function(config){
15905 Roo.Component.call(this, config);
15909 * Fires after the component is resized.
15910 * @param {Roo.Component} this
15911 * @param {Number} adjWidth The box-adjusted width that was set
15912 * @param {Number} adjHeight The box-adjusted height that was set
15913 * @param {Number} rawWidth The width that was originally specified
15914 * @param {Number} rawHeight The height that was originally specified
15919 * Fires after the component is moved.
15920 * @param {Roo.Component} this
15921 * @param {Number} x The new x position
15922 * @param {Number} y The new y position
15928 Roo.extend(Roo.BoxComponent, Roo.Component, {
15929 // private, set in afterRender to signify that the component has been rendered
15931 // private, used to defer height settings to subclasses
15932 deferHeight: false,
15933 /** @cfg {Number} width
15934 * width (optional) size of component
15936 /** @cfg {Number} height
15937 * height (optional) size of component
15941 * Sets the width and height of the component. This method fires the resize event. This method can accept
15942 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15943 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15944 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15945 * @return {Roo.BoxComponent} this
15947 setSize : function(w, h){
15948 // support for standard size objects
15949 if(typeof w == 'object'){
15954 if(!this.boxReady){
15960 // prevent recalcs when not needed
15961 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15964 this.lastSize = {width: w, height: h};
15966 var adj = this.adjustSize(w, h);
15967 var aw = adj.width, ah = adj.height;
15968 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15969 var rz = this.getResizeEl();
15970 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15971 rz.setSize(aw, ah);
15972 }else if(!this.deferHeight && ah !== undefined){
15974 }else if(aw !== undefined){
15977 this.onResize(aw, ah, w, h);
15978 this.fireEvent('resize', this, aw, ah, w, h);
15984 * Gets the current size of the component's underlying element.
15985 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15987 getSize : function(){
15988 return this.el.getSize();
15992 * Gets the current XY position of the component's underlying element.
15993 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15994 * @return {Array} The XY position of the element (e.g., [100, 200])
15996 getPosition : function(local){
15997 if(local === true){
15998 return [this.el.getLeft(true), this.el.getTop(true)];
16000 return this.xy || this.el.getXY();
16004 * Gets the current box measurements of the component's underlying element.
16005 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16006 * @returns {Object} box An object in the format {x, y, width, height}
16008 getBox : function(local){
16009 var s = this.el.getSize();
16011 s.x = this.el.getLeft(true);
16012 s.y = this.el.getTop(true);
16014 var xy = this.xy || this.el.getXY();
16022 * Sets the current box measurements of the component's underlying element.
16023 * @param {Object} box An object in the format {x, y, width, height}
16024 * @returns {Roo.BoxComponent} this
16026 updateBox : function(box){
16027 this.setSize(box.width, box.height);
16028 this.setPagePosition(box.x, box.y);
16033 getResizeEl : function(){
16034 return this.resizeEl || this.el;
16038 getPositionEl : function(){
16039 return this.positionEl || this.el;
16043 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16044 * This method fires the move event.
16045 * @param {Number} left The new left
16046 * @param {Number} top The new top
16047 * @returns {Roo.BoxComponent} this
16049 setPosition : function(x, y){
16052 if(!this.boxReady){
16055 var adj = this.adjustPosition(x, y);
16056 var ax = adj.x, ay = adj.y;
16058 var el = this.getPositionEl();
16059 if(ax !== undefined || ay !== undefined){
16060 if(ax !== undefined && ay !== undefined){
16061 el.setLeftTop(ax, ay);
16062 }else if(ax !== undefined){
16064 }else if(ay !== undefined){
16067 this.onPosition(ax, ay);
16068 this.fireEvent('move', this, ax, ay);
16074 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16075 * This method fires the move event.
16076 * @param {Number} x The new x position
16077 * @param {Number} y The new y position
16078 * @returns {Roo.BoxComponent} this
16080 setPagePosition : function(x, y){
16083 if(!this.boxReady){
16086 if(x === undefined || y === undefined){ // cannot translate undefined points
16089 var p = this.el.translatePoints(x, y);
16090 this.setPosition(p.left, p.top);
16095 onRender : function(ct, position){
16096 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16098 this.resizeEl = Roo.get(this.resizeEl);
16100 if(this.positionEl){
16101 this.positionEl = Roo.get(this.positionEl);
16106 afterRender : function(){
16107 Roo.BoxComponent.superclass.afterRender.call(this);
16108 this.boxReady = true;
16109 this.setSize(this.width, this.height);
16110 if(this.x || this.y){
16111 this.setPosition(this.x, this.y);
16113 if(this.pageX || this.pageY){
16114 this.setPagePosition(this.pageX, this.pageY);
16119 * Force the component's size to recalculate based on the underlying element's current height and width.
16120 * @returns {Roo.BoxComponent} this
16122 syncSize : function(){
16123 delete this.lastSize;
16124 this.setSize(this.el.getWidth(), this.el.getHeight());
16129 * Called after the component is resized, this method is empty by default but can be implemented by any
16130 * subclass that needs to perform custom logic after a resize occurs.
16131 * @param {Number} adjWidth The box-adjusted width that was set
16132 * @param {Number} adjHeight The box-adjusted height that was set
16133 * @param {Number} rawWidth The width that was originally specified
16134 * @param {Number} rawHeight The height that was originally specified
16136 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16141 * Called after the component is moved, this method is empty by default but can be implemented by any
16142 * subclass that needs to perform custom logic after a move occurs.
16143 * @param {Number} x The new x position
16144 * @param {Number} y The new y position
16146 onPosition : function(x, y){
16151 adjustSize : function(w, h){
16152 if(this.autoWidth){
16155 if(this.autoHeight){
16158 return {width : w, height: h};
16162 adjustPosition : function(x, y){
16163 return {x : x, y: y};
16167 * Ext JS Library 1.1.1
16168 * Copyright(c) 2006-2007, Ext JS, LLC.
16170 * Originally Released Under LGPL - original licence link has changed is not relivant.
16173 * <script type="text/javascript">
16178 * @extends Roo.Element
16179 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16180 * automatic maintaining of shadow/shim positions.
16181 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16182 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16183 * you can pass a string with a CSS class name. False turns off the shadow.
16184 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16185 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16186 * @cfg {String} cls CSS class to add to the element
16187 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16188 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16190 * @param {Object} config An object with config options.
16191 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16194 Roo.Layer = function(config, existingEl){
16195 config = config || {};
16196 var dh = Roo.DomHelper;
16197 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16199 this.dom = Roo.getDom(existingEl);
16202 var o = config.dh || {tag: "div", cls: "x-layer"};
16203 this.dom = dh.append(pel, o);
16206 this.addClass(config.cls);
16208 this.constrain = config.constrain !== false;
16209 this.visibilityMode = Roo.Element.VISIBILITY;
16211 this.id = this.dom.id = config.id;
16213 this.id = Roo.id(this.dom);
16215 this.zindex = config.zindex || this.getZIndex();
16216 this.position("absolute", this.zindex);
16218 this.shadowOffset = config.shadowOffset || 4;
16219 this.shadow = new Roo.Shadow({
16220 offset : this.shadowOffset,
16221 mode : config.shadow
16224 this.shadowOffset = 0;
16226 this.useShim = config.shim !== false && Roo.useShims;
16227 this.useDisplay = config.useDisplay;
16231 var supr = Roo.Element.prototype;
16233 // shims are shared among layer to keep from having 100 iframes
16236 Roo.extend(Roo.Layer, Roo.Element, {
16238 getZIndex : function(){
16239 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16242 getShim : function(){
16249 var shim = shims.shift();
16251 shim = this.createShim();
16252 shim.enableDisplayMode('block');
16253 shim.dom.style.display = 'none';
16254 shim.dom.style.visibility = 'visible';
16256 var pn = this.dom.parentNode;
16257 if(shim.dom.parentNode != pn){
16258 pn.insertBefore(shim.dom, this.dom);
16260 shim.setStyle('z-index', this.getZIndex()-2);
16265 hideShim : function(){
16267 this.shim.setDisplayed(false);
16268 shims.push(this.shim);
16273 disableShadow : function(){
16275 this.shadowDisabled = true;
16276 this.shadow.hide();
16277 this.lastShadowOffset = this.shadowOffset;
16278 this.shadowOffset = 0;
16282 enableShadow : function(show){
16284 this.shadowDisabled = false;
16285 this.shadowOffset = this.lastShadowOffset;
16286 delete this.lastShadowOffset;
16294 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16295 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16296 sync : function(doShow){
16297 var sw = this.shadow;
16298 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16299 var sh = this.getShim();
16301 var w = this.getWidth(),
16302 h = this.getHeight();
16304 var l = this.getLeft(true),
16305 t = this.getTop(true);
16307 if(sw && !this.shadowDisabled){
16308 if(doShow && !sw.isVisible()){
16311 sw.realign(l, t, w, h);
16317 // fit the shim behind the shadow, so it is shimmed too
16318 var a = sw.adjusts, s = sh.dom.style;
16319 s.left = (Math.min(l, l+a.l))+"px";
16320 s.top = (Math.min(t, t+a.t))+"px";
16321 s.width = (w+a.w)+"px";
16322 s.height = (h+a.h)+"px";
16329 sh.setLeftTop(l, t);
16336 destroy : function(){
16339 this.shadow.hide();
16341 this.removeAllListeners();
16342 var pn = this.dom.parentNode;
16344 pn.removeChild(this.dom);
16346 Roo.Element.uncache(this.id);
16349 remove : function(){
16354 beginUpdate : function(){
16355 this.updating = true;
16359 endUpdate : function(){
16360 this.updating = false;
16365 hideUnders : function(negOffset){
16367 this.shadow.hide();
16373 constrainXY : function(){
16374 if(this.constrain){
16375 var vw = Roo.lib.Dom.getViewWidth(),
16376 vh = Roo.lib.Dom.getViewHeight();
16377 var s = Roo.get(document).getScroll();
16379 var xy = this.getXY();
16380 var x = xy[0], y = xy[1];
16381 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16382 // only move it if it needs it
16384 // first validate right/bottom
16385 if((x + w) > vw+s.left){
16386 x = vw - w - this.shadowOffset;
16389 if((y + h) > vh+s.top){
16390 y = vh - h - this.shadowOffset;
16393 // then make sure top/left isn't negative
16404 var ay = this.avoidY;
16405 if(y <= ay && (y+h) >= ay){
16411 supr.setXY.call(this, xy);
16417 isVisible : function(){
16418 return this.visible;
16422 showAction : function(){
16423 this.visible = true; // track visibility to prevent getStyle calls
16424 if(this.useDisplay === true){
16425 this.setDisplayed("");
16426 }else if(this.lastXY){
16427 supr.setXY.call(this, this.lastXY);
16428 }else if(this.lastLT){
16429 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16434 hideAction : function(){
16435 this.visible = false;
16436 if(this.useDisplay === true){
16437 this.setDisplayed(false);
16439 this.setLeftTop(-10000,-10000);
16443 // overridden Element method
16444 setVisible : function(v, a, d, c, e){
16449 var cb = function(){
16454 }.createDelegate(this);
16455 supr.setVisible.call(this, true, true, d, cb, e);
16458 this.hideUnders(true);
16467 }.createDelegate(this);
16469 supr.setVisible.call(this, v, a, d, cb, e);
16478 storeXY : function(xy){
16479 delete this.lastLT;
16483 storeLeftTop : function(left, top){
16484 delete this.lastXY;
16485 this.lastLT = [left, top];
16489 beforeFx : function(){
16490 this.beforeAction();
16491 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16495 afterFx : function(){
16496 Roo.Layer.superclass.afterFx.apply(this, arguments);
16497 this.sync(this.isVisible());
16501 beforeAction : function(){
16502 if(!this.updating && this.shadow){
16503 this.shadow.hide();
16507 // overridden Element method
16508 setLeft : function(left){
16509 this.storeLeftTop(left, this.getTop(true));
16510 supr.setLeft.apply(this, arguments);
16514 setTop : function(top){
16515 this.storeLeftTop(this.getLeft(true), top);
16516 supr.setTop.apply(this, arguments);
16520 setLeftTop : function(left, top){
16521 this.storeLeftTop(left, top);
16522 supr.setLeftTop.apply(this, arguments);
16526 setXY : function(xy, a, d, c, e){
16528 this.beforeAction();
16530 var cb = this.createCB(c);
16531 supr.setXY.call(this, xy, a, d, cb, e);
16538 createCB : function(c){
16549 // overridden Element method
16550 setX : function(x, a, d, c, e){
16551 this.setXY([x, this.getY()], a, d, c, e);
16554 // overridden Element method
16555 setY : function(y, a, d, c, e){
16556 this.setXY([this.getX(), y], a, d, c, e);
16559 // overridden Element method
16560 setSize : function(w, h, a, d, c, e){
16561 this.beforeAction();
16562 var cb = this.createCB(c);
16563 supr.setSize.call(this, w, h, a, d, cb, e);
16569 // overridden Element method
16570 setWidth : function(w, a, d, c, e){
16571 this.beforeAction();
16572 var cb = this.createCB(c);
16573 supr.setWidth.call(this, w, a, d, cb, e);
16579 // overridden Element method
16580 setHeight : function(h, a, d, c, e){
16581 this.beforeAction();
16582 var cb = this.createCB(c);
16583 supr.setHeight.call(this, h, a, d, cb, e);
16589 // overridden Element method
16590 setBounds : function(x, y, w, h, a, d, c, e){
16591 this.beforeAction();
16592 var cb = this.createCB(c);
16594 this.storeXY([x, y]);
16595 supr.setXY.call(this, [x, y]);
16596 supr.setSize.call(this, w, h, a, d, cb, e);
16599 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16605 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16606 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16607 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16608 * @param {Number} zindex The new z-index to set
16609 * @return {this} The Layer
16611 setZIndex : function(zindex){
16612 this.zindex = zindex;
16613 this.setStyle("z-index", zindex + 2);
16615 this.shadow.setZIndex(zindex + 1);
16618 this.shim.setStyle("z-index", zindex);
16623 * Original code for Roojs - LGPL
16624 * <script type="text/javascript">
16628 * @class Roo.XComponent
16629 * A delayed Element creator...
16630 * Or a way to group chunks of interface together.
16631 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16632 * used in conjunction with XComponent.build() it will create an instance of each element,
16633 * then call addxtype() to build the User interface.
16635 * Mypart.xyx = new Roo.XComponent({
16637 parent : 'Mypart.xyz', // empty == document.element.!!
16641 disabled : function() {}
16643 tree : function() { // return an tree of xtype declared components
16647 xtype : 'NestedLayoutPanel',
16654 * It can be used to build a big heiracy, with parent etc.
16655 * or you can just use this to render a single compoent to a dom element
16656 * MYPART.render(Roo.Element | String(id) | dom_element )
16663 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16664 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16666 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16668 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16669 * - if mulitple topModules exist, the last one is defined as the top module.
16673 * When the top level or multiple modules are to embedded into a existing HTML page,
16674 * the parent element can container '#id' of the element where the module will be drawn.
16678 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16679 * it relies more on a include mechanism, where sub modules are included into an outer page.
16680 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16682 * Bootstrap Roo Included elements
16684 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16685 * hence confusing the component builder as it thinks there are multiple top level elements.
16687 * String Over-ride & Translations
16689 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16690 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16691 * are needed. @see Roo.XComponent.overlayString
16695 * @extends Roo.util.Observable
16697 * @param cfg {Object} configuration of component
16700 Roo.XComponent = function(cfg) {
16701 Roo.apply(this, cfg);
16705 * Fires when this the componnt is built
16706 * @param {Roo.XComponent} c the component
16711 this.region = this.region || 'center'; // default..
16712 Roo.XComponent.register(this);
16713 this.modules = false;
16714 this.el = false; // where the layout goes..
16718 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16721 * The created element (with Roo.factory())
16722 * @type {Roo.Layout}
16728 * for BC - use el in new code
16729 * @type {Roo.Layout}
16735 * for BC - use el in new code
16736 * @type {Roo.Layout}
16741 * @cfg {Function|boolean} disabled
16742 * If this module is disabled by some rule, return true from the funtion
16747 * @cfg {String} parent
16748 * Name of parent element which it get xtype added to..
16753 * @cfg {String} order
16754 * Used to set the order in which elements are created (usefull for multiple tabs)
16759 * @cfg {String} name
16760 * String to display while loading.
16764 * @cfg {String} region
16765 * Region to render component to (defaults to center)
16770 * @cfg {Array} items
16771 * A single item array - the first element is the root of the tree..
16772 * It's done this way to stay compatible with the Xtype system...
16778 * The method that retuns the tree of parts that make up this compoennt
16785 * render element to dom or tree
16786 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16789 render : function(el)
16793 var hp = this.parent ? 1 : 0;
16794 Roo.debug && Roo.log(this);
16796 var tree = this._tree ? this._tree() : this.tree();
16799 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16800 // if parent is a '#.....' string, then let's use that..
16801 var ename = this.parent.substr(1);
16802 this.parent = false;
16803 Roo.debug && Roo.log(ename);
16805 case 'bootstrap-body':
16806 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16807 // this is the BorderLayout standard?
16808 this.parent = { el : true };
16811 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16812 // need to insert stuff...
16814 el : new Roo.bootstrap.layout.Border({
16815 el : document.body,
16821 tabPosition: 'top',
16822 //resizeTabs: true,
16823 alwaysShowTabs: true,
16833 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16834 this.parent = { el : new Roo.bootstrap.Body() };
16835 Roo.debug && Roo.log("setting el to doc body");
16838 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16842 this.parent = { el : true};
16845 el = Roo.get(ename);
16846 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16847 this.parent = { el : true};
16854 if (!el && !this.parent) {
16855 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16860 Roo.debug && Roo.log("EL:");
16861 Roo.debug && Roo.log(el);
16862 Roo.debug && Roo.log("this.parent.el:");
16863 Roo.debug && Roo.log(this.parent.el);
16866 // altertive root elements ??? - we need a better way to indicate these.
16867 var is_alt = Roo.XComponent.is_alt ||
16868 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16869 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16870 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16874 if (!this.parent && is_alt) {
16875 //el = Roo.get(document.body);
16876 this.parent = { el : true };
16881 if (!this.parent) {
16883 Roo.debug && Roo.log("no parent - creating one");
16885 el = el ? Roo.get(el) : false;
16887 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16890 el : new Roo.bootstrap.layout.Border({
16891 el: el || document.body,
16897 tabPosition: 'top',
16898 //resizeTabs: true,
16899 alwaysShowTabs: false,
16902 overflow: 'visible'
16908 // it's a top level one..
16910 el : new Roo.BorderLayout(el || document.body, {
16915 tabPosition: 'top',
16916 //resizeTabs: true,
16917 alwaysShowTabs: el && hp? false : true,
16918 hideTabs: el || !hp ? true : false,
16926 if (!this.parent.el) {
16927 // probably an old style ctor, which has been disabled.
16931 // The 'tree' method is '_tree now'
16933 tree.region = tree.region || this.region;
16934 var is_body = false;
16935 if (this.parent.el === true) {
16936 // bootstrap... - body..
16940 this.parent.el = Roo.factory(tree);
16944 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16945 this.fireEvent('built', this);
16947 this.panel = this.el;
16948 this.layout = this.panel.layout;
16949 this.parentLayout = this.parent.layout || false;
16955 Roo.apply(Roo.XComponent, {
16957 * @property hideProgress
16958 * true to disable the building progress bar.. usefull on single page renders.
16961 hideProgress : false,
16963 * @property buildCompleted
16964 * True when the builder has completed building the interface.
16967 buildCompleted : false,
16970 * @property topModule
16971 * the upper most module - uses document.element as it's constructor.
16978 * @property modules
16979 * array of modules to be created by registration system.
16980 * @type {Array} of Roo.XComponent
16985 * @property elmodules
16986 * array of modules to be created by which use #ID
16987 * @type {Array} of Roo.XComponent
16994 * Is an alternative Root - normally used by bootstrap or other systems,
16995 * where the top element in the tree can wrap 'body'
16996 * @type {boolean} (default false)
17001 * @property build_from_html
17002 * Build elements from html - used by bootstrap HTML stuff
17003 * - this is cleared after build is completed
17004 * @type {boolean} (default false)
17007 build_from_html : false,
17009 * Register components to be built later.
17011 * This solves the following issues
17012 * - Building is not done on page load, but after an authentication process has occured.
17013 * - Interface elements are registered on page load
17014 * - Parent Interface elements may not be loaded before child, so this handles that..
17021 module : 'Pman.Tab.projectMgr',
17023 parent : 'Pman.layout',
17024 disabled : false, // or use a function..
17027 * * @param {Object} details about module
17029 register : function(obj) {
17031 Roo.XComponent.event.fireEvent('register', obj);
17032 switch(typeof(obj.disabled) ) {
17038 if ( obj.disabled() ) {
17044 if (obj.disabled || obj.region == '#disabled') {
17050 this.modules.push(obj);
17054 * convert a string to an object..
17055 * eg. 'AAA.BBB' -> finds AAA.BBB
17059 toObject : function(str)
17061 if (!str || typeof(str) == 'object') {
17064 if (str.substring(0,1) == '#') {
17068 var ar = str.split('.');
17073 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17075 throw "Module not found : " + str;
17079 throw "Module not found : " + str;
17081 Roo.each(ar, function(e) {
17082 if (typeof(o[e]) == 'undefined') {
17083 throw "Module not found : " + str;
17094 * move modules into their correct place in the tree..
17097 preBuild : function ()
17100 Roo.each(this.modules , function (obj)
17102 Roo.XComponent.event.fireEvent('beforebuild', obj);
17104 var opar = obj.parent;
17106 obj.parent = this.toObject(opar);
17108 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17113 Roo.debug && Roo.log("GOT top level module");
17114 Roo.debug && Roo.log(obj);
17115 obj.modules = new Roo.util.MixedCollection(false,
17116 function(o) { return o.order + '' }
17118 this.topModule = obj;
17121 // parent is a string (usually a dom element name..)
17122 if (typeof(obj.parent) == 'string') {
17123 this.elmodules.push(obj);
17126 if (obj.parent.constructor != Roo.XComponent) {
17127 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17129 if (!obj.parent.modules) {
17130 obj.parent.modules = new Roo.util.MixedCollection(false,
17131 function(o) { return o.order + '' }
17134 if (obj.parent.disabled) {
17135 obj.disabled = true;
17137 obj.parent.modules.add(obj);
17142 * make a list of modules to build.
17143 * @return {Array} list of modules.
17146 buildOrder : function()
17149 var cmp = function(a,b) {
17150 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17152 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17153 throw "No top level modules to build";
17156 // make a flat list in order of modules to build.
17157 var mods = this.topModule ? [ this.topModule ] : [];
17160 // elmodules (is a list of DOM based modules )
17161 Roo.each(this.elmodules, function(e) {
17163 if (!this.topModule &&
17164 typeof(e.parent) == 'string' &&
17165 e.parent.substring(0,1) == '#' &&
17166 Roo.get(e.parent.substr(1))
17169 _this.topModule = e;
17175 // add modules to their parents..
17176 var addMod = function(m) {
17177 Roo.debug && Roo.log("build Order: add: " + m.name);
17180 if (m.modules && !m.disabled) {
17181 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17182 m.modules.keySort('ASC', cmp );
17183 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17185 m.modules.each(addMod);
17187 Roo.debug && Roo.log("build Order: no child modules");
17189 // not sure if this is used any more..
17191 m.finalize.name = m.name + " (clean up) ";
17192 mods.push(m.finalize);
17196 if (this.topModule && this.topModule.modules) {
17197 this.topModule.modules.keySort('ASC', cmp );
17198 this.topModule.modules.each(addMod);
17204 * Build the registered modules.
17205 * @param {Object} parent element.
17206 * @param {Function} optional method to call after module has been added.
17210 build : function(opts)
17213 if (typeof(opts) != 'undefined') {
17214 Roo.apply(this,opts);
17218 var mods = this.buildOrder();
17220 //this.allmods = mods;
17221 //Roo.debug && Roo.log(mods);
17223 if (!mods.length) { // should not happen
17224 throw "NO modules!!!";
17228 var msg = "Building Interface...";
17229 // flash it up as modal - so we store the mask!?
17230 if (!this.hideProgress && Roo.MessageBox) {
17231 Roo.MessageBox.show({ title: 'loading' });
17232 Roo.MessageBox.show({
17233 title: "Please wait...",
17243 var total = mods.length;
17246 var progressRun = function() {
17247 if (!mods.length) {
17248 Roo.debug && Roo.log('hide?');
17249 if (!this.hideProgress && Roo.MessageBox) {
17250 Roo.MessageBox.hide();
17252 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17254 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17260 var m = mods.shift();
17263 Roo.debug && Roo.log(m);
17264 // not sure if this is supported any more.. - modules that are are just function
17265 if (typeof(m) == 'function') {
17267 return progressRun.defer(10, _this);
17271 msg = "Building Interface " + (total - mods.length) +
17273 (m.name ? (' - ' + m.name) : '');
17274 Roo.debug && Roo.log(msg);
17275 if (!_this.hideProgress && Roo.MessageBox) {
17276 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17280 // is the module disabled?
17281 var disabled = (typeof(m.disabled) == 'function') ?
17282 m.disabled.call(m.module.disabled) : m.disabled;
17286 return progressRun(); // we do not update the display!
17294 // it's 10 on top level, and 1 on others??? why...
17295 return progressRun.defer(10, _this);
17298 progressRun.defer(1, _this);
17304 * Overlay a set of modified strings onto a component
17305 * This is dependant on our builder exporting the strings and 'named strings' elements.
17307 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17308 * @param {Object} associative array of 'named' string and it's new value.
17311 overlayStrings : function( component, strings )
17313 if (typeof(component['_named_strings']) == 'undefined') {
17314 throw "ERROR: component does not have _named_strings";
17316 for ( var k in strings ) {
17317 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17318 if (md !== false) {
17319 component['_strings'][md] = strings[k];
17321 Roo.log('could not find named string: ' + k + ' in');
17322 Roo.log(component);
17337 * wrapper for event.on - aliased later..
17338 * Typically use to register a event handler for register:
17340 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17349 Roo.XComponent.event = new Roo.util.Observable({
17353 * Fires when an Component is registered,
17354 * set the disable property on the Component to stop registration.
17355 * @param {Roo.XComponent} c the component being registerd.
17360 * @event beforebuild
17361 * Fires before each Component is built
17362 * can be used to apply permissions.
17363 * @param {Roo.XComponent} c the component being registerd.
17366 'beforebuild' : true,
17368 * @event buildcomplete
17369 * Fires on the top level element when all elements have been built
17370 * @param {Roo.XComponent} the top level component.
17372 'buildcomplete' : true
17377 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17380 * marked - a markdown parser
17381 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17382 * https://github.com/chjj/marked
17388 * Roo.Markdown - is a very crude wrapper around marked..
17392 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17394 * Note: move the sample code to the bottom of this
17395 * file before uncommenting it.
17400 Roo.Markdown.toHtml = function(text) {
17402 var c = new Roo.Markdown.marked.setOptions({
17403 renderer: new Roo.Markdown.marked.Renderer(),
17414 text = text.replace(/\\\n/g,' ');
17415 return Roo.Markdown.marked(text);
17420 // Wraps all "globals" so that the only thing
17421 // exposed is makeHtml().
17427 * eval:var:unescape
17435 var escape = function (html, encode) {
17437 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17438 .replace(/</g, '<')
17439 .replace(/>/g, '>')
17440 .replace(/"/g, '"')
17441 .replace(/'/g, ''');
17444 var unescape = function (html) {
17445 // explicitly match decimal, hex, and named HTML entities
17446 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17447 n = n.toLowerCase();
17448 if (n === 'colon') { return ':'; }
17449 if (n.charAt(0) === '#') {
17450 return n.charAt(1) === 'x'
17451 ? String.fromCharCode(parseInt(n.substring(2), 16))
17452 : String.fromCharCode(+n.substring(1));
17458 var replace = function (regex, opt) {
17459 regex = regex.source;
17461 return function self(name, val) {
17462 if (!name) { return new RegExp(regex, opt); }
17463 val = val.source || val;
17464 val = val.replace(/(^|[^\[])\^/g, '$1');
17465 regex = regex.replace(name, val);
17474 var noop = function () {}
17480 var merge = function (obj) {
17485 for (; i < arguments.length; i++) {
17486 target = arguments[i];
17487 for (key in target) {
17488 if (Object.prototype.hasOwnProperty.call(target, key)) {
17489 obj[key] = target[key];
17499 * Block-Level Grammar
17507 code: /^( {4}[^\n]+\n*)+/,
17509 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17510 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17512 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17513 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17514 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17515 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17516 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17518 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17522 block.bullet = /(?:[*+-]|\d+\.)/;
17523 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17524 block.item = replace(block.item, 'gm')
17525 (/bull/g, block.bullet)
17528 block.list = replace(block.list)
17529 (/bull/g, block.bullet)
17530 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17531 ('def', '\\n+(?=' + block.def.source + ')')
17534 block.blockquote = replace(block.blockquote)
17538 block._tag = '(?!(?:'
17539 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17540 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17541 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17543 block.html = replace(block.html)
17544 ('comment', /<!--[\s\S]*?-->/)
17545 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17546 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17547 (/tag/g, block._tag)
17550 block.paragraph = replace(block.paragraph)
17552 ('heading', block.heading)
17553 ('lheading', block.lheading)
17554 ('blockquote', block.blockquote)
17555 ('tag', '<' + block._tag)
17560 * Normal Block Grammar
17563 block.normal = merge({}, block);
17566 * GFM Block Grammar
17569 block.gfm = merge({}, block.normal, {
17570 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17572 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17575 block.gfm.paragraph = replace(block.paragraph)
17577 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17578 + block.list.source.replace('\\1', '\\3') + '|')
17582 * GFM + Tables Block Grammar
17585 block.tables = merge({}, block.gfm, {
17586 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17587 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17594 var Lexer = function (options) {
17596 this.tokens.links = {};
17597 this.options = options || marked.defaults;
17598 this.rules = block.normal;
17600 if (this.options.gfm) {
17601 if (this.options.tables) {
17602 this.rules = block.tables;
17604 this.rules = block.gfm;
17610 * Expose Block Rules
17613 Lexer.rules = block;
17616 * Static Lex Method
17619 Lexer.lex = function(src, options) {
17620 var lexer = new Lexer(options);
17621 return lexer.lex(src);
17628 Lexer.prototype.lex = function(src) {
17630 .replace(/\r\n|\r/g, '\n')
17631 .replace(/\t/g, ' ')
17632 .replace(/\u00a0/g, ' ')
17633 .replace(/\u2424/g, '\n');
17635 return this.token(src, true);
17642 Lexer.prototype.token = function(src, top, bq) {
17643 var src = src.replace(/^ +$/gm, '')
17656 if (cap = this.rules.newline.exec(src)) {
17657 src = src.substring(cap[0].length);
17658 if (cap[0].length > 1) {
17666 if (cap = this.rules.code.exec(src)) {
17667 src = src.substring(cap[0].length);
17668 cap = cap[0].replace(/^ {4}/gm, '');
17671 text: !this.options.pedantic
17672 ? cap.replace(/\n+$/, '')
17679 if (cap = this.rules.fences.exec(src)) {
17680 src = src.substring(cap[0].length);
17690 if (cap = this.rules.heading.exec(src)) {
17691 src = src.substring(cap[0].length);
17694 depth: cap[1].length,
17700 // table no leading pipe (gfm)
17701 if (top && (cap = this.rules.nptable.exec(src))) {
17702 src = src.substring(cap[0].length);
17706 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17707 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17708 cells: cap[3].replace(/\n$/, '').split('\n')
17711 for (i = 0; i < item.align.length; i++) {
17712 if (/^ *-+: *$/.test(item.align[i])) {
17713 item.align[i] = 'right';
17714 } else if (/^ *:-+: *$/.test(item.align[i])) {
17715 item.align[i] = 'center';
17716 } else if (/^ *:-+ *$/.test(item.align[i])) {
17717 item.align[i] = 'left';
17719 item.align[i] = null;
17723 for (i = 0; i < item.cells.length; i++) {
17724 item.cells[i] = item.cells[i].split(/ *\| */);
17727 this.tokens.push(item);
17733 if (cap = this.rules.lheading.exec(src)) {
17734 src = src.substring(cap[0].length);
17737 depth: cap[2] === '=' ? 1 : 2,
17744 if (cap = this.rules.hr.exec(src)) {
17745 src = src.substring(cap[0].length);
17753 if (cap = this.rules.blockquote.exec(src)) {
17754 src = src.substring(cap[0].length);
17757 type: 'blockquote_start'
17760 cap = cap[0].replace(/^ *> ?/gm, '');
17762 // Pass `top` to keep the current
17763 // "toplevel" state. This is exactly
17764 // how markdown.pl works.
17765 this.token(cap, top, true);
17768 type: 'blockquote_end'
17775 if (cap = this.rules.list.exec(src)) {
17776 src = src.substring(cap[0].length);
17780 type: 'list_start',
17781 ordered: bull.length > 1
17784 // Get each top-level item.
17785 cap = cap[0].match(this.rules.item);
17791 for (; i < l; i++) {
17794 // Remove the list item's bullet
17795 // so it is seen as the next token.
17796 space = item.length;
17797 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17799 // Outdent whatever the
17800 // list item contains. Hacky.
17801 if (~item.indexOf('\n ')) {
17802 space -= item.length;
17803 item = !this.options.pedantic
17804 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17805 : item.replace(/^ {1,4}/gm, '');
17808 // Determine whether the next list item belongs here.
17809 // Backpedal if it does not belong in this list.
17810 if (this.options.smartLists && i !== l - 1) {
17811 b = block.bullet.exec(cap[i + 1])[0];
17812 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17813 src = cap.slice(i + 1).join('\n') + src;
17818 // Determine whether item is loose or not.
17819 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17820 // for discount behavior.
17821 loose = next || /\n\n(?!\s*$)/.test(item);
17823 next = item.charAt(item.length - 1) === '\n';
17824 if (!loose) { loose = next; }
17829 ? 'loose_item_start'
17830 : 'list_item_start'
17834 this.token(item, false, bq);
17837 type: 'list_item_end'
17849 if (cap = this.rules.html.exec(src)) {
17850 src = src.substring(cap[0].length);
17852 type: this.options.sanitize
17855 pre: !this.options.sanitizer
17856 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17863 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17864 src = src.substring(cap[0].length);
17865 this.tokens.links[cap[1].toLowerCase()] = {
17873 if (top && (cap = this.rules.table.exec(src))) {
17874 src = src.substring(cap[0].length);
17878 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17879 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17880 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17883 for (i = 0; i < item.align.length; i++) {
17884 if (/^ *-+: *$/.test(item.align[i])) {
17885 item.align[i] = 'right';
17886 } else if (/^ *:-+: *$/.test(item.align[i])) {
17887 item.align[i] = 'center';
17888 } else if (/^ *:-+ *$/.test(item.align[i])) {
17889 item.align[i] = 'left';
17891 item.align[i] = null;
17895 for (i = 0; i < item.cells.length; i++) {
17896 item.cells[i] = item.cells[i]
17897 .replace(/^ *\| *| *\| *$/g, '')
17901 this.tokens.push(item);
17906 // top-level paragraph
17907 if (top && (cap = this.rules.paragraph.exec(src))) {
17908 src = src.substring(cap[0].length);
17911 text: cap[1].charAt(cap[1].length - 1) === '\n'
17912 ? cap[1].slice(0, -1)
17919 if (cap = this.rules.text.exec(src)) {
17920 // Top-level should never reach here.
17921 src = src.substring(cap[0].length);
17931 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17935 return this.tokens;
17939 * Inline-Level Grammar
17943 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17944 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17946 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17947 link: /^!?\[(inside)\]\(href\)/,
17948 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17949 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17950 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17951 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17952 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17953 br: /^ {2,}\n(?!\s*$)/,
17955 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17958 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17959 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17961 inline.link = replace(inline.link)
17962 ('inside', inline._inside)
17963 ('href', inline._href)
17966 inline.reflink = replace(inline.reflink)
17967 ('inside', inline._inside)
17971 * Normal Inline Grammar
17974 inline.normal = merge({}, inline);
17977 * Pedantic Inline Grammar
17980 inline.pedantic = merge({}, inline.normal, {
17981 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17982 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17986 * GFM Inline Grammar
17989 inline.gfm = merge({}, inline.normal, {
17990 escape: replace(inline.escape)('])', '~|])')(),
17991 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17992 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17993 text: replace(inline.text)
17995 ('|', '|https?://|')
18000 * GFM + Line Breaks Inline Grammar
18003 inline.breaks = merge({}, inline.gfm, {
18004 br: replace(inline.br)('{2,}', '*')(),
18005 text: replace(inline.gfm.text)('{2,}', '*')()
18009 * Inline Lexer & Compiler
18012 var InlineLexer = function (links, options) {
18013 this.options = options || marked.defaults;
18014 this.links = links;
18015 this.rules = inline.normal;
18016 this.renderer = this.options.renderer || new Renderer;
18017 this.renderer.options = this.options;
18021 Error('Tokens array requires a `links` property.');
18024 if (this.options.gfm) {
18025 if (this.options.breaks) {
18026 this.rules = inline.breaks;
18028 this.rules = inline.gfm;
18030 } else if (this.options.pedantic) {
18031 this.rules = inline.pedantic;
18036 * Expose Inline Rules
18039 InlineLexer.rules = inline;
18042 * Static Lexing/Compiling Method
18045 InlineLexer.output = function(src, links, options) {
18046 var inline = new InlineLexer(links, options);
18047 return inline.output(src);
18054 InlineLexer.prototype.output = function(src) {
18063 if (cap = this.rules.escape.exec(src)) {
18064 src = src.substring(cap[0].length);
18070 if (cap = this.rules.autolink.exec(src)) {
18071 src = src.substring(cap[0].length);
18072 if (cap[2] === '@') {
18073 text = cap[1].charAt(6) === ':'
18074 ? this.mangle(cap[1].substring(7))
18075 : this.mangle(cap[1]);
18076 href = this.mangle('mailto:') + text;
18078 text = escape(cap[1]);
18081 out += this.renderer.link(href, null, text);
18086 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18087 src = src.substring(cap[0].length);
18088 text = escape(cap[1]);
18090 out += this.renderer.link(href, null, text);
18095 if (cap = this.rules.tag.exec(src)) {
18096 if (!this.inLink && /^<a /i.test(cap[0])) {
18097 this.inLink = true;
18098 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18099 this.inLink = false;
18101 src = src.substring(cap[0].length);
18102 out += this.options.sanitize
18103 ? this.options.sanitizer
18104 ? this.options.sanitizer(cap[0])
18111 if (cap = this.rules.link.exec(src)) {
18112 src = src.substring(cap[0].length);
18113 this.inLink = true;
18114 out += this.outputLink(cap, {
18118 this.inLink = false;
18123 if ((cap = this.rules.reflink.exec(src))
18124 || (cap = this.rules.nolink.exec(src))) {
18125 src = src.substring(cap[0].length);
18126 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18127 link = this.links[link.toLowerCase()];
18128 if (!link || !link.href) {
18129 out += cap[0].charAt(0);
18130 src = cap[0].substring(1) + src;
18133 this.inLink = true;
18134 out += this.outputLink(cap, link);
18135 this.inLink = false;
18140 if (cap = this.rules.strong.exec(src)) {
18141 src = src.substring(cap[0].length);
18142 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18147 if (cap = this.rules.em.exec(src)) {
18148 src = src.substring(cap[0].length);
18149 out += this.renderer.em(this.output(cap[2] || cap[1]));
18154 if (cap = this.rules.code.exec(src)) {
18155 src = src.substring(cap[0].length);
18156 out += this.renderer.codespan(escape(cap[2], true));
18161 if (cap = this.rules.br.exec(src)) {
18162 src = src.substring(cap[0].length);
18163 out += this.renderer.br();
18168 if (cap = this.rules.del.exec(src)) {
18169 src = src.substring(cap[0].length);
18170 out += this.renderer.del(this.output(cap[1]));
18175 if (cap = this.rules.text.exec(src)) {
18176 src = src.substring(cap[0].length);
18177 out += this.renderer.text(escape(this.smartypants(cap[0])));
18183 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18194 InlineLexer.prototype.outputLink = function(cap, link) {
18195 var href = escape(link.href)
18196 , title = link.title ? escape(link.title) : null;
18198 return cap[0].charAt(0) !== '!'
18199 ? this.renderer.link(href, title, this.output(cap[1]))
18200 : this.renderer.image(href, title, escape(cap[1]));
18204 * Smartypants Transformations
18207 InlineLexer.prototype.smartypants = function(text) {
18208 if (!this.options.smartypants) { return text; }
18211 .replace(/---/g, '\u2014')
18213 .replace(/--/g, '\u2013')
18215 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18216 // closing singles & apostrophes
18217 .replace(/'/g, '\u2019')
18219 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18221 .replace(/"/g, '\u201d')
18223 .replace(/\.{3}/g, '\u2026');
18230 InlineLexer.prototype.mangle = function(text) {
18231 if (!this.options.mangle) { return text; }
18237 for (; i < l; i++) {
18238 ch = text.charCodeAt(i);
18239 if (Math.random() > 0.5) {
18240 ch = 'x' + ch.toString(16);
18242 out += '&#' + ch + ';';
18253 * eval:var:Renderer
18256 var Renderer = function (options) {
18257 this.options = options || {};
18260 Renderer.prototype.code = function(code, lang, escaped) {
18261 if (this.options.highlight) {
18262 var out = this.options.highlight(code, lang);
18263 if (out != null && out !== code) {
18268 // hack!!! - it's already escapeD?
18273 return '<pre><code>'
18274 + (escaped ? code : escape(code, true))
18275 + '\n</code></pre>';
18278 return '<pre><code class="'
18279 + this.options.langPrefix
18280 + escape(lang, true)
18282 + (escaped ? code : escape(code, true))
18283 + '\n</code></pre>\n';
18286 Renderer.prototype.blockquote = function(quote) {
18287 return '<blockquote>\n' + quote + '</blockquote>\n';
18290 Renderer.prototype.html = function(html) {
18294 Renderer.prototype.heading = function(text, level, raw) {
18298 + this.options.headerPrefix
18299 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18307 Renderer.prototype.hr = function() {
18308 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18311 Renderer.prototype.list = function(body, ordered) {
18312 var type = ordered ? 'ol' : 'ul';
18313 return '<' + type + '>\n' + body + '</' + type + '>\n';
18316 Renderer.prototype.listitem = function(text) {
18317 return '<li>' + text + '</li>\n';
18320 Renderer.prototype.paragraph = function(text) {
18321 return '<p>' + text + '</p>\n';
18324 Renderer.prototype.table = function(header, body) {
18325 return '<table class="table table-striped">\n'
18335 Renderer.prototype.tablerow = function(content) {
18336 return '<tr>\n' + content + '</tr>\n';
18339 Renderer.prototype.tablecell = function(content, flags) {
18340 var type = flags.header ? 'th' : 'td';
18341 var tag = flags.align
18342 ? '<' + type + ' style="text-align:' + flags.align + '">'
18343 : '<' + type + '>';
18344 return tag + content + '</' + type + '>\n';
18347 // span level renderer
18348 Renderer.prototype.strong = function(text) {
18349 return '<strong>' + text + '</strong>';
18352 Renderer.prototype.em = function(text) {
18353 return '<em>' + text + '</em>';
18356 Renderer.prototype.codespan = function(text) {
18357 return '<code>' + text + '</code>';
18360 Renderer.prototype.br = function() {
18361 return this.options.xhtml ? '<br/>' : '<br>';
18364 Renderer.prototype.del = function(text) {
18365 return '<del>' + text + '</del>';
18368 Renderer.prototype.link = function(href, title, text) {
18369 if (this.options.sanitize) {
18371 var prot = decodeURIComponent(unescape(href))
18372 .replace(/[^\w:]/g, '')
18377 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18381 var out = '<a href="' + href + '"';
18383 out += ' title="' + title + '"';
18385 out += '>' + text + '</a>';
18389 Renderer.prototype.image = function(href, title, text) {
18390 var out = '<img src="' + href + '" alt="' + text + '"';
18392 out += ' title="' + title + '"';
18394 out += this.options.xhtml ? '/>' : '>';
18398 Renderer.prototype.text = function(text) {
18403 * Parsing & Compiling
18409 var Parser= function (options) {
18412 this.options = options || marked.defaults;
18413 this.options.renderer = this.options.renderer || new Renderer;
18414 this.renderer = this.options.renderer;
18415 this.renderer.options = this.options;
18419 * Static Parse Method
18422 Parser.parse = function(src, options, renderer) {
18423 var parser = new Parser(options, renderer);
18424 return parser.parse(src);
18431 Parser.prototype.parse = function(src) {
18432 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18433 this.tokens = src.reverse();
18436 while (this.next()) {
18447 Parser.prototype.next = function() {
18448 return this.token = this.tokens.pop();
18452 * Preview Next Token
18455 Parser.prototype.peek = function() {
18456 return this.tokens[this.tokens.length - 1] || 0;
18460 * Parse Text Tokens
18463 Parser.prototype.parseText = function() {
18464 var body = this.token.text;
18466 while (this.peek().type === 'text') {
18467 body += '\n' + this.next().text;
18470 return this.inline.output(body);
18474 * Parse Current Token
18477 Parser.prototype.tok = function() {
18478 switch (this.token.type) {
18483 return this.renderer.hr();
18486 return this.renderer.heading(
18487 this.inline.output(this.token.text),
18492 return this.renderer.code(this.token.text,
18494 this.token.escaped);
18507 for (i = 0; i < this.token.header.length; i++) {
18508 flags = { header: true, align: this.token.align[i] };
18509 cell += this.renderer.tablecell(
18510 this.inline.output(this.token.header[i]),
18511 { header: true, align: this.token.align[i] }
18514 header += this.renderer.tablerow(cell);
18516 for (i = 0; i < this.token.cells.length; i++) {
18517 row = this.token.cells[i];
18520 for (j = 0; j < row.length; j++) {
18521 cell += this.renderer.tablecell(
18522 this.inline.output(row[j]),
18523 { header: false, align: this.token.align[j] }
18527 body += this.renderer.tablerow(cell);
18529 return this.renderer.table(header, body);
18531 case 'blockquote_start': {
18534 while (this.next().type !== 'blockquote_end') {
18535 body += this.tok();
18538 return this.renderer.blockquote(body);
18540 case 'list_start': {
18542 , ordered = this.token.ordered;
18544 while (this.next().type !== 'list_end') {
18545 body += this.tok();
18548 return this.renderer.list(body, ordered);
18550 case 'list_item_start': {
18553 while (this.next().type !== 'list_item_end') {
18554 body += this.token.type === 'text'
18559 return this.renderer.listitem(body);
18561 case 'loose_item_start': {
18564 while (this.next().type !== 'list_item_end') {
18565 body += this.tok();
18568 return this.renderer.listitem(body);
18571 var html = !this.token.pre && !this.options.pedantic
18572 ? this.inline.output(this.token.text)
18574 return this.renderer.html(html);
18576 case 'paragraph': {
18577 return this.renderer.paragraph(this.inline.output(this.token.text));
18580 return this.renderer.paragraph(this.parseText());
18592 var marked = function (src, opt, callback) {
18593 if (callback || typeof opt === 'function') {
18599 opt = merge({}, marked.defaults, opt || {});
18601 var highlight = opt.highlight
18607 tokens = Lexer.lex(src, opt)
18609 return callback(e);
18612 pending = tokens.length;
18616 var done = function(err) {
18618 opt.highlight = highlight;
18619 return callback(err);
18625 out = Parser.parse(tokens, opt);
18630 opt.highlight = highlight;
18634 : callback(null, out);
18637 if (!highlight || highlight.length < 3) {
18641 delete opt.highlight;
18643 if (!pending) { return done(); }
18645 for (; i < tokens.length; i++) {
18647 if (token.type !== 'code') {
18648 return --pending || done();
18650 return highlight(token.text, token.lang, function(err, code) {
18651 if (err) { return done(err); }
18652 if (code == null || code === token.text) {
18653 return --pending || done();
18656 token.escaped = true;
18657 --pending || done();
18665 if (opt) { opt = merge({}, marked.defaults, opt); }
18666 return Parser.parse(Lexer.lex(src, opt), opt);
18668 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18669 if ((opt || marked.defaults).silent) {
18670 return '<p>An error occured:</p><pre>'
18671 + escape(e.message + '', true)
18683 marked.setOptions = function(opt) {
18684 merge(marked.defaults, opt);
18688 marked.defaults = {
18699 langPrefix: 'lang-',
18700 smartypants: false,
18702 renderer: new Renderer,
18710 marked.Parser = Parser;
18711 marked.parser = Parser.parse;
18713 marked.Renderer = Renderer;
18715 marked.Lexer = Lexer;
18716 marked.lexer = Lexer.lex;
18718 marked.InlineLexer = InlineLexer;
18719 marked.inlineLexer = InlineLexer.output;
18721 marked.parse = marked;
18723 Roo.Markdown.marked = marked;
18727 * Ext JS Library 1.1.1
18728 * Copyright(c) 2006-2007, Ext JS, LLC.
18730 * Originally Released Under LGPL - original licence link has changed is not relivant.
18733 * <script type="text/javascript">
18739 * These classes are derivatives of the similarly named classes in the YUI Library.
18740 * The original license:
18741 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18742 * Code licensed under the BSD License:
18743 * http://developer.yahoo.net/yui/license.txt
18748 var Event=Roo.EventManager;
18749 var Dom=Roo.lib.Dom;
18752 * @class Roo.dd.DragDrop
18753 * @extends Roo.util.Observable
18754 * Defines the interface and base operation of items that that can be
18755 * dragged or can be drop targets. It was designed to be extended, overriding
18756 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18757 * Up to three html elements can be associated with a DragDrop instance:
18759 * <li>linked element: the element that is passed into the constructor.
18760 * This is the element which defines the boundaries for interaction with
18761 * other DragDrop objects.</li>
18762 * <li>handle element(s): The drag operation only occurs if the element that
18763 * was clicked matches a handle element. By default this is the linked
18764 * element, but there are times that you will want only a portion of the
18765 * linked element to initiate the drag operation, and the setHandleElId()
18766 * method provides a way to define this.</li>
18767 * <li>drag element: this represents the element that would be moved along
18768 * with the cursor during a drag operation. By default, this is the linked
18769 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18770 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18773 * This class should not be instantiated until the onload event to ensure that
18774 * the associated elements are available.
18775 * The following would define a DragDrop obj that would interact with any
18776 * other DragDrop obj in the "group1" group:
18778 * dd = new Roo.dd.DragDrop("div1", "group1");
18780 * Since none of the event handlers have been implemented, nothing would
18781 * actually happen if you were to run the code above. Normally you would
18782 * override this class or one of the default implementations, but you can
18783 * also override the methods you want on an instance of the class...
18785 * dd.onDragDrop = function(e, id) {
18786 * alert("dd was dropped on " + id);
18790 * @param {String} id of the element that is linked to this instance
18791 * @param {String} sGroup the group of related DragDrop objects
18792 * @param {object} config an object containing configurable attributes
18793 * Valid properties for DragDrop:
18794 * padding, isTarget, maintainOffset, primaryButtonOnly
18796 Roo.dd.DragDrop = function(id, sGroup, config) {
18798 this.init(id, sGroup, config);
18803 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18806 * The id of the element associated with this object. This is what we
18807 * refer to as the "linked element" because the size and position of
18808 * this element is used to determine when the drag and drop objects have
18816 * Configuration attributes passed into the constructor
18823 * The id of the element that will be dragged. By default this is same
18824 * as the linked element , but could be changed to another element. Ex:
18826 * @property dragElId
18833 * the id of the element that initiates the drag operation. By default
18834 * this is the linked element, but could be changed to be a child of this
18835 * element. This lets us do things like only starting the drag when the
18836 * header element within the linked html element is clicked.
18837 * @property handleElId
18844 * An associative array of HTML tags that will be ignored if clicked.
18845 * @property invalidHandleTypes
18846 * @type {string: string}
18848 invalidHandleTypes: null,
18851 * An associative array of ids for elements that will be ignored if clicked
18852 * @property invalidHandleIds
18853 * @type {string: string}
18855 invalidHandleIds: null,
18858 * An indexted array of css class names for elements that will be ignored
18860 * @property invalidHandleClasses
18863 invalidHandleClasses: null,
18866 * The linked element's absolute X position at the time the drag was
18868 * @property startPageX
18875 * The linked element's absolute X position at the time the drag was
18877 * @property startPageY
18884 * The group defines a logical collection of DragDrop objects that are
18885 * related. Instances only get events when interacting with other
18886 * DragDrop object in the same group. This lets us define multiple
18887 * groups using a single DragDrop subclass if we want.
18889 * @type {string: string}
18894 * Individual drag/drop instances can be locked. This will prevent
18895 * onmousedown start drag.
18903 * Lock this instance
18906 lock: function() { this.locked = true; },
18909 * Unlock this instace
18912 unlock: function() { this.locked = false; },
18915 * By default, all insances can be a drop target. This can be disabled by
18916 * setting isTarget to false.
18923 * The padding configured for this drag and drop object for calculating
18924 * the drop zone intersection with this object.
18931 * Cached reference to the linked element
18932 * @property _domRef
18938 * Internal typeof flag
18939 * @property __ygDragDrop
18942 __ygDragDrop: true,
18945 * Set to true when horizontal contraints are applied
18946 * @property constrainX
18953 * Set to true when vertical contraints are applied
18954 * @property constrainY
18961 * The left constraint
18969 * The right constraint
18977 * The up constraint
18986 * The down constraint
18994 * Maintain offsets when we resetconstraints. Set to true when you want
18995 * the position of the element relative to its parent to stay the same
18996 * when the page changes
18998 * @property maintainOffset
19001 maintainOffset: false,
19004 * Array of pixel locations the element will snap to if we specified a
19005 * horizontal graduation/interval. This array is generated automatically
19006 * when you define a tick interval.
19013 * Array of pixel locations the element will snap to if we specified a
19014 * vertical graduation/interval. This array is generated automatically
19015 * when you define a tick interval.
19022 * By default the drag and drop instance will only respond to the primary
19023 * button click (left button for a right-handed mouse). Set to true to
19024 * allow drag and drop to start with any mouse click that is propogated
19026 * @property primaryButtonOnly
19029 primaryButtonOnly: true,
19032 * The availabe property is false until the linked dom element is accessible.
19033 * @property available
19039 * By default, drags can only be initiated if the mousedown occurs in the
19040 * region the linked element is. This is done in part to work around a
19041 * bug in some browsers that mis-report the mousedown if the previous
19042 * mouseup happened outside of the window. This property is set to true
19043 * if outer handles are defined.
19045 * @property hasOuterHandles
19049 hasOuterHandles: false,
19052 * Code that executes immediately before the startDrag event
19053 * @method b4StartDrag
19056 b4StartDrag: function(x, y) { },
19059 * Abstract method called after a drag/drop object is clicked
19060 * and the drag or mousedown time thresholds have beeen met.
19061 * @method startDrag
19062 * @param {int} X click location
19063 * @param {int} Y click location
19065 startDrag: function(x, y) { /* override this */ },
19068 * Code that executes immediately before the onDrag event
19072 b4Drag: function(e) { },
19075 * Abstract method called during the onMouseMove event while dragging an
19078 * @param {Event} e the mousemove event
19080 onDrag: function(e) { /* override this */ },
19083 * Abstract method called when this element fist begins hovering over
19084 * another DragDrop obj
19085 * @method onDragEnter
19086 * @param {Event} e the mousemove event
19087 * @param {String|DragDrop[]} id In POINT mode, the element
19088 * id this is hovering over. In INTERSECT mode, an array of one or more
19089 * dragdrop items being hovered over.
19091 onDragEnter: function(e, id) { /* override this */ },
19094 * Code that executes immediately before the onDragOver event
19095 * @method b4DragOver
19098 b4DragOver: function(e) { },
19101 * Abstract method called when this element is hovering over another
19103 * @method onDragOver
19104 * @param {Event} e the mousemove event
19105 * @param {String|DragDrop[]} id In POINT mode, the element
19106 * id this is hovering over. In INTERSECT mode, an array of dd items
19107 * being hovered over.
19109 onDragOver: function(e, id) { /* override this */ },
19112 * Code that executes immediately before the onDragOut event
19113 * @method b4DragOut
19116 b4DragOut: function(e) { },
19119 * Abstract method called when we are no longer hovering over an element
19120 * @method onDragOut
19121 * @param {Event} e the mousemove event
19122 * @param {String|DragDrop[]} id In POINT mode, the element
19123 * id this was hovering over. In INTERSECT mode, an array of dd items
19124 * that the mouse is no longer over.
19126 onDragOut: function(e, id) { /* override this */ },
19129 * Code that executes immediately before the onDragDrop event
19130 * @method b4DragDrop
19133 b4DragDrop: function(e) { },
19136 * Abstract method called when this item is dropped on another DragDrop
19138 * @method onDragDrop
19139 * @param {Event} e the mouseup event
19140 * @param {String|DragDrop[]} id In POINT mode, the element
19141 * id this was dropped on. In INTERSECT mode, an array of dd items this
19144 onDragDrop: function(e, id) { /* override this */ },
19147 * Abstract method called when this item is dropped on an area with no
19149 * @method onInvalidDrop
19150 * @param {Event} e the mouseup event
19152 onInvalidDrop: function(e) { /* override this */ },
19155 * Code that executes immediately before the endDrag event
19156 * @method b4EndDrag
19159 b4EndDrag: function(e) { },
19162 * Fired when we are done dragging the object
19164 * @param {Event} e the mouseup event
19166 endDrag: function(e) { /* override this */ },
19169 * Code executed immediately before the onMouseDown event
19170 * @method b4MouseDown
19171 * @param {Event} e the mousedown event
19174 b4MouseDown: function(e) { },
19177 * Event handler that fires when a drag/drop obj gets a mousedown
19178 * @method onMouseDown
19179 * @param {Event} e the mousedown event
19181 onMouseDown: function(e) { /* override this */ },
19184 * Event handler that fires when a drag/drop obj gets a mouseup
19185 * @method onMouseUp
19186 * @param {Event} e the mouseup event
19188 onMouseUp: function(e) { /* override this */ },
19191 * Override the onAvailable method to do what is needed after the initial
19192 * position was determined.
19193 * @method onAvailable
19195 onAvailable: function () {
19199 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19202 defaultPadding : {left:0, right:0, top:0, bottom:0},
19205 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19209 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19210 { dragElId: "existingProxyDiv" });
19211 dd.startDrag = function(){
19212 this.constrainTo("parent-id");
19215 * Or you can initalize it using the {@link Roo.Element} object:
19217 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19218 startDrag : function(){
19219 this.constrainTo("parent-id");
19223 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19224 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19225 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19226 * an object containing the sides to pad. For example: {right:10, bottom:10}
19227 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19229 constrainTo : function(constrainTo, pad, inContent){
19230 if(typeof pad == "number"){
19231 pad = {left: pad, right:pad, top:pad, bottom:pad};
19233 pad = pad || this.defaultPadding;
19234 var b = Roo.get(this.getEl()).getBox();
19235 var ce = Roo.get(constrainTo);
19236 var s = ce.getScroll();
19237 var c, cd = ce.dom;
19238 if(cd == document.body){
19239 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19242 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19246 var topSpace = b.y - c.y;
19247 var leftSpace = b.x - c.x;
19249 this.resetConstraints();
19250 this.setXConstraint(leftSpace - (pad.left||0), // left
19251 c.width - leftSpace - b.width - (pad.right||0) //right
19253 this.setYConstraint(topSpace - (pad.top||0), //top
19254 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19259 * Returns a reference to the linked element
19261 * @return {HTMLElement} the html element
19263 getEl: function() {
19264 if (!this._domRef) {
19265 this._domRef = Roo.getDom(this.id);
19268 return this._domRef;
19272 * Returns a reference to the actual element to drag. By default this is
19273 * the same as the html element, but it can be assigned to another
19274 * element. An example of this can be found in Roo.dd.DDProxy
19275 * @method getDragEl
19276 * @return {HTMLElement} the html element
19278 getDragEl: function() {
19279 return Roo.getDom(this.dragElId);
19283 * Sets up the DragDrop object. Must be called in the constructor of any
19284 * Roo.dd.DragDrop subclass
19286 * @param id the id of the linked element
19287 * @param {String} sGroup the group of related items
19288 * @param {object} config configuration attributes
19290 init: function(id, sGroup, config) {
19291 this.initTarget(id, sGroup, config);
19292 if (!Roo.isTouch) {
19293 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19295 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19296 // Event.on(this.id, "selectstart", Event.preventDefault);
19300 * Initializes Targeting functionality only... the object does not
19301 * get a mousedown handler.
19302 * @method initTarget
19303 * @param id the id of the linked element
19304 * @param {String} sGroup the group of related items
19305 * @param {object} config configuration attributes
19307 initTarget: function(id, sGroup, config) {
19309 // configuration attributes
19310 this.config = config || {};
19312 // create a local reference to the drag and drop manager
19313 this.DDM = Roo.dd.DDM;
19314 // initialize the groups array
19317 // assume that we have an element reference instead of an id if the
19318 // parameter is not a string
19319 if (typeof id !== "string") {
19326 // add to an interaction group
19327 this.addToGroup((sGroup) ? sGroup : "default");
19329 // We don't want to register this as the handle with the manager
19330 // so we just set the id rather than calling the setter.
19331 this.handleElId = id;
19333 // the linked element is the element that gets dragged by default
19334 this.setDragElId(id);
19336 // by default, clicked anchors will not start drag operations.
19337 this.invalidHandleTypes = { A: "A" };
19338 this.invalidHandleIds = {};
19339 this.invalidHandleClasses = [];
19341 this.applyConfig();
19343 this.handleOnAvailable();
19347 * Applies the configuration parameters that were passed into the constructor.
19348 * This is supposed to happen at each level through the inheritance chain. So
19349 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19350 * DragDrop in order to get all of the parameters that are available in
19352 * @method applyConfig
19354 applyConfig: function() {
19356 // configurable properties:
19357 // padding, isTarget, maintainOffset, primaryButtonOnly
19358 this.padding = this.config.padding || [0, 0, 0, 0];
19359 this.isTarget = (this.config.isTarget !== false);
19360 this.maintainOffset = (this.config.maintainOffset);
19361 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19366 * Executed when the linked element is available
19367 * @method handleOnAvailable
19370 handleOnAvailable: function() {
19371 this.available = true;
19372 this.resetConstraints();
19373 this.onAvailable();
19377 * Configures the padding for the target zone in px. Effectively expands
19378 * (or reduces) the virtual object size for targeting calculations.
19379 * Supports css-style shorthand; if only one parameter is passed, all sides
19380 * will have that padding, and if only two are passed, the top and bottom
19381 * will have the first param, the left and right the second.
19382 * @method setPadding
19383 * @param {int} iTop Top pad
19384 * @param {int} iRight Right pad
19385 * @param {int} iBot Bot pad
19386 * @param {int} iLeft Left pad
19388 setPadding: function(iTop, iRight, iBot, iLeft) {
19389 // this.padding = [iLeft, iRight, iTop, iBot];
19390 if (!iRight && 0 !== iRight) {
19391 this.padding = [iTop, iTop, iTop, iTop];
19392 } else if (!iBot && 0 !== iBot) {
19393 this.padding = [iTop, iRight, iTop, iRight];
19395 this.padding = [iTop, iRight, iBot, iLeft];
19400 * Stores the initial placement of the linked element.
19401 * @method setInitialPosition
19402 * @param {int} diffX the X offset, default 0
19403 * @param {int} diffY the Y offset, default 0
19405 setInitPosition: function(diffX, diffY) {
19406 var el = this.getEl();
19408 if (!this.DDM.verifyEl(el)) {
19412 var dx = diffX || 0;
19413 var dy = diffY || 0;
19415 var p = Dom.getXY( el );
19417 this.initPageX = p[0] - dx;
19418 this.initPageY = p[1] - dy;
19420 this.lastPageX = p[0];
19421 this.lastPageY = p[1];
19424 this.setStartPosition(p);
19428 * Sets the start position of the element. This is set when the obj
19429 * is initialized, the reset when a drag is started.
19430 * @method setStartPosition
19431 * @param pos current position (from previous lookup)
19434 setStartPosition: function(pos) {
19435 var p = pos || Dom.getXY( this.getEl() );
19436 this.deltaSetXY = null;
19438 this.startPageX = p[0];
19439 this.startPageY = p[1];
19443 * Add this instance to a group of related drag/drop objects. All
19444 * instances belong to at least one group, and can belong to as many
19445 * groups as needed.
19446 * @method addToGroup
19447 * @param sGroup {string} the name of the group
19449 addToGroup: function(sGroup) {
19450 this.groups[sGroup] = true;
19451 this.DDM.regDragDrop(this, sGroup);
19455 * Remove's this instance from the supplied interaction group
19456 * @method removeFromGroup
19457 * @param {string} sGroup The group to drop
19459 removeFromGroup: function(sGroup) {
19460 if (this.groups[sGroup]) {
19461 delete this.groups[sGroup];
19464 this.DDM.removeDDFromGroup(this, sGroup);
19468 * Allows you to specify that an element other than the linked element
19469 * will be moved with the cursor during a drag
19470 * @method setDragElId
19471 * @param id {string} the id of the element that will be used to initiate the drag
19473 setDragElId: function(id) {
19474 this.dragElId = id;
19478 * Allows you to specify a child of the linked element that should be
19479 * used to initiate the drag operation. An example of this would be if
19480 * you have a content div with text and links. Clicking anywhere in the
19481 * content area would normally start the drag operation. Use this method
19482 * to specify that an element inside of the content div is the element
19483 * that starts the drag operation.
19484 * @method setHandleElId
19485 * @param id {string} the id of the element that will be used to
19486 * initiate the drag.
19488 setHandleElId: function(id) {
19489 if (typeof id !== "string") {
19492 this.handleElId = id;
19493 this.DDM.regHandle(this.id, id);
19497 * Allows you to set an element outside of the linked element as a drag
19499 * @method setOuterHandleElId
19500 * @param id the id of the element that will be used to initiate the drag
19502 setOuterHandleElId: function(id) {
19503 if (typeof id !== "string") {
19506 Event.on(id, "mousedown",
19507 this.handleMouseDown, this);
19508 this.setHandleElId(id);
19510 this.hasOuterHandles = true;
19514 * Remove all drag and drop hooks for this element
19517 unreg: function() {
19518 Event.un(this.id, "mousedown",
19519 this.handleMouseDown);
19520 Event.un(this.id, "touchstart",
19521 this.handleMouseDown);
19522 this._domRef = null;
19523 this.DDM._remove(this);
19526 destroy : function(){
19531 * Returns true if this instance is locked, or the drag drop mgr is locked
19532 * (meaning that all drag/drop is disabled on the page.)
19534 * @return {boolean} true if this obj or all drag/drop is locked, else
19537 isLocked: function() {
19538 return (this.DDM.isLocked() || this.locked);
19542 * Fired when this object is clicked
19543 * @method handleMouseDown
19545 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19548 handleMouseDown: function(e, oDD){
19550 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19551 //Roo.log('not touch/ button !=0');
19554 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19555 return; // double touch..
19559 if (this.isLocked()) {
19560 //Roo.log('locked');
19564 this.DDM.refreshCache(this.groups);
19565 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19566 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19567 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19568 //Roo.log('no outer handes or not over target');
19571 // Roo.log('check validator');
19572 if (this.clickValidator(e)) {
19573 // Roo.log('validate success');
19574 // set the initial element position
19575 this.setStartPosition();
19578 this.b4MouseDown(e);
19579 this.onMouseDown(e);
19581 this.DDM.handleMouseDown(e, this);
19583 this.DDM.stopEvent(e);
19591 clickValidator: function(e) {
19592 var target = e.getTarget();
19593 return ( this.isValidHandleChild(target) &&
19594 (this.id == this.handleElId ||
19595 this.DDM.handleWasClicked(target, this.id)) );
19599 * Allows you to specify a tag name that should not start a drag operation
19600 * when clicked. This is designed to facilitate embedding links within a
19601 * drag handle that do something other than start the drag.
19602 * @method addInvalidHandleType
19603 * @param {string} tagName the type of element to exclude
19605 addInvalidHandleType: function(tagName) {
19606 var type = tagName.toUpperCase();
19607 this.invalidHandleTypes[type] = type;
19611 * Lets you to specify an element id for a child of a drag handle
19612 * that should not initiate a drag
19613 * @method addInvalidHandleId
19614 * @param {string} id the element id of the element you wish to ignore
19616 addInvalidHandleId: function(id) {
19617 if (typeof id !== "string") {
19620 this.invalidHandleIds[id] = id;
19624 * Lets you specify a css class of elements that will not initiate a drag
19625 * @method addInvalidHandleClass
19626 * @param {string} cssClass the class of the elements you wish to ignore
19628 addInvalidHandleClass: function(cssClass) {
19629 this.invalidHandleClasses.push(cssClass);
19633 * Unsets an excluded tag name set by addInvalidHandleType
19634 * @method removeInvalidHandleType
19635 * @param {string} tagName the type of element to unexclude
19637 removeInvalidHandleType: function(tagName) {
19638 var type = tagName.toUpperCase();
19639 // this.invalidHandleTypes[type] = null;
19640 delete this.invalidHandleTypes[type];
19644 * Unsets an invalid handle id
19645 * @method removeInvalidHandleId
19646 * @param {string} id the id of the element to re-enable
19648 removeInvalidHandleId: function(id) {
19649 if (typeof id !== "string") {
19652 delete this.invalidHandleIds[id];
19656 * Unsets an invalid css class
19657 * @method removeInvalidHandleClass
19658 * @param {string} cssClass the class of the element(s) you wish to
19661 removeInvalidHandleClass: function(cssClass) {
19662 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19663 if (this.invalidHandleClasses[i] == cssClass) {
19664 delete this.invalidHandleClasses[i];
19670 * Checks the tag exclusion list to see if this click should be ignored
19671 * @method isValidHandleChild
19672 * @param {HTMLElement} node the HTMLElement to evaluate
19673 * @return {boolean} true if this is a valid tag type, false if not
19675 isValidHandleChild: function(node) {
19678 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19681 nodeName = node.nodeName.toUpperCase();
19683 nodeName = node.nodeName;
19685 valid = valid && !this.invalidHandleTypes[nodeName];
19686 valid = valid && !this.invalidHandleIds[node.id];
19688 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19689 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19698 * Create the array of horizontal tick marks if an interval was specified
19699 * in setXConstraint().
19700 * @method setXTicks
19703 setXTicks: function(iStartX, iTickSize) {
19705 this.xTickSize = iTickSize;
19709 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19711 this.xTicks[this.xTicks.length] = i;
19716 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19718 this.xTicks[this.xTicks.length] = i;
19723 this.xTicks.sort(this.DDM.numericSort) ;
19727 * Create the array of vertical tick marks if an interval was specified in
19728 * setYConstraint().
19729 * @method setYTicks
19732 setYTicks: function(iStartY, iTickSize) {
19734 this.yTickSize = iTickSize;
19738 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19740 this.yTicks[this.yTicks.length] = i;
19745 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19747 this.yTicks[this.yTicks.length] = i;
19752 this.yTicks.sort(this.DDM.numericSort) ;
19756 * By default, the element can be dragged any place on the screen. Use
19757 * this method to limit the horizontal travel of the element. Pass in
19758 * 0,0 for the parameters if you want to lock the drag to the y axis.
19759 * @method setXConstraint
19760 * @param {int} iLeft the number of pixels the element can move to the left
19761 * @param {int} iRight the number of pixels the element can move to the
19763 * @param {int} iTickSize optional parameter for specifying that the
19765 * should move iTickSize pixels at a time.
19767 setXConstraint: function(iLeft, iRight, iTickSize) {
19768 this.leftConstraint = iLeft;
19769 this.rightConstraint = iRight;
19771 this.minX = this.initPageX - iLeft;
19772 this.maxX = this.initPageX + iRight;
19773 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19775 this.constrainX = true;
19779 * Clears any constraints applied to this instance. Also clears ticks
19780 * since they can't exist independent of a constraint at this time.
19781 * @method clearConstraints
19783 clearConstraints: function() {
19784 this.constrainX = false;
19785 this.constrainY = false;
19790 * Clears any tick interval defined for this instance
19791 * @method clearTicks
19793 clearTicks: function() {
19794 this.xTicks = null;
19795 this.yTicks = null;
19796 this.xTickSize = 0;
19797 this.yTickSize = 0;
19801 * By default, the element can be dragged any place on the screen. Set
19802 * this to limit the vertical travel of the element. Pass in 0,0 for the
19803 * parameters if you want to lock the drag to the x axis.
19804 * @method setYConstraint
19805 * @param {int} iUp the number of pixels the element can move up
19806 * @param {int} iDown the number of pixels the element can move down
19807 * @param {int} iTickSize optional parameter for specifying that the
19808 * element should move iTickSize pixels at a time.
19810 setYConstraint: function(iUp, iDown, iTickSize) {
19811 this.topConstraint = iUp;
19812 this.bottomConstraint = iDown;
19814 this.minY = this.initPageY - iUp;
19815 this.maxY = this.initPageY + iDown;
19816 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19818 this.constrainY = true;
19823 * resetConstraints must be called if you manually reposition a dd element.
19824 * @method resetConstraints
19825 * @param {boolean} maintainOffset
19827 resetConstraints: function() {
19830 // Maintain offsets if necessary
19831 if (this.initPageX || this.initPageX === 0) {
19832 // figure out how much this thing has moved
19833 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19834 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19836 this.setInitPosition(dx, dy);
19838 // This is the first time we have detected the element's position
19840 this.setInitPosition();
19843 if (this.constrainX) {
19844 this.setXConstraint( this.leftConstraint,
19845 this.rightConstraint,
19849 if (this.constrainY) {
19850 this.setYConstraint( this.topConstraint,
19851 this.bottomConstraint,
19857 * Normally the drag element is moved pixel by pixel, but we can specify
19858 * that it move a number of pixels at a time. This method resolves the
19859 * location when we have it set up like this.
19861 * @param {int} val where we want to place the object
19862 * @param {int[]} tickArray sorted array of valid points
19863 * @return {int} the closest tick
19866 getTick: function(val, tickArray) {
19869 // If tick interval is not defined, it is effectively 1 pixel,
19870 // so we return the value passed to us.
19872 } else if (tickArray[0] >= val) {
19873 // The value is lower than the first tick, so we return the first
19875 return tickArray[0];
19877 for (var i=0, len=tickArray.length; i<len; ++i) {
19879 if (tickArray[next] && tickArray[next] >= val) {
19880 var diff1 = val - tickArray[i];
19881 var diff2 = tickArray[next] - val;
19882 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19886 // The value is larger than the last tick, so we return the last
19888 return tickArray[tickArray.length - 1];
19895 * @return {string} string representation of the dd obj
19897 toString: function() {
19898 return ("DragDrop " + this.id);
19906 * Ext JS Library 1.1.1
19907 * Copyright(c) 2006-2007, Ext JS, LLC.
19909 * Originally Released Under LGPL - original licence link has changed is not relivant.
19912 * <script type="text/javascript">
19917 * The drag and drop utility provides a framework for building drag and drop
19918 * applications. In addition to enabling drag and drop for specific elements,
19919 * the drag and drop elements are tracked by the manager class, and the
19920 * interactions between the various elements are tracked during the drag and
19921 * the implementing code is notified about these important moments.
19924 // Only load the library once. Rewriting the manager class would orphan
19925 // existing drag and drop instances.
19926 if (!Roo.dd.DragDropMgr) {
19929 * @class Roo.dd.DragDropMgr
19930 * DragDropMgr is a singleton that tracks the element interaction for
19931 * all DragDrop items in the window. Generally, you will not call
19932 * this class directly, but it does have helper methods that could
19933 * be useful in your DragDrop implementations.
19936 Roo.dd.DragDropMgr = function() {
19938 var Event = Roo.EventManager;
19943 * Two dimensional Array of registered DragDrop objects. The first
19944 * dimension is the DragDrop item group, the second the DragDrop
19947 * @type {string: string}
19954 * Array of element ids defined as drag handles. Used to determine
19955 * if the element that generated the mousedown event is actually the
19956 * handle and not the html element itself.
19957 * @property handleIds
19958 * @type {string: string}
19965 * the DragDrop object that is currently being dragged
19966 * @property dragCurrent
19974 * the DragDrop object(s) that are being hovered over
19975 * @property dragOvers
19983 * the X distance between the cursor and the object being dragged
19992 * the Y distance between the cursor and the object being dragged
20001 * Flag to determine if we should prevent the default behavior of the
20002 * events we define. By default this is true, but this can be set to
20003 * false if you need the default behavior (not recommended)
20004 * @property preventDefault
20008 preventDefault: true,
20011 * Flag to determine if we should stop the propagation of the events
20012 * we generate. This is true by default but you may want to set it to
20013 * false if the html element contains other features that require the
20015 * @property stopPropagation
20019 stopPropagation: true,
20022 * Internal flag that is set to true when drag and drop has been
20024 * @property initialized
20031 * All drag and drop can be disabled.
20039 * Called the first time an element is registered.
20045 this.initialized = true;
20049 * In point mode, drag and drop interaction is defined by the
20050 * location of the cursor during the drag/drop
20058 * In intersect mode, drag and drop interactio nis defined by the
20059 * overlap of two or more drag and drop objects.
20060 * @property INTERSECT
20067 * The current drag and drop mode. Default: POINT
20075 * Runs method on all drag and drop objects
20076 * @method _execOnAll
20080 _execOnAll: function(sMethod, args) {
20081 for (var i in this.ids) {
20082 for (var j in this.ids[i]) {
20083 var oDD = this.ids[i][j];
20084 if (! this.isTypeOfDD(oDD)) {
20087 oDD[sMethod].apply(oDD, args);
20093 * Drag and drop initialization. Sets up the global event handlers
20098 _onLoad: function() {
20102 if (!Roo.isTouch) {
20103 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20104 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20106 Event.on(document, "touchend", this.handleMouseUp, this, true);
20107 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20109 Event.on(window, "unload", this._onUnload, this, true);
20110 Event.on(window, "resize", this._onResize, this, true);
20111 // Event.on(window, "mouseout", this._test);
20116 * Reset constraints on all drag and drop objs
20117 * @method _onResize
20121 _onResize: function(e) {
20122 this._execOnAll("resetConstraints", []);
20126 * Lock all drag and drop functionality
20130 lock: function() { this.locked = true; },
20133 * Unlock all drag and drop functionality
20137 unlock: function() { this.locked = false; },
20140 * Is drag and drop locked?
20142 * @return {boolean} True if drag and drop is locked, false otherwise.
20145 isLocked: function() { return this.locked; },
20148 * Location cache that is set for all drag drop objects when a drag is
20149 * initiated, cleared when the drag is finished.
20150 * @property locationCache
20157 * Set useCache to false if you want to force object the lookup of each
20158 * drag and drop linked element constantly during a drag.
20159 * @property useCache
20166 * The number of pixels that the mouse needs to move after the
20167 * mousedown before the drag is initiated. Default=3;
20168 * @property clickPixelThresh
20172 clickPixelThresh: 3,
20175 * The number of milliseconds after the mousedown event to initiate the
20176 * drag if we don't get a mouseup event. Default=1000
20177 * @property clickTimeThresh
20181 clickTimeThresh: 350,
20184 * Flag that indicates that either the drag pixel threshold or the
20185 * mousdown time threshold has been met
20186 * @property dragThreshMet
20191 dragThreshMet: false,
20194 * Timeout used for the click time threshold
20195 * @property clickTimeout
20200 clickTimeout: null,
20203 * The X position of the mousedown event stored for later use when a
20204 * drag threshold is met.
20213 * The Y position of the mousedown event stored for later use when a
20214 * drag threshold is met.
20223 * Each DragDrop instance must be registered with the DragDropMgr.
20224 * This is executed in DragDrop.init()
20225 * @method regDragDrop
20226 * @param {DragDrop} oDD the DragDrop object to register
20227 * @param {String} sGroup the name of the group this element belongs to
20230 regDragDrop: function(oDD, sGroup) {
20231 if (!this.initialized) { this.init(); }
20233 if (!this.ids[sGroup]) {
20234 this.ids[sGroup] = {};
20236 this.ids[sGroup][oDD.id] = oDD;
20240 * Removes the supplied dd instance from the supplied group. Executed
20241 * by DragDrop.removeFromGroup, so don't call this function directly.
20242 * @method removeDDFromGroup
20246 removeDDFromGroup: function(oDD, sGroup) {
20247 if (!this.ids[sGroup]) {
20248 this.ids[sGroup] = {};
20251 var obj = this.ids[sGroup];
20252 if (obj && obj[oDD.id]) {
20253 delete obj[oDD.id];
20258 * Unregisters a drag and drop item. This is executed in
20259 * DragDrop.unreg, use that method instead of calling this directly.
20264 _remove: function(oDD) {
20265 for (var g in oDD.groups) {
20266 if (g && this.ids[g][oDD.id]) {
20267 delete this.ids[g][oDD.id];
20270 delete this.handleIds[oDD.id];
20274 * Each DragDrop handle element must be registered. This is done
20275 * automatically when executing DragDrop.setHandleElId()
20276 * @method regHandle
20277 * @param {String} sDDId the DragDrop id this element is a handle for
20278 * @param {String} sHandleId the id of the element that is the drag
20282 regHandle: function(sDDId, sHandleId) {
20283 if (!this.handleIds[sDDId]) {
20284 this.handleIds[sDDId] = {};
20286 this.handleIds[sDDId][sHandleId] = sHandleId;
20290 * Utility function to determine if a given element has been
20291 * registered as a drag drop item.
20292 * @method isDragDrop
20293 * @param {String} id the element id to check
20294 * @return {boolean} true if this element is a DragDrop item,
20298 isDragDrop: function(id) {
20299 return ( this.getDDById(id) ) ? true : false;
20303 * Returns the drag and drop instances that are in all groups the
20304 * passed in instance belongs to.
20305 * @method getRelated
20306 * @param {DragDrop} p_oDD the obj to get related data for
20307 * @param {boolean} bTargetsOnly if true, only return targetable objs
20308 * @return {DragDrop[]} the related instances
20311 getRelated: function(p_oDD, bTargetsOnly) {
20313 for (var i in p_oDD.groups) {
20314 for (j in this.ids[i]) {
20315 var dd = this.ids[i][j];
20316 if (! this.isTypeOfDD(dd)) {
20319 if (!bTargetsOnly || dd.isTarget) {
20320 oDDs[oDDs.length] = dd;
20329 * Returns true if the specified dd target is a legal target for
20330 * the specifice drag obj
20331 * @method isLegalTarget
20332 * @param {DragDrop} the drag obj
20333 * @param {DragDrop} the target
20334 * @return {boolean} true if the target is a legal target for the
20338 isLegalTarget: function (oDD, oTargetDD) {
20339 var targets = this.getRelated(oDD, true);
20340 for (var i=0, len=targets.length;i<len;++i) {
20341 if (targets[i].id == oTargetDD.id) {
20350 * My goal is to be able to transparently determine if an object is
20351 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20352 * returns "object", oDD.constructor.toString() always returns
20353 * "DragDrop" and not the name of the subclass. So for now it just
20354 * evaluates a well-known variable in DragDrop.
20355 * @method isTypeOfDD
20356 * @param {Object} the object to evaluate
20357 * @return {boolean} true if typeof oDD = DragDrop
20360 isTypeOfDD: function (oDD) {
20361 return (oDD && oDD.__ygDragDrop);
20365 * Utility function to determine if a given element has been
20366 * registered as a drag drop handle for the given Drag Drop object.
20368 * @param {String} id the element id to check
20369 * @return {boolean} true if this element is a DragDrop handle, false
20373 isHandle: function(sDDId, sHandleId) {
20374 return ( this.handleIds[sDDId] &&
20375 this.handleIds[sDDId][sHandleId] );
20379 * Returns the DragDrop instance for a given id
20380 * @method getDDById
20381 * @param {String} id the id of the DragDrop object
20382 * @return {DragDrop} the drag drop object, null if it is not found
20385 getDDById: function(id) {
20386 for (var i in this.ids) {
20387 if (this.ids[i][id]) {
20388 return this.ids[i][id];
20395 * Fired after a registered DragDrop object gets the mousedown event.
20396 * Sets up the events required to track the object being dragged
20397 * @method handleMouseDown
20398 * @param {Event} e the event
20399 * @param oDD the DragDrop object being dragged
20403 handleMouseDown: function(e, oDD) {
20405 Roo.QuickTips.disable();
20407 this.currentTarget = e.getTarget();
20409 this.dragCurrent = oDD;
20411 var el = oDD.getEl();
20413 // track start position
20414 this.startX = e.getPageX();
20415 this.startY = e.getPageY();
20417 this.deltaX = this.startX - el.offsetLeft;
20418 this.deltaY = this.startY - el.offsetTop;
20420 this.dragThreshMet = false;
20422 this.clickTimeout = setTimeout(
20424 var DDM = Roo.dd.DDM;
20425 DDM.startDrag(DDM.startX, DDM.startY);
20427 this.clickTimeThresh );
20431 * Fired when either the drag pixel threshol or the mousedown hold
20432 * time threshold has been met.
20433 * @method startDrag
20434 * @param x {int} the X position of the original mousedown
20435 * @param y {int} the Y position of the original mousedown
20438 startDrag: function(x, y) {
20439 clearTimeout(this.clickTimeout);
20440 if (this.dragCurrent) {
20441 this.dragCurrent.b4StartDrag(x, y);
20442 this.dragCurrent.startDrag(x, y);
20444 this.dragThreshMet = true;
20448 * Internal function to handle the mouseup event. Will be invoked
20449 * from the context of the document.
20450 * @method handleMouseUp
20451 * @param {Event} e the event
20455 handleMouseUp: function(e) {
20458 Roo.QuickTips.enable();
20460 if (! this.dragCurrent) {
20464 clearTimeout(this.clickTimeout);
20466 if (this.dragThreshMet) {
20467 this.fireEvents(e, true);
20477 * Utility to stop event propagation and event default, if these
20478 * features are turned on.
20479 * @method stopEvent
20480 * @param {Event} e the event as returned by this.getEvent()
20483 stopEvent: function(e){
20484 if(this.stopPropagation) {
20485 e.stopPropagation();
20488 if (this.preventDefault) {
20489 e.preventDefault();
20494 * Internal function to clean up event handlers after the drag
20495 * operation is complete
20497 * @param {Event} e the event
20501 stopDrag: function(e) {
20502 // Fire the drag end event for the item that was dragged
20503 if (this.dragCurrent) {
20504 if (this.dragThreshMet) {
20505 this.dragCurrent.b4EndDrag(e);
20506 this.dragCurrent.endDrag(e);
20509 this.dragCurrent.onMouseUp(e);
20512 this.dragCurrent = null;
20513 this.dragOvers = {};
20517 * Internal function to handle the mousemove event. Will be invoked
20518 * from the context of the html element.
20520 * @TODO figure out what we can do about mouse events lost when the
20521 * user drags objects beyond the window boundary. Currently we can
20522 * detect this in internet explorer by verifying that the mouse is
20523 * down during the mousemove event. Firefox doesn't give us the
20524 * button state on the mousemove event.
20525 * @method handleMouseMove
20526 * @param {Event} e the event
20530 handleMouseMove: function(e) {
20531 if (! this.dragCurrent) {
20535 // var button = e.which || e.button;
20537 // check for IE mouseup outside of page boundary
20538 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20540 return this.handleMouseUp(e);
20543 if (!this.dragThreshMet) {
20544 var diffX = Math.abs(this.startX - e.getPageX());
20545 var diffY = Math.abs(this.startY - e.getPageY());
20546 if (diffX > this.clickPixelThresh ||
20547 diffY > this.clickPixelThresh) {
20548 this.startDrag(this.startX, this.startY);
20552 if (this.dragThreshMet) {
20553 this.dragCurrent.b4Drag(e);
20554 this.dragCurrent.onDrag(e);
20555 if(!this.dragCurrent.moveOnly){
20556 this.fireEvents(e, false);
20566 * Iterates over all of the DragDrop elements to find ones we are
20567 * hovering over or dropping on
20568 * @method fireEvents
20569 * @param {Event} e the event
20570 * @param {boolean} isDrop is this a drop op or a mouseover op?
20574 fireEvents: function(e, isDrop) {
20575 var dc = this.dragCurrent;
20577 // If the user did the mouse up outside of the window, we could
20578 // get here even though we have ended the drag.
20579 if (!dc || dc.isLocked()) {
20583 var pt = e.getPoint();
20585 // cache the previous dragOver array
20591 var enterEvts = [];
20593 // Check to see if the object(s) we were hovering over is no longer
20594 // being hovered over so we can fire the onDragOut event
20595 for (var i in this.dragOvers) {
20597 var ddo = this.dragOvers[i];
20599 if (! this.isTypeOfDD(ddo)) {
20603 if (! this.isOverTarget(pt, ddo, this.mode)) {
20604 outEvts.push( ddo );
20607 oldOvers[i] = true;
20608 delete this.dragOvers[i];
20611 for (var sGroup in dc.groups) {
20613 if ("string" != typeof sGroup) {
20617 for (i in this.ids[sGroup]) {
20618 var oDD = this.ids[sGroup][i];
20619 if (! this.isTypeOfDD(oDD)) {
20623 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20624 if (this.isOverTarget(pt, oDD, this.mode)) {
20625 // look for drop interactions
20627 dropEvts.push( oDD );
20628 // look for drag enter and drag over interactions
20631 // initial drag over: dragEnter fires
20632 if (!oldOvers[oDD.id]) {
20633 enterEvts.push( oDD );
20634 // subsequent drag overs: dragOver fires
20636 overEvts.push( oDD );
20639 this.dragOvers[oDD.id] = oDD;
20647 if (outEvts.length) {
20648 dc.b4DragOut(e, outEvts);
20649 dc.onDragOut(e, outEvts);
20652 if (enterEvts.length) {
20653 dc.onDragEnter(e, enterEvts);
20656 if (overEvts.length) {
20657 dc.b4DragOver(e, overEvts);
20658 dc.onDragOver(e, overEvts);
20661 if (dropEvts.length) {
20662 dc.b4DragDrop(e, dropEvts);
20663 dc.onDragDrop(e, dropEvts);
20667 // fire dragout events
20669 for (i=0, len=outEvts.length; i<len; ++i) {
20670 dc.b4DragOut(e, outEvts[i].id);
20671 dc.onDragOut(e, outEvts[i].id);
20674 // fire enter events
20675 for (i=0,len=enterEvts.length; i<len; ++i) {
20676 // dc.b4DragEnter(e, oDD.id);
20677 dc.onDragEnter(e, enterEvts[i].id);
20680 // fire over events
20681 for (i=0,len=overEvts.length; i<len; ++i) {
20682 dc.b4DragOver(e, overEvts[i].id);
20683 dc.onDragOver(e, overEvts[i].id);
20686 // fire drop events
20687 for (i=0, len=dropEvts.length; i<len; ++i) {
20688 dc.b4DragDrop(e, dropEvts[i].id);
20689 dc.onDragDrop(e, dropEvts[i].id);
20694 // notify about a drop that did not find a target
20695 if (isDrop && !dropEvts.length) {
20696 dc.onInvalidDrop(e);
20702 * Helper function for getting the best match from the list of drag
20703 * and drop objects returned by the drag and drop events when we are
20704 * in INTERSECT mode. It returns either the first object that the
20705 * cursor is over, or the object that has the greatest overlap with
20706 * the dragged element.
20707 * @method getBestMatch
20708 * @param {DragDrop[]} dds The array of drag and drop objects
20710 * @return {DragDrop} The best single match
20713 getBestMatch: function(dds) {
20715 // Return null if the input is not what we expect
20716 //if (!dds || !dds.length || dds.length == 0) {
20718 // If there is only one item, it wins
20719 //} else if (dds.length == 1) {
20721 var len = dds.length;
20726 // Loop through the targeted items
20727 for (var i=0; i<len; ++i) {
20729 // If the cursor is over the object, it wins. If the
20730 // cursor is over multiple matches, the first one we come
20732 if (dd.cursorIsOver) {
20735 // Otherwise the object with the most overlap wins
20738 winner.overlap.getArea() < dd.overlap.getArea()) {
20749 * Refreshes the cache of the top-left and bottom-right points of the
20750 * drag and drop objects in the specified group(s). This is in the
20751 * format that is stored in the drag and drop instance, so typical
20754 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20758 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20760 * @TODO this really should be an indexed array. Alternatively this
20761 * method could accept both.
20762 * @method refreshCache
20763 * @param {Object} groups an associative array of groups to refresh
20766 refreshCache: function(groups) {
20767 for (var sGroup in groups) {
20768 if ("string" != typeof sGroup) {
20771 for (var i in this.ids[sGroup]) {
20772 var oDD = this.ids[sGroup][i];
20774 if (this.isTypeOfDD(oDD)) {
20775 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20776 var loc = this.getLocation(oDD);
20778 this.locationCache[oDD.id] = loc;
20780 delete this.locationCache[oDD.id];
20781 // this will unregister the drag and drop object if
20782 // the element is not in a usable state
20791 * This checks to make sure an element exists and is in the DOM. The
20792 * main purpose is to handle cases where innerHTML is used to remove
20793 * drag and drop objects from the DOM. IE provides an 'unspecified
20794 * error' when trying to access the offsetParent of such an element
20796 * @param {HTMLElement} el the element to check
20797 * @return {boolean} true if the element looks usable
20800 verifyEl: function(el) {
20805 parent = el.offsetParent;
20808 parent = el.offsetParent;
20819 * Returns a Region object containing the drag and drop element's position
20820 * and size, including the padding configured for it
20821 * @method getLocation
20822 * @param {DragDrop} oDD the drag and drop object to get the
20824 * @return {Roo.lib.Region} a Region object representing the total area
20825 * the element occupies, including any padding
20826 * the instance is configured for.
20829 getLocation: function(oDD) {
20830 if (! this.isTypeOfDD(oDD)) {
20834 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20837 pos= Roo.lib.Dom.getXY(el);
20845 x2 = x1 + el.offsetWidth;
20847 y2 = y1 + el.offsetHeight;
20849 t = y1 - oDD.padding[0];
20850 r = x2 + oDD.padding[1];
20851 b = y2 + oDD.padding[2];
20852 l = x1 - oDD.padding[3];
20854 return new Roo.lib.Region( t, r, b, l );
20858 * Checks the cursor location to see if it over the target
20859 * @method isOverTarget
20860 * @param {Roo.lib.Point} pt The point to evaluate
20861 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20862 * @return {boolean} true if the mouse is over the target
20866 isOverTarget: function(pt, oTarget, intersect) {
20867 // use cache if available
20868 var loc = this.locationCache[oTarget.id];
20869 if (!loc || !this.useCache) {
20870 loc = this.getLocation(oTarget);
20871 this.locationCache[oTarget.id] = loc;
20879 oTarget.cursorIsOver = loc.contains( pt );
20881 // DragDrop is using this as a sanity check for the initial mousedown
20882 // in this case we are done. In POINT mode, if the drag obj has no
20883 // contraints, we are also done. Otherwise we need to evaluate the
20884 // location of the target as related to the actual location of the
20885 // dragged element.
20886 var dc = this.dragCurrent;
20887 if (!dc || !dc.getTargetCoord ||
20888 (!intersect && !dc.constrainX && !dc.constrainY)) {
20889 return oTarget.cursorIsOver;
20892 oTarget.overlap = null;
20894 // Get the current location of the drag element, this is the
20895 // location of the mouse event less the delta that represents
20896 // where the original mousedown happened on the element. We
20897 // need to consider constraints and ticks as well.
20898 var pos = dc.getTargetCoord(pt.x, pt.y);
20900 var el = dc.getDragEl();
20901 var curRegion = new Roo.lib.Region( pos.y,
20902 pos.x + el.offsetWidth,
20903 pos.y + el.offsetHeight,
20906 var overlap = curRegion.intersect(loc);
20909 oTarget.overlap = overlap;
20910 return (intersect) ? true : oTarget.cursorIsOver;
20917 * unload event handler
20918 * @method _onUnload
20922 _onUnload: function(e, me) {
20923 Roo.dd.DragDropMgr.unregAll();
20927 * Cleans up the drag and drop events and objects.
20932 unregAll: function() {
20934 if (this.dragCurrent) {
20936 this.dragCurrent = null;
20939 this._execOnAll("unreg", []);
20941 for (i in this.elementCache) {
20942 delete this.elementCache[i];
20945 this.elementCache = {};
20950 * A cache of DOM elements
20951 * @property elementCache
20958 * Get the wrapper for the DOM element specified
20959 * @method getElWrapper
20960 * @param {String} id the id of the element to get
20961 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20963 * @deprecated This wrapper isn't that useful
20966 getElWrapper: function(id) {
20967 var oWrapper = this.elementCache[id];
20968 if (!oWrapper || !oWrapper.el) {
20969 oWrapper = this.elementCache[id] =
20970 new this.ElementWrapper(Roo.getDom(id));
20976 * Returns the actual DOM element
20977 * @method getElement
20978 * @param {String} id the id of the elment to get
20979 * @return {Object} The element
20980 * @deprecated use Roo.getDom instead
20983 getElement: function(id) {
20984 return Roo.getDom(id);
20988 * Returns the style property for the DOM element (i.e.,
20989 * document.getElById(id).style)
20991 * @param {String} id the id of the elment to get
20992 * @return {Object} The style property of the element
20993 * @deprecated use Roo.getDom instead
20996 getCss: function(id) {
20997 var el = Roo.getDom(id);
20998 return (el) ? el.style : null;
21002 * Inner class for cached elements
21003 * @class DragDropMgr.ElementWrapper
21008 ElementWrapper: function(el) {
21013 this.el = el || null;
21018 this.id = this.el && el.id;
21020 * A reference to the style property
21023 this.css = this.el && el.style;
21027 * Returns the X position of an html element
21029 * @param el the element for which to get the position
21030 * @return {int} the X coordinate
21032 * @deprecated use Roo.lib.Dom.getX instead
21035 getPosX: function(el) {
21036 return Roo.lib.Dom.getX(el);
21040 * Returns the Y position of an html element
21042 * @param el the element for which to get the position
21043 * @return {int} the Y coordinate
21044 * @deprecated use Roo.lib.Dom.getY instead
21047 getPosY: function(el) {
21048 return Roo.lib.Dom.getY(el);
21052 * Swap two nodes. In IE, we use the native method, for others we
21053 * emulate the IE behavior
21055 * @param n1 the first node to swap
21056 * @param n2 the other node to swap
21059 swapNode: function(n1, n2) {
21063 var p = n2.parentNode;
21064 var s = n2.nextSibling;
21067 p.insertBefore(n1, n2);
21068 } else if (n2 == n1.nextSibling) {
21069 p.insertBefore(n2, n1);
21071 n1.parentNode.replaceChild(n2, n1);
21072 p.insertBefore(n1, s);
21078 * Returns the current scroll position
21079 * @method getScroll
21083 getScroll: function () {
21084 var t, l, dde=document.documentElement, db=document.body;
21085 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21087 l = dde.scrollLeft;
21094 return { top: t, left: l };
21098 * Returns the specified element style property
21100 * @param {HTMLElement} el the element
21101 * @param {string} styleProp the style property
21102 * @return {string} The value of the style property
21103 * @deprecated use Roo.lib.Dom.getStyle
21106 getStyle: function(el, styleProp) {
21107 return Roo.fly(el).getStyle(styleProp);
21111 * Gets the scrollTop
21112 * @method getScrollTop
21113 * @return {int} the document's scrollTop
21116 getScrollTop: function () { return this.getScroll().top; },
21119 * Gets the scrollLeft
21120 * @method getScrollLeft
21121 * @return {int} the document's scrollTop
21124 getScrollLeft: function () { return this.getScroll().left; },
21127 * Sets the x/y position of an element to the location of the
21130 * @param {HTMLElement} moveEl The element to move
21131 * @param {HTMLElement} targetEl The position reference element
21134 moveToEl: function (moveEl, targetEl) {
21135 var aCoord = Roo.lib.Dom.getXY(targetEl);
21136 Roo.lib.Dom.setXY(moveEl, aCoord);
21140 * Numeric array sort function
21141 * @method numericSort
21144 numericSort: function(a, b) { return (a - b); },
21148 * @property _timeoutCount
21155 * Trying to make the load order less important. Without this we get
21156 * an error if this file is loaded before the Event Utility.
21157 * @method _addListeners
21161 _addListeners: function() {
21162 var DDM = Roo.dd.DDM;
21163 if ( Roo.lib.Event && document ) {
21166 if (DDM._timeoutCount > 2000) {
21168 setTimeout(DDM._addListeners, 10);
21169 if (document && document.body) {
21170 DDM._timeoutCount += 1;
21177 * Recursively searches the immediate parent and all child nodes for
21178 * the handle element in order to determine wheter or not it was
21180 * @method handleWasClicked
21181 * @param node the html element to inspect
21184 handleWasClicked: function(node, id) {
21185 if (this.isHandle(id, node.id)) {
21188 // check to see if this is a text node child of the one we want
21189 var p = node.parentNode;
21192 if (this.isHandle(id, p.id)) {
21207 // shorter alias, save a few bytes
21208 Roo.dd.DDM = Roo.dd.DragDropMgr;
21209 Roo.dd.DDM._addListeners();
21213 * Ext JS Library 1.1.1
21214 * Copyright(c) 2006-2007, Ext JS, LLC.
21216 * Originally Released Under LGPL - original licence link has changed is not relivant.
21219 * <script type="text/javascript">
21224 * A DragDrop implementation where the linked element follows the
21225 * mouse cursor during a drag.
21226 * @extends Roo.dd.DragDrop
21228 * @param {String} id the id of the linked element
21229 * @param {String} sGroup the group of related DragDrop items
21230 * @param {object} config an object containing configurable attributes
21231 * Valid properties for DD:
21234 Roo.dd.DD = function(id, sGroup, config) {
21236 this.init(id, sGroup, config);
21240 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21243 * When set to true, the utility automatically tries to scroll the browser
21244 * window wehn a drag and drop element is dragged near the viewport boundary.
21245 * Defaults to true.
21252 * Sets the pointer offset to the distance between the linked element's top
21253 * left corner and the location the element was clicked
21254 * @method autoOffset
21255 * @param {int} iPageX the X coordinate of the click
21256 * @param {int} iPageY the Y coordinate of the click
21258 autoOffset: function(iPageX, iPageY) {
21259 var x = iPageX - this.startPageX;
21260 var y = iPageY - this.startPageY;
21261 this.setDelta(x, y);
21265 * Sets the pointer offset. You can call this directly to force the
21266 * offset to be in a particular location (e.g., pass in 0,0 to set it
21267 * to the center of the object)
21269 * @param {int} iDeltaX the distance from the left
21270 * @param {int} iDeltaY the distance from the top
21272 setDelta: function(iDeltaX, iDeltaY) {
21273 this.deltaX = iDeltaX;
21274 this.deltaY = iDeltaY;
21278 * Sets the drag element to the location of the mousedown or click event,
21279 * maintaining the cursor location relative to the location on the element
21280 * that was clicked. Override this if you want to place the element in a
21281 * location other than where the cursor is.
21282 * @method setDragElPos
21283 * @param {int} iPageX the X coordinate of the mousedown or drag event
21284 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21286 setDragElPos: function(iPageX, iPageY) {
21287 // the first time we do this, we are going to check to make sure
21288 // the element has css positioning
21290 var el = this.getDragEl();
21291 this.alignElWithMouse(el, iPageX, iPageY);
21295 * Sets the element to the location of the mousedown or click event,
21296 * maintaining the cursor location relative to the location on the element
21297 * that was clicked. Override this if you want to place the element in a
21298 * location other than where the cursor is.
21299 * @method alignElWithMouse
21300 * @param {HTMLElement} el the element to move
21301 * @param {int} iPageX the X coordinate of the mousedown or drag event
21302 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21304 alignElWithMouse: function(el, iPageX, iPageY) {
21305 var oCoord = this.getTargetCoord(iPageX, iPageY);
21306 var fly = el.dom ? el : Roo.fly(el);
21307 if (!this.deltaSetXY) {
21308 var aCoord = [oCoord.x, oCoord.y];
21310 var newLeft = fly.getLeft(true);
21311 var newTop = fly.getTop(true);
21312 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21314 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21317 this.cachePosition(oCoord.x, oCoord.y);
21318 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21323 * Saves the most recent position so that we can reset the constraints and
21324 * tick marks on-demand. We need to know this so that we can calculate the
21325 * number of pixels the element is offset from its original position.
21326 * @method cachePosition
21327 * @param iPageX the current x position (optional, this just makes it so we
21328 * don't have to look it up again)
21329 * @param iPageY the current y position (optional, this just makes it so we
21330 * don't have to look it up again)
21332 cachePosition: function(iPageX, iPageY) {
21334 this.lastPageX = iPageX;
21335 this.lastPageY = iPageY;
21337 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21338 this.lastPageX = aCoord[0];
21339 this.lastPageY = aCoord[1];
21344 * Auto-scroll the window if the dragged object has been moved beyond the
21345 * visible window boundary.
21346 * @method autoScroll
21347 * @param {int} x the drag element's x position
21348 * @param {int} y the drag element's y position
21349 * @param {int} h the height of the drag element
21350 * @param {int} w the width of the drag element
21353 autoScroll: function(x, y, h, w) {
21356 // The client height
21357 var clientH = Roo.lib.Dom.getViewWidth();
21359 // The client width
21360 var clientW = Roo.lib.Dom.getViewHeight();
21362 // The amt scrolled down
21363 var st = this.DDM.getScrollTop();
21365 // The amt scrolled right
21366 var sl = this.DDM.getScrollLeft();
21368 // Location of the bottom of the element
21371 // Location of the right of the element
21374 // The distance from the cursor to the bottom of the visible area,
21375 // adjusted so that we don't scroll if the cursor is beyond the
21376 // element drag constraints
21377 var toBot = (clientH + st - y - this.deltaY);
21379 // The distance from the cursor to the right of the visible area
21380 var toRight = (clientW + sl - x - this.deltaX);
21383 // How close to the edge the cursor must be before we scroll
21384 // var thresh = (document.all) ? 100 : 40;
21387 // How many pixels to scroll per autoscroll op. This helps to reduce
21388 // clunky scrolling. IE is more sensitive about this ... it needs this
21389 // value to be higher.
21390 var scrAmt = (document.all) ? 80 : 30;
21392 // Scroll down if we are near the bottom of the visible page and the
21393 // obj extends below the crease
21394 if ( bot > clientH && toBot < thresh ) {
21395 window.scrollTo(sl, st + scrAmt);
21398 // Scroll up if the window is scrolled down and the top of the object
21399 // goes above the top border
21400 if ( y < st && st > 0 && y - st < thresh ) {
21401 window.scrollTo(sl, st - scrAmt);
21404 // Scroll right if the obj is beyond the right border and the cursor is
21405 // near the border.
21406 if ( right > clientW && toRight < thresh ) {
21407 window.scrollTo(sl + scrAmt, st);
21410 // Scroll left if the window has been scrolled to the right and the obj
21411 // extends past the left border
21412 if ( x < sl && sl > 0 && x - sl < thresh ) {
21413 window.scrollTo(sl - scrAmt, st);
21419 * Finds the location the element should be placed if we want to move
21420 * it to where the mouse location less the click offset would place us.
21421 * @method getTargetCoord
21422 * @param {int} iPageX the X coordinate of the click
21423 * @param {int} iPageY the Y coordinate of the click
21424 * @return an object that contains the coordinates (Object.x and Object.y)
21427 getTargetCoord: function(iPageX, iPageY) {
21430 var x = iPageX - this.deltaX;
21431 var y = iPageY - this.deltaY;
21433 if (this.constrainX) {
21434 if (x < this.minX) { x = this.minX; }
21435 if (x > this.maxX) { x = this.maxX; }
21438 if (this.constrainY) {
21439 if (y < this.minY) { y = this.minY; }
21440 if (y > this.maxY) { y = this.maxY; }
21443 x = this.getTick(x, this.xTicks);
21444 y = this.getTick(y, this.yTicks);
21451 * Sets up config options specific to this class. Overrides
21452 * Roo.dd.DragDrop, but all versions of this method through the
21453 * inheritance chain are called
21455 applyConfig: function() {
21456 Roo.dd.DD.superclass.applyConfig.call(this);
21457 this.scroll = (this.config.scroll !== false);
21461 * Event that fires prior to the onMouseDown event. Overrides
21464 b4MouseDown: function(e) {
21465 // this.resetConstraints();
21466 this.autoOffset(e.getPageX(),
21471 * Event that fires prior to the onDrag event. Overrides
21474 b4Drag: function(e) {
21475 this.setDragElPos(e.getPageX(),
21479 toString: function() {
21480 return ("DD " + this.id);
21483 //////////////////////////////////////////////////////////////////////////
21484 // Debugging ygDragDrop events that can be overridden
21485 //////////////////////////////////////////////////////////////////////////
21487 startDrag: function(x, y) {
21490 onDrag: function(e) {
21493 onDragEnter: function(e, id) {
21496 onDragOver: function(e, id) {
21499 onDragOut: function(e, id) {
21502 onDragDrop: function(e, id) {
21505 endDrag: function(e) {
21512 * Ext JS Library 1.1.1
21513 * Copyright(c) 2006-2007, Ext JS, LLC.
21515 * Originally Released Under LGPL - original licence link has changed is not relivant.
21518 * <script type="text/javascript">
21522 * @class Roo.dd.DDProxy
21523 * A DragDrop implementation that inserts an empty, bordered div into
21524 * the document that follows the cursor during drag operations. At the time of
21525 * the click, the frame div is resized to the dimensions of the linked html
21526 * element, and moved to the exact location of the linked element.
21528 * References to the "frame" element refer to the single proxy element that
21529 * was created to be dragged in place of all DDProxy elements on the
21532 * @extends Roo.dd.DD
21534 * @param {String} id the id of the linked html element
21535 * @param {String} sGroup the group of related DragDrop objects
21536 * @param {object} config an object containing configurable attributes
21537 * Valid properties for DDProxy in addition to those in DragDrop:
21538 * resizeFrame, centerFrame, dragElId
21540 Roo.dd.DDProxy = function(id, sGroup, config) {
21542 this.init(id, sGroup, config);
21548 * The default drag frame div id
21549 * @property Roo.dd.DDProxy.dragElId
21553 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21555 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21558 * By default we resize the drag frame to be the same size as the element
21559 * we want to drag (this is to get the frame effect). We can turn it off
21560 * if we want a different behavior.
21561 * @property resizeFrame
21567 * By default the frame is positioned exactly where the drag element is, so
21568 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21569 * you do not have constraints on the obj is to have the drag frame centered
21570 * around the cursor. Set centerFrame to true for this effect.
21571 * @property centerFrame
21574 centerFrame: false,
21577 * Creates the proxy element if it does not yet exist
21578 * @method createFrame
21580 createFrame: function() {
21582 var body = document.body;
21584 if (!body || !body.firstChild) {
21585 setTimeout( function() { self.createFrame(); }, 50 );
21589 var div = this.getDragEl();
21592 div = document.createElement("div");
21593 div.id = this.dragElId;
21596 s.position = "absolute";
21597 s.visibility = "hidden";
21599 s.border = "2px solid #aaa";
21602 // appendChild can blow up IE if invoked prior to the window load event
21603 // while rendering a table. It is possible there are other scenarios
21604 // that would cause this to happen as well.
21605 body.insertBefore(div, body.firstChild);
21610 * Initialization for the drag frame element. Must be called in the
21611 * constructor of all subclasses
21612 * @method initFrame
21614 initFrame: function() {
21615 this.createFrame();
21618 applyConfig: function() {
21619 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21621 this.resizeFrame = (this.config.resizeFrame !== false);
21622 this.centerFrame = (this.config.centerFrame);
21623 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21627 * Resizes the drag frame to the dimensions of the clicked object, positions
21628 * it over the object, and finally displays it
21629 * @method showFrame
21630 * @param {int} iPageX X click position
21631 * @param {int} iPageY Y click position
21634 showFrame: function(iPageX, iPageY) {
21635 var el = this.getEl();
21636 var dragEl = this.getDragEl();
21637 var s = dragEl.style;
21639 this._resizeProxy();
21641 if (this.centerFrame) {
21642 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21643 Math.round(parseInt(s.height, 10)/2) );
21646 this.setDragElPos(iPageX, iPageY);
21648 Roo.fly(dragEl).show();
21652 * The proxy is automatically resized to the dimensions of the linked
21653 * element when a drag is initiated, unless resizeFrame is set to false
21654 * @method _resizeProxy
21657 _resizeProxy: function() {
21658 if (this.resizeFrame) {
21659 var el = this.getEl();
21660 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21664 // overrides Roo.dd.DragDrop
21665 b4MouseDown: function(e) {
21666 var x = e.getPageX();
21667 var y = e.getPageY();
21668 this.autoOffset(x, y);
21669 this.setDragElPos(x, y);
21672 // overrides Roo.dd.DragDrop
21673 b4StartDrag: function(x, y) {
21674 // show the drag frame
21675 this.showFrame(x, y);
21678 // overrides Roo.dd.DragDrop
21679 b4EndDrag: function(e) {
21680 Roo.fly(this.getDragEl()).hide();
21683 // overrides Roo.dd.DragDrop
21684 // By default we try to move the element to the last location of the frame.
21685 // This is so that the default behavior mirrors that of Roo.dd.DD.
21686 endDrag: function(e) {
21688 var lel = this.getEl();
21689 var del = this.getDragEl();
21691 // Show the drag frame briefly so we can get its position
21692 del.style.visibility = "";
21695 // Hide the linked element before the move to get around a Safari
21697 lel.style.visibility = "hidden";
21698 Roo.dd.DDM.moveToEl(lel, del);
21699 del.style.visibility = "hidden";
21700 lel.style.visibility = "";
21705 beforeMove : function(){
21709 afterDrag : function(){
21713 toString: function() {
21714 return ("DDProxy " + this.id);
21720 * Ext JS Library 1.1.1
21721 * Copyright(c) 2006-2007, Ext JS, LLC.
21723 * Originally Released Under LGPL - original licence link has changed is not relivant.
21726 * <script type="text/javascript">
21730 * @class Roo.dd.DDTarget
21731 * A DragDrop implementation that does not move, but can be a drop
21732 * target. You would get the same result by simply omitting implementation
21733 * for the event callbacks, but this way we reduce the processing cost of the
21734 * event listener and the callbacks.
21735 * @extends Roo.dd.DragDrop
21737 * @param {String} id the id of the element that is a drop target
21738 * @param {String} sGroup the group of related DragDrop objects
21739 * @param {object} config an object containing configurable attributes
21740 * Valid properties for DDTarget in addition to those in
21744 Roo.dd.DDTarget = function(id, sGroup, config) {
21746 this.initTarget(id, sGroup, config);
21748 if (config && (config.listeners || config.events)) {
21749 Roo.dd.DragDrop.superclass.constructor.call(this, {
21750 listeners : config.listeners || {},
21751 events : config.events || {}
21756 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21757 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21758 toString: function() {
21759 return ("DDTarget " + this.id);
21764 * Ext JS Library 1.1.1
21765 * Copyright(c) 2006-2007, Ext JS, LLC.
21767 * Originally Released Under LGPL - original licence link has changed is not relivant.
21770 * <script type="text/javascript">
21775 * @class Roo.dd.ScrollManager
21776 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21777 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21780 Roo.dd.ScrollManager = function(){
21781 var ddm = Roo.dd.DragDropMgr;
21788 var onStop = function(e){
21793 var triggerRefresh = function(){
21794 if(ddm.dragCurrent){
21795 ddm.refreshCache(ddm.dragCurrent.groups);
21799 var doScroll = function(){
21800 if(ddm.dragCurrent){
21801 var dds = Roo.dd.ScrollManager;
21803 if(proc.el.scroll(proc.dir, dds.increment)){
21807 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21812 var clearProc = function(){
21814 clearInterval(proc.id);
21821 var startProc = function(el, dir){
21822 Roo.log('scroll startproc');
21826 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21829 var onFire = function(e, isDrop){
21831 if(isDrop || !ddm.dragCurrent){ return; }
21832 var dds = Roo.dd.ScrollManager;
21833 if(!dragEl || dragEl != ddm.dragCurrent){
21834 dragEl = ddm.dragCurrent;
21835 // refresh regions on drag start
21836 dds.refreshCache();
21839 var xy = Roo.lib.Event.getXY(e);
21840 var pt = new Roo.lib.Point(xy[0], xy[1]);
21841 for(var id in els){
21842 var el = els[id], r = el._region;
21843 if(r && r.contains(pt) && el.isScrollable()){
21844 if(r.bottom - pt.y <= dds.thresh){
21846 startProc(el, "down");
21849 }else if(r.right - pt.x <= dds.thresh){
21851 startProc(el, "left");
21854 }else if(pt.y - r.top <= dds.thresh){
21856 startProc(el, "up");
21859 }else if(pt.x - r.left <= dds.thresh){
21861 startProc(el, "right");
21870 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21871 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21875 * Registers new overflow element(s) to auto scroll
21876 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21878 register : function(el){
21879 if(el instanceof Array){
21880 for(var i = 0, len = el.length; i < len; i++) {
21881 this.register(el[i]);
21887 Roo.dd.ScrollManager.els = els;
21891 * Unregisters overflow element(s) so they are no longer scrolled
21892 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21894 unregister : function(el){
21895 if(el instanceof Array){
21896 for(var i = 0, len = el.length; i < len; i++) {
21897 this.unregister(el[i]);
21906 * The number of pixels from the edge of a container the pointer needs to be to
21907 * trigger scrolling (defaults to 25)
21913 * The number of pixels to scroll in each scroll increment (defaults to 50)
21919 * The frequency of scrolls in milliseconds (defaults to 500)
21925 * True to animate the scroll (defaults to true)
21931 * The animation duration in seconds -
21932 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21938 * Manually trigger a cache refresh.
21940 refreshCache : function(){
21941 for(var id in els){
21942 if(typeof els[id] == 'object'){ // for people extending the object prototype
21943 els[id]._region = els[id].getRegion();
21950 * Ext JS Library 1.1.1
21951 * Copyright(c) 2006-2007, Ext JS, LLC.
21953 * Originally Released Under LGPL - original licence link has changed is not relivant.
21956 * <script type="text/javascript">
21961 * @class Roo.dd.Registry
21962 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21963 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21966 Roo.dd.Registry = function(){
21969 var autoIdSeed = 0;
21971 var getId = function(el, autogen){
21972 if(typeof el == "string"){
21976 if(!id && autogen !== false){
21977 id = "roodd-" + (++autoIdSeed);
21985 * Register a drag drop element
21986 * @param {String|HTMLElement} element The id or DOM node to register
21987 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21988 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21989 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21990 * populated in the data object (if applicable):
21992 Value Description<br />
21993 --------- ------------------------------------------<br />
21994 handles Array of DOM nodes that trigger dragging<br />
21995 for the element being registered<br />
21996 isHandle True if the element passed in triggers<br />
21997 dragging itself, else false
22000 register : function(el, data){
22002 if(typeof el == "string"){
22003 el = document.getElementById(el);
22006 elements[getId(el)] = data;
22007 if(data.isHandle !== false){
22008 handles[data.ddel.id] = data;
22011 var hs = data.handles;
22012 for(var i = 0, len = hs.length; i < len; i++){
22013 handles[getId(hs[i])] = data;
22019 * Unregister a drag drop element
22020 * @param {String|HTMLElement} element The id or DOM node to unregister
22022 unregister : function(el){
22023 var id = getId(el, false);
22024 var data = elements[id];
22026 delete elements[id];
22028 var hs = data.handles;
22029 for(var i = 0, len = hs.length; i < len; i++){
22030 delete handles[getId(hs[i], false)];
22037 * Returns the handle registered for a DOM Node by id
22038 * @param {String|HTMLElement} id The DOM node or id to look up
22039 * @return {Object} handle The custom handle data
22041 getHandle : function(id){
22042 if(typeof id != "string"){ // must be element?
22045 return handles[id];
22049 * Returns the handle that is registered for the DOM node that is the target of the event
22050 * @param {Event} e The event
22051 * @return {Object} handle The custom handle data
22053 getHandleFromEvent : function(e){
22054 var t = Roo.lib.Event.getTarget(e);
22055 return t ? handles[t.id] : null;
22059 * Returns a custom data object that is registered for a DOM node by id
22060 * @param {String|HTMLElement} id The DOM node or id to look up
22061 * @return {Object} data The custom data
22063 getTarget : function(id){
22064 if(typeof id != "string"){ // must be element?
22067 return elements[id];
22071 * Returns a custom data object that is registered for the DOM node that is the target of the event
22072 * @param {Event} e The event
22073 * @return {Object} data The custom data
22075 getTargetFromEvent : function(e){
22076 var t = Roo.lib.Event.getTarget(e);
22077 return t ? elements[t.id] || handles[t.id] : null;
22082 * Ext JS Library 1.1.1
22083 * Copyright(c) 2006-2007, Ext JS, LLC.
22085 * Originally Released Under LGPL - original licence link has changed is not relivant.
22088 * <script type="text/javascript">
22093 * @class Roo.dd.StatusProxy
22094 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22095 * default drag proxy used by all Roo.dd components.
22097 * @param {Object} config
22099 Roo.dd.StatusProxy = function(config){
22100 Roo.apply(this, config);
22101 this.id = this.id || Roo.id();
22102 this.el = new Roo.Layer({
22104 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22105 {tag: "div", cls: "x-dd-drop-icon"},
22106 {tag: "div", cls: "x-dd-drag-ghost"}
22109 shadow: !config || config.shadow !== false
22111 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22112 this.dropStatus = this.dropNotAllowed;
22115 Roo.dd.StatusProxy.prototype = {
22117 * @cfg {String} dropAllowed
22118 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22120 dropAllowed : "x-dd-drop-ok",
22122 * @cfg {String} dropNotAllowed
22123 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22125 dropNotAllowed : "x-dd-drop-nodrop",
22128 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22129 * over the current target element.
22130 * @param {String} cssClass The css class for the new drop status indicator image
22132 setStatus : function(cssClass){
22133 cssClass = cssClass || this.dropNotAllowed;
22134 if(this.dropStatus != cssClass){
22135 this.el.replaceClass(this.dropStatus, cssClass);
22136 this.dropStatus = cssClass;
22141 * Resets the status indicator to the default dropNotAllowed value
22142 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22144 reset : function(clearGhost){
22145 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22146 this.dropStatus = this.dropNotAllowed;
22148 this.ghost.update("");
22153 * Updates the contents of the ghost element
22154 * @param {String} html The html that will replace the current innerHTML of the ghost element
22156 update : function(html){
22157 if(typeof html == "string"){
22158 this.ghost.update(html);
22160 this.ghost.update("");
22161 html.style.margin = "0";
22162 this.ghost.dom.appendChild(html);
22164 // ensure float = none set?? cant remember why though.
22165 var el = this.ghost.dom.firstChild;
22167 Roo.fly(el).setStyle('float', 'none');
22172 * Returns the underlying proxy {@link Roo.Layer}
22173 * @return {Roo.Layer} el
22175 getEl : function(){
22180 * Returns the ghost element
22181 * @return {Roo.Element} el
22183 getGhost : function(){
22189 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22191 hide : function(clear){
22199 * Stops the repair animation if it's currently running
22202 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22208 * Displays this proxy
22215 * Force the Layer to sync its shadow and shim positions to the element
22222 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22223 * invalid drop operation by the item being dragged.
22224 * @param {Array} xy The XY position of the element ([x, y])
22225 * @param {Function} callback The function to call after the repair is complete
22226 * @param {Object} scope The scope in which to execute the callback
22228 repair : function(xy, callback, scope){
22229 this.callback = callback;
22230 this.scope = scope;
22231 if(xy && this.animRepair !== false){
22232 this.el.addClass("x-dd-drag-repair");
22233 this.el.hideUnders(true);
22234 this.anim = this.el.shift({
22235 duration: this.repairDuration || .5,
22239 callback: this.afterRepair,
22243 this.afterRepair();
22248 afterRepair : function(){
22250 if(typeof this.callback == "function"){
22251 this.callback.call(this.scope || this);
22253 this.callback = null;
22258 * Ext JS Library 1.1.1
22259 * Copyright(c) 2006-2007, Ext JS, LLC.
22261 * Originally Released Under LGPL - original licence link has changed is not relivant.
22264 * <script type="text/javascript">
22268 * @class Roo.dd.DragSource
22269 * @extends Roo.dd.DDProxy
22270 * A simple class that provides the basic implementation needed to make any element draggable.
22272 * @param {String/HTMLElement/Element} el The container element
22273 * @param {Object} config
22275 Roo.dd.DragSource = function(el, config){
22276 this.el = Roo.get(el);
22277 this.dragData = {};
22279 Roo.apply(this, config);
22282 this.proxy = new Roo.dd.StatusProxy();
22285 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22286 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22288 this.dragging = false;
22291 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22293 * @cfg {String} dropAllowed
22294 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22296 dropAllowed : "x-dd-drop-ok",
22298 * @cfg {String} dropNotAllowed
22299 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22301 dropNotAllowed : "x-dd-drop-nodrop",
22304 * Returns the data object associated with this drag source
22305 * @return {Object} data An object containing arbitrary data
22307 getDragData : function(e){
22308 return this.dragData;
22312 onDragEnter : function(e, id){
22313 var target = Roo.dd.DragDropMgr.getDDById(id);
22314 this.cachedTarget = target;
22315 if(this.beforeDragEnter(target, e, id) !== false){
22316 if(target.isNotifyTarget){
22317 var status = target.notifyEnter(this, e, this.dragData);
22318 this.proxy.setStatus(status);
22320 this.proxy.setStatus(this.dropAllowed);
22323 if(this.afterDragEnter){
22325 * An empty function by default, but provided so that you can perform a custom action
22326 * when the dragged item enters the drop target by providing an implementation.
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 * @method afterDragEnter
22332 this.afterDragEnter(target, e, id);
22338 * An empty function by default, but provided so that you can perform a custom action
22339 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22340 * @param {Roo.dd.DragDrop} target The drop target
22341 * @param {Event} e The event object
22342 * @param {String} id The id of the dragged element
22343 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22345 beforeDragEnter : function(target, e, id){
22350 alignElWithMouse: function() {
22351 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22356 onDragOver : function(e, id){
22357 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22358 if(this.beforeDragOver(target, e, id) !== false){
22359 if(target.isNotifyTarget){
22360 var status = target.notifyOver(this, e, this.dragData);
22361 this.proxy.setStatus(status);
22364 if(this.afterDragOver){
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 by providing an implementation.
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 * @method afterDragOver
22373 this.afterDragOver(target, e, id);
22379 * An empty function by default, but provided so that you can perform a custom action
22380 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22381 * @param {Roo.dd.DragDrop} target The drop target
22382 * @param {Event} e The event object
22383 * @param {String} id The id of the dragged element
22384 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22386 beforeDragOver : function(target, e, id){
22391 onDragOut : function(e, id){
22392 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22393 if(this.beforeDragOut(target, e, id) !== false){
22394 if(target.isNotifyTarget){
22395 target.notifyOut(this, e, this.dragData);
22397 this.proxy.reset();
22398 if(this.afterDragOut){
22400 * An empty function by default, but provided so that you can perform a custom action
22401 * after the dragged item is dragged out of the target without dropping.
22402 * @param {Roo.dd.DragDrop} target The drop target
22403 * @param {Event} e The event object
22404 * @param {String} id The id of the dragged element
22405 * @method afterDragOut
22407 this.afterDragOut(target, e, id);
22410 this.cachedTarget = null;
22414 * An empty function by default, but provided so that you can perform a custom action before the dragged
22415 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22416 * @param {Roo.dd.DragDrop} target The drop target
22417 * @param {Event} e The event object
22418 * @param {String} id The id of the dragged element
22419 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22421 beforeDragOut : function(target, e, id){
22426 onDragDrop : function(e, id){
22427 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22428 if(this.beforeDragDrop(target, e, id) !== false){
22429 if(target.isNotifyTarget){
22430 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22431 this.onValidDrop(target, e, id);
22433 this.onInvalidDrop(target, e, id);
22436 this.onValidDrop(target, e, id);
22439 if(this.afterDragDrop){
22441 * An empty function by default, but provided so that you can perform a custom action
22442 * after a valid drag drop has occurred by providing an implementation.
22443 * @param {Roo.dd.DragDrop} target The drop target
22444 * @param {Event} e The event object
22445 * @param {String} id The id of the dropped element
22446 * @method afterDragDrop
22448 this.afterDragDrop(target, e, id);
22451 delete this.cachedTarget;
22455 * An empty function by default, but provided so that you can perform a custom action before the dragged
22456 * item is dropped onto the target and optionally cancel the onDragDrop.
22457 * @param {Roo.dd.DragDrop} target The drop target
22458 * @param {Event} e The event object
22459 * @param {String} id The id of the dragged element
22460 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22462 beforeDragDrop : function(target, e, id){
22467 onValidDrop : function(target, e, id){
22469 if(this.afterValidDrop){
22471 * An empty function by default, but provided so that you can perform a custom action
22472 * after a valid drop has occurred by providing an implementation.
22473 * @param {Object} target The target DD
22474 * @param {Event} e The event object
22475 * @param {String} id The id of the dropped element
22476 * @method afterInvalidDrop
22478 this.afterValidDrop(target, e, id);
22483 getRepairXY : function(e, data){
22484 return this.el.getXY();
22488 onInvalidDrop : function(target, e, id){
22489 this.beforeInvalidDrop(target, e, id);
22490 if(this.cachedTarget){
22491 if(this.cachedTarget.isNotifyTarget){
22492 this.cachedTarget.notifyOut(this, e, this.dragData);
22494 this.cacheTarget = null;
22496 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22498 if(this.afterInvalidDrop){
22500 * An empty function by default, but provided so that you can perform a custom action
22501 * after an invalid drop has occurred by providing an implementation.
22502 * @param {Event} e The event object
22503 * @param {String} id The id of the dropped element
22504 * @method afterInvalidDrop
22506 this.afterInvalidDrop(e, id);
22511 afterRepair : function(){
22513 this.el.highlight(this.hlColor || "c3daf9");
22515 this.dragging = false;
22519 * An empty function by default, but provided so that you can perform a custom action after an invalid
22520 * drop has occurred.
22521 * @param {Roo.dd.DragDrop} target The drop target
22522 * @param {Event} e The event object
22523 * @param {String} id The id of the dragged element
22524 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22526 beforeInvalidDrop : function(target, e, id){
22531 handleMouseDown : function(e){
22532 if(this.dragging) {
22535 var data = this.getDragData(e);
22536 if(data && this.onBeforeDrag(data, e) !== false){
22537 this.dragData = data;
22539 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22544 * An empty function by default, but provided so that you can perform a custom action before the initial
22545 * drag event begins and optionally cancel it.
22546 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22547 * @param {Event} e The event object
22548 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22550 onBeforeDrag : function(data, e){
22555 * An empty function by default, but provided so that you can perform a custom action once the initial
22556 * drag event has begun. The drag cannot be canceled from this function.
22557 * @param {Number} x The x position of the click on the dragged object
22558 * @param {Number} y The y position of the click on the dragged object
22560 onStartDrag : Roo.emptyFn,
22562 // private - YUI override
22563 startDrag : function(x, y){
22564 this.proxy.reset();
22565 this.dragging = true;
22566 this.proxy.update("");
22567 this.onInitDrag(x, y);
22572 onInitDrag : function(x, y){
22573 var clone = this.el.dom.cloneNode(true);
22574 clone.id = Roo.id(); // prevent duplicate ids
22575 this.proxy.update(clone);
22576 this.onStartDrag(x, y);
22581 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22582 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22584 getProxy : function(){
22589 * Hides the drag source's {@link Roo.dd.StatusProxy}
22591 hideProxy : function(){
22593 this.proxy.reset(true);
22594 this.dragging = false;
22598 triggerCacheRefresh : function(){
22599 Roo.dd.DDM.refreshCache(this.groups);
22602 // private - override to prevent hiding
22603 b4EndDrag: function(e) {
22606 // private - override to prevent moving
22607 endDrag : function(e){
22608 this.onEndDrag(this.dragData, e);
22612 onEndDrag : function(data, e){
22615 // private - pin to cursor
22616 autoOffset : function(x, y) {
22617 this.setDelta(-12, -20);
22621 * Ext JS Library 1.1.1
22622 * Copyright(c) 2006-2007, Ext JS, LLC.
22624 * Originally Released Under LGPL - original licence link has changed is not relivant.
22627 * <script type="text/javascript">
22632 * @class Roo.dd.DropTarget
22633 * @extends Roo.dd.DDTarget
22634 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22635 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22637 * @param {String/HTMLElement/Element} el The container element
22638 * @param {Object} config
22640 Roo.dd.DropTarget = function(el, config){
22641 this.el = Roo.get(el);
22643 var listeners = false; ;
22644 if (config && config.listeners) {
22645 listeners= config.listeners;
22646 delete config.listeners;
22648 Roo.apply(this, config);
22650 if(this.containerScroll){
22651 Roo.dd.ScrollManager.register(this.el);
22655 * @scope Roo.dd.DropTarget
22660 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22661 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22662 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22664 * IMPORTANT : it should set this.valid to true|false
22666 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22667 * @param {Event} e The event
22668 * @param {Object} data An object containing arbitrary data supplied by the drag source
22674 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22675 * This method will be called on every mouse movement while the drag source is over the drop target.
22676 * This default implementation simply returns the dropAllowed config value.
22678 * IMPORTANT : it should set this.valid to true|false
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 source has been dragged
22689 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22690 * overClass (if any) from the drop element.
22693 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22694 * @param {Event} e The event
22695 * @param {Object} data An object containing arbitrary data supplied by the drag source
22701 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22702 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22703 * implementation that does something to process the drop event and returns true so that the drag source's
22704 * repair action does not run.
22706 * IMPORTANT : it should set this.success
22708 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22709 * @param {Event} e The event
22710 * @param {Object} data An object containing arbitrary data supplied by the drag source
22716 Roo.dd.DropTarget.superclass.constructor.call( this,
22718 this.ddGroup || this.group,
22721 listeners : listeners || {}
22729 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22731 * @cfg {String} overClass
22732 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22735 * @cfg {String} ddGroup
22736 * The drag drop group to handle drop events for
22740 * @cfg {String} dropAllowed
22741 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22743 dropAllowed : "x-dd-drop-ok",
22745 * @cfg {String} dropNotAllowed
22746 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22748 dropNotAllowed : "x-dd-drop-nodrop",
22750 * @cfg {boolean} success
22751 * set this after drop listener..
22755 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22756 * if the drop point is valid for over/enter..
22763 isNotifyTarget : true,
22768 notifyEnter : function(dd, e, data)
22771 this.fireEvent('enter', dd, e, data);
22772 if(this.overClass){
22773 this.el.addClass(this.overClass);
22775 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22776 this.valid ? this.dropAllowed : this.dropNotAllowed
22783 notifyOver : function(dd, e, data)
22786 this.fireEvent('over', dd, e, data);
22787 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22788 this.valid ? this.dropAllowed : this.dropNotAllowed
22795 notifyOut : function(dd, e, data)
22797 this.fireEvent('out', dd, e, data);
22798 if(this.overClass){
22799 this.el.removeClass(this.overClass);
22806 notifyDrop : function(dd, e, data)
22808 this.success = false;
22809 this.fireEvent('drop', dd, e, data);
22810 return this.success;
22814 * Ext JS Library 1.1.1
22815 * Copyright(c) 2006-2007, Ext JS, LLC.
22817 * Originally Released Under LGPL - original licence link has changed is not relivant.
22820 * <script type="text/javascript">
22825 * @class Roo.dd.DragZone
22826 * @extends Roo.dd.DragSource
22827 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22828 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22830 * @param {String/HTMLElement/Element} el The container element
22831 * @param {Object} config
22833 Roo.dd.DragZone = function(el, config){
22834 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22835 if(this.containerScroll){
22836 Roo.dd.ScrollManager.register(this.el);
22840 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22842 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22843 * for auto scrolling during drag operations.
22846 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22847 * method after a failed drop (defaults to "c3daf9" - light blue)
22851 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22852 * for a valid target to drag based on the mouse down. Override this method
22853 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22854 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22855 * @param {EventObject} e The mouse down event
22856 * @return {Object} The dragData
22858 getDragData : function(e){
22859 return Roo.dd.Registry.getHandleFromEvent(e);
22863 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22864 * this.dragData.ddel
22865 * @param {Number} x The x position of the click on the dragged object
22866 * @param {Number} y The y position of the click on the dragged object
22867 * @return {Boolean} true to continue the drag, false to cancel
22869 onInitDrag : function(x, y){
22870 this.proxy.update(this.dragData.ddel.cloneNode(true));
22871 this.onStartDrag(x, y);
22876 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22878 afterRepair : function(){
22880 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22882 this.dragging = false;
22886 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22887 * the XY of this.dragData.ddel
22888 * @param {EventObject} e The mouse up event
22889 * @return {Array} The xy location (e.g. [100, 200])
22891 getRepairXY : function(e){
22892 return Roo.Element.fly(this.dragData.ddel).getXY();
22896 * Ext JS Library 1.1.1
22897 * Copyright(c) 2006-2007, Ext JS, LLC.
22899 * Originally Released Under LGPL - original licence link has changed is not relivant.
22902 * <script type="text/javascript">
22905 * @class Roo.dd.DropZone
22906 * @extends Roo.dd.DropTarget
22907 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22908 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22910 * @param {String/HTMLElement/Element} el The container element
22911 * @param {Object} config
22913 Roo.dd.DropZone = function(el, config){
22914 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22917 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22919 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22920 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22921 * provide your own custom lookup.
22922 * @param {Event} e The event
22923 * @return {Object} data The custom data
22925 getTargetFromEvent : function(e){
22926 return Roo.dd.Registry.getTargetFromEvent(e);
22930 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22931 * that it has registered. This method has no default implementation and should be overridden to provide
22932 * node-specific processing if necessary.
22933 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22934 * {@link #getTargetFromEvent} for this node)
22935 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22936 * @param {Event} e The event
22937 * @param {Object} data An object containing arbitrary data supplied by the drag source
22939 onNodeEnter : function(n, dd, e, data){
22944 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22945 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22946 * overridden to provide the proper feedback.
22947 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22948 * {@link #getTargetFromEvent} for this node)
22949 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22950 * @param {Event} e The event
22951 * @param {Object} data An object containing arbitrary data supplied by the drag source
22952 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22953 * underlying {@link Roo.dd.StatusProxy} can be updated
22955 onNodeOver : function(n, dd, e, data){
22956 return this.dropAllowed;
22960 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22961 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22962 * node-specific processing if necessary.
22963 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22964 * {@link #getTargetFromEvent} for this node)
22965 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22966 * @param {Event} e The event
22967 * @param {Object} data An object containing arbitrary data supplied by the drag source
22969 onNodeOut : function(n, dd, e, data){
22974 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22975 * the drop node. The default implementation returns false, so it should be overridden to provide the
22976 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22977 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22978 * {@link #getTargetFromEvent} for this node)
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 {Boolean} True if the drop was valid, else false
22984 onNodeDrop : function(n, dd, e, data){
22989 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22990 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22991 * it should be overridden to provide the proper feedback if necessary.
22992 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22993 * @param {Event} e The event
22994 * @param {Object} data An object containing arbitrary data supplied by the drag source
22995 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22996 * underlying {@link Roo.dd.StatusProxy} can be updated
22998 onContainerOver : function(dd, e, data){
22999 return this.dropNotAllowed;
23003 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23004 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
23005 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23006 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
23007 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23008 * @param {Event} e The event
23009 * @param {Object} data An object containing arbitrary data supplied by the drag source
23010 * @return {Boolean} True if the drop was valid, else false
23012 onContainerDrop : function(dd, e, data){
23017 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23018 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
23019 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23020 * you should override this method and provide a custom implementation.
23021 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23022 * @param {Event} e The event
23023 * @param {Object} data An object containing arbitrary data supplied by the drag source
23024 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23025 * underlying {@link Roo.dd.StatusProxy} can be updated
23027 notifyEnter : function(dd, e, data){
23028 return this.dropNotAllowed;
23032 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23033 * This method will be called on every mouse movement while the drag source is over the drop zone.
23034 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23035 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23036 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23037 * registered node, it will call {@link #onContainerOver}.
23038 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23039 * @param {Event} e The event
23040 * @param {Object} data An object containing arbitrary data supplied by the drag source
23041 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23042 * underlying {@link Roo.dd.StatusProxy} can be updated
23044 notifyOver : function(dd, e, data){
23045 var n = this.getTargetFromEvent(e);
23046 if(!n){ // not over valid drop target
23047 if(this.lastOverNode){
23048 this.onNodeOut(this.lastOverNode, dd, e, data);
23049 this.lastOverNode = null;
23051 return this.onContainerOver(dd, e, data);
23053 if(this.lastOverNode != n){
23054 if(this.lastOverNode){
23055 this.onNodeOut(this.lastOverNode, dd, e, data);
23057 this.onNodeEnter(n, dd, e, data);
23058 this.lastOverNode = n;
23060 return this.onNodeOver(n, dd, e, data);
23064 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23065 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23066 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23067 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23068 * @param {Event} e The event
23069 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23071 notifyOut : function(dd, e, data){
23072 if(this.lastOverNode){
23073 this.onNodeOut(this.lastOverNode, dd, e, data);
23074 this.lastOverNode = null;
23079 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23080 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23081 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23082 * otherwise it will call {@link #onContainerDrop}.
23083 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23084 * @param {Event} e The event
23085 * @param {Object} data An object containing arbitrary data supplied by the drag source
23086 * @return {Boolean} True if the drop was valid, else false
23088 notifyDrop : function(dd, e, data){
23089 if(this.lastOverNode){
23090 this.onNodeOut(this.lastOverNode, dd, e, data);
23091 this.lastOverNode = null;
23093 var n = this.getTargetFromEvent(e);
23095 this.onNodeDrop(n, dd, e, data) :
23096 this.onContainerDrop(dd, e, data);
23100 triggerCacheRefresh : function(){
23101 Roo.dd.DDM.refreshCache(this.groups);
23105 * Ext JS Library 1.1.1
23106 * Copyright(c) 2006-2007, Ext JS, LLC.
23108 * Originally Released Under LGPL - original licence link has changed is not relivant.
23111 * <script type="text/javascript">
23116 * @class Roo.data.SortTypes
23118 * Defines the default sorting (casting?) comparison functions used when sorting data.
23120 Roo.data.SortTypes = {
23122 * Default sort that does nothing
23123 * @param {Mixed} s The value being converted
23124 * @return {Mixed} The comparison value
23126 none : function(s){
23131 * The regular expression used to strip tags
23135 stripTagsRE : /<\/?[^>]+>/gi,
23138 * Strips all HTML tags to sort on text only
23139 * @param {Mixed} s The value being converted
23140 * @return {String} The comparison value
23142 asText : function(s){
23143 return String(s).replace(this.stripTagsRE, "");
23147 * Strips all HTML tags to sort on text only - Case insensitive
23148 * @param {Mixed} s The value being converted
23149 * @return {String} The comparison value
23151 asUCText : function(s){
23152 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23156 * Case insensitive string
23157 * @param {Mixed} s The value being converted
23158 * @return {String} The comparison value
23160 asUCString : function(s) {
23161 return String(s).toUpperCase();
23166 * @param {Mixed} s The value being converted
23167 * @return {Number} The comparison value
23169 asDate : function(s) {
23173 if(s instanceof Date){
23174 return s.getTime();
23176 return Date.parse(String(s));
23181 * @param {Mixed} s The value being converted
23182 * @return {Float} The comparison value
23184 asFloat : function(s) {
23185 var val = parseFloat(String(s).replace(/,/g, ""));
23194 * @param {Mixed} s The value being converted
23195 * @return {Number} The comparison value
23197 asInt : function(s) {
23198 var val = parseInt(String(s).replace(/,/g, ""));
23206 * Ext JS Library 1.1.1
23207 * Copyright(c) 2006-2007, Ext JS, LLC.
23209 * Originally Released Under LGPL - original licence link has changed is not relivant.
23212 * <script type="text/javascript">
23216 * @class Roo.data.Record
23217 * Instances of this class encapsulate both record <em>definition</em> information, and record
23218 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
23219 * to access Records cached in an {@link Roo.data.Store} object.<br>
23221 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
23222 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
23225 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
23227 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
23228 * {@link #create}. The parameters are the same.
23229 * @param {Array} data An associative Array of data values keyed by the field name.
23230 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
23231 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
23232 * not specified an integer id is generated.
23234 Roo.data.Record = function(data, id){
23235 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
23240 * Generate a constructor for a specific record layout.
23241 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
23242 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
23243 * Each field definition object may contain the following properties: <ul>
23244 * <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,
23245 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
23246 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
23247 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
23248 * is being used, then this is a string containing the javascript expression to reference the data relative to
23249 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
23250 * to the data item relative to the record element. If the mapping expression is the same as the field name,
23251 * this may be omitted.</p></li>
23252 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
23253 * <ul><li>auto (Default, implies no conversion)</li>
23258 * <li>date</li></ul></p></li>
23259 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
23260 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
23261 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
23262 * by the Reader into an object that will be stored in the Record. It is passed the
23263 * following parameters:<ul>
23264 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
23266 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
23268 * <br>usage:<br><pre><code>
23269 var TopicRecord = Roo.data.Record.create(
23270 {name: 'title', mapping: 'topic_title'},
23271 {name: 'author', mapping: 'username'},
23272 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
23273 {name: 'lastPost', mapping: 'post_time', type: 'date'},
23274 {name: 'lastPoster', mapping: 'user2'},
23275 {name: 'excerpt', mapping: 'post_text'}
23278 var myNewRecord = new TopicRecord({
23279 title: 'Do my job please',
23282 lastPost: new Date(),
23283 lastPoster: 'Animal',
23284 excerpt: 'No way dude!'
23286 myStore.add(myNewRecord);
23291 Roo.data.Record.create = function(o){
23292 var f = function(){
23293 f.superclass.constructor.apply(this, arguments);
23295 Roo.extend(f, Roo.data.Record);
23296 var p = f.prototype;
23297 p.fields = new Roo.util.MixedCollection(false, function(field){
23300 for(var i = 0, len = o.length; i < len; i++){
23301 p.fields.add(new Roo.data.Field(o[i]));
23303 f.getField = function(name){
23304 return p.fields.get(name);
23309 Roo.data.Record.AUTO_ID = 1000;
23310 Roo.data.Record.EDIT = 'edit';
23311 Roo.data.Record.REJECT = 'reject';
23312 Roo.data.Record.COMMIT = 'commit';
23314 Roo.data.Record.prototype = {
23316 * Readonly flag - true if this record has been modified.
23325 join : function(store){
23326 this.store = store;
23330 * Set the named field to the specified value.
23331 * @param {String} name The name of the field to set.
23332 * @param {Object} value The value to set the field to.
23334 set : function(name, value){
23335 if(this.data[name] == value){
23339 if(!this.modified){
23340 this.modified = {};
23342 if(typeof this.modified[name] == 'undefined'){
23343 this.modified[name] = this.data[name];
23345 this.data[name] = value;
23346 if(!this.editing && this.store){
23347 this.store.afterEdit(this);
23352 * Get the value of the named field.
23353 * @param {String} name The name of the field to get the value of.
23354 * @return {Object} The value of the field.
23356 get : function(name){
23357 return this.data[name];
23361 beginEdit : function(){
23362 this.editing = true;
23363 this.modified = {};
23367 cancelEdit : function(){
23368 this.editing = false;
23369 delete this.modified;
23373 endEdit : function(){
23374 this.editing = false;
23375 if(this.dirty && this.store){
23376 this.store.afterEdit(this);
23381 * Usually called by the {@link Roo.data.Store} which owns the Record.
23382 * Rejects all changes made to the Record since either creation, or the last commit operation.
23383 * Modified fields are reverted to their original values.
23385 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23386 * of reject operations.
23388 reject : function(){
23389 var m = this.modified;
23391 if(typeof m[n] != "function"){
23392 this.data[n] = m[n];
23395 this.dirty = false;
23396 delete this.modified;
23397 this.editing = false;
23399 this.store.afterReject(this);
23404 * Usually called by the {@link Roo.data.Store} which owns the Record.
23405 * Commits all changes made to the Record since either creation, or the last commit operation.
23407 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23408 * of commit operations.
23410 commit : function(){
23411 this.dirty = false;
23412 delete this.modified;
23413 this.editing = false;
23415 this.store.afterCommit(this);
23420 hasError : function(){
23421 return this.error != null;
23425 clearError : function(){
23430 * Creates a copy of this record.
23431 * @param {String} id (optional) A new record id if you don't want to use this record's id
23434 copy : function(newId) {
23435 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
23439 * Ext JS Library 1.1.1
23440 * Copyright(c) 2006-2007, Ext JS, LLC.
23442 * Originally Released Under LGPL - original licence link has changed is not relivant.
23445 * <script type="text/javascript">
23451 * @class Roo.data.Store
23452 * @extends Roo.util.Observable
23453 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
23454 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
23456 * 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
23457 * has no knowledge of the format of the data returned by the Proxy.<br>
23459 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
23460 * instances from the data object. These records are cached and made available through accessor functions.
23462 * Creates a new Store.
23463 * @param {Object} config A config object containing the objects needed for the Store to access data,
23464 * and read the data into Records.
23466 Roo.data.Store = function(config){
23467 this.data = new Roo.util.MixedCollection(false);
23468 this.data.getKey = function(o){
23471 this.baseParams = {};
23473 this.paramNames = {
23478 "multisort" : "_multisort"
23481 if(config && config.data){
23482 this.inlineData = config.data;
23483 delete config.data;
23486 Roo.apply(this, config);
23488 if(this.reader){ // reader passed
23489 this.reader = Roo.factory(this.reader, Roo.data);
23490 this.reader.xmodule = this.xmodule || false;
23491 if(!this.recordType){
23492 this.recordType = this.reader.recordType;
23494 if(this.reader.onMetaChange){
23495 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
23499 if(this.recordType){
23500 this.fields = this.recordType.prototype.fields;
23502 this.modified = [];
23506 * @event datachanged
23507 * Fires when the data cache has changed, and a widget which is using this Store
23508 * as a Record cache should refresh its view.
23509 * @param {Store} this
23511 datachanged : true,
23513 * @event metachange
23514 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
23515 * @param {Store} this
23516 * @param {Object} meta The JSON metadata
23521 * Fires when Records have been added to the Store
23522 * @param {Store} this
23523 * @param {Roo.data.Record[]} records The array of Records added
23524 * @param {Number} index The index at which the record(s) were added
23529 * Fires when a Record has been removed from the Store
23530 * @param {Store} this
23531 * @param {Roo.data.Record} record The Record that was removed
23532 * @param {Number} index The index at which the record was removed
23537 * Fires when a Record has been updated
23538 * @param {Store} this
23539 * @param {Roo.data.Record} record The Record that was updated
23540 * @param {String} operation The update operation being performed. Value may be one of:
23542 Roo.data.Record.EDIT
23543 Roo.data.Record.REJECT
23544 Roo.data.Record.COMMIT
23550 * Fires when the data cache has been cleared.
23551 * @param {Store} this
23555 * @event beforeload
23556 * Fires before a request is made for a new data object. If the beforeload handler returns false
23557 * the load action will be canceled.
23558 * @param {Store} this
23559 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23563 * @event beforeloadadd
23564 * Fires after a new set of Records has been loaded.
23565 * @param {Store} this
23566 * @param {Roo.data.Record[]} records The Records that were loaded
23567 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23569 beforeloadadd : true,
23572 * Fires after a new set of Records has been loaded, before they are added to the store.
23573 * @param {Store} this
23574 * @param {Roo.data.Record[]} records The Records that were loaded
23575 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23576 * @params {Object} return from reader
23580 * @event loadexception
23581 * Fires if an exception occurs in the Proxy during loading.
23582 * Called with the signature of the Proxy's "loadexception" event.
23583 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
23586 * @param {Object} return from JsonData.reader() - success, totalRecords, records
23587 * @param {Object} load options
23588 * @param {Object} jsonData from your request (normally this contains the Exception)
23590 loadexception : true
23594 this.proxy = Roo.factory(this.proxy, Roo.data);
23595 this.proxy.xmodule = this.xmodule || false;
23596 this.relayEvents(this.proxy, ["loadexception"]);
23598 this.sortToggle = {};
23599 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
23601 Roo.data.Store.superclass.constructor.call(this);
23603 if(this.inlineData){
23604 this.loadData(this.inlineData);
23605 delete this.inlineData;
23609 Roo.extend(Roo.data.Store, Roo.util.Observable, {
23611 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
23612 * without a remote query - used by combo/forms at present.
23616 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
23619 * @cfg {Array} data Inline data to be loaded when the store is initialized.
23622 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
23623 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
23626 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
23627 * on any HTTP request
23630 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
23633 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
23637 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
23638 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
23640 remoteSort : false,
23643 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
23644 * loaded or when a record is removed. (defaults to false).
23646 pruneModifiedRecords : false,
23649 lastOptions : null,
23652 * Add Records to the Store and fires the add event.
23653 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23655 add : function(records){
23656 records = [].concat(records);
23657 for(var i = 0, len = records.length; i < len; i++){
23658 records[i].join(this);
23660 var index = this.data.length;
23661 this.data.addAll(records);
23662 this.fireEvent("add", this, records, index);
23666 * Remove a Record from the Store and fires the remove event.
23667 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23669 remove : function(record){
23670 var index = this.data.indexOf(record);
23671 this.data.removeAt(index);
23673 if(this.pruneModifiedRecords){
23674 this.modified.remove(record);
23676 this.fireEvent("remove", this, record, index);
23680 * Remove all Records from the Store and fires the clear event.
23682 removeAll : function(){
23684 if(this.pruneModifiedRecords){
23685 this.modified = [];
23687 this.fireEvent("clear", this);
23691 * Inserts Records to the Store at the given index and fires the add event.
23692 * @param {Number} index The start index at which to insert the passed Records.
23693 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23695 insert : function(index, records){
23696 records = [].concat(records);
23697 for(var i = 0, len = records.length; i < len; i++){
23698 this.data.insert(index, records[i]);
23699 records[i].join(this);
23701 this.fireEvent("add", this, records, index);
23705 * Get the index within the cache of the passed Record.
23706 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23707 * @return {Number} The index of the passed Record. Returns -1 if not found.
23709 indexOf : function(record){
23710 return this.data.indexOf(record);
23714 * Get the index within the cache of the Record with the passed id.
23715 * @param {String} id The id of the Record to find.
23716 * @return {Number} The index of the Record. Returns -1 if not found.
23718 indexOfId : function(id){
23719 return this.data.indexOfKey(id);
23723 * Get the Record with the specified id.
23724 * @param {String} id The id of the Record to find.
23725 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23727 getById : function(id){
23728 return this.data.key(id);
23732 * Get the Record at the specified index.
23733 * @param {Number} index The index of the Record to find.
23734 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23736 getAt : function(index){
23737 return this.data.itemAt(index);
23741 * Returns a range of Records between specified indices.
23742 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23743 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23744 * @return {Roo.data.Record[]} An array of Records
23746 getRange : function(start, end){
23747 return this.data.getRange(start, end);
23751 storeOptions : function(o){
23752 o = Roo.apply({}, o);
23755 this.lastOptions = o;
23759 * Loads the Record cache from the configured Proxy using the configured Reader.
23761 * If using remote paging, then the first load call must specify the <em>start</em>
23762 * and <em>limit</em> properties in the options.params property to establish the initial
23763 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23765 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23766 * and this call will return before the new data has been loaded. Perform any post-processing
23767 * in a callback function, or in a "load" event handler.</strong>
23769 * @param {Object} options An object containing properties which control loading options:<ul>
23770 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23771 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23772 * passed the following arguments:<ul>
23773 * <li>r : Roo.data.Record[]</li>
23774 * <li>options: Options object from the load call</li>
23775 * <li>success: Boolean success indicator</li></ul></li>
23776 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23777 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23780 load : function(options){
23781 options = options || {};
23782 if(this.fireEvent("beforeload", this, options) !== false){
23783 this.storeOptions(options);
23784 var p = Roo.apply(options.params || {}, this.baseParams);
23785 // if meta was not loaded from remote source.. try requesting it.
23786 if (!this.reader.metaFromRemote) {
23787 p._requestMeta = 1;
23789 if(this.sortInfo && this.remoteSort){
23790 var pn = this.paramNames;
23791 p[pn["sort"]] = this.sortInfo.field;
23792 p[pn["dir"]] = this.sortInfo.direction;
23794 if (this.multiSort) {
23795 var pn = this.paramNames;
23796 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23799 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23804 * Reloads the Record cache from the configured Proxy using the configured Reader and
23805 * the options from the last load operation performed.
23806 * @param {Object} options (optional) An object containing properties which may override the options
23807 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23808 * the most recently used options are reused).
23810 reload : function(options){
23811 this.load(Roo.applyIf(options||{}, this.lastOptions));
23815 // Called as a callback by the Reader during a load operation.
23816 loadRecords : function(o, options, success){
23817 if(!o || success === false){
23818 if(success !== false){
23819 this.fireEvent("load", this, [], options, o);
23821 if(options.callback){
23822 options.callback.call(options.scope || this, [], options, false);
23826 // if data returned failure - throw an exception.
23827 if (o.success === false) {
23828 // show a message if no listener is registered.
23829 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23830 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23832 // loadmask wil be hooked into this..
23833 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23836 var r = o.records, t = o.totalRecords || r.length;
23838 this.fireEvent("beforeloadadd", this, r, options, o);
23840 if(!options || options.add !== true){
23841 if(this.pruneModifiedRecords){
23842 this.modified = [];
23844 for(var i = 0, len = r.length; i < len; i++){
23848 this.data = this.snapshot;
23849 delete this.snapshot;
23852 this.data.addAll(r);
23853 this.totalLength = t;
23855 this.fireEvent("datachanged", this);
23857 this.totalLength = Math.max(t, this.data.length+r.length);
23861 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23863 var e = new Roo.data.Record({});
23865 e.set(this.parent.displayField, this.parent.emptyTitle);
23866 e.set(this.parent.valueField, '');
23871 this.fireEvent("load", this, r, options, o);
23872 if(options.callback){
23873 options.callback.call(options.scope || this, r, options, true);
23879 * Loads data from a passed data block. A Reader which understands the format of the data
23880 * must have been configured in the constructor.
23881 * @param {Object} data The data block from which to read the Records. The format of the data expected
23882 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23883 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23885 loadData : function(o, append){
23886 var r = this.reader.readRecords(o);
23887 this.loadRecords(r, {add: append}, true);
23891 * using 'cn' the nested child reader read the child array into it's child stores.
23892 * @param {Object} rec The record with a 'children array
23894 loadDataFromChildren : function(rec)
23896 this.loadData(this.reader.toLoadData(rec));
23901 * Gets the number of cached records.
23903 * <em>If using paging, this may not be the total size of the dataset. If the data object
23904 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23905 * the data set size</em>
23907 getCount : function(){
23908 return this.data.length || 0;
23912 * Gets the total number of records in the dataset as returned by the server.
23914 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23915 * the dataset size</em>
23917 getTotalCount : function(){
23918 return this.totalLength || 0;
23922 * Returns the sort state of the Store as an object with two properties:
23924 field {String} The name of the field by which the Records are sorted
23925 direction {String} The sort order, "ASC" or "DESC"
23928 getSortState : function(){
23929 return this.sortInfo;
23933 applySort : function(){
23934 if(this.sortInfo && !this.remoteSort){
23935 var s = this.sortInfo, f = s.field;
23936 var st = this.fields.get(f).sortType;
23937 var fn = function(r1, r2){
23938 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23939 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23941 this.data.sort(s.direction, fn);
23942 if(this.snapshot && this.snapshot != this.data){
23943 this.snapshot.sort(s.direction, fn);
23949 * Sets the default sort column and order to be used by the next load operation.
23950 * @param {String} fieldName The name of the field to sort by.
23951 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23953 setDefaultSort : function(field, dir){
23954 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23958 * Sort the Records.
23959 * If remote sorting is used, the sort is performed on the server, and the cache is
23960 * reloaded. If local sorting is used, the cache is sorted internally.
23961 * @param {String} fieldName The name of the field to sort by.
23962 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23964 sort : function(fieldName, dir){
23965 var f = this.fields.get(fieldName);
23967 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23969 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23970 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23975 this.sortToggle[f.name] = dir;
23976 this.sortInfo = {field: f.name, direction: dir};
23977 if(!this.remoteSort){
23979 this.fireEvent("datachanged", this);
23981 this.load(this.lastOptions);
23986 * Calls the specified function for each of the Records in the cache.
23987 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23988 * Returning <em>false</em> aborts and exits the iteration.
23989 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23991 each : function(fn, scope){
23992 this.data.each(fn, scope);
23996 * Gets all records modified since the last commit. Modified records are persisted across load operations
23997 * (e.g., during paging).
23998 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
24000 getModifiedRecords : function(){
24001 return this.modified;
24005 createFilterFn : function(property, value, anyMatch){
24006 if(!value.exec){ // not a regex
24007 value = String(value);
24008 if(value.length == 0){
24011 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
24013 return function(r){
24014 return value.test(r.data[property]);
24019 * Sums the value of <i>property</i> for each record between start and end and returns the result.
24020 * @param {String} property A field on your records
24021 * @param {Number} start The record index to start at (defaults to 0)
24022 * @param {Number} end The last record index to include (defaults to length - 1)
24023 * @return {Number} The sum
24025 sum : function(property, start, end){
24026 var rs = this.data.items, v = 0;
24027 start = start || 0;
24028 end = (end || end === 0) ? end : rs.length-1;
24030 for(var i = start; i <= end; i++){
24031 v += (rs[i].data[property] || 0);
24037 * Filter the records by a specified property.
24038 * @param {String} field A field on your records
24039 * @param {String/RegExp} value Either a string that the field
24040 * should start with or a RegExp to test against the field
24041 * @param {Boolean} anyMatch True to match any part not just the beginning
24043 filter : function(property, value, anyMatch){
24044 var fn = this.createFilterFn(property, value, anyMatch);
24045 return fn ? this.filterBy(fn) : this.clearFilter();
24049 * Filter by a function. The specified function will be called with each
24050 * record in this data source. If the function returns true the record is included,
24051 * otherwise it is filtered.
24052 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24053 * @param {Object} scope (optional) The scope of the function (defaults to this)
24055 filterBy : function(fn, scope){
24056 this.snapshot = this.snapshot || this.data;
24057 this.data = this.queryBy(fn, scope||this);
24058 this.fireEvent("datachanged", this);
24062 * Query the records by a specified property.
24063 * @param {String} field A field on your records
24064 * @param {String/RegExp} value Either a string that the field
24065 * should start with or a RegExp to test against the field
24066 * @param {Boolean} anyMatch True to match any part not just the beginning
24067 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24069 query : function(property, value, anyMatch){
24070 var fn = this.createFilterFn(property, value, anyMatch);
24071 return fn ? this.queryBy(fn) : this.data.clone();
24075 * Query by a function. The specified function will be called with each
24076 * record in this data source. If the function returns true the record is included
24078 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24079 * @param {Object} scope (optional) The scope of the function (defaults to this)
24080 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24082 queryBy : function(fn, scope){
24083 var data = this.snapshot || this.data;
24084 return data.filterBy(fn, scope||this);
24088 * Collects unique values for a particular dataIndex from this store.
24089 * @param {String} dataIndex The property to collect
24090 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24091 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24092 * @return {Array} An array of the unique values
24094 collect : function(dataIndex, allowNull, bypassFilter){
24095 var d = (bypassFilter === true && this.snapshot) ?
24096 this.snapshot.items : this.data.items;
24097 var v, sv, r = [], l = {};
24098 for(var i = 0, len = d.length; i < len; i++){
24099 v = d[i].data[dataIndex];
24101 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24110 * Revert to a view of the Record cache with no filtering applied.
24111 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24113 clearFilter : function(suppressEvent){
24114 if(this.snapshot && this.snapshot != this.data){
24115 this.data = this.snapshot;
24116 delete this.snapshot;
24117 if(suppressEvent !== true){
24118 this.fireEvent("datachanged", this);
24124 afterEdit : function(record){
24125 if(this.modified.indexOf(record) == -1){
24126 this.modified.push(record);
24128 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24132 afterReject : function(record){
24133 this.modified.remove(record);
24134 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24138 afterCommit : function(record){
24139 this.modified.remove(record);
24140 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24144 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24145 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24147 commitChanges : function(){
24148 var m = this.modified.slice(0);
24149 this.modified = [];
24150 for(var i = 0, len = m.length; i < len; i++){
24156 * Cancel outstanding changes on all changed records.
24158 rejectChanges : function(){
24159 var m = this.modified.slice(0);
24160 this.modified = [];
24161 for(var i = 0, len = m.length; i < len; i++){
24166 onMetaChange : function(meta, rtype, o){
24167 this.recordType = rtype;
24168 this.fields = rtype.prototype.fields;
24169 delete this.snapshot;
24170 this.sortInfo = meta.sortInfo || this.sortInfo;
24171 this.modified = [];
24172 this.fireEvent('metachange', this, this.reader.meta);
24175 moveIndex : function(data, type)
24177 var index = this.indexOf(data);
24179 var newIndex = index + type;
24183 this.insert(newIndex, data);
24188 * Ext JS Library 1.1.1
24189 * Copyright(c) 2006-2007, Ext JS, LLC.
24191 * Originally Released Under LGPL - original licence link has changed is not relivant.
24194 * <script type="text/javascript">
24198 * @class Roo.data.SimpleStore
24199 * @extends Roo.data.Store
24200 * Small helper class to make creating Stores from Array data easier.
24201 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24202 * @cfg {Array} fields An array of field definition objects, or field name strings.
24203 * @cfg {Object} an existing reader (eg. copied from another store)
24204 * @cfg {Array} data The multi-dimensional array of data
24206 * @param {Object} config
24208 Roo.data.SimpleStore = function(config)
24210 Roo.data.SimpleStore.superclass.constructor.call(this, {
24212 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24215 Roo.data.Record.create(config.fields)
24217 proxy : new Roo.data.MemoryProxy(config.data)
24221 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24223 * Ext JS Library 1.1.1
24224 * Copyright(c) 2006-2007, Ext JS, LLC.
24226 * Originally Released Under LGPL - original licence link has changed is not relivant.
24229 * <script type="text/javascript">
24234 * @extends Roo.data.Store
24235 * @class Roo.data.JsonStore
24236 * Small helper class to make creating Stores for JSON data easier. <br/>
24238 var store = new Roo.data.JsonStore({
24239 url: 'get-images.php',
24241 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24244 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24245 * JsonReader and HttpProxy (unless inline data is provided).</b>
24246 * @cfg {Array} fields An array of field definition objects, or field name strings.
24248 * @param {Object} config
24250 Roo.data.JsonStore = function(c){
24251 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24252 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24253 reader: new Roo.data.JsonReader(c, c.fields)
24256 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
24258 * Ext JS Library 1.1.1
24259 * Copyright(c) 2006-2007, Ext JS, LLC.
24261 * Originally Released Under LGPL - original licence link has changed is not relivant.
24264 * <script type="text/javascript">
24268 Roo.data.Field = function(config){
24269 if(typeof config == "string"){
24270 config = {name: config};
24272 Roo.apply(this, config);
24275 this.type = "auto";
24278 var st = Roo.data.SortTypes;
24279 // named sortTypes are supported, here we look them up
24280 if(typeof this.sortType == "string"){
24281 this.sortType = st[this.sortType];
24284 // set default sortType for strings and dates
24285 if(!this.sortType){
24288 this.sortType = st.asUCString;
24291 this.sortType = st.asDate;
24294 this.sortType = st.none;
24299 var stripRe = /[\$,%]/g;
24301 // prebuilt conversion function for this field, instead of
24302 // switching every time we're reading a value
24304 var cv, dateFormat = this.dateFormat;
24309 cv = function(v){ return v; };
24312 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24316 return v !== undefined && v !== null && v !== '' ?
24317 parseInt(String(v).replace(stripRe, ""), 10) : '';
24322 return v !== undefined && v !== null && v !== '' ?
24323 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24328 cv = function(v){ return v === true || v === "true" || v == 1; };
24335 if(v instanceof Date){
24339 if(dateFormat == "timestamp"){
24340 return new Date(v*1000);
24342 return Date.parseDate(v, dateFormat);
24344 var parsed = Date.parse(v);
24345 return parsed ? new Date(parsed) : null;
24354 Roo.data.Field.prototype = {
24362 * Ext JS Library 1.1.1
24363 * Copyright(c) 2006-2007, Ext JS, LLC.
24365 * Originally Released Under LGPL - original licence link has changed is not relivant.
24368 * <script type="text/javascript">
24371 // Base class for reading structured data from a data source. This class is intended to be
24372 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24375 * @class Roo.data.DataReader
24376 * Base class for reading structured data from a data source. This class is intended to be
24377 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24380 Roo.data.DataReader = function(meta, recordType){
24384 this.recordType = recordType instanceof Array ?
24385 Roo.data.Record.create(recordType) : recordType;
24388 Roo.data.DataReader.prototype = {
24391 readerType : 'Data',
24393 * Create an empty record
24394 * @param {Object} data (optional) - overlay some values
24395 * @return {Roo.data.Record} record created.
24397 newRow : function(d) {
24399 this.recordType.prototype.fields.each(function(c) {
24401 case 'int' : da[c.name] = 0; break;
24402 case 'date' : da[c.name] = new Date(); break;
24403 case 'float' : da[c.name] = 0.0; break;
24404 case 'boolean' : da[c.name] = false; break;
24405 default : da[c.name] = ""; break;
24409 return new this.recordType(Roo.apply(da, d));
24415 * Ext JS Library 1.1.1
24416 * Copyright(c) 2006-2007, Ext JS, LLC.
24418 * Originally Released Under LGPL - original licence link has changed is not relivant.
24421 * <script type="text/javascript">
24425 * @class Roo.data.DataProxy
24426 * @extends Roo.data.Observable
24427 * This class is an abstract base class for implementations which provide retrieval of
24428 * unformatted data objects.<br>
24430 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24431 * (of the appropriate type which knows how to parse the data object) to provide a block of
24432 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24434 * Custom implementations must implement the load method as described in
24435 * {@link Roo.data.HttpProxy#load}.
24437 Roo.data.DataProxy = function(){
24440 * @event beforeload
24441 * Fires before a network request is made to retrieve a data object.
24442 * @param {Object} This DataProxy object.
24443 * @param {Object} params The params parameter to the load function.
24448 * Fires before the load method's callback is called.
24449 * @param {Object} This DataProxy object.
24450 * @param {Object} o The data object.
24451 * @param {Object} arg The callback argument object passed to the load function.
24455 * @event loadexception
24456 * Fires if an Exception occurs during data retrieval.
24457 * @param {Object} This DataProxy object.
24458 * @param {Object} o The data object.
24459 * @param {Object} arg The callback argument object passed to the load function.
24460 * @param {Object} e The Exception.
24462 loadexception : true
24464 Roo.data.DataProxy.superclass.constructor.call(this);
24467 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24470 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24474 * Ext JS Library 1.1.1
24475 * Copyright(c) 2006-2007, Ext JS, LLC.
24477 * Originally Released Under LGPL - original licence link has changed is not relivant.
24480 * <script type="text/javascript">
24483 * @class Roo.data.MemoryProxy
24484 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24485 * to the Reader when its load method is called.
24487 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24489 Roo.data.MemoryProxy = function(data){
24493 Roo.data.MemoryProxy.superclass.constructor.call(this);
24497 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24500 * Load data from the requested source (in this case an in-memory
24501 * data object passed to the constructor), read the data object into
24502 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24503 * process that block using the passed callback.
24504 * @param {Object} params This parameter is not used by the MemoryProxy class.
24505 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24506 * object into a block of Roo.data.Records.
24507 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24508 * The function must be passed <ul>
24509 * <li>The Record block object</li>
24510 * <li>The "arg" argument from the load function</li>
24511 * <li>A boolean success indicator</li>
24513 * @param {Object} scope The scope in which to call the callback
24514 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24516 load : function(params, reader, callback, scope, arg){
24517 params = params || {};
24520 result = reader.readRecords(params.data ? params.data :this.data);
24522 this.fireEvent("loadexception", this, arg, null, e);
24523 callback.call(scope, null, arg, false);
24526 callback.call(scope, result, arg, true);
24530 update : function(params, records){
24535 * Ext JS Library 1.1.1
24536 * Copyright(c) 2006-2007, Ext JS, LLC.
24538 * Originally Released Under LGPL - original licence link has changed is not relivant.
24541 * <script type="text/javascript">
24544 * @class Roo.data.HttpProxy
24545 * @extends Roo.data.DataProxy
24546 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24547 * configured to reference a certain URL.<br><br>
24549 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24550 * from which the running page was served.<br><br>
24552 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24554 * Be aware that to enable the browser to parse an XML document, the server must set
24555 * the Content-Type header in the HTTP response to "text/xml".
24557 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24558 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24559 * will be used to make the request.
24561 Roo.data.HttpProxy = function(conn){
24562 Roo.data.HttpProxy.superclass.constructor.call(this);
24563 // is conn a conn config or a real conn?
24565 this.useAjax = !conn || !conn.events;
24569 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24570 // thse are take from connection...
24573 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24576 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24577 * extra parameters to each request made by this object. (defaults to undefined)
24580 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24581 * to each request made by this object. (defaults to undefined)
24584 * @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)
24587 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24590 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24596 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24600 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24601 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24602 * a finer-grained basis than the DataProxy events.
24604 getConnection : function(){
24605 return this.useAjax ? Roo.Ajax : this.conn;
24609 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24610 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24611 * process that block using the passed callback.
24612 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24613 * for the request to the remote server.
24614 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24615 * object into a block of Roo.data.Records.
24616 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24617 * The function must be passed <ul>
24618 * <li>The Record block object</li>
24619 * <li>The "arg" argument from the load function</li>
24620 * <li>A boolean success indicator</li>
24622 * @param {Object} scope The scope in which to call the callback
24623 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24625 load : function(params, reader, callback, scope, arg){
24626 if(this.fireEvent("beforeload", this, params) !== false){
24628 params : params || {},
24630 callback : callback,
24635 callback : this.loadResponse,
24639 Roo.applyIf(o, this.conn);
24640 if(this.activeRequest){
24641 Roo.Ajax.abort(this.activeRequest);
24643 this.activeRequest = Roo.Ajax.request(o);
24645 this.conn.request(o);
24648 callback.call(scope||this, null, arg, false);
24653 loadResponse : function(o, success, response){
24654 delete this.activeRequest;
24656 this.fireEvent("loadexception", this, o, response);
24657 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24662 result = o.reader.read(response);
24664 this.fireEvent("loadexception", this, o, response, e);
24665 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24669 this.fireEvent("load", this, o, o.request.arg);
24670 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24674 update : function(dataSet){
24679 updateResponse : function(dataSet){
24684 * Ext JS Library 1.1.1
24685 * Copyright(c) 2006-2007, Ext JS, LLC.
24687 * Originally Released Under LGPL - original licence link has changed is not relivant.
24690 * <script type="text/javascript">
24694 * @class Roo.data.ScriptTagProxy
24695 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24696 * other than the originating domain of the running page.<br><br>
24698 * <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
24699 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24701 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24702 * source code that is used as the source inside a <script> tag.<br><br>
24704 * In order for the browser to process the returned data, the server must wrap the data object
24705 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24706 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24707 * depending on whether the callback name was passed:
24710 boolean scriptTag = false;
24711 String cb = request.getParameter("callback");
24714 response.setContentType("text/javascript");
24716 response.setContentType("application/x-json");
24718 Writer out = response.getWriter();
24720 out.write(cb + "(");
24722 out.print(dataBlock.toJsonString());
24729 * @param {Object} config A configuration object.
24731 Roo.data.ScriptTagProxy = function(config){
24732 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24733 Roo.apply(this, config);
24734 this.head = document.getElementsByTagName("head")[0];
24737 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24739 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24741 * @cfg {String} url The URL from which to request the data object.
24744 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24748 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24749 * the server the name of the callback function set up by the load call to process the returned data object.
24750 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24751 * javascript output which calls this named function passing the data object as its only parameter.
24753 callbackParam : "callback",
24755 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24756 * name to the request.
24761 * Load data from the configured URL, read the data object into
24762 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24763 * process that block using the passed callback.
24764 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24765 * for the request to the remote server.
24766 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24767 * object into a block of Roo.data.Records.
24768 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24769 * The function must be passed <ul>
24770 * <li>The Record block object</li>
24771 * <li>The "arg" argument from the load function</li>
24772 * <li>A boolean success indicator</li>
24774 * @param {Object} scope The scope in which to call the callback
24775 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24777 load : function(params, reader, callback, scope, arg){
24778 if(this.fireEvent("beforeload", this, params) !== false){
24780 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24782 var url = this.url;
24783 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24785 url += "&_dc=" + (new Date().getTime());
24787 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24790 cb : "stcCallback"+transId,
24791 scriptId : "stcScript"+transId,
24795 callback : callback,
24801 window[trans.cb] = function(o){
24802 conn.handleResponse(o, trans);
24805 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24807 if(this.autoAbort !== false){
24811 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24813 var script = document.createElement("script");
24814 script.setAttribute("src", url);
24815 script.setAttribute("type", "text/javascript");
24816 script.setAttribute("id", trans.scriptId);
24817 this.head.appendChild(script);
24819 this.trans = trans;
24821 callback.call(scope||this, null, arg, false);
24826 isLoading : function(){
24827 return this.trans ? true : false;
24831 * Abort the current server request.
24833 abort : function(){
24834 if(this.isLoading()){
24835 this.destroyTrans(this.trans);
24840 destroyTrans : function(trans, isLoaded){
24841 this.head.removeChild(document.getElementById(trans.scriptId));
24842 clearTimeout(trans.timeoutId);
24844 window[trans.cb] = undefined;
24846 delete window[trans.cb];
24849 // if hasn't been loaded, wait for load to remove it to prevent script error
24850 window[trans.cb] = function(){
24851 window[trans.cb] = undefined;
24853 delete window[trans.cb];
24860 handleResponse : function(o, trans){
24861 this.trans = false;
24862 this.destroyTrans(trans, true);
24865 result = trans.reader.readRecords(o);
24867 this.fireEvent("loadexception", this, o, trans.arg, e);
24868 trans.callback.call(trans.scope||window, null, trans.arg, false);
24871 this.fireEvent("load", this, o, trans.arg);
24872 trans.callback.call(trans.scope||window, result, trans.arg, true);
24876 handleFailure : function(trans){
24877 this.trans = false;
24878 this.destroyTrans(trans, false);
24879 this.fireEvent("loadexception", this, null, trans.arg);
24880 trans.callback.call(trans.scope||window, null, trans.arg, false);
24884 * Ext JS Library 1.1.1
24885 * Copyright(c) 2006-2007, Ext JS, LLC.
24887 * Originally Released Under LGPL - original licence link has changed is not relivant.
24890 * <script type="text/javascript">
24894 * @class Roo.data.JsonReader
24895 * @extends Roo.data.DataReader
24896 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24897 * based on mappings in a provided Roo.data.Record constructor.
24899 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24900 * in the reply previously.
24905 var RecordDef = Roo.data.Record.create([
24906 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24907 {name: 'occupation'} // This field will use "occupation" as the mapping.
24909 var myReader = new Roo.data.JsonReader({
24910 totalProperty: "results", // The property which contains the total dataset size (optional)
24911 root: "rows", // The property which contains an Array of row objects
24912 id: "id" // The property within each row object that provides an ID for the record (optional)
24916 * This would consume a JSON file like this:
24918 { 'results': 2, 'rows': [
24919 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24920 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24923 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24924 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24925 * paged from the remote server.
24926 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24927 * @cfg {String} root name of the property which contains the Array of row objects.
24928 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24929 * @cfg {Array} fields Array of field definition objects
24931 * Create a new JsonReader
24932 * @param {Object} meta Metadata configuration options
24933 * @param {Object} recordType Either an Array of field definition objects,
24934 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24936 Roo.data.JsonReader = function(meta, recordType){
24939 // set some defaults:
24940 Roo.applyIf(meta, {
24941 totalProperty: 'total',
24942 successProperty : 'success',
24947 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24949 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24951 readerType : 'Json',
24954 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24955 * Used by Store query builder to append _requestMeta to params.
24958 metaFromRemote : false,
24960 * This method is only used by a DataProxy which has retrieved data from a remote server.
24961 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24962 * @return {Object} data A data block which is used by an Roo.data.Store object as
24963 * a cache of Roo.data.Records.
24965 read : function(response){
24966 var json = response.responseText;
24968 var o = /* eval:var:o */ eval("("+json+")");
24970 throw {message: "JsonReader.read: Json object not found"};
24976 this.metaFromRemote = true;
24977 this.meta = o.metaData;
24978 this.recordType = Roo.data.Record.create(o.metaData.fields);
24979 this.onMetaChange(this.meta, this.recordType, o);
24981 return this.readRecords(o);
24984 // private function a store will implement
24985 onMetaChange : function(meta, recordType, o){
24992 simpleAccess: function(obj, subsc) {
24999 getJsonAccessor: function(){
25001 return function(expr) {
25003 return(re.test(expr))
25004 ? new Function("obj", "return obj." + expr)
25009 return Roo.emptyFn;
25014 * Create a data block containing Roo.data.Records from an XML document.
25015 * @param {Object} o An object which contains an Array of row objects in the property specified
25016 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
25017 * which contains the total size of the dataset.
25018 * @return {Object} data A data block which is used by an Roo.data.Store object as
25019 * a cache of Roo.data.Records.
25021 readRecords : function(o){
25023 * After any data loads, the raw JSON data is available for further custom processing.
25027 var s = this.meta, Record = this.recordType,
25028 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
25030 // Generate extraction functions for the totalProperty, the root, the id, and for each field
25032 if(s.totalProperty) {
25033 this.getTotal = this.getJsonAccessor(s.totalProperty);
25035 if(s.successProperty) {
25036 this.getSuccess = this.getJsonAccessor(s.successProperty);
25038 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
25040 var g = this.getJsonAccessor(s.id);
25041 this.getId = function(rec) {
25043 return (r === undefined || r === "") ? null : r;
25046 this.getId = function(){return null;};
25049 for(var jj = 0; jj < fl; jj++){
25051 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
25052 this.ef[jj] = this.getJsonAccessor(map);
25056 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
25057 if(s.totalProperty){
25058 var vt = parseInt(this.getTotal(o), 10);
25063 if(s.successProperty){
25064 var vs = this.getSuccess(o);
25065 if(vs === false || vs === 'false'){
25070 for(var i = 0; i < c; i++){
25073 var id = this.getId(n);
25074 for(var j = 0; j < fl; j++){
25076 var v = this.ef[j](n);
25078 Roo.log('missing convert for ' + f.name);
25082 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25084 var record = new Record(values, id);
25086 records[i] = record;
25092 totalRecords : totalRecords
25095 // used when loading children.. @see loadDataFromChildren
25096 toLoadData: function(rec)
25098 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25099 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25100 return { data : data, total : data.length };
25105 * Ext JS Library 1.1.1
25106 * Copyright(c) 2006-2007, Ext JS, LLC.
25108 * Originally Released Under LGPL - original licence link has changed is not relivant.
25111 * <script type="text/javascript">
25115 * @class Roo.data.XmlReader
25116 * @extends Roo.data.DataReader
25117 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25118 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25120 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25121 * header in the HTTP response must be set to "text/xml".</em>
25125 var RecordDef = Roo.data.Record.create([
25126 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25127 {name: 'occupation'} // This field will use "occupation" as the mapping.
25129 var myReader = new Roo.data.XmlReader({
25130 totalRecords: "results", // The element which contains the total dataset size (optional)
25131 record: "row", // The repeated element which contains row information
25132 id: "id" // The element within the row that provides an ID for the record (optional)
25136 * This would consume an XML file like this:
25140 <results>2</results>
25143 <name>Bill</name>
25144 <occupation>Gardener</occupation>
25148 <name>Ben</name>
25149 <occupation>Horticulturalist</occupation>
25153 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25154 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25155 * paged from the remote server.
25156 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25157 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25158 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25159 * a record identifier value.
25161 * Create a new XmlReader
25162 * @param {Object} meta Metadata configuration options
25163 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25164 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25165 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25167 Roo.data.XmlReader = function(meta, recordType){
25169 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25171 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25173 readerType : 'Xml',
25176 * This method is only used by a DataProxy which has retrieved data from a remote server.
25177 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25178 * to contain a method called 'responseXML' that returns an XML document object.
25179 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25180 * a cache of Roo.data.Records.
25182 read : function(response){
25183 var doc = response.responseXML;
25185 throw {message: "XmlReader.read: XML Document not available"};
25187 return this.readRecords(doc);
25191 * Create a data block containing Roo.data.Records from an XML document.
25192 * @param {Object} doc A parsed XML document.
25193 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25194 * a cache of Roo.data.Records.
25196 readRecords : function(doc){
25198 * After any data loads/reads, the raw XML Document is available for further custom processing.
25199 * @type XMLDocument
25201 this.xmlData = doc;
25202 var root = doc.documentElement || doc;
25203 var q = Roo.DomQuery;
25204 var recordType = this.recordType, fields = recordType.prototype.fields;
25205 var sid = this.meta.id;
25206 var totalRecords = 0, success = true;
25207 if(this.meta.totalRecords){
25208 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25211 if(this.meta.success){
25212 var sv = q.selectValue(this.meta.success, root, true);
25213 success = sv !== false && sv !== 'false';
25216 var ns = q.select(this.meta.record, root);
25217 for(var i = 0, len = ns.length; i < len; i++) {
25220 var id = sid ? q.selectValue(sid, n) : undefined;
25221 for(var j = 0, jlen = fields.length; j < jlen; j++){
25222 var f = fields.items[j];
25223 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25225 values[f.name] = v;
25227 var record = new recordType(values, id);
25229 records[records.length] = record;
25235 totalRecords : totalRecords || records.length
25240 * Ext JS Library 1.1.1
25241 * Copyright(c) 2006-2007, Ext JS, LLC.
25243 * Originally Released Under LGPL - original licence link has changed is not relivant.
25246 * <script type="text/javascript">
25250 * @class Roo.data.ArrayReader
25251 * @extends Roo.data.DataReader
25252 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25253 * Each element of that Array represents a row of data fields. The
25254 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25255 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25259 var RecordDef = Roo.data.Record.create([
25260 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25261 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25263 var myReader = new Roo.data.ArrayReader({
25264 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25268 * This would consume an Array like this:
25270 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25274 * Create a new JsonReader
25275 * @param {Object} meta Metadata configuration options.
25276 * @param {Object|Array} recordType Either an Array of field definition objects
25278 * @cfg {Array} fields Array of field definition objects
25279 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25280 * as specified to {@link Roo.data.Record#create},
25281 * or an {@link Roo.data.Record} object
25284 * created using {@link Roo.data.Record#create}.
25286 Roo.data.ArrayReader = function(meta, recordType)
25288 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25291 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25294 * Create a data block containing Roo.data.Records from an XML document.
25295 * @param {Object} o An Array of row objects which represents the dataset.
25296 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25297 * a cache of Roo.data.Records.
25299 readRecords : function(o)
25301 var sid = this.meta ? this.meta.id : null;
25302 var recordType = this.recordType, fields = recordType.prototype.fields;
25305 for(var i = 0; i < root.length; i++){
25308 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25309 for(var j = 0, jlen = fields.length; j < jlen; j++){
25310 var f = fields.items[j];
25311 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25312 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25314 values[f.name] = v;
25316 var record = new recordType(values, id);
25318 records[records.length] = record;
25322 totalRecords : records.length
25325 // used when loading children.. @see loadDataFromChildren
25326 toLoadData: function(rec)
25328 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25329 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25336 * Ext JS Library 1.1.1
25337 * Copyright(c) 2006-2007, Ext JS, LLC.
25339 * Originally Released Under LGPL - original licence link has changed is not relivant.
25342 * <script type="text/javascript">
25347 * @class Roo.data.Tree
25348 * @extends Roo.util.Observable
25349 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25350 * in the tree have most standard DOM functionality.
25352 * @param {Node} root (optional) The root node
25354 Roo.data.Tree = function(root){
25355 this.nodeHash = {};
25357 * The root node for this tree
25362 this.setRootNode(root);
25367 * Fires when a new child node is appended to a node in this tree.
25368 * @param {Tree} tree The owner tree
25369 * @param {Node} parent The parent node
25370 * @param {Node} node The newly appended node
25371 * @param {Number} index The index of the newly appended node
25376 * Fires when a child node is removed from a node in this tree.
25377 * @param {Tree} tree The owner tree
25378 * @param {Node} parent The parent node
25379 * @param {Node} node The child node removed
25384 * Fires when a node is moved to a new location in the tree
25385 * @param {Tree} tree The owner tree
25386 * @param {Node} node The node moved
25387 * @param {Node} oldParent The old parent of this node
25388 * @param {Node} newParent The new parent of this node
25389 * @param {Number} index The index it was moved to
25394 * Fires when a new child node is inserted in a node in this tree.
25395 * @param {Tree} tree The owner tree
25396 * @param {Node} parent The parent node
25397 * @param {Node} node The child node inserted
25398 * @param {Node} refNode The child node the node was inserted before
25402 * @event beforeappend
25403 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25404 * @param {Tree} tree The owner tree
25405 * @param {Node} parent The parent node
25406 * @param {Node} node The child node to be appended
25408 "beforeappend" : true,
25410 * @event beforeremove
25411 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25412 * @param {Tree} tree The owner tree
25413 * @param {Node} parent The parent node
25414 * @param {Node} node The child node to be removed
25416 "beforeremove" : true,
25418 * @event beforemove
25419 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25420 * @param {Tree} tree The owner tree
25421 * @param {Node} node The node being moved
25422 * @param {Node} oldParent The parent of the node
25423 * @param {Node} newParent The new parent the node is moving to
25424 * @param {Number} index The index it is being moved to
25426 "beforemove" : true,
25428 * @event beforeinsert
25429 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25430 * @param {Tree} tree The owner tree
25431 * @param {Node} parent The parent node
25432 * @param {Node} node The child node to be inserted
25433 * @param {Node} refNode The child node the node is being inserted before
25435 "beforeinsert" : true
25438 Roo.data.Tree.superclass.constructor.call(this);
25441 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25442 pathSeparator: "/",
25444 proxyNodeEvent : function(){
25445 return this.fireEvent.apply(this, arguments);
25449 * Returns the root node for this tree.
25452 getRootNode : function(){
25457 * Sets the root node for this tree.
25458 * @param {Node} node
25461 setRootNode : function(node){
25463 node.ownerTree = this;
25464 node.isRoot = true;
25465 this.registerNode(node);
25470 * Gets a node in this tree by its id.
25471 * @param {String} id
25474 getNodeById : function(id){
25475 return this.nodeHash[id];
25478 registerNode : function(node){
25479 this.nodeHash[node.id] = node;
25482 unregisterNode : function(node){
25483 delete this.nodeHash[node.id];
25486 toString : function(){
25487 return "[Tree"+(this.id?" "+this.id:"")+"]";
25492 * @class Roo.data.Node
25493 * @extends Roo.util.Observable
25494 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25495 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25497 * @param {Object} attributes The attributes/config for the node
25499 Roo.data.Node = function(attributes){
25501 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25504 this.attributes = attributes || {};
25505 this.leaf = this.attributes.leaf;
25507 * The node id. @type String
25509 this.id = this.attributes.id;
25511 this.id = Roo.id(null, "ynode-");
25512 this.attributes.id = this.id;
25517 * All child nodes of this node. @type Array
25519 this.childNodes = [];
25520 if(!this.childNodes.indexOf){ // indexOf is a must
25521 this.childNodes.indexOf = function(o){
25522 for(var i = 0, len = this.length; i < len; i++){
25531 * The parent node for this node. @type Node
25533 this.parentNode = null;
25535 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25537 this.firstChild = null;
25539 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25541 this.lastChild = null;
25543 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25545 this.previousSibling = null;
25547 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25549 this.nextSibling = null;
25554 * Fires when a new child node is appended
25555 * @param {Tree} tree The owner tree
25556 * @param {Node} this This node
25557 * @param {Node} node The newly appended node
25558 * @param {Number} index The index of the newly appended node
25563 * Fires when a child node is removed
25564 * @param {Tree} tree The owner tree
25565 * @param {Node} this This node
25566 * @param {Node} node The removed node
25571 * Fires when this node is moved to a new location in the tree
25572 * @param {Tree} tree The owner tree
25573 * @param {Node} this This node
25574 * @param {Node} oldParent The old parent of this node
25575 * @param {Node} newParent The new parent of this node
25576 * @param {Number} index The index it was moved to
25581 * Fires when a new child node is inserted.
25582 * @param {Tree} tree The owner tree
25583 * @param {Node} this This node
25584 * @param {Node} node The child node inserted
25585 * @param {Node} refNode The child node the node was inserted before
25589 * @event beforeappend
25590 * Fires before a new child is appended, return false to cancel the append.
25591 * @param {Tree} tree The owner tree
25592 * @param {Node} this This node
25593 * @param {Node} node The child node to be appended
25595 "beforeappend" : true,
25597 * @event beforeremove
25598 * Fires before a child is removed, return false to cancel the remove.
25599 * @param {Tree} tree The owner tree
25600 * @param {Node} this This node
25601 * @param {Node} node The child node to be removed
25603 "beforeremove" : true,
25605 * @event beforemove
25606 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25607 * @param {Tree} tree The owner tree
25608 * @param {Node} this This node
25609 * @param {Node} oldParent The parent of this node
25610 * @param {Node} newParent The new parent this node is moving to
25611 * @param {Number} index The index it is being moved to
25613 "beforemove" : true,
25615 * @event beforeinsert
25616 * Fires before a new child is inserted, return false to cancel the insert.
25617 * @param {Tree} tree The owner tree
25618 * @param {Node} this This node
25619 * @param {Node} node The child node to be inserted
25620 * @param {Node} refNode The child node the node is being inserted before
25622 "beforeinsert" : true
25624 this.listeners = this.attributes.listeners;
25625 Roo.data.Node.superclass.constructor.call(this);
25628 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25629 fireEvent : function(evtName){
25630 // first do standard event for this node
25631 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25634 // then bubble it up to the tree if the event wasn't cancelled
25635 var ot = this.getOwnerTree();
25637 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25645 * Returns true if this node is a leaf
25646 * @return {Boolean}
25648 isLeaf : function(){
25649 return this.leaf === true;
25653 setFirstChild : function(node){
25654 this.firstChild = node;
25658 setLastChild : function(node){
25659 this.lastChild = node;
25664 * Returns true if this node is the last child of its parent
25665 * @return {Boolean}
25667 isLast : function(){
25668 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25672 * Returns true if this node is the first child of its parent
25673 * @return {Boolean}
25675 isFirst : function(){
25676 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25679 hasChildNodes : function(){
25680 return !this.isLeaf() && this.childNodes.length > 0;
25684 * Insert node(s) as the last child node of this node.
25685 * @param {Node/Array} node The node or Array of nodes to append
25686 * @return {Node} The appended node if single append, or null if an array was passed
25688 appendChild : function(node){
25690 if(node instanceof Array){
25692 }else if(arguments.length > 1){
25696 // if passed an array or multiple args do them one by one
25698 for(var i = 0, len = multi.length; i < len; i++) {
25699 this.appendChild(multi[i]);
25702 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25705 var index = this.childNodes.length;
25706 var oldParent = node.parentNode;
25707 // it's a move, make sure we move it cleanly
25709 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25712 oldParent.removeChild(node);
25715 index = this.childNodes.length;
25717 this.setFirstChild(node);
25719 this.childNodes.push(node);
25720 node.parentNode = this;
25721 var ps = this.childNodes[index-1];
25723 node.previousSibling = ps;
25724 ps.nextSibling = node;
25726 node.previousSibling = null;
25728 node.nextSibling = null;
25729 this.setLastChild(node);
25730 node.setOwnerTree(this.getOwnerTree());
25731 this.fireEvent("append", this.ownerTree, this, node, index);
25732 if(this.ownerTree) {
25733 this.ownerTree.fireEvent("appendnode", this, node, index);
25736 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25743 * Removes a child node from this node.
25744 * @param {Node} node The node to remove
25745 * @return {Node} The removed node
25747 removeChild : function(node){
25748 var index = this.childNodes.indexOf(node);
25752 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25756 // remove it from childNodes collection
25757 this.childNodes.splice(index, 1);
25760 if(node.previousSibling){
25761 node.previousSibling.nextSibling = node.nextSibling;
25763 if(node.nextSibling){
25764 node.nextSibling.previousSibling = node.previousSibling;
25767 // update child refs
25768 if(this.firstChild == node){
25769 this.setFirstChild(node.nextSibling);
25771 if(this.lastChild == node){
25772 this.setLastChild(node.previousSibling);
25775 node.setOwnerTree(null);
25776 // clear any references from the node
25777 node.parentNode = null;
25778 node.previousSibling = null;
25779 node.nextSibling = null;
25780 this.fireEvent("remove", this.ownerTree, this, node);
25785 * Inserts the first node before the second node in this nodes childNodes collection.
25786 * @param {Node} node The node to insert
25787 * @param {Node} refNode The node to insert before (if null the node is appended)
25788 * @return {Node} The inserted node
25790 insertBefore : function(node, refNode){
25791 if(!refNode){ // like standard Dom, refNode can be null for append
25792 return this.appendChild(node);
25795 if(node == refNode){
25799 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25802 var index = this.childNodes.indexOf(refNode);
25803 var oldParent = node.parentNode;
25804 var refIndex = index;
25806 // when moving internally, indexes will change after remove
25807 if(oldParent == this && this.childNodes.indexOf(node) < index){
25811 // it's a move, make sure we move it cleanly
25813 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25816 oldParent.removeChild(node);
25819 this.setFirstChild(node);
25821 this.childNodes.splice(refIndex, 0, node);
25822 node.parentNode = this;
25823 var ps = this.childNodes[refIndex-1];
25825 node.previousSibling = ps;
25826 ps.nextSibling = node;
25828 node.previousSibling = null;
25830 node.nextSibling = refNode;
25831 refNode.previousSibling = node;
25832 node.setOwnerTree(this.getOwnerTree());
25833 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25835 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25841 * Returns the child node at the specified index.
25842 * @param {Number} index
25845 item : function(index){
25846 return this.childNodes[index];
25850 * Replaces one child node in this node with another.
25851 * @param {Node} newChild The replacement node
25852 * @param {Node} oldChild The node to replace
25853 * @return {Node} The replaced node
25855 replaceChild : function(newChild, oldChild){
25856 this.insertBefore(newChild, oldChild);
25857 this.removeChild(oldChild);
25862 * Returns the index of a child node
25863 * @param {Node} node
25864 * @return {Number} The index of the node or -1 if it was not found
25866 indexOf : function(child){
25867 return this.childNodes.indexOf(child);
25871 * Returns the tree this node is in.
25874 getOwnerTree : function(){
25875 // if it doesn't have one, look for one
25876 if(!this.ownerTree){
25880 this.ownerTree = p.ownerTree;
25886 return this.ownerTree;
25890 * Returns depth of this node (the root node has a depth of 0)
25893 getDepth : function(){
25896 while(p.parentNode){
25904 setOwnerTree : function(tree){
25905 // if it's move, we need to update everyone
25906 if(tree != this.ownerTree){
25907 if(this.ownerTree){
25908 this.ownerTree.unregisterNode(this);
25910 this.ownerTree = tree;
25911 var cs = this.childNodes;
25912 for(var i = 0, len = cs.length; i < len; i++) {
25913 cs[i].setOwnerTree(tree);
25916 tree.registerNode(this);
25922 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25923 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25924 * @return {String} The path
25926 getPath : function(attr){
25927 attr = attr || "id";
25928 var p = this.parentNode;
25929 var b = [this.attributes[attr]];
25931 b.unshift(p.attributes[attr]);
25934 var sep = this.getOwnerTree().pathSeparator;
25935 return sep + b.join(sep);
25939 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25940 * function call will be the scope provided or the current node. The arguments to the function
25941 * will be the args provided or the current node. If the function returns false at any point,
25942 * the bubble is stopped.
25943 * @param {Function} fn The function to call
25944 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25945 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25947 bubble : function(fn, scope, args){
25950 if(fn.call(scope || p, args || p) === false){
25958 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25959 * function call will be the scope provided or the current node. The arguments to the function
25960 * will be the args provided or the current node. If the function returns false at any point,
25961 * the cascade is stopped on that branch.
25962 * @param {Function} fn The function to call
25963 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25964 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25966 cascade : function(fn, scope, args){
25967 if(fn.call(scope || this, args || this) !== false){
25968 var cs = this.childNodes;
25969 for(var i = 0, len = cs.length; i < len; i++) {
25970 cs[i].cascade(fn, scope, args);
25976 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25977 * function call will be the scope provided or the current node. The arguments to the function
25978 * will be the args provided or the current node. If the function returns false at any point,
25979 * the iteration stops.
25980 * @param {Function} fn The function to call
25981 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25982 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25984 eachChild : function(fn, scope, args){
25985 var cs = this.childNodes;
25986 for(var i = 0, len = cs.length; i < len; i++) {
25987 if(fn.call(scope || this, args || cs[i]) === false){
25994 * Finds the first child that has the attribute with the specified value.
25995 * @param {String} attribute The attribute name
25996 * @param {Mixed} value The value to search for
25997 * @return {Node} The found child or null if none was found
25999 findChild : function(attribute, value){
26000 var cs = this.childNodes;
26001 for(var i = 0, len = cs.length; i < len; i++) {
26002 if(cs[i].attributes[attribute] == value){
26010 * Finds the first child by a custom function. The child matches if the function passed
26012 * @param {Function} fn
26013 * @param {Object} scope (optional)
26014 * @return {Node} The found child or null if none was found
26016 findChildBy : function(fn, scope){
26017 var cs = this.childNodes;
26018 for(var i = 0, len = cs.length; i < len; i++) {
26019 if(fn.call(scope||cs[i], cs[i]) === true){
26027 * Sorts this nodes children using the supplied sort function
26028 * @param {Function} fn
26029 * @param {Object} scope (optional)
26031 sort : function(fn, scope){
26032 var cs = this.childNodes;
26033 var len = cs.length;
26035 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
26037 for(var i = 0; i < len; i++){
26039 n.previousSibling = cs[i-1];
26040 n.nextSibling = cs[i+1];
26042 this.setFirstChild(n);
26045 this.setLastChild(n);
26052 * Returns true if this node is an ancestor (at any point) of the passed node.
26053 * @param {Node} node
26054 * @return {Boolean}
26056 contains : function(node){
26057 return node.isAncestor(this);
26061 * Returns true if the passed node is an ancestor (at any point) of this node.
26062 * @param {Node} node
26063 * @return {Boolean}
26065 isAncestor : function(node){
26066 var p = this.parentNode;
26076 toString : function(){
26077 return "[Node"+(this.id?" "+this.id:"")+"]";
26081 * Ext JS Library 1.1.1
26082 * Copyright(c) 2006-2007, Ext JS, LLC.
26084 * Originally Released Under LGPL - original licence link has changed is not relivant.
26087 * <script type="text/javascript">
26092 * @class Roo.Shadow
26093 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26094 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26095 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26097 * Create a new Shadow
26098 * @param {Object} config The config object
26100 Roo.Shadow = function(config){
26101 Roo.apply(this, config);
26102 if(typeof this.mode != "string"){
26103 this.mode = this.defaultMode;
26105 var o = this.offset, a = {h: 0};
26106 var rad = Math.floor(this.offset/2);
26107 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26113 a.l -= this.offset + rad;
26114 a.t -= this.offset + rad;
26125 a.l -= (this.offset - rad);
26126 a.t -= this.offset + rad;
26128 a.w -= (this.offset - rad)*2;
26139 a.l -= (this.offset - rad);
26140 a.t -= (this.offset - rad);
26142 a.w -= (this.offset + rad + 1);
26143 a.h -= (this.offset + rad);
26152 Roo.Shadow.prototype = {
26154 * @cfg {String} mode
26155 * The shadow display mode. Supports the following options:<br />
26156 * sides: Shadow displays on both sides and bottom only<br />
26157 * frame: Shadow displays equally on all four sides<br />
26158 * drop: Traditional bottom-right drop shadow (default)
26161 * @cfg {String} offset
26162 * The number of pixels to offset the shadow from the element (defaults to 4)
26167 defaultMode: "drop",
26170 * Displays the shadow under the target element
26171 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26173 show : function(target){
26174 target = Roo.get(target);
26176 this.el = Roo.Shadow.Pool.pull();
26177 if(this.el.dom.nextSibling != target.dom){
26178 this.el.insertBefore(target);
26181 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26183 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26186 target.getLeft(true),
26187 target.getTop(true),
26191 this.el.dom.style.display = "block";
26195 * Returns true if the shadow is visible, else false
26197 isVisible : function(){
26198 return this.el ? true : false;
26202 * Direct alignment when values are already available. Show must be called at least once before
26203 * calling this method to ensure it is initialized.
26204 * @param {Number} left The target element left position
26205 * @param {Number} top The target element top position
26206 * @param {Number} width The target element width
26207 * @param {Number} height The target element height
26209 realign : function(l, t, w, h){
26213 var a = this.adjusts, d = this.el.dom, s = d.style;
26215 s.left = (l+a.l)+"px";
26216 s.top = (t+a.t)+"px";
26217 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26219 if(s.width != sws || s.height != shs){
26223 var cn = d.childNodes;
26224 var sww = Math.max(0, (sw-12))+"px";
26225 cn[0].childNodes[1].style.width = sww;
26226 cn[1].childNodes[1].style.width = sww;
26227 cn[2].childNodes[1].style.width = sww;
26228 cn[1].style.height = Math.max(0, (sh-12))+"px";
26234 * Hides this shadow
26238 this.el.dom.style.display = "none";
26239 Roo.Shadow.Pool.push(this.el);
26245 * Adjust the z-index of this shadow
26246 * @param {Number} zindex The new z-index
26248 setZIndex : function(z){
26251 this.el.setStyle("z-index", z);
26256 // Private utility class that manages the internal Shadow cache
26257 Roo.Shadow.Pool = function(){
26259 var markup = Roo.isIE ?
26260 '<div class="x-ie-shadow"></div>' :
26261 '<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>';
26264 var sh = p.shift();
26266 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26267 sh.autoBoxAdjust = false;
26272 push : function(sh){
26278 * Ext JS Library 1.1.1
26279 * Copyright(c) 2006-2007, Ext JS, LLC.
26281 * Originally Released Under LGPL - original licence link has changed is not relivant.
26284 * <script type="text/javascript">
26289 * @class Roo.SplitBar
26290 * @extends Roo.util.Observable
26291 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26295 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26296 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26297 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26298 split.minSize = 100;
26299 split.maxSize = 600;
26300 split.animate = true;
26301 split.on('moved', splitterMoved);
26304 * Create a new SplitBar
26305 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26306 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26307 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26308 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26309 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26310 position of the SplitBar).
26312 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26315 this.el = Roo.get(dragElement, true);
26316 this.el.dom.unselectable = "on";
26318 this.resizingEl = Roo.get(resizingElement, true);
26322 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26323 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26326 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26329 * The minimum size of the resizing element. (Defaults to 0)
26335 * The maximum size of the resizing element. (Defaults to 2000)
26338 this.maxSize = 2000;
26341 * Whether to animate the transition to the new size
26344 this.animate = false;
26347 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26350 this.useShim = false;
26355 if(!existingProxy){
26357 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26359 this.proxy = Roo.get(existingProxy).dom;
26362 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26365 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26368 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26371 this.dragSpecs = {};
26374 * @private The adapter to use to positon and resize elements
26376 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26377 this.adapter.init(this);
26379 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26381 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26382 this.el.addClass("x-splitbar-h");
26385 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26386 this.el.addClass("x-splitbar-v");
26392 * Fires when the splitter is moved (alias for {@link #event-moved})
26393 * @param {Roo.SplitBar} this
26394 * @param {Number} newSize the new width or height
26399 * Fires when the splitter is moved
26400 * @param {Roo.SplitBar} this
26401 * @param {Number} newSize the new width or height
26405 * @event beforeresize
26406 * Fires before the splitter is dragged
26407 * @param {Roo.SplitBar} this
26409 "beforeresize" : true,
26411 "beforeapply" : true
26414 Roo.util.Observable.call(this);
26417 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26418 onStartProxyDrag : function(x, y){
26419 this.fireEvent("beforeresize", this);
26421 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26423 o.enableDisplayMode("block");
26424 // all splitbars share the same overlay
26425 Roo.SplitBar.prototype.overlay = o;
26427 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26428 this.overlay.show();
26429 Roo.get(this.proxy).setDisplayed("block");
26430 var size = this.adapter.getElementSize(this);
26431 this.activeMinSize = this.getMinimumSize();;
26432 this.activeMaxSize = this.getMaximumSize();;
26433 var c1 = size - this.activeMinSize;
26434 var c2 = Math.max(this.activeMaxSize - size, 0);
26435 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26436 this.dd.resetConstraints();
26437 this.dd.setXConstraint(
26438 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26439 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26441 this.dd.setYConstraint(0, 0);
26443 this.dd.resetConstraints();
26444 this.dd.setXConstraint(0, 0);
26445 this.dd.setYConstraint(
26446 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26447 this.placement == Roo.SplitBar.TOP ? c2 : c1
26450 this.dragSpecs.startSize = size;
26451 this.dragSpecs.startPoint = [x, y];
26452 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26456 * @private Called after the drag operation by the DDProxy
26458 onEndProxyDrag : function(e){
26459 Roo.get(this.proxy).setDisplayed(false);
26460 var endPoint = Roo.lib.Event.getXY(e);
26462 this.overlay.hide();
26465 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26466 newSize = this.dragSpecs.startSize +
26467 (this.placement == Roo.SplitBar.LEFT ?
26468 endPoint[0] - this.dragSpecs.startPoint[0] :
26469 this.dragSpecs.startPoint[0] - endPoint[0]
26472 newSize = this.dragSpecs.startSize +
26473 (this.placement == Roo.SplitBar.TOP ?
26474 endPoint[1] - this.dragSpecs.startPoint[1] :
26475 this.dragSpecs.startPoint[1] - endPoint[1]
26478 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26479 if(newSize != this.dragSpecs.startSize){
26480 if(this.fireEvent('beforeapply', this, newSize) !== false){
26481 this.adapter.setElementSize(this, newSize);
26482 this.fireEvent("moved", this, newSize);
26483 this.fireEvent("resize", this, newSize);
26489 * Get the adapter this SplitBar uses
26490 * @return The adapter object
26492 getAdapter : function(){
26493 return this.adapter;
26497 * Set the adapter this SplitBar uses
26498 * @param {Object} adapter A SplitBar adapter object
26500 setAdapter : function(adapter){
26501 this.adapter = adapter;
26502 this.adapter.init(this);
26506 * Gets the minimum size for the resizing element
26507 * @return {Number} The minimum size
26509 getMinimumSize : function(){
26510 return this.minSize;
26514 * Sets the minimum size for the resizing element
26515 * @param {Number} minSize The minimum size
26517 setMinimumSize : function(minSize){
26518 this.minSize = minSize;
26522 * Gets the maximum size for the resizing element
26523 * @return {Number} The maximum size
26525 getMaximumSize : function(){
26526 return this.maxSize;
26530 * Sets the maximum size for the resizing element
26531 * @param {Number} maxSize The maximum size
26533 setMaximumSize : function(maxSize){
26534 this.maxSize = maxSize;
26538 * Sets the initialize size for the resizing element
26539 * @param {Number} size The initial size
26541 setCurrentSize : function(size){
26542 var oldAnimate = this.animate;
26543 this.animate = false;
26544 this.adapter.setElementSize(this, size);
26545 this.animate = oldAnimate;
26549 * Destroy this splitbar.
26550 * @param {Boolean} removeEl True to remove the element
26552 destroy : function(removeEl){
26554 this.shim.remove();
26557 this.proxy.parentNode.removeChild(this.proxy);
26565 * @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.
26567 Roo.SplitBar.createProxy = function(dir){
26568 var proxy = new Roo.Element(document.createElement("div"));
26569 proxy.unselectable();
26570 var cls = 'x-splitbar-proxy';
26571 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26572 document.body.appendChild(proxy.dom);
26577 * @class Roo.SplitBar.BasicLayoutAdapter
26578 * Default Adapter. It assumes the splitter and resizing element are not positioned
26579 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26581 Roo.SplitBar.BasicLayoutAdapter = function(){
26584 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26585 // do nothing for now
26586 init : function(s){
26590 * Called before drag operations to get the current size of the resizing element.
26591 * @param {Roo.SplitBar} s The SplitBar using this adapter
26593 getElementSize : function(s){
26594 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26595 return s.resizingEl.getWidth();
26597 return s.resizingEl.getHeight();
26602 * Called after drag operations to set the size of the resizing element.
26603 * @param {Roo.SplitBar} s The SplitBar using this adapter
26604 * @param {Number} newSize The new size to set
26605 * @param {Function} onComplete A function to be invoked when resizing is complete
26607 setElementSize : function(s, newSize, onComplete){
26608 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26610 s.resizingEl.setWidth(newSize);
26612 onComplete(s, newSize);
26615 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26620 s.resizingEl.setHeight(newSize);
26622 onComplete(s, newSize);
26625 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26632 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26633 * @extends Roo.SplitBar.BasicLayoutAdapter
26634 * Adapter that moves the splitter element to align with the resized sizing element.
26635 * Used with an absolute positioned SplitBar.
26636 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26637 * document.body, make sure you assign an id to the body element.
26639 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26640 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26641 this.container = Roo.get(container);
26644 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26645 init : function(s){
26646 this.basic.init(s);
26649 getElementSize : function(s){
26650 return this.basic.getElementSize(s);
26653 setElementSize : function(s, newSize, onComplete){
26654 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26657 moveSplitter : function(s){
26658 var yes = Roo.SplitBar;
26659 switch(s.placement){
26661 s.el.setX(s.resizingEl.getRight());
26664 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26667 s.el.setY(s.resizingEl.getBottom());
26670 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26677 * Orientation constant - Create a vertical SplitBar
26681 Roo.SplitBar.VERTICAL = 1;
26684 * Orientation constant - Create a horizontal SplitBar
26688 Roo.SplitBar.HORIZONTAL = 2;
26691 * Placement constant - The resizing element is to the left of the splitter element
26695 Roo.SplitBar.LEFT = 1;
26698 * Placement constant - The resizing element is to the right of the splitter element
26702 Roo.SplitBar.RIGHT = 2;
26705 * Placement constant - The resizing element is positioned above the splitter element
26709 Roo.SplitBar.TOP = 3;
26712 * Placement constant - The resizing element is positioned under splitter element
26716 Roo.SplitBar.BOTTOM = 4;
26719 * Ext JS Library 1.1.1
26720 * Copyright(c) 2006-2007, Ext JS, LLC.
26722 * Originally Released Under LGPL - original licence link has changed is not relivant.
26725 * <script type="text/javascript">
26730 * @extends Roo.util.Observable
26731 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26732 * This class also supports single and multi selection modes. <br>
26733 * Create a data model bound view:
26735 var store = new Roo.data.Store(...);
26737 var view = new Roo.View({
26739 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26741 singleSelect: true,
26742 selectedClass: "ydataview-selected",
26746 // listen for node click?
26747 view.on("click", function(vw, index, node, e){
26748 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26752 dataModel.load("foobar.xml");
26754 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26756 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26757 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26759 * Note: old style constructor is still suported (container, template, config)
26762 * Create a new View
26763 * @param {Object} config The config object
26766 Roo.View = function(config, depreciated_tpl, depreciated_config){
26768 this.parent = false;
26770 if (typeof(depreciated_tpl) == 'undefined') {
26771 // new way.. - universal constructor.
26772 Roo.apply(this, config);
26773 this.el = Roo.get(this.el);
26776 this.el = Roo.get(config);
26777 this.tpl = depreciated_tpl;
26778 Roo.apply(this, depreciated_config);
26780 this.wrapEl = this.el.wrap().wrap();
26781 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26784 if(typeof(this.tpl) == "string"){
26785 this.tpl = new Roo.Template(this.tpl);
26787 // support xtype ctors..
26788 this.tpl = new Roo.factory(this.tpl, Roo);
26792 this.tpl.compile();
26797 * @event beforeclick
26798 * Fires before a click is processed. Returns false to cancel the default action.
26799 * @param {Roo.View} this
26800 * @param {Number} index The index of the target node
26801 * @param {HTMLElement} node The target node
26802 * @param {Roo.EventObject} e The raw event object
26804 "beforeclick" : true,
26807 * Fires when a template node is clicked.
26808 * @param {Roo.View} this
26809 * @param {Number} index The index of the target node
26810 * @param {HTMLElement} node The target node
26811 * @param {Roo.EventObject} e The raw event object
26816 * Fires when a template node is double clicked.
26817 * @param {Roo.View} this
26818 * @param {Number} index The index of the target node
26819 * @param {HTMLElement} node The target node
26820 * @param {Roo.EventObject} e The raw event object
26824 * @event contextmenu
26825 * Fires when a template node is right clicked.
26826 * @param {Roo.View} this
26827 * @param {Number} index The index of the target node
26828 * @param {HTMLElement} node The target node
26829 * @param {Roo.EventObject} e The raw event object
26831 "contextmenu" : true,
26833 * @event selectionchange
26834 * Fires when the selected nodes change.
26835 * @param {Roo.View} this
26836 * @param {Array} selections Array of the selected nodes
26838 "selectionchange" : true,
26841 * @event beforeselect
26842 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26843 * @param {Roo.View} this
26844 * @param {HTMLElement} node The node to be selected
26845 * @param {Array} selections Array of currently selected nodes
26847 "beforeselect" : true,
26849 * @event preparedata
26850 * Fires on every row to render, to allow you to change the data.
26851 * @param {Roo.View} this
26852 * @param {Object} data to be rendered (change this)
26854 "preparedata" : true
26862 "click": this.onClick,
26863 "dblclick": this.onDblClick,
26864 "contextmenu": this.onContextMenu,
26868 this.selections = [];
26870 this.cmp = new Roo.CompositeElementLite([]);
26872 this.store = Roo.factory(this.store, Roo.data);
26873 this.setStore(this.store, true);
26876 if ( this.footer && this.footer.xtype) {
26878 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26880 this.footer.dataSource = this.store;
26881 this.footer.container = fctr;
26882 this.footer = Roo.factory(this.footer, Roo);
26883 fctr.insertFirst(this.el);
26885 // this is a bit insane - as the paging toolbar seems to detach the el..
26886 // dom.parentNode.parentNode.parentNode
26887 // they get detached?
26891 Roo.View.superclass.constructor.call(this);
26896 Roo.extend(Roo.View, Roo.util.Observable, {
26899 * @cfg {Roo.data.Store} store Data store to load data from.
26904 * @cfg {String|Roo.Element} el The container element.
26909 * @cfg {String|Roo.Template} tpl The template used by this View
26913 * @cfg {String} dataName the named area of the template to use as the data area
26914 * Works with domtemplates roo-name="name"
26918 * @cfg {String} selectedClass The css class to add to selected nodes
26920 selectedClass : "x-view-selected",
26922 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26927 * @cfg {String} text to display on mask (default Loading)
26931 * @cfg {Boolean} multiSelect Allow multiple selection
26933 multiSelect : false,
26935 * @cfg {Boolean} singleSelect Allow single selection
26937 singleSelect: false,
26940 * @cfg {Boolean} toggleSelect - selecting
26942 toggleSelect : false,
26945 * @cfg {Boolean} tickable - selecting
26950 * Returns the element this view is bound to.
26951 * @return {Roo.Element}
26953 getEl : function(){
26954 return this.wrapEl;
26960 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26962 refresh : function(){
26963 //Roo.log('refresh');
26966 // if we are using something like 'domtemplate', then
26967 // the what gets used is:
26968 // t.applySubtemplate(NAME, data, wrapping data..)
26969 // the outer template then get' applied with
26970 // the store 'extra data'
26971 // and the body get's added to the
26972 // roo-name="data" node?
26973 // <span class='roo-tpl-{name}'></span> ?????
26977 this.clearSelections();
26978 this.el.update("");
26980 var records = this.store.getRange();
26981 if(records.length < 1) {
26983 // is this valid?? = should it render a template??
26985 this.el.update(this.emptyText);
26989 if (this.dataName) {
26990 this.el.update(t.apply(this.store.meta)); //????
26991 el = this.el.child('.roo-tpl-' + this.dataName);
26994 for(var i = 0, len = records.length; i < len; i++){
26995 var data = this.prepareData(records[i].data, i, records[i]);
26996 this.fireEvent("preparedata", this, data, i, records[i]);
26998 var d = Roo.apply({}, data);
27001 Roo.apply(d, {'roo-id' : Roo.id()});
27005 Roo.each(this.parent.item, function(item){
27006 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
27009 Roo.apply(d, {'roo-data-checked' : 'checked'});
27013 html[html.length] = Roo.util.Format.trim(
27015 t.applySubtemplate(this.dataName, d, this.store.meta) :
27022 el.update(html.join(""));
27023 this.nodes = el.dom.childNodes;
27024 this.updateIndexes(0);
27029 * Function to override to reformat the data that is sent to
27030 * the template for each node.
27031 * DEPRICATED - use the preparedata event handler.
27032 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
27033 * a JSON object for an UpdateManager bound view).
27035 prepareData : function(data, index, record)
27037 this.fireEvent("preparedata", this, data, index, record);
27041 onUpdate : function(ds, record){
27042 // Roo.log('on update');
27043 this.clearSelections();
27044 var index = this.store.indexOf(record);
27045 var n = this.nodes[index];
27046 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
27047 n.parentNode.removeChild(n);
27048 this.updateIndexes(index, index);
27054 onAdd : function(ds, records, index)
27056 //Roo.log(['on Add', ds, records, index] );
27057 this.clearSelections();
27058 if(this.nodes.length == 0){
27062 var n = this.nodes[index];
27063 for(var i = 0, len = records.length; i < len; i++){
27064 var d = this.prepareData(records[i].data, i, records[i]);
27066 this.tpl.insertBefore(n, d);
27069 this.tpl.append(this.el, d);
27072 this.updateIndexes(index);
27075 onRemove : function(ds, record, index){
27076 // Roo.log('onRemove');
27077 this.clearSelections();
27078 var el = this.dataName ?
27079 this.el.child('.roo-tpl-' + this.dataName) :
27082 el.dom.removeChild(this.nodes[index]);
27083 this.updateIndexes(index);
27087 * Refresh an individual node.
27088 * @param {Number} index
27090 refreshNode : function(index){
27091 this.onUpdate(this.store, this.store.getAt(index));
27094 updateIndexes : function(startIndex, endIndex){
27095 var ns = this.nodes;
27096 startIndex = startIndex || 0;
27097 endIndex = endIndex || ns.length - 1;
27098 for(var i = startIndex; i <= endIndex; i++){
27099 ns[i].nodeIndex = i;
27104 * Changes the data store this view uses and refresh the view.
27105 * @param {Store} store
27107 setStore : function(store, initial){
27108 if(!initial && this.store){
27109 this.store.un("datachanged", this.refresh);
27110 this.store.un("add", this.onAdd);
27111 this.store.un("remove", this.onRemove);
27112 this.store.un("update", this.onUpdate);
27113 this.store.un("clear", this.refresh);
27114 this.store.un("beforeload", this.onBeforeLoad);
27115 this.store.un("load", this.onLoad);
27116 this.store.un("loadexception", this.onLoad);
27120 store.on("datachanged", this.refresh, this);
27121 store.on("add", this.onAdd, this);
27122 store.on("remove", this.onRemove, this);
27123 store.on("update", this.onUpdate, this);
27124 store.on("clear", this.refresh, this);
27125 store.on("beforeload", this.onBeforeLoad, this);
27126 store.on("load", this.onLoad, this);
27127 store.on("loadexception", this.onLoad, this);
27135 * onbeforeLoad - masks the loading area.
27138 onBeforeLoad : function(store,opts)
27140 //Roo.log('onBeforeLoad');
27142 this.el.update("");
27144 this.el.mask(this.mask ? this.mask : "Loading" );
27146 onLoad : function ()
27153 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27154 * @param {HTMLElement} node
27155 * @return {HTMLElement} The template node
27157 findItemFromChild : function(node){
27158 var el = this.dataName ?
27159 this.el.child('.roo-tpl-' + this.dataName,true) :
27162 if(!node || node.parentNode == el){
27165 var p = node.parentNode;
27166 while(p && p != el){
27167 if(p.parentNode == el){
27176 onClick : function(e){
27177 var item = this.findItemFromChild(e.getTarget());
27179 var index = this.indexOf(item);
27180 if(this.onItemClick(item, index, e) !== false){
27181 this.fireEvent("click", this, index, item, e);
27184 this.clearSelections();
27189 onContextMenu : function(e){
27190 var item = this.findItemFromChild(e.getTarget());
27192 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27197 onDblClick : function(e){
27198 var item = this.findItemFromChild(e.getTarget());
27200 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27204 onItemClick : function(item, index, e)
27206 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27209 if (this.toggleSelect) {
27210 var m = this.isSelected(item) ? 'unselect' : 'select';
27213 _t[m](item, true, false);
27216 if(this.multiSelect || this.singleSelect){
27217 if(this.multiSelect && e.shiftKey && this.lastSelection){
27218 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27220 this.select(item, this.multiSelect && e.ctrlKey);
27221 this.lastSelection = item;
27224 if(!this.tickable){
27225 e.preventDefault();
27233 * Get the number of selected nodes.
27236 getSelectionCount : function(){
27237 return this.selections.length;
27241 * Get the currently selected nodes.
27242 * @return {Array} An array of HTMLElements
27244 getSelectedNodes : function(){
27245 return this.selections;
27249 * Get the indexes of the selected nodes.
27252 getSelectedIndexes : function(){
27253 var indexes = [], s = this.selections;
27254 for(var i = 0, len = s.length; i < len; i++){
27255 indexes.push(s[i].nodeIndex);
27261 * Clear all selections
27262 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27264 clearSelections : function(suppressEvent){
27265 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27266 this.cmp.elements = this.selections;
27267 this.cmp.removeClass(this.selectedClass);
27268 this.selections = [];
27269 if(!suppressEvent){
27270 this.fireEvent("selectionchange", this, this.selections);
27276 * Returns true if the passed node is selected
27277 * @param {HTMLElement/Number} node The node or node index
27278 * @return {Boolean}
27280 isSelected : function(node){
27281 var s = this.selections;
27285 node = this.getNode(node);
27286 return s.indexOf(node) !== -1;
27291 * @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
27292 * @param {Boolean} keepExisting (optional) true to keep existing selections
27293 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27295 select : function(nodeInfo, keepExisting, suppressEvent){
27296 if(nodeInfo instanceof Array){
27298 this.clearSelections(true);
27300 for(var i = 0, len = nodeInfo.length; i < len; i++){
27301 this.select(nodeInfo[i], true, true);
27305 var node = this.getNode(nodeInfo);
27306 if(!node || this.isSelected(node)){
27307 return; // already selected.
27310 this.clearSelections(true);
27313 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27314 Roo.fly(node).addClass(this.selectedClass);
27315 this.selections.push(node);
27316 if(!suppressEvent){
27317 this.fireEvent("selectionchange", this, this.selections);
27325 * @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
27326 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27327 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27329 unselect : function(nodeInfo, keepExisting, suppressEvent)
27331 if(nodeInfo instanceof Array){
27332 Roo.each(this.selections, function(s) {
27333 this.unselect(s, nodeInfo);
27337 var node = this.getNode(nodeInfo);
27338 if(!node || !this.isSelected(node)){
27339 //Roo.log("not selected");
27340 return; // not selected.
27344 Roo.each(this.selections, function(s) {
27346 Roo.fly(node).removeClass(this.selectedClass);
27353 this.selections= ns;
27354 this.fireEvent("selectionchange", this, this.selections);
27358 * Gets a template node.
27359 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27360 * @return {HTMLElement} The node or null if it wasn't found
27362 getNode : function(nodeInfo){
27363 if(typeof nodeInfo == "string"){
27364 return document.getElementById(nodeInfo);
27365 }else if(typeof nodeInfo == "number"){
27366 return this.nodes[nodeInfo];
27372 * Gets a range template nodes.
27373 * @param {Number} startIndex
27374 * @param {Number} endIndex
27375 * @return {Array} An array of nodes
27377 getNodes : function(start, end){
27378 var ns = this.nodes;
27379 start = start || 0;
27380 end = typeof end == "undefined" ? ns.length - 1 : end;
27383 for(var i = start; i <= end; i++){
27387 for(var i = start; i >= end; i--){
27395 * Finds the index of the passed node
27396 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27397 * @return {Number} The index of the node or -1
27399 indexOf : function(node){
27400 node = this.getNode(node);
27401 if(typeof node.nodeIndex == "number"){
27402 return node.nodeIndex;
27404 var ns = this.nodes;
27405 for(var i = 0, len = ns.length; i < len; i++){
27415 * Ext JS Library 1.1.1
27416 * Copyright(c) 2006-2007, Ext JS, LLC.
27418 * Originally Released Under LGPL - original licence link has changed is not relivant.
27421 * <script type="text/javascript">
27425 * @class Roo.JsonView
27426 * @extends Roo.View
27427 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27429 var view = new Roo.JsonView({
27430 container: "my-element",
27431 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27436 // listen for node click?
27437 view.on("click", function(vw, index, node, e){
27438 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27441 // direct load of JSON data
27442 view.load("foobar.php");
27444 // Example from my blog list
27445 var tpl = new Roo.Template(
27446 '<div class="entry">' +
27447 '<a class="entry-title" href="{link}">{title}</a>' +
27448 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27449 "</div><hr />"
27452 var moreView = new Roo.JsonView({
27453 container : "entry-list",
27457 moreView.on("beforerender", this.sortEntries, this);
27459 url: "/blog/get-posts.php",
27460 params: "allposts=true",
27461 text: "Loading Blog Entries..."
27465 * Note: old code is supported with arguments : (container, template, config)
27469 * Create a new JsonView
27471 * @param {Object} config The config object
27474 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27477 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27479 var um = this.el.getUpdateManager();
27480 um.setRenderer(this);
27481 um.on("update", this.onLoad, this);
27482 um.on("failure", this.onLoadException, this);
27485 * @event beforerender
27486 * Fires before rendering of the downloaded JSON data.
27487 * @param {Roo.JsonView} this
27488 * @param {Object} data The JSON data loaded
27492 * Fires when data is loaded.
27493 * @param {Roo.JsonView} this
27494 * @param {Object} data The JSON data loaded
27495 * @param {Object} response The raw Connect response object
27498 * @event loadexception
27499 * Fires when loading fails.
27500 * @param {Roo.JsonView} this
27501 * @param {Object} response The raw Connect response object
27504 'beforerender' : true,
27506 'loadexception' : true
27509 Roo.extend(Roo.JsonView, Roo.View, {
27511 * @type {String} The root property in the loaded JSON object that contains the data
27516 * Refreshes the view.
27518 refresh : function(){
27519 this.clearSelections();
27520 this.el.update("");
27522 var o = this.jsonData;
27523 if(o && o.length > 0){
27524 for(var i = 0, len = o.length; i < len; i++){
27525 var data = this.prepareData(o[i], i, o);
27526 html[html.length] = this.tpl.apply(data);
27529 html.push(this.emptyText);
27531 this.el.update(html.join(""));
27532 this.nodes = this.el.dom.childNodes;
27533 this.updateIndexes(0);
27537 * 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.
27538 * @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:
27541 url: "your-url.php",
27542 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27543 callback: yourFunction,
27544 scope: yourObject, //(optional scope)
27547 text: "Loading...",
27552 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27553 * 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.
27554 * @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}
27555 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27556 * @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.
27559 var um = this.el.getUpdateManager();
27560 um.update.apply(um, arguments);
27563 // note - render is a standard framework call...
27564 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27565 render : function(el, response){
27567 this.clearSelections();
27568 this.el.update("");
27571 if (response != '') {
27572 o = Roo.util.JSON.decode(response.responseText);
27575 o = o[this.jsonRoot];
27581 * The current JSON data or null
27584 this.beforeRender();
27589 * Get the number of records in the current JSON dataset
27592 getCount : function(){
27593 return this.jsonData ? this.jsonData.length : 0;
27597 * Returns the JSON object for the specified node(s)
27598 * @param {HTMLElement/Array} node The node or an array of nodes
27599 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27600 * you get the JSON object for the node
27602 getNodeData : function(node){
27603 if(node instanceof Array){
27605 for(var i = 0, len = node.length; i < len; i++){
27606 data.push(this.getNodeData(node[i]));
27610 return this.jsonData[this.indexOf(node)] || null;
27613 beforeRender : function(){
27614 this.snapshot = this.jsonData;
27616 this.sort.apply(this, this.sortInfo);
27618 this.fireEvent("beforerender", this, this.jsonData);
27621 onLoad : function(el, o){
27622 this.fireEvent("load", this, this.jsonData, o);
27625 onLoadException : function(el, o){
27626 this.fireEvent("loadexception", this, o);
27630 * Filter the data by a specific property.
27631 * @param {String} property A property on your JSON objects
27632 * @param {String/RegExp} value Either string that the property values
27633 * should start with, or a RegExp to test against the property
27635 filter : function(property, value){
27638 var ss = this.snapshot;
27639 if(typeof value == "string"){
27640 var vlen = value.length;
27642 this.clearFilter();
27645 value = value.toLowerCase();
27646 for(var i = 0, len = ss.length; i < len; i++){
27648 if(o[property].substr(0, vlen).toLowerCase() == value){
27652 } else if(value.exec){ // regex?
27653 for(var i = 0, len = ss.length; i < len; i++){
27655 if(value.test(o[property])){
27662 this.jsonData = data;
27668 * Filter by a function. The passed function will be called with each
27669 * object in the current dataset. If the function returns true the value is kept,
27670 * otherwise it is filtered.
27671 * @param {Function} fn
27672 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27674 filterBy : function(fn, scope){
27677 var ss = this.snapshot;
27678 for(var i = 0, len = ss.length; i < len; i++){
27680 if(fn.call(scope || this, o)){
27684 this.jsonData = data;
27690 * Clears the current filter.
27692 clearFilter : function(){
27693 if(this.snapshot && this.jsonData != this.snapshot){
27694 this.jsonData = this.snapshot;
27701 * Sorts the data for this view and refreshes it.
27702 * @param {String} property A property on your JSON objects to sort on
27703 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27704 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27706 sort : function(property, dir, sortType){
27707 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27710 var dsc = dir && dir.toLowerCase() == "desc";
27711 var f = function(o1, o2){
27712 var v1 = sortType ? sortType(o1[p]) : o1[p];
27713 var v2 = sortType ? sortType(o2[p]) : o2[p];
27716 return dsc ? +1 : -1;
27717 } else if(v1 > v2){
27718 return dsc ? -1 : +1;
27723 this.jsonData.sort(f);
27725 if(this.jsonData != this.snapshot){
27726 this.snapshot.sort(f);
27732 * Ext JS Library 1.1.1
27733 * Copyright(c) 2006-2007, Ext JS, LLC.
27735 * Originally Released Under LGPL - original licence link has changed is not relivant.
27738 * <script type="text/javascript">
27743 * @class Roo.ColorPalette
27744 * @extends Roo.Component
27745 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27746 * Here's an example of typical usage:
27748 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27749 cp.render('my-div');
27751 cp.on('select', function(palette, selColor){
27752 // do something with selColor
27756 * Create a new ColorPalette
27757 * @param {Object} config The config object
27759 Roo.ColorPalette = function(config){
27760 Roo.ColorPalette.superclass.constructor.call(this, config);
27764 * Fires when a color is selected
27765 * @param {ColorPalette} this
27766 * @param {String} color The 6-digit color hex code (without the # symbol)
27772 this.on("select", this.handler, this.scope, true);
27775 Roo.extend(Roo.ColorPalette, Roo.Component, {
27777 * @cfg {String} itemCls
27778 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27780 itemCls : "x-color-palette",
27782 * @cfg {String} value
27783 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27784 * the hex codes are case-sensitive.
27787 clickEvent:'click',
27789 ctype: "Roo.ColorPalette",
27792 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27794 allowReselect : false,
27797 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27798 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27799 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27800 * of colors with the width setting until the box is symmetrical.</p>
27801 * <p>You can override individual colors if needed:</p>
27803 var cp = new Roo.ColorPalette();
27804 cp.colors[0] = "FF0000"; // change the first box to red
27807 Or you can provide a custom array of your own for complete control:
27809 var cp = new Roo.ColorPalette();
27810 cp.colors = ["000000", "993300", "333300"];
27815 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27816 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27817 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27818 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27819 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27823 onRender : function(container, position){
27824 var t = new Roo.MasterTemplate(
27825 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27827 var c = this.colors;
27828 for(var i = 0, len = c.length; i < len; i++){
27831 var el = document.createElement("div");
27832 el.className = this.itemCls;
27834 container.dom.insertBefore(el, position);
27835 this.el = Roo.get(el);
27836 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27837 if(this.clickEvent != 'click'){
27838 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27843 afterRender : function(){
27844 Roo.ColorPalette.superclass.afterRender.call(this);
27846 var s = this.value;
27853 handleClick : function(e, t){
27854 e.preventDefault();
27855 if(!this.disabled){
27856 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27857 this.select(c.toUpperCase());
27862 * Selects the specified color in the palette (fires the select event)
27863 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27865 select : function(color){
27866 color = color.replace("#", "");
27867 if(color != this.value || this.allowReselect){
27870 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27872 el.child("a.color-"+color).addClass("x-color-palette-sel");
27873 this.value = color;
27874 this.fireEvent("select", this, color);
27879 * Ext JS Library 1.1.1
27880 * Copyright(c) 2006-2007, Ext JS, LLC.
27882 * Originally Released Under LGPL - original licence link has changed is not relivant.
27885 * <script type="text/javascript">
27889 * @class Roo.DatePicker
27890 * @extends Roo.Component
27891 * Simple date picker class.
27893 * Create a new DatePicker
27894 * @param {Object} config The config object
27896 Roo.DatePicker = function(config){
27897 Roo.DatePicker.superclass.constructor.call(this, config);
27899 this.value = config && config.value ?
27900 config.value.clearTime() : new Date().clearTime();
27905 * Fires when a date is selected
27906 * @param {DatePicker} this
27907 * @param {Date} date The selected date
27911 * @event monthchange
27912 * Fires when the displayed month changes
27913 * @param {DatePicker} this
27914 * @param {Date} date The selected month
27916 'monthchange': true
27920 this.on("select", this.handler, this.scope || this);
27922 // build the disabledDatesRE
27923 if(!this.disabledDatesRE && this.disabledDates){
27924 var dd = this.disabledDates;
27926 for(var i = 0; i < dd.length; i++){
27928 if(i != dd.length-1) {
27932 this.disabledDatesRE = new RegExp(re + ")");
27936 Roo.extend(Roo.DatePicker, Roo.Component, {
27938 * @cfg {String} todayText
27939 * The text to display on the button that selects the current date (defaults to "Today")
27941 todayText : "Today",
27943 * @cfg {String} okText
27944 * The text to display on the ok button
27946 okText : " OK ", //   to give the user extra clicking room
27948 * @cfg {String} cancelText
27949 * The text to display on the cancel button
27951 cancelText : "Cancel",
27953 * @cfg {String} todayTip
27954 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27956 todayTip : "{0} (Spacebar)",
27958 * @cfg {Date} minDate
27959 * Minimum allowable date (JavaScript date object, defaults to null)
27963 * @cfg {Date} maxDate
27964 * Maximum allowable date (JavaScript date object, defaults to null)
27968 * @cfg {String} minText
27969 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27971 minText : "This date is before the minimum date",
27973 * @cfg {String} maxText
27974 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27976 maxText : "This date is after the maximum date",
27978 * @cfg {String} format
27979 * The default date format string which can be overriden for localization support. The format must be
27980 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27984 * @cfg {Array} disabledDays
27985 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27987 disabledDays : null,
27989 * @cfg {String} disabledDaysText
27990 * The tooltip to display when the date falls on a disabled day (defaults to "")
27992 disabledDaysText : "",
27994 * @cfg {RegExp} disabledDatesRE
27995 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27997 disabledDatesRE : null,
27999 * @cfg {String} disabledDatesText
28000 * The tooltip text to display when the date falls on a disabled date (defaults to "")
28002 disabledDatesText : "",
28004 * @cfg {Boolean} constrainToViewport
28005 * True to constrain the date picker to the viewport (defaults to true)
28007 constrainToViewport : true,
28009 * @cfg {Array} monthNames
28010 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
28012 monthNames : Date.monthNames,
28014 * @cfg {Array} dayNames
28015 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
28017 dayNames : Date.dayNames,
28019 * @cfg {String} nextText
28020 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
28022 nextText: 'Next Month (Control+Right)',
28024 * @cfg {String} prevText
28025 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
28027 prevText: 'Previous Month (Control+Left)',
28029 * @cfg {String} monthYearText
28030 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
28032 monthYearText: 'Choose a month (Control+Up/Down to move years)',
28034 * @cfg {Number} startDay
28035 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
28039 * @cfg {Bool} showClear
28040 * Show a clear button (usefull for date form elements that can be blank.)
28046 * Sets the value of the date field
28047 * @param {Date} value The date to set
28049 setValue : function(value){
28050 var old = this.value;
28052 if (typeof(value) == 'string') {
28054 value = Date.parseDate(value, this.format);
28057 value = new Date();
28060 this.value = value.clearTime(true);
28062 this.update(this.value);
28067 * Gets the current selected value of the date field
28068 * @return {Date} The selected date
28070 getValue : function(){
28075 focus : function(){
28077 this.update(this.activeDate);
28082 onRender : function(container, position){
28085 '<table cellspacing="0">',
28086 '<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>',
28087 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28088 var dn = this.dayNames;
28089 for(var i = 0; i < 7; i++){
28090 var d = this.startDay+i;
28094 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28096 m[m.length] = "</tr></thead><tbody><tr>";
28097 for(var i = 0; i < 42; i++) {
28098 if(i % 7 == 0 && i != 0){
28099 m[m.length] = "</tr><tr>";
28101 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28103 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28104 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28106 var el = document.createElement("div");
28107 el.className = "x-date-picker";
28108 el.innerHTML = m.join("");
28110 container.dom.insertBefore(el, position);
28112 this.el = Roo.get(el);
28113 this.eventEl = Roo.get(el.firstChild);
28115 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28116 handler: this.showPrevMonth,
28118 preventDefault:true,
28122 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28123 handler: this.showNextMonth,
28125 preventDefault:true,
28129 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28131 this.monthPicker = this.el.down('div.x-date-mp');
28132 this.monthPicker.enableDisplayMode('block');
28134 var kn = new Roo.KeyNav(this.eventEl, {
28135 "left" : function(e){
28137 this.showPrevMonth() :
28138 this.update(this.activeDate.add("d", -1));
28141 "right" : function(e){
28143 this.showNextMonth() :
28144 this.update(this.activeDate.add("d", 1));
28147 "up" : function(e){
28149 this.showNextYear() :
28150 this.update(this.activeDate.add("d", -7));
28153 "down" : function(e){
28155 this.showPrevYear() :
28156 this.update(this.activeDate.add("d", 7));
28159 "pageUp" : function(e){
28160 this.showNextMonth();
28163 "pageDown" : function(e){
28164 this.showPrevMonth();
28167 "enter" : function(e){
28168 e.stopPropagation();
28175 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28177 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28179 this.el.unselectable();
28181 this.cells = this.el.select("table.x-date-inner tbody td");
28182 this.textNodes = this.el.query("table.x-date-inner tbody span");
28184 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28186 tooltip: this.monthYearText
28189 this.mbtn.on('click', this.showMonthPicker, this);
28190 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28193 var today = (new Date()).dateFormat(this.format);
28195 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28196 if (this.showClear) {
28197 baseTb.add( new Roo.Toolbar.Fill());
28200 text: String.format(this.todayText, today),
28201 tooltip: String.format(this.todayTip, today),
28202 handler: this.selectToday,
28206 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28209 if (this.showClear) {
28211 baseTb.add( new Roo.Toolbar.Fill());
28214 cls: 'x-btn-icon x-btn-clear',
28215 handler: function() {
28217 this.fireEvent("select", this, '');
28227 this.update(this.value);
28230 createMonthPicker : function(){
28231 if(!this.monthPicker.dom.firstChild){
28232 var buf = ['<table border="0" cellspacing="0">'];
28233 for(var i = 0; i < 6; i++){
28235 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28236 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28238 '<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>' :
28239 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28243 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28245 '</button><button type="button" class="x-date-mp-cancel">',
28247 '</button></td></tr>',
28250 this.monthPicker.update(buf.join(''));
28251 this.monthPicker.on('click', this.onMonthClick, this);
28252 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28254 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28255 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28257 this.mpMonths.each(function(m, a, i){
28260 m.dom.xmonth = 5 + Math.round(i * .5);
28262 m.dom.xmonth = Math.round((i-1) * .5);
28268 showMonthPicker : function(){
28269 this.createMonthPicker();
28270 var size = this.el.getSize();
28271 this.monthPicker.setSize(size);
28272 this.monthPicker.child('table').setSize(size);
28274 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28275 this.updateMPMonth(this.mpSelMonth);
28276 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28277 this.updateMPYear(this.mpSelYear);
28279 this.monthPicker.slideIn('t', {duration:.2});
28282 updateMPYear : function(y){
28284 var ys = this.mpYears.elements;
28285 for(var i = 1; i <= 10; i++){
28286 var td = ys[i-1], y2;
28288 y2 = y + Math.round(i * .5);
28289 td.firstChild.innerHTML = y2;
28292 y2 = y - (5-Math.round(i * .5));
28293 td.firstChild.innerHTML = y2;
28296 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28300 updateMPMonth : function(sm){
28301 this.mpMonths.each(function(m, a, i){
28302 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28306 selectMPMonth: function(m){
28310 onMonthClick : function(e, t){
28312 var el = new Roo.Element(t), pn;
28313 if(el.is('button.x-date-mp-cancel')){
28314 this.hideMonthPicker();
28316 else if(el.is('button.x-date-mp-ok')){
28317 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28318 this.hideMonthPicker();
28320 else if(pn = el.up('td.x-date-mp-month', 2)){
28321 this.mpMonths.removeClass('x-date-mp-sel');
28322 pn.addClass('x-date-mp-sel');
28323 this.mpSelMonth = pn.dom.xmonth;
28325 else if(pn = el.up('td.x-date-mp-year', 2)){
28326 this.mpYears.removeClass('x-date-mp-sel');
28327 pn.addClass('x-date-mp-sel');
28328 this.mpSelYear = pn.dom.xyear;
28330 else if(el.is('a.x-date-mp-prev')){
28331 this.updateMPYear(this.mpyear-10);
28333 else if(el.is('a.x-date-mp-next')){
28334 this.updateMPYear(this.mpyear+10);
28338 onMonthDblClick : function(e, t){
28340 var el = new Roo.Element(t), pn;
28341 if(pn = el.up('td.x-date-mp-month', 2)){
28342 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28343 this.hideMonthPicker();
28345 else if(pn = el.up('td.x-date-mp-year', 2)){
28346 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28347 this.hideMonthPicker();
28351 hideMonthPicker : function(disableAnim){
28352 if(this.monthPicker){
28353 if(disableAnim === true){
28354 this.monthPicker.hide();
28356 this.monthPicker.slideOut('t', {duration:.2});
28362 showPrevMonth : function(e){
28363 this.update(this.activeDate.add("mo", -1));
28367 showNextMonth : function(e){
28368 this.update(this.activeDate.add("mo", 1));
28372 showPrevYear : function(){
28373 this.update(this.activeDate.add("y", -1));
28377 showNextYear : function(){
28378 this.update(this.activeDate.add("y", 1));
28382 handleMouseWheel : function(e){
28383 var delta = e.getWheelDelta();
28385 this.showPrevMonth();
28387 } else if(delta < 0){
28388 this.showNextMonth();
28394 handleDateClick : function(e, t){
28396 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28397 this.setValue(new Date(t.dateValue));
28398 this.fireEvent("select", this, this.value);
28403 selectToday : function(){
28404 this.setValue(new Date().clearTime());
28405 this.fireEvent("select", this, this.value);
28409 update : function(date)
28411 var vd = this.activeDate;
28412 this.activeDate = date;
28414 var t = date.getTime();
28415 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28416 this.cells.removeClass("x-date-selected");
28417 this.cells.each(function(c){
28418 if(c.dom.firstChild.dateValue == t){
28419 c.addClass("x-date-selected");
28420 setTimeout(function(){
28421 try{c.dom.firstChild.focus();}catch(e){}
28430 var days = date.getDaysInMonth();
28431 var firstOfMonth = date.getFirstDateOfMonth();
28432 var startingPos = firstOfMonth.getDay()-this.startDay;
28434 if(startingPos <= this.startDay){
28438 var pm = date.add("mo", -1);
28439 var prevStart = pm.getDaysInMonth()-startingPos;
28441 var cells = this.cells.elements;
28442 var textEls = this.textNodes;
28443 days += startingPos;
28445 // convert everything to numbers so it's fast
28446 var day = 86400000;
28447 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28448 var today = new Date().clearTime().getTime();
28449 var sel = date.clearTime().getTime();
28450 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28451 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28452 var ddMatch = this.disabledDatesRE;
28453 var ddText = this.disabledDatesText;
28454 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28455 var ddaysText = this.disabledDaysText;
28456 var format = this.format;
28458 var setCellClass = function(cal, cell){
28460 var t = d.getTime();
28461 cell.firstChild.dateValue = t;
28463 cell.className += " x-date-today";
28464 cell.title = cal.todayText;
28467 cell.className += " x-date-selected";
28468 setTimeout(function(){
28469 try{cell.firstChild.focus();}catch(e){}
28474 cell.className = " x-date-disabled";
28475 cell.title = cal.minText;
28479 cell.className = " x-date-disabled";
28480 cell.title = cal.maxText;
28484 if(ddays.indexOf(d.getDay()) != -1){
28485 cell.title = ddaysText;
28486 cell.className = " x-date-disabled";
28489 if(ddMatch && format){
28490 var fvalue = d.dateFormat(format);
28491 if(ddMatch.test(fvalue)){
28492 cell.title = ddText.replace("%0", fvalue);
28493 cell.className = " x-date-disabled";
28499 for(; i < startingPos; i++) {
28500 textEls[i].innerHTML = (++prevStart);
28501 d.setDate(d.getDate()+1);
28502 cells[i].className = "x-date-prevday";
28503 setCellClass(this, cells[i]);
28505 for(; i < days; i++){
28506 intDay = i - startingPos + 1;
28507 textEls[i].innerHTML = (intDay);
28508 d.setDate(d.getDate()+1);
28509 cells[i].className = "x-date-active";
28510 setCellClass(this, cells[i]);
28513 for(; i < 42; i++) {
28514 textEls[i].innerHTML = (++extraDays);
28515 d.setDate(d.getDate()+1);
28516 cells[i].className = "x-date-nextday";
28517 setCellClass(this, cells[i]);
28520 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28521 this.fireEvent('monthchange', this, date);
28523 if(!this.internalRender){
28524 var main = this.el.dom.firstChild;
28525 var w = main.offsetWidth;
28526 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28527 Roo.fly(main).setWidth(w);
28528 this.internalRender = true;
28529 // opera does not respect the auto grow header center column
28530 // then, after it gets a width opera refuses to recalculate
28531 // without a second pass
28532 if(Roo.isOpera && !this.secondPass){
28533 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28534 this.secondPass = true;
28535 this.update.defer(10, this, [date]);
28543 * Ext JS Library 1.1.1
28544 * Copyright(c) 2006-2007, Ext JS, LLC.
28546 * Originally Released Under LGPL - original licence link has changed is not relivant.
28549 * <script type="text/javascript">
28552 * @class Roo.TabPanel
28553 * @extends Roo.util.Observable
28554 * A lightweight tab container.
28558 // basic tabs 1, built from existing content
28559 var tabs = new Roo.TabPanel("tabs1");
28560 tabs.addTab("script", "View Script");
28561 tabs.addTab("markup", "View Markup");
28562 tabs.activate("script");
28564 // more advanced tabs, built from javascript
28565 var jtabs = new Roo.TabPanel("jtabs");
28566 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28568 // set up the UpdateManager
28569 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28570 var updater = tab2.getUpdateManager();
28571 updater.setDefaultUrl("ajax1.htm");
28572 tab2.on('activate', updater.refresh, updater, true);
28574 // Use setUrl for Ajax loading
28575 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28576 tab3.setUrl("ajax2.htm", null, true);
28579 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28582 jtabs.activate("jtabs-1");
28585 * Create a new TabPanel.
28586 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28587 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28589 Roo.TabPanel = function(container, config){
28591 * The container element for this TabPanel.
28592 * @type Roo.Element
28594 this.el = Roo.get(container, true);
28596 if(typeof config == "boolean"){
28597 this.tabPosition = config ? "bottom" : "top";
28599 Roo.apply(this, config);
28602 if(this.tabPosition == "bottom"){
28603 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28604 this.el.addClass("x-tabs-bottom");
28606 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28607 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28608 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28610 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28612 if(this.tabPosition != "bottom"){
28613 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28614 * @type Roo.Element
28616 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28617 this.el.addClass("x-tabs-top");
28621 this.bodyEl.setStyle("position", "relative");
28623 this.active = null;
28624 this.activateDelegate = this.activate.createDelegate(this);
28629 * Fires when the active tab changes
28630 * @param {Roo.TabPanel} this
28631 * @param {Roo.TabPanelItem} activePanel The new active tab
28635 * @event beforetabchange
28636 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28637 * @param {Roo.TabPanel} this
28638 * @param {Object} e Set cancel to true on this object to cancel the tab change
28639 * @param {Roo.TabPanelItem} tab The tab being changed to
28641 "beforetabchange" : true
28644 Roo.EventManager.onWindowResize(this.onResize, this);
28645 this.cpad = this.el.getPadding("lr");
28646 this.hiddenCount = 0;
28649 // toolbar on the tabbar support...
28650 if (this.toolbar) {
28651 var tcfg = this.toolbar;
28652 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28653 this.toolbar = new Roo.Toolbar(tcfg);
28654 if (Roo.isSafari) {
28655 var tbl = tcfg.container.child('table', true);
28656 tbl.setAttribute('width', '100%');
28663 Roo.TabPanel.superclass.constructor.call(this);
28666 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28668 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28670 tabPosition : "top",
28672 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28674 currentTabWidth : 0,
28676 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28680 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28684 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28686 preferredTabWidth : 175,
28688 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28690 resizeTabs : false,
28692 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28694 monitorResize : true,
28696 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28701 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28702 * @param {String} id The id of the div to use <b>or create</b>
28703 * @param {String} text The text for the tab
28704 * @param {String} content (optional) Content to put in the TabPanelItem body
28705 * @param {Boolean} closable (optional) True to create a close icon on the tab
28706 * @return {Roo.TabPanelItem} The created TabPanelItem
28708 addTab : function(id, text, content, closable){
28709 var item = new Roo.TabPanelItem(this, id, text, closable);
28710 this.addTabItem(item);
28712 item.setContent(content);
28718 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28719 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28720 * @return {Roo.TabPanelItem}
28722 getTab : function(id){
28723 return this.items[id];
28727 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28728 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28730 hideTab : function(id){
28731 var t = this.items[id];
28734 this.hiddenCount++;
28735 this.autoSizeTabs();
28740 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28741 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28743 unhideTab : function(id){
28744 var t = this.items[id];
28746 t.setHidden(false);
28747 this.hiddenCount--;
28748 this.autoSizeTabs();
28753 * Adds an existing {@link Roo.TabPanelItem}.
28754 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28756 addTabItem : function(item){
28757 this.items[item.id] = item;
28758 this.items.push(item);
28759 if(this.resizeTabs){
28760 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28761 this.autoSizeTabs();
28768 * Removes a {@link Roo.TabPanelItem}.
28769 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28771 removeTab : function(id){
28772 var items = this.items;
28773 var tab = items[id];
28774 if(!tab) { return; }
28775 var index = items.indexOf(tab);
28776 if(this.active == tab && items.length > 1){
28777 var newTab = this.getNextAvailable(index);
28782 this.stripEl.dom.removeChild(tab.pnode.dom);
28783 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28784 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28786 items.splice(index, 1);
28787 delete this.items[tab.id];
28788 tab.fireEvent("close", tab);
28789 tab.purgeListeners();
28790 this.autoSizeTabs();
28793 getNextAvailable : function(start){
28794 var items = this.items;
28796 // look for a next tab that will slide over to
28797 // replace the one being removed
28798 while(index < items.length){
28799 var item = items[++index];
28800 if(item && !item.isHidden()){
28804 // if one isn't found select the previous tab (on the left)
28807 var item = items[--index];
28808 if(item && !item.isHidden()){
28816 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28817 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28819 disableTab : function(id){
28820 var tab = this.items[id];
28821 if(tab && this.active != tab){
28827 * Enables a {@link Roo.TabPanelItem} that is disabled.
28828 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28830 enableTab : function(id){
28831 var tab = this.items[id];
28836 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28837 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28838 * @return {Roo.TabPanelItem} The TabPanelItem.
28840 activate : function(id){
28841 var tab = this.items[id];
28845 if(tab == this.active || tab.disabled){
28849 this.fireEvent("beforetabchange", this, e, tab);
28850 if(e.cancel !== true && !tab.disabled){
28852 this.active.hide();
28854 this.active = this.items[id];
28855 this.active.show();
28856 this.fireEvent("tabchange", this, this.active);
28862 * Gets the active {@link Roo.TabPanelItem}.
28863 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28865 getActiveTab : function(){
28866 return this.active;
28870 * Updates the tab body element to fit the height of the container element
28871 * for overflow scrolling
28872 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28874 syncHeight : function(targetHeight){
28875 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28876 var bm = this.bodyEl.getMargins();
28877 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28878 this.bodyEl.setHeight(newHeight);
28882 onResize : function(){
28883 if(this.monitorResize){
28884 this.autoSizeTabs();
28889 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28891 beginUpdate : function(){
28892 this.updating = true;
28896 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28898 endUpdate : function(){
28899 this.updating = false;
28900 this.autoSizeTabs();
28904 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28906 autoSizeTabs : function(){
28907 var count = this.items.length;
28908 var vcount = count - this.hiddenCount;
28909 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28912 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28913 var availWidth = Math.floor(w / vcount);
28914 var b = this.stripBody;
28915 if(b.getWidth() > w){
28916 var tabs = this.items;
28917 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28918 if(availWidth < this.minTabWidth){
28919 /*if(!this.sleft){ // incomplete scrolling code
28920 this.createScrollButtons();
28923 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28926 if(this.currentTabWidth < this.preferredTabWidth){
28927 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28933 * Returns the number of tabs in this TabPanel.
28936 getCount : function(){
28937 return this.items.length;
28941 * Resizes all the tabs to the passed width
28942 * @param {Number} The new width
28944 setTabWidth : function(width){
28945 this.currentTabWidth = width;
28946 for(var i = 0, len = this.items.length; i < len; i++) {
28947 if(!this.items[i].isHidden()) {
28948 this.items[i].setWidth(width);
28954 * Destroys this TabPanel
28955 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28957 destroy : function(removeEl){
28958 Roo.EventManager.removeResizeListener(this.onResize, this);
28959 for(var i = 0, len = this.items.length; i < len; i++){
28960 this.items[i].purgeListeners();
28962 if(removeEl === true){
28963 this.el.update("");
28970 * @class Roo.TabPanelItem
28971 * @extends Roo.util.Observable
28972 * Represents an individual item (tab plus body) in a TabPanel.
28973 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28974 * @param {String} id The id of this TabPanelItem
28975 * @param {String} text The text for the tab of this TabPanelItem
28976 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28978 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28980 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28981 * @type Roo.TabPanel
28983 this.tabPanel = tabPanel;
28985 * The id for this TabPanelItem
28990 this.disabled = false;
28994 this.loaded = false;
28995 this.closable = closable;
28998 * The body element for this TabPanelItem.
28999 * @type Roo.Element
29001 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
29002 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
29003 this.bodyEl.setStyle("display", "block");
29004 this.bodyEl.setStyle("zoom", "1");
29007 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
29009 this.el = Roo.get(els.el, true);
29010 this.inner = Roo.get(els.inner, true);
29011 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
29012 this.pnode = Roo.get(els.el.parentNode, true);
29013 this.el.on("mousedown", this.onTabMouseDown, this);
29014 this.el.on("click", this.onTabClick, this);
29017 var c = Roo.get(els.close, true);
29018 c.dom.title = this.closeText;
29019 c.addClassOnOver("close-over");
29020 c.on("click", this.closeClick, this);
29026 * Fires when this tab becomes the active tab.
29027 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29028 * @param {Roo.TabPanelItem} this
29032 * @event beforeclose
29033 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
29034 * @param {Roo.TabPanelItem} this
29035 * @param {Object} e Set cancel to true on this object to cancel the close.
29037 "beforeclose": true,
29040 * Fires when this tab is closed.
29041 * @param {Roo.TabPanelItem} this
29045 * @event deactivate
29046 * Fires when this tab is no longer the active tab.
29047 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29048 * @param {Roo.TabPanelItem} this
29050 "deactivate" : true
29052 this.hidden = false;
29054 Roo.TabPanelItem.superclass.constructor.call(this);
29057 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
29058 purgeListeners : function(){
29059 Roo.util.Observable.prototype.purgeListeners.call(this);
29060 this.el.removeAllListeners();
29063 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
29066 this.pnode.addClass("on");
29069 this.tabPanel.stripWrap.repaint();
29071 this.fireEvent("activate", this.tabPanel, this);
29075 * Returns true if this tab is the active tab.
29076 * @return {Boolean}
29078 isActive : function(){
29079 return this.tabPanel.getActiveTab() == this;
29083 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29086 this.pnode.removeClass("on");
29088 this.fireEvent("deactivate", this.tabPanel, this);
29091 hideAction : function(){
29092 this.bodyEl.hide();
29093 this.bodyEl.setStyle("position", "absolute");
29094 this.bodyEl.setLeft("-20000px");
29095 this.bodyEl.setTop("-20000px");
29098 showAction : function(){
29099 this.bodyEl.setStyle("position", "relative");
29100 this.bodyEl.setTop("");
29101 this.bodyEl.setLeft("");
29102 this.bodyEl.show();
29106 * Set the tooltip for the tab.
29107 * @param {String} tooltip The tab's tooltip
29109 setTooltip : function(text){
29110 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29111 this.textEl.dom.qtip = text;
29112 this.textEl.dom.removeAttribute('title');
29114 this.textEl.dom.title = text;
29118 onTabClick : function(e){
29119 e.preventDefault();
29120 this.tabPanel.activate(this.id);
29123 onTabMouseDown : function(e){
29124 e.preventDefault();
29125 this.tabPanel.activate(this.id);
29128 getWidth : function(){
29129 return this.inner.getWidth();
29132 setWidth : function(width){
29133 var iwidth = width - this.pnode.getPadding("lr");
29134 this.inner.setWidth(iwidth);
29135 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29136 this.pnode.setWidth(width);
29140 * Show or hide the tab
29141 * @param {Boolean} hidden True to hide or false to show.
29143 setHidden : function(hidden){
29144 this.hidden = hidden;
29145 this.pnode.setStyle("display", hidden ? "none" : "");
29149 * Returns true if this tab is "hidden"
29150 * @return {Boolean}
29152 isHidden : function(){
29153 return this.hidden;
29157 * Returns the text for this tab
29160 getText : function(){
29164 autoSize : function(){
29165 //this.el.beginMeasure();
29166 this.textEl.setWidth(1);
29168 * #2804 [new] Tabs in Roojs
29169 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29171 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29172 //this.el.endMeasure();
29176 * Sets the text for the tab (Note: this also sets the tooltip text)
29177 * @param {String} text The tab's text and tooltip
29179 setText : function(text){
29181 this.textEl.update(text);
29182 this.setTooltip(text);
29183 if(!this.tabPanel.resizeTabs){
29188 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29190 activate : function(){
29191 this.tabPanel.activate(this.id);
29195 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29197 disable : function(){
29198 if(this.tabPanel.active != this){
29199 this.disabled = true;
29200 this.pnode.addClass("disabled");
29205 * Enables this TabPanelItem if it was previously disabled.
29207 enable : function(){
29208 this.disabled = false;
29209 this.pnode.removeClass("disabled");
29213 * Sets the content for this TabPanelItem.
29214 * @param {String} content The content
29215 * @param {Boolean} loadScripts true to look for and load scripts
29217 setContent : function(content, loadScripts){
29218 this.bodyEl.update(content, loadScripts);
29222 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29223 * @return {Roo.UpdateManager} The UpdateManager
29225 getUpdateManager : function(){
29226 return this.bodyEl.getUpdateManager();
29230 * Set a URL to be used to load the content for this TabPanelItem.
29231 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29232 * @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)
29233 * @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)
29234 * @return {Roo.UpdateManager} The UpdateManager
29236 setUrl : function(url, params, loadOnce){
29237 if(this.refreshDelegate){
29238 this.un('activate', this.refreshDelegate);
29240 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29241 this.on("activate", this.refreshDelegate);
29242 return this.bodyEl.getUpdateManager();
29246 _handleRefresh : function(url, params, loadOnce){
29247 if(!loadOnce || !this.loaded){
29248 var updater = this.bodyEl.getUpdateManager();
29249 updater.update(url, params, this._setLoaded.createDelegate(this));
29254 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29255 * Will fail silently if the setUrl method has not been called.
29256 * This does not activate the panel, just updates its content.
29258 refresh : function(){
29259 if(this.refreshDelegate){
29260 this.loaded = false;
29261 this.refreshDelegate();
29266 _setLoaded : function(){
29267 this.loaded = true;
29271 closeClick : function(e){
29274 this.fireEvent("beforeclose", this, o);
29275 if(o.cancel !== true){
29276 this.tabPanel.removeTab(this.id);
29280 * The text displayed in the tooltip for the close icon.
29283 closeText : "Close this tab"
29287 Roo.TabPanel.prototype.createStrip = function(container){
29288 var strip = document.createElement("div");
29289 strip.className = "x-tabs-wrap";
29290 container.appendChild(strip);
29294 Roo.TabPanel.prototype.createStripList = function(strip){
29295 // div wrapper for retard IE
29296 // returns the "tr" element.
29297 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29298 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29299 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29300 return strip.firstChild.firstChild.firstChild.firstChild;
29303 Roo.TabPanel.prototype.createBody = function(container){
29304 var body = document.createElement("div");
29305 Roo.id(body, "tab-body");
29306 Roo.fly(body).addClass("x-tabs-body");
29307 container.appendChild(body);
29311 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29312 var body = Roo.getDom(id);
29314 body = document.createElement("div");
29317 Roo.fly(body).addClass("x-tabs-item-body");
29318 bodyEl.insertBefore(body, bodyEl.firstChild);
29322 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29323 var td = document.createElement("td");
29324 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29325 //stripEl.appendChild(td);
29327 td.className = "x-tabs-closable";
29328 if(!this.closeTpl){
29329 this.closeTpl = new Roo.Template(
29330 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29331 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29332 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29335 var el = this.closeTpl.overwrite(td, {"text": text});
29336 var close = el.getElementsByTagName("div")[0];
29337 var inner = el.getElementsByTagName("em")[0];
29338 return {"el": el, "close": close, "inner": inner};
29341 this.tabTpl = new Roo.Template(
29342 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29343 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29346 var el = this.tabTpl.overwrite(td, {"text": text});
29347 var inner = el.getElementsByTagName("em")[0];
29348 return {"el": el, "inner": inner};
29352 * Ext JS Library 1.1.1
29353 * Copyright(c) 2006-2007, Ext JS, LLC.
29355 * Originally Released Under LGPL - original licence link has changed is not relivant.
29358 * <script type="text/javascript">
29362 * @class Roo.Button
29363 * @extends Roo.util.Observable
29364 * Simple Button class
29365 * @cfg {String} text The button text
29366 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29367 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29368 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29369 * @cfg {Object} scope The scope of the handler
29370 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29371 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29372 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29373 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29374 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29375 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29376 applies if enableToggle = true)
29377 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29378 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29379 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29381 * Create a new button
29382 * @param {Object} config The config object
29384 Roo.Button = function(renderTo, config)
29388 renderTo = config.renderTo || false;
29391 Roo.apply(this, config);
29395 * Fires when this button is clicked
29396 * @param {Button} this
29397 * @param {EventObject} e The click event
29402 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29403 * @param {Button} this
29404 * @param {Boolean} pressed
29409 * Fires when the mouse hovers over the button
29410 * @param {Button} this
29411 * @param {Event} e The event object
29413 'mouseover' : true,
29416 * Fires when the mouse exits the button
29417 * @param {Button} this
29418 * @param {Event} e The event object
29423 * Fires when the button is rendered
29424 * @param {Button} this
29429 this.menu = Roo.menu.MenuMgr.get(this.menu);
29431 // register listeners first!! - so render can be captured..
29432 Roo.util.Observable.call(this);
29434 this.render(renderTo);
29440 Roo.extend(Roo.Button, Roo.util.Observable, {
29446 * Read-only. True if this button is hidden
29451 * Read-only. True if this button is disabled
29456 * Read-only. True if this button is pressed (only if enableToggle = true)
29462 * @cfg {Number} tabIndex
29463 * The DOM tabIndex for this button (defaults to undefined)
29465 tabIndex : undefined,
29468 * @cfg {Boolean} enableToggle
29469 * True to enable pressed/not pressed toggling (defaults to false)
29471 enableToggle: false,
29473 * @cfg {Mixed} menu
29474 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29478 * @cfg {String} menuAlign
29479 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29481 menuAlign : "tl-bl?",
29484 * @cfg {String} iconCls
29485 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29487 iconCls : undefined,
29489 * @cfg {String} type
29490 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29495 menuClassTarget: 'tr',
29498 * @cfg {String} clickEvent
29499 * The type of event to map to the button's event handler (defaults to 'click')
29501 clickEvent : 'click',
29504 * @cfg {Boolean} handleMouseEvents
29505 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29507 handleMouseEvents : true,
29510 * @cfg {String} tooltipType
29511 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29513 tooltipType : 'qtip',
29516 * @cfg {String} cls
29517 * A CSS class to apply to the button's main element.
29521 * @cfg {Roo.Template} template (Optional)
29522 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29523 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29524 * require code modifications if required elements (e.g. a button) aren't present.
29528 render : function(renderTo){
29530 if(this.hideParent){
29531 this.parentEl = Roo.get(renderTo);
29533 if(!this.dhconfig){
29534 if(!this.template){
29535 if(!Roo.Button.buttonTemplate){
29536 // hideous table template
29537 Roo.Button.buttonTemplate = new Roo.Template(
29538 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29539 '<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>',
29540 "</tr></tbody></table>");
29542 this.template = Roo.Button.buttonTemplate;
29544 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29545 var btnEl = btn.child("button:first");
29546 btnEl.on('focus', this.onFocus, this);
29547 btnEl.on('blur', this.onBlur, this);
29549 btn.addClass(this.cls);
29552 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29555 btnEl.addClass(this.iconCls);
29557 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29560 if(this.tabIndex !== undefined){
29561 btnEl.dom.tabIndex = this.tabIndex;
29564 if(typeof this.tooltip == 'object'){
29565 Roo.QuickTips.tips(Roo.apply({
29569 btnEl.dom[this.tooltipType] = this.tooltip;
29573 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29577 this.el.dom.id = this.el.id = this.id;
29580 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29581 this.menu.on("show", this.onMenuShow, this);
29582 this.menu.on("hide", this.onMenuHide, this);
29584 btn.addClass("x-btn");
29585 if(Roo.isIE && !Roo.isIE7){
29586 this.autoWidth.defer(1, this);
29590 if(this.handleMouseEvents){
29591 btn.on("mouseover", this.onMouseOver, this);
29592 btn.on("mouseout", this.onMouseOut, this);
29593 btn.on("mousedown", this.onMouseDown, this);
29595 btn.on(this.clickEvent, this.onClick, this);
29596 //btn.on("mouseup", this.onMouseUp, this);
29603 Roo.ButtonToggleMgr.register(this);
29605 this.el.addClass("x-btn-pressed");
29608 var repeater = new Roo.util.ClickRepeater(btn,
29609 typeof this.repeat == "object" ? this.repeat : {}
29611 repeater.on("click", this.onClick, this);
29614 this.fireEvent('render', this);
29618 * Returns the button's underlying element
29619 * @return {Roo.Element} The element
29621 getEl : function(){
29626 * Destroys this Button and removes any listeners.
29628 destroy : function(){
29629 Roo.ButtonToggleMgr.unregister(this);
29630 this.el.removeAllListeners();
29631 this.purgeListeners();
29636 autoWidth : function(){
29638 this.el.setWidth("auto");
29639 if(Roo.isIE7 && Roo.isStrict){
29640 var ib = this.el.child('button');
29641 if(ib && ib.getWidth() > 20){
29643 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29648 this.el.beginMeasure();
29650 if(this.el.getWidth() < this.minWidth){
29651 this.el.setWidth(this.minWidth);
29654 this.el.endMeasure();
29661 * Assigns this button's click handler
29662 * @param {Function} handler The function to call when the button is clicked
29663 * @param {Object} scope (optional) Scope for the function passed in
29665 setHandler : function(handler, scope){
29666 this.handler = handler;
29667 this.scope = scope;
29671 * Sets this button's text
29672 * @param {String} text The button text
29674 setText : function(text){
29677 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29683 * Gets the text for this button
29684 * @return {String} The button text
29686 getText : function(){
29694 this.hidden = false;
29696 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29704 this.hidden = true;
29706 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29711 * Convenience function for boolean show/hide
29712 * @param {Boolean} visible True to show, false to hide
29714 setVisible: function(visible){
29723 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29724 * @param {Boolean} state (optional) Force a particular state
29726 toggle : function(state){
29727 state = state === undefined ? !this.pressed : state;
29728 if(state != this.pressed){
29730 this.el.addClass("x-btn-pressed");
29731 this.pressed = true;
29732 this.fireEvent("toggle", this, true);
29734 this.el.removeClass("x-btn-pressed");
29735 this.pressed = false;
29736 this.fireEvent("toggle", this, false);
29738 if(this.toggleHandler){
29739 this.toggleHandler.call(this.scope || this, this, state);
29747 focus : function(){
29748 this.el.child('button:first').focus();
29752 * Disable this button
29754 disable : function(){
29756 this.el.addClass("x-btn-disabled");
29758 this.disabled = true;
29762 * Enable this button
29764 enable : function(){
29766 this.el.removeClass("x-btn-disabled");
29768 this.disabled = false;
29772 * Convenience function for boolean enable/disable
29773 * @param {Boolean} enabled True to enable, false to disable
29775 setDisabled : function(v){
29776 this[v !== true ? "enable" : "disable"]();
29780 onClick : function(e)
29783 e.preventDefault();
29788 if(!this.disabled){
29789 if(this.enableToggle){
29792 if(this.menu && !this.menu.isVisible()){
29793 this.menu.show(this.el, this.menuAlign);
29795 this.fireEvent("click", this, e);
29797 this.el.removeClass("x-btn-over");
29798 this.handler.call(this.scope || this, this, e);
29803 onMouseOver : function(e){
29804 if(!this.disabled){
29805 this.el.addClass("x-btn-over");
29806 this.fireEvent('mouseover', this, e);
29810 onMouseOut : function(e){
29811 if(!e.within(this.el, true)){
29812 this.el.removeClass("x-btn-over");
29813 this.fireEvent('mouseout', this, e);
29817 onFocus : function(e){
29818 if(!this.disabled){
29819 this.el.addClass("x-btn-focus");
29823 onBlur : function(e){
29824 this.el.removeClass("x-btn-focus");
29827 onMouseDown : function(e){
29828 if(!this.disabled && e.button == 0){
29829 this.el.addClass("x-btn-click");
29830 Roo.get(document).on('mouseup', this.onMouseUp, this);
29834 onMouseUp : function(e){
29836 this.el.removeClass("x-btn-click");
29837 Roo.get(document).un('mouseup', this.onMouseUp, this);
29841 onMenuShow : function(e){
29842 this.el.addClass("x-btn-menu-active");
29845 onMenuHide : function(e){
29846 this.el.removeClass("x-btn-menu-active");
29850 // Private utility class used by Button
29851 Roo.ButtonToggleMgr = function(){
29854 function toggleGroup(btn, state){
29856 var g = groups[btn.toggleGroup];
29857 for(var i = 0, l = g.length; i < l; i++){
29859 g[i].toggle(false);
29866 register : function(btn){
29867 if(!btn.toggleGroup){
29870 var g = groups[btn.toggleGroup];
29872 g = groups[btn.toggleGroup] = [];
29875 btn.on("toggle", toggleGroup);
29878 unregister : function(btn){
29879 if(!btn.toggleGroup){
29882 var g = groups[btn.toggleGroup];
29885 btn.un("toggle", toggleGroup);
29891 * Ext JS Library 1.1.1
29892 * Copyright(c) 2006-2007, Ext JS, LLC.
29894 * Originally Released Under LGPL - original licence link has changed is not relivant.
29897 * <script type="text/javascript">
29901 * @class Roo.SplitButton
29902 * @extends Roo.Button
29903 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29904 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29905 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29906 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29907 * @cfg {String} arrowTooltip The title attribute of the arrow
29909 * Create a new menu button
29910 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29911 * @param {Object} config The config object
29913 Roo.SplitButton = function(renderTo, config){
29914 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29916 * @event arrowclick
29917 * Fires when this button's arrow is clicked
29918 * @param {SplitButton} this
29919 * @param {EventObject} e The click event
29921 this.addEvents({"arrowclick":true});
29924 Roo.extend(Roo.SplitButton, Roo.Button, {
29925 render : function(renderTo){
29926 // this is one sweet looking template!
29927 var tpl = new Roo.Template(
29928 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29929 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29930 '<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>',
29931 "</tbody></table></td><td>",
29932 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29933 '<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>',
29934 "</tbody></table></td></tr></table>"
29936 var btn = tpl.append(renderTo, [this.text, this.type], true);
29937 var btnEl = btn.child("button");
29939 btn.addClass(this.cls);
29942 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29945 btnEl.addClass(this.iconCls);
29947 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29951 if(this.handleMouseEvents){
29952 btn.on("mouseover", this.onMouseOver, this);
29953 btn.on("mouseout", this.onMouseOut, this);
29954 btn.on("mousedown", this.onMouseDown, this);
29955 btn.on("mouseup", this.onMouseUp, this);
29957 btn.on(this.clickEvent, this.onClick, this);
29959 if(typeof this.tooltip == 'object'){
29960 Roo.QuickTips.tips(Roo.apply({
29964 btnEl.dom[this.tooltipType] = this.tooltip;
29967 if(this.arrowTooltip){
29968 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29977 this.el.addClass("x-btn-pressed");
29979 if(Roo.isIE && !Roo.isIE7){
29980 this.autoWidth.defer(1, this);
29985 this.menu.on("show", this.onMenuShow, this);
29986 this.menu.on("hide", this.onMenuHide, this);
29988 this.fireEvent('render', this);
29992 autoWidth : function(){
29994 var tbl = this.el.child("table:first");
29995 var tbl2 = this.el.child("table:last");
29996 this.el.setWidth("auto");
29997 tbl.setWidth("auto");
29998 if(Roo.isIE7 && Roo.isStrict){
29999 var ib = this.el.child('button:first');
30000 if(ib && ib.getWidth() > 20){
30002 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30007 this.el.beginMeasure();
30009 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
30010 tbl.setWidth(this.minWidth-tbl2.getWidth());
30013 this.el.endMeasure();
30016 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
30020 * Sets this button's click handler
30021 * @param {Function} handler The function to call when the button is clicked
30022 * @param {Object} scope (optional) Scope for the function passed above
30024 setHandler : function(handler, scope){
30025 this.handler = handler;
30026 this.scope = scope;
30030 * Sets this button's arrow click handler
30031 * @param {Function} handler The function to call when the arrow is clicked
30032 * @param {Object} scope (optional) Scope for the function passed above
30034 setArrowHandler : function(handler, scope){
30035 this.arrowHandler = handler;
30036 this.scope = scope;
30042 focus : function(){
30044 this.el.child("button:first").focus();
30049 onClick : function(e){
30050 e.preventDefault();
30051 if(!this.disabled){
30052 if(e.getTarget(".x-btn-menu-arrow-wrap")){
30053 if(this.menu && !this.menu.isVisible()){
30054 this.menu.show(this.el, this.menuAlign);
30056 this.fireEvent("arrowclick", this, e);
30057 if(this.arrowHandler){
30058 this.arrowHandler.call(this.scope || this, this, e);
30061 this.fireEvent("click", this, e);
30063 this.handler.call(this.scope || this, this, e);
30069 onMouseDown : function(e){
30070 if(!this.disabled){
30071 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30075 onMouseUp : function(e){
30076 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30081 // backwards compat
30082 Roo.MenuButton = Roo.SplitButton;/*
30084 * Ext JS Library 1.1.1
30085 * Copyright(c) 2006-2007, Ext JS, LLC.
30087 * Originally Released Under LGPL - original licence link has changed is not relivant.
30090 * <script type="text/javascript">
30094 * @class Roo.Toolbar
30095 * Basic Toolbar class.
30097 * Creates a new Toolbar
30098 * @param {Object} container The config object
30100 Roo.Toolbar = function(container, buttons, config)
30102 /// old consturctor format still supported..
30103 if(container instanceof Array){ // omit the container for later rendering
30104 buttons = container;
30108 if (typeof(container) == 'object' && container.xtype) {
30109 config = container;
30110 container = config.container;
30111 buttons = config.buttons || []; // not really - use items!!
30114 if (config && config.items) {
30115 xitems = config.items;
30116 delete config.items;
30118 Roo.apply(this, config);
30119 this.buttons = buttons;
30122 this.render(container);
30124 this.xitems = xitems;
30125 Roo.each(xitems, function(b) {
30131 Roo.Toolbar.prototype = {
30133 * @cfg {Array} items
30134 * array of button configs or elements to add (will be converted to a MixedCollection)
30138 * @cfg {String/HTMLElement/Element} container
30139 * The id or element that will contain the toolbar
30142 render : function(ct){
30143 this.el = Roo.get(ct);
30145 this.el.addClass(this.cls);
30147 // using a table allows for vertical alignment
30148 // 100% width is needed by Safari...
30149 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30150 this.tr = this.el.child("tr", true);
30152 this.items = new Roo.util.MixedCollection(false, function(o){
30153 return o.id || ("item" + (++autoId));
30156 this.add.apply(this, this.buttons);
30157 delete this.buttons;
30162 * Adds element(s) to the toolbar -- this function takes a variable number of
30163 * arguments of mixed type and adds them to the toolbar.
30164 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30166 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30167 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30168 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30169 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30170 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30171 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30172 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30173 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30174 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30176 * @param {Mixed} arg2
30177 * @param {Mixed} etc.
30180 var a = arguments, l = a.length;
30181 for(var i = 0; i < l; i++){
30186 _add : function(el) {
30189 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30192 if (el.applyTo){ // some kind of form field
30193 return this.addField(el);
30195 if (el.render){ // some kind of Toolbar.Item
30196 return this.addItem(el);
30198 if (typeof el == "string"){ // string
30199 if(el == "separator" || el == "-"){
30200 return this.addSeparator();
30203 return this.addSpacer();
30206 return this.addFill();
30208 return this.addText(el);
30211 if(el.tagName){ // element
30212 return this.addElement(el);
30214 if(typeof el == "object"){ // must be button config?
30215 return this.addButton(el);
30217 // and now what?!?!
30223 * Add an Xtype element
30224 * @param {Object} xtype Xtype Object
30225 * @return {Object} created Object
30227 addxtype : function(e){
30228 return this.add(e);
30232 * Returns the Element for this toolbar.
30233 * @return {Roo.Element}
30235 getEl : function(){
30241 * @return {Roo.Toolbar.Item} The separator item
30243 addSeparator : function(){
30244 return this.addItem(new Roo.Toolbar.Separator());
30248 * Adds a spacer element
30249 * @return {Roo.Toolbar.Spacer} The spacer item
30251 addSpacer : function(){
30252 return this.addItem(new Roo.Toolbar.Spacer());
30256 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30257 * @return {Roo.Toolbar.Fill} The fill item
30259 addFill : function(){
30260 return this.addItem(new Roo.Toolbar.Fill());
30264 * Adds any standard HTML element to the toolbar
30265 * @param {String/HTMLElement/Element} el The element or id of the element to add
30266 * @return {Roo.Toolbar.Item} The element's item
30268 addElement : function(el){
30269 return this.addItem(new Roo.Toolbar.Item(el));
30272 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30273 * @type Roo.util.MixedCollection
30278 * Adds any Toolbar.Item or subclass
30279 * @param {Roo.Toolbar.Item} item
30280 * @return {Roo.Toolbar.Item} The item
30282 addItem : function(item){
30283 var td = this.nextBlock();
30285 this.items.add(item);
30290 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30291 * @param {Object/Array} config A button config or array of configs
30292 * @return {Roo.Toolbar.Button/Array}
30294 addButton : function(config){
30295 if(config instanceof Array){
30297 for(var i = 0, len = config.length; i < len; i++) {
30298 buttons.push(this.addButton(config[i]));
30303 if(!(config instanceof Roo.Toolbar.Button)){
30305 new Roo.Toolbar.SplitButton(config) :
30306 new Roo.Toolbar.Button(config);
30308 var td = this.nextBlock();
30315 * Adds text to the toolbar
30316 * @param {String} text The text to add
30317 * @return {Roo.Toolbar.Item} The element's item
30319 addText : function(text){
30320 return this.addItem(new Roo.Toolbar.TextItem(text));
30324 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30325 * @param {Number} index The index where the item is to be inserted
30326 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30327 * @return {Roo.Toolbar.Button/Item}
30329 insertButton : function(index, item){
30330 if(item instanceof Array){
30332 for(var i = 0, len = item.length; i < len; i++) {
30333 buttons.push(this.insertButton(index + i, item[i]));
30337 if (!(item instanceof Roo.Toolbar.Button)){
30338 item = new Roo.Toolbar.Button(item);
30340 var td = document.createElement("td");
30341 this.tr.insertBefore(td, this.tr.childNodes[index]);
30343 this.items.insert(index, item);
30348 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30349 * @param {Object} config
30350 * @return {Roo.Toolbar.Item} The element's item
30352 addDom : function(config, returnEl){
30353 var td = this.nextBlock();
30354 Roo.DomHelper.overwrite(td, config);
30355 var ti = new Roo.Toolbar.Item(td.firstChild);
30357 this.items.add(ti);
30362 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30363 * @type Roo.util.MixedCollection
30368 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30369 * Note: the field should not have been rendered yet. For a field that has already been
30370 * rendered, use {@link #addElement}.
30371 * @param {Roo.form.Field} field
30372 * @return {Roo.ToolbarItem}
30376 addField : function(field) {
30377 if (!this.fields) {
30379 this.fields = new Roo.util.MixedCollection(false, function(o){
30380 return o.id || ("item" + (++autoId));
30385 var td = this.nextBlock();
30387 var ti = new Roo.Toolbar.Item(td.firstChild);
30389 this.items.add(ti);
30390 this.fields.add(field);
30401 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30402 this.el.child('div').hide();
30410 this.el.child('div').show();
30414 nextBlock : function(){
30415 var td = document.createElement("td");
30416 this.tr.appendChild(td);
30421 destroy : function(){
30422 if(this.items){ // rendered?
30423 Roo.destroy.apply(Roo, this.items.items);
30425 if(this.fields){ // rendered?
30426 Roo.destroy.apply(Roo, this.fields.items);
30428 Roo.Element.uncache(this.el, this.tr);
30433 * @class Roo.Toolbar.Item
30434 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30436 * Creates a new Item
30437 * @param {HTMLElement} el
30439 Roo.Toolbar.Item = function(el){
30441 if (typeof (el.xtype) != 'undefined') {
30446 this.el = Roo.getDom(el);
30447 this.id = Roo.id(this.el);
30448 this.hidden = false;
30453 * Fires when the button is rendered
30454 * @param {Button} this
30458 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30460 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30461 //Roo.Toolbar.Item.prototype = {
30464 * Get this item's HTML Element
30465 * @return {HTMLElement}
30467 getEl : function(){
30472 render : function(td){
30475 td.appendChild(this.el);
30477 this.fireEvent('render', this);
30481 * Removes and destroys this item.
30483 destroy : function(){
30484 this.td.parentNode.removeChild(this.td);
30491 this.hidden = false;
30492 this.td.style.display = "";
30499 this.hidden = true;
30500 this.td.style.display = "none";
30504 * Convenience function for boolean show/hide.
30505 * @param {Boolean} visible true to show/false to hide
30507 setVisible: function(visible){
30516 * Try to focus this item.
30518 focus : function(){
30519 Roo.fly(this.el).focus();
30523 * Disables this item.
30525 disable : function(){
30526 Roo.fly(this.td).addClass("x-item-disabled");
30527 this.disabled = true;
30528 this.el.disabled = true;
30532 * Enables this item.
30534 enable : function(){
30535 Roo.fly(this.td).removeClass("x-item-disabled");
30536 this.disabled = false;
30537 this.el.disabled = false;
30543 * @class Roo.Toolbar.Separator
30544 * @extends Roo.Toolbar.Item
30545 * A simple toolbar separator class
30547 * Creates a new Separator
30549 Roo.Toolbar.Separator = function(cfg){
30551 var s = document.createElement("span");
30552 s.className = "ytb-sep";
30557 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30559 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30560 enable:Roo.emptyFn,
30561 disable:Roo.emptyFn,
30566 * @class Roo.Toolbar.Spacer
30567 * @extends Roo.Toolbar.Item
30568 * A simple element that adds extra horizontal space to a toolbar.
30570 * Creates a new Spacer
30572 Roo.Toolbar.Spacer = function(cfg){
30573 var s = document.createElement("div");
30574 s.className = "ytb-spacer";
30578 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30580 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30581 enable:Roo.emptyFn,
30582 disable:Roo.emptyFn,
30587 * @class Roo.Toolbar.Fill
30588 * @extends Roo.Toolbar.Spacer
30589 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30591 * Creates a new Spacer
30593 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30595 render : function(td){
30596 td.style.width = '100%';
30597 Roo.Toolbar.Fill.superclass.render.call(this, td);
30602 * @class Roo.Toolbar.TextItem
30603 * @extends Roo.Toolbar.Item
30604 * A simple class that renders text directly into a toolbar.
30606 * Creates a new TextItem
30607 * @cfg {string} text
30609 Roo.Toolbar.TextItem = function(cfg){
30610 var text = cfg || "";
30611 if (typeof(cfg) == 'object') {
30612 text = cfg.text || "";
30616 var s = document.createElement("span");
30617 s.className = "ytb-text";
30618 s.innerHTML = text;
30623 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30625 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30628 enable:Roo.emptyFn,
30629 disable:Roo.emptyFn,
30634 * @class Roo.Toolbar.Button
30635 * @extends Roo.Button
30636 * A button that renders into a toolbar.
30638 * Creates a new Button
30639 * @param {Object} config A standard {@link Roo.Button} config object
30641 Roo.Toolbar.Button = function(config){
30642 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30644 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30645 render : function(td){
30647 Roo.Toolbar.Button.superclass.render.call(this, td);
30651 * Removes and destroys this button
30653 destroy : function(){
30654 Roo.Toolbar.Button.superclass.destroy.call(this);
30655 this.td.parentNode.removeChild(this.td);
30659 * Shows this button
30662 this.hidden = false;
30663 this.td.style.display = "";
30667 * Hides this button
30670 this.hidden = true;
30671 this.td.style.display = "none";
30675 * Disables this item
30677 disable : function(){
30678 Roo.fly(this.td).addClass("x-item-disabled");
30679 this.disabled = true;
30683 * Enables this item
30685 enable : function(){
30686 Roo.fly(this.td).removeClass("x-item-disabled");
30687 this.disabled = false;
30690 // backwards compat
30691 Roo.ToolbarButton = Roo.Toolbar.Button;
30694 * @class Roo.Toolbar.SplitButton
30695 * @extends Roo.SplitButton
30696 * A menu button that renders into a toolbar.
30698 * Creates a new SplitButton
30699 * @param {Object} config A standard {@link Roo.SplitButton} config object
30701 Roo.Toolbar.SplitButton = function(config){
30702 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30704 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30705 render : function(td){
30707 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30711 * Removes and destroys this button
30713 destroy : function(){
30714 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30715 this.td.parentNode.removeChild(this.td);
30719 * Shows this button
30722 this.hidden = false;
30723 this.td.style.display = "";
30727 * Hides this button
30730 this.hidden = true;
30731 this.td.style.display = "none";
30735 // backwards compat
30736 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30738 * Ext JS Library 1.1.1
30739 * Copyright(c) 2006-2007, Ext JS, LLC.
30741 * Originally Released Under LGPL - original licence link has changed is not relivant.
30744 * <script type="text/javascript">
30748 * @class Roo.PagingToolbar
30749 * @extends Roo.Toolbar
30750 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30752 * Create a new PagingToolbar
30753 * @param {Object} config The config object
30755 Roo.PagingToolbar = function(el, ds, config)
30757 // old args format still supported... - xtype is prefered..
30758 if (typeof(el) == 'object' && el.xtype) {
30759 // created from xtype...
30761 ds = el.dataSource;
30762 el = config.container;
30765 if (config.items) {
30766 items = config.items;
30770 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30773 this.renderButtons(this.el);
30776 // supprot items array.
30778 Roo.each(items, function(e) {
30779 this.add(Roo.factory(e));
30784 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30786 * @cfg {Roo.data.Store} dataSource
30787 * The underlying data store providing the paged data
30790 * @cfg {String/HTMLElement/Element} container
30791 * container The id or element that will contain the toolbar
30794 * @cfg {Boolean} displayInfo
30795 * True to display the displayMsg (defaults to false)
30798 * @cfg {Number} pageSize
30799 * The number of records to display per page (defaults to 20)
30803 * @cfg {String} displayMsg
30804 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30806 displayMsg : 'Displaying {0} - {1} of {2}',
30808 * @cfg {String} emptyMsg
30809 * The message to display when no records are found (defaults to "No data to display")
30811 emptyMsg : 'No data to display',
30813 * Customizable piece of the default paging text (defaults to "Page")
30816 beforePageText : "Page",
30818 * Customizable piece of the default paging text (defaults to "of %0")
30821 afterPageText : "of {0}",
30823 * Customizable piece of the default paging text (defaults to "First Page")
30826 firstText : "First Page",
30828 * Customizable piece of the default paging text (defaults to "Previous Page")
30831 prevText : "Previous Page",
30833 * Customizable piece of the default paging text (defaults to "Next Page")
30836 nextText : "Next Page",
30838 * Customizable piece of the default paging text (defaults to "Last Page")
30841 lastText : "Last Page",
30843 * Customizable piece of the default paging text (defaults to "Refresh")
30846 refreshText : "Refresh",
30849 renderButtons : function(el){
30850 Roo.PagingToolbar.superclass.render.call(this, el);
30851 this.first = this.addButton({
30852 tooltip: this.firstText,
30853 cls: "x-btn-icon x-grid-page-first",
30855 handler: this.onClick.createDelegate(this, ["first"])
30857 this.prev = this.addButton({
30858 tooltip: this.prevText,
30859 cls: "x-btn-icon x-grid-page-prev",
30861 handler: this.onClick.createDelegate(this, ["prev"])
30863 //this.addSeparator();
30864 this.add(this.beforePageText);
30865 this.field = Roo.get(this.addDom({
30870 cls: "x-grid-page-number"
30872 this.field.on("keydown", this.onPagingKeydown, this);
30873 this.field.on("focus", function(){this.dom.select();});
30874 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30875 this.field.setHeight(18);
30876 //this.addSeparator();
30877 this.next = this.addButton({
30878 tooltip: this.nextText,
30879 cls: "x-btn-icon x-grid-page-next",
30881 handler: this.onClick.createDelegate(this, ["next"])
30883 this.last = this.addButton({
30884 tooltip: this.lastText,
30885 cls: "x-btn-icon x-grid-page-last",
30887 handler: this.onClick.createDelegate(this, ["last"])
30889 //this.addSeparator();
30890 this.loading = this.addButton({
30891 tooltip: this.refreshText,
30892 cls: "x-btn-icon x-grid-loading",
30893 handler: this.onClick.createDelegate(this, ["refresh"])
30896 if(this.displayInfo){
30897 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30902 updateInfo : function(){
30903 if(this.displayEl){
30904 var count = this.ds.getCount();
30905 var msg = count == 0 ?
30909 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30911 this.displayEl.update(msg);
30916 onLoad : function(ds, r, o){
30917 this.cursor = o.params ? o.params.start : 0;
30918 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30920 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30921 this.field.dom.value = ap;
30922 this.first.setDisabled(ap == 1);
30923 this.prev.setDisabled(ap == 1);
30924 this.next.setDisabled(ap == ps);
30925 this.last.setDisabled(ap == ps);
30926 this.loading.enable();
30931 getPageData : function(){
30932 var total = this.ds.getTotalCount();
30935 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30936 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30941 onLoadError : function(){
30942 this.loading.enable();
30946 onPagingKeydown : function(e){
30947 var k = e.getKey();
30948 var d = this.getPageData();
30950 var v = this.field.dom.value, pageNum;
30951 if(!v || isNaN(pageNum = parseInt(v, 10))){
30952 this.field.dom.value = d.activePage;
30955 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30956 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30959 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))
30961 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30962 this.field.dom.value = pageNum;
30963 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30966 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30968 var v = this.field.dom.value, pageNum;
30969 var increment = (e.shiftKey) ? 10 : 1;
30970 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30973 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30974 this.field.dom.value = d.activePage;
30977 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30979 this.field.dom.value = parseInt(v, 10) + increment;
30980 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30981 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30988 beforeLoad : function(){
30990 this.loading.disable();
30995 onClick : function(which){
30999 ds.load({params:{start: 0, limit: this.pageSize}});
31002 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
31005 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
31008 var total = ds.getTotalCount();
31009 var extra = total % this.pageSize;
31010 var lastStart = extra ? (total - extra) : total-this.pageSize;
31011 ds.load({params:{start: lastStart, limit: this.pageSize}});
31014 ds.load({params:{start: this.cursor, limit: this.pageSize}});
31020 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
31021 * @param {Roo.data.Store} store The data store to unbind
31023 unbind : function(ds){
31024 ds.un("beforeload", this.beforeLoad, this);
31025 ds.un("load", this.onLoad, this);
31026 ds.un("loadexception", this.onLoadError, this);
31027 ds.un("remove", this.updateInfo, this);
31028 ds.un("add", this.updateInfo, this);
31029 this.ds = undefined;
31033 * Binds the paging toolbar to the specified {@link Roo.data.Store}
31034 * @param {Roo.data.Store} store The data store to bind
31036 bind : function(ds){
31037 ds.on("beforeload", this.beforeLoad, this);
31038 ds.on("load", this.onLoad, this);
31039 ds.on("loadexception", this.onLoadError, this);
31040 ds.on("remove", this.updateInfo, this);
31041 ds.on("add", this.updateInfo, this);
31046 * Ext JS Library 1.1.1
31047 * Copyright(c) 2006-2007, Ext JS, LLC.
31049 * Originally Released Under LGPL - original licence link has changed is not relivant.
31052 * <script type="text/javascript">
31056 * @class Roo.Resizable
31057 * @extends Roo.util.Observable
31058 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
31059 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
31060 * 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
31061 * the element will be wrapped for you automatically.</p>
31062 * <p>Here is the list of valid resize handles:</p>
31065 ------ -------------------
31074 'hd' horizontal drag
31077 * <p>Here's an example showing the creation of a typical Resizable:</p>
31079 var resizer = new Roo.Resizable("element-id", {
31087 resizer.on("resize", myHandler);
31089 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31090 * resizer.east.setDisplayed(false);</p>
31091 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31092 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31093 * resize operation's new size (defaults to [0, 0])
31094 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31095 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31096 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31097 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31098 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31099 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31100 * @cfg {Number} width The width of the element in pixels (defaults to null)
31101 * @cfg {Number} height The height of the element in pixels (defaults to null)
31102 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31103 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31104 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31105 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31106 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31107 * in favor of the handles config option (defaults to false)
31108 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31109 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31110 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31111 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31112 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31113 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31114 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31115 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31116 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31117 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31118 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31120 * Create a new resizable component
31121 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31122 * @param {Object} config configuration options
31124 Roo.Resizable = function(el, config)
31126 this.el = Roo.get(el);
31128 if(config && config.wrap){
31129 config.resizeChild = this.el;
31130 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31131 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31132 this.el.setStyle("overflow", "hidden");
31133 this.el.setPositioning(config.resizeChild.getPositioning());
31134 config.resizeChild.clearPositioning();
31135 if(!config.width || !config.height){
31136 var csize = config.resizeChild.getSize();
31137 this.el.setSize(csize.width, csize.height);
31139 if(config.pinned && !config.adjustments){
31140 config.adjustments = "auto";
31144 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31145 this.proxy.unselectable();
31146 this.proxy.enableDisplayMode('block');
31148 Roo.apply(this, config);
31151 this.disableTrackOver = true;
31152 this.el.addClass("x-resizable-pinned");
31154 // if the element isn't positioned, make it relative
31155 var position = this.el.getStyle("position");
31156 if(position != "absolute" && position != "fixed"){
31157 this.el.setStyle("position", "relative");
31159 if(!this.handles){ // no handles passed, must be legacy style
31160 this.handles = 's,e,se';
31161 if(this.multiDirectional){
31162 this.handles += ',n,w';
31165 if(this.handles == "all"){
31166 this.handles = "n s e w ne nw se sw";
31168 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31169 var ps = Roo.Resizable.positions;
31170 for(var i = 0, len = hs.length; i < len; i++){
31171 if(hs[i] && ps[hs[i]]){
31172 var pos = ps[hs[i]];
31173 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31177 this.corner = this.southeast;
31179 // updateBox = the box can move..
31180 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31181 this.updateBox = true;
31184 this.activeHandle = null;
31186 if(this.resizeChild){
31187 if(typeof this.resizeChild == "boolean"){
31188 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31190 this.resizeChild = Roo.get(this.resizeChild, true);
31194 if(this.adjustments == "auto"){
31195 var rc = this.resizeChild;
31196 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31197 if(rc && (hw || hn)){
31198 rc.position("relative");
31199 rc.setLeft(hw ? hw.el.getWidth() : 0);
31200 rc.setTop(hn ? hn.el.getHeight() : 0);
31202 this.adjustments = [
31203 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31204 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31208 if(this.draggable){
31209 this.dd = this.dynamic ?
31210 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31211 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31217 * @event beforeresize
31218 * Fired before resize is allowed. Set enabled to false to cancel resize.
31219 * @param {Roo.Resizable} this
31220 * @param {Roo.EventObject} e The mousedown event
31222 "beforeresize" : true,
31225 * Fired a resizing.
31226 * @param {Roo.Resizable} this
31227 * @param {Number} x The new x position
31228 * @param {Number} y The new y position
31229 * @param {Number} w The new w width
31230 * @param {Number} h The new h hight
31231 * @param {Roo.EventObject} e The mouseup event
31236 * Fired after a resize.
31237 * @param {Roo.Resizable} this
31238 * @param {Number} width The new width
31239 * @param {Number} height The new height
31240 * @param {Roo.EventObject} e The mouseup event
31245 if(this.width !== null && this.height !== null){
31246 this.resizeTo(this.width, this.height);
31248 this.updateChildSize();
31251 this.el.dom.style.zoom = 1;
31253 Roo.Resizable.superclass.constructor.call(this);
31256 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31257 resizeChild : false,
31258 adjustments : [0, 0],
31268 multiDirectional : false,
31269 disableTrackOver : false,
31270 easing : 'easeOutStrong',
31271 widthIncrement : 0,
31272 heightIncrement : 0,
31276 preserveRatio : false,
31277 transparent: false,
31283 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31285 constrainTo: undefined,
31287 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31289 resizeRegion: undefined,
31293 * Perform a manual resize
31294 * @param {Number} width
31295 * @param {Number} height
31297 resizeTo : function(width, height){
31298 this.el.setSize(width, height);
31299 this.updateChildSize();
31300 this.fireEvent("resize", this, width, height, null);
31304 startSizing : function(e, handle){
31305 this.fireEvent("beforeresize", this, e);
31306 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31309 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31310 this.overlay.unselectable();
31311 this.overlay.enableDisplayMode("block");
31312 this.overlay.on("mousemove", this.onMouseMove, this);
31313 this.overlay.on("mouseup", this.onMouseUp, this);
31315 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31317 this.resizing = true;
31318 this.startBox = this.el.getBox();
31319 this.startPoint = e.getXY();
31320 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31321 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31323 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31324 this.overlay.show();
31326 if(this.constrainTo) {
31327 var ct = Roo.get(this.constrainTo);
31328 this.resizeRegion = ct.getRegion().adjust(
31329 ct.getFrameWidth('t'),
31330 ct.getFrameWidth('l'),
31331 -ct.getFrameWidth('b'),
31332 -ct.getFrameWidth('r')
31336 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31338 this.proxy.setBox(this.startBox);
31340 this.proxy.setStyle('visibility', 'visible');
31346 onMouseDown : function(handle, e){
31349 this.activeHandle = handle;
31350 this.startSizing(e, handle);
31355 onMouseUp : function(e){
31356 var size = this.resizeElement();
31357 this.resizing = false;
31359 this.overlay.hide();
31361 this.fireEvent("resize", this, size.width, size.height, e);
31365 updateChildSize : function(){
31367 if(this.resizeChild){
31369 var child = this.resizeChild;
31370 var adj = this.adjustments;
31371 if(el.dom.offsetWidth){
31372 var b = el.getSize(true);
31373 child.setSize(b.width+adj[0], b.height+adj[1]);
31375 // Second call here for IE
31376 // The first call enables instant resizing and
31377 // the second call corrects scroll bars if they
31380 setTimeout(function(){
31381 if(el.dom.offsetWidth){
31382 var b = el.getSize(true);
31383 child.setSize(b.width+adj[0], b.height+adj[1]);
31391 snap : function(value, inc, min){
31392 if(!inc || !value) {
31395 var newValue = value;
31396 var m = value % inc;
31399 newValue = value + (inc-m);
31401 newValue = value - m;
31404 return Math.max(min, newValue);
31408 resizeElement : function(){
31409 var box = this.proxy.getBox();
31410 if(this.updateBox){
31411 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31413 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31415 this.updateChildSize();
31423 constrain : function(v, diff, m, mx){
31426 }else if(v - diff > mx){
31433 onMouseMove : function(e){
31436 try{// try catch so if something goes wrong the user doesn't get hung
31438 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31442 //var curXY = this.startPoint;
31443 var curSize = this.curSize || this.startBox;
31444 var x = this.startBox.x, y = this.startBox.y;
31445 var ox = x, oy = y;
31446 var w = curSize.width, h = curSize.height;
31447 var ow = w, oh = h;
31448 var mw = this.minWidth, mh = this.minHeight;
31449 var mxw = this.maxWidth, mxh = this.maxHeight;
31450 var wi = this.widthIncrement;
31451 var hi = this.heightIncrement;
31453 var eventXY = e.getXY();
31454 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31455 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31457 var pos = this.activeHandle.position;
31462 w = Math.min(Math.max(mw, w), mxw);
31467 h = Math.min(Math.max(mh, h), mxh);
31472 w = Math.min(Math.max(mw, w), mxw);
31473 h = Math.min(Math.max(mh, h), mxh);
31476 diffY = this.constrain(h, diffY, mh, mxh);
31483 var adiffX = Math.abs(diffX);
31484 var sub = (adiffX % wi); // how much
31485 if (sub > (wi/2)) { // far enough to snap
31486 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31488 // remove difference..
31489 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31493 x = Math.max(this.minX, x);
31496 diffX = this.constrain(w, diffX, mw, mxw);
31502 w = Math.min(Math.max(mw, w), mxw);
31503 diffY = this.constrain(h, diffY, mh, mxh);
31508 diffX = this.constrain(w, diffX, mw, mxw);
31509 diffY = this.constrain(h, diffY, mh, mxh);
31516 diffX = this.constrain(w, diffX, mw, mxw);
31518 h = Math.min(Math.max(mh, h), mxh);
31524 var sw = this.snap(w, wi, mw);
31525 var sh = this.snap(h, hi, mh);
31526 if(sw != w || sh != h){
31549 if(this.preserveRatio){
31554 h = Math.min(Math.max(mh, h), mxh);
31559 w = Math.min(Math.max(mw, w), mxw);
31564 w = Math.min(Math.max(mw, w), mxw);
31570 w = Math.min(Math.max(mw, w), mxw);
31576 h = Math.min(Math.max(mh, h), mxh);
31584 h = Math.min(Math.max(mh, h), mxh);
31594 h = Math.min(Math.max(mh, h), mxh);
31602 if (pos == 'hdrag') {
31605 this.proxy.setBounds(x, y, w, h);
31607 this.resizeElement();
31611 this.fireEvent("resizing", this, x, y, w, h, e);
31615 handleOver : function(){
31617 this.el.addClass("x-resizable-over");
31622 handleOut : function(){
31623 if(!this.resizing){
31624 this.el.removeClass("x-resizable-over");
31629 * Returns the element this component is bound to.
31630 * @return {Roo.Element}
31632 getEl : function(){
31637 * Returns the resizeChild element (or null).
31638 * @return {Roo.Element}
31640 getResizeChild : function(){
31641 return this.resizeChild;
31643 groupHandler : function()
31648 * Destroys this resizable. If the element was wrapped and
31649 * removeEl is not true then the element remains.
31650 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31652 destroy : function(removeEl){
31653 this.proxy.remove();
31655 this.overlay.removeAllListeners();
31656 this.overlay.remove();
31658 var ps = Roo.Resizable.positions;
31660 if(typeof ps[k] != "function" && this[ps[k]]){
31661 var h = this[ps[k]];
31662 h.el.removeAllListeners();
31667 this.el.update("");
31674 // hash to map config positions to true positions
31675 Roo.Resizable.positions = {
31676 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31681 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31683 // only initialize the template if resizable is used
31684 var tpl = Roo.DomHelper.createTemplate(
31685 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31688 Roo.Resizable.Handle.prototype.tpl = tpl;
31690 this.position = pos;
31692 // show north drag fro topdra
31693 var handlepos = pos == 'hdrag' ? 'north' : pos;
31695 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31696 if (pos == 'hdrag') {
31697 this.el.setStyle('cursor', 'pointer');
31699 this.el.unselectable();
31701 this.el.setOpacity(0);
31703 this.el.on("mousedown", this.onMouseDown, this);
31704 if(!disableTrackOver){
31705 this.el.on("mouseover", this.onMouseOver, this);
31706 this.el.on("mouseout", this.onMouseOut, this);
31711 Roo.Resizable.Handle.prototype = {
31712 afterResize : function(rz){
31717 onMouseDown : function(e){
31718 this.rz.onMouseDown(this, e);
31721 onMouseOver : function(e){
31722 this.rz.handleOver(this, e);
31725 onMouseOut : function(e){
31726 this.rz.handleOut(this, e);
31730 * Ext JS Library 1.1.1
31731 * Copyright(c) 2006-2007, Ext JS, LLC.
31733 * Originally Released Under LGPL - original licence link has changed is not relivant.
31736 * <script type="text/javascript">
31740 * @class Roo.Editor
31741 * @extends Roo.Component
31742 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31744 * Create a new Editor
31745 * @param {Roo.form.Field} field The Field object (or descendant)
31746 * @param {Object} config The config object
31748 Roo.Editor = function(field, config){
31749 Roo.Editor.superclass.constructor.call(this, config);
31750 this.field = field;
31753 * @event beforestartedit
31754 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31755 * false from the handler of this event.
31756 * @param {Editor} this
31757 * @param {Roo.Element} boundEl The underlying element bound to this editor
31758 * @param {Mixed} value The field value being set
31760 "beforestartedit" : true,
31763 * Fires when this editor is displayed
31764 * @param {Roo.Element} boundEl The underlying element bound to this editor
31765 * @param {Mixed} value The starting field value
31767 "startedit" : true,
31769 * @event beforecomplete
31770 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31771 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31772 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31773 * event will not fire since no edit actually occurred.
31774 * @param {Editor} this
31775 * @param {Mixed} value The current field value
31776 * @param {Mixed} startValue The original field value
31778 "beforecomplete" : true,
31781 * Fires after editing is complete and any changed value has been written to the underlying field.
31782 * @param {Editor} this
31783 * @param {Mixed} value The current field value
31784 * @param {Mixed} startValue The original field value
31788 * @event specialkey
31789 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31790 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31791 * @param {Roo.form.Field} this
31792 * @param {Roo.EventObject} e The event object
31794 "specialkey" : true
31798 Roo.extend(Roo.Editor, Roo.Component, {
31800 * @cfg {Boolean/String} autosize
31801 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31802 * or "height" to adopt the height only (defaults to false)
31805 * @cfg {Boolean} revertInvalid
31806 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31807 * validation fails (defaults to true)
31810 * @cfg {Boolean} ignoreNoChange
31811 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31812 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31813 * will never be ignored.
31816 * @cfg {Boolean} hideEl
31817 * False to keep the bound element visible while the editor is displayed (defaults to true)
31820 * @cfg {Mixed} value
31821 * The data value of the underlying field (defaults to "")
31825 * @cfg {String} alignment
31826 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31830 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31831 * for bottom-right shadow (defaults to "frame")
31835 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31839 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31841 completeOnEnter : false,
31843 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31845 cancelOnEsc : false,
31847 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31852 onRender : function(ct, position){
31853 this.el = new Roo.Layer({
31854 shadow: this.shadow,
31860 constrain: this.constrain
31862 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31863 if(this.field.msgTarget != 'title'){
31864 this.field.msgTarget = 'qtip';
31866 this.field.render(this.el);
31868 this.field.el.dom.setAttribute('autocomplete', 'off');
31870 this.field.on("specialkey", this.onSpecialKey, this);
31871 if(this.swallowKeys){
31872 this.field.el.swallowEvent(['keydown','keypress']);
31875 this.field.on("blur", this.onBlur, this);
31876 if(this.field.grow){
31877 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31881 onSpecialKey : function(field, e)
31883 //Roo.log('editor onSpecialKey');
31884 if(this.completeOnEnter && e.getKey() == e.ENTER){
31886 this.completeEdit();
31889 // do not fire special key otherwise it might hide close the editor...
31890 if(e.getKey() == e.ENTER){
31893 if(this.cancelOnEsc && e.getKey() == e.ESC){
31897 this.fireEvent('specialkey', field, e);
31902 * Starts the editing process and shows the editor.
31903 * @param {String/HTMLElement/Element} el The element to edit
31904 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31905 * to the innerHTML of el.
31907 startEdit : function(el, value){
31909 this.completeEdit();
31911 this.boundEl = Roo.get(el);
31912 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31913 if(!this.rendered){
31914 this.render(this.parentEl || document.body);
31916 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31919 this.startValue = v;
31920 this.field.setValue(v);
31922 var sz = this.boundEl.getSize();
31923 switch(this.autoSize){
31925 this.setSize(sz.width, "");
31928 this.setSize("", sz.height);
31931 this.setSize(sz.width, sz.height);
31934 this.el.alignTo(this.boundEl, this.alignment);
31935 this.editing = true;
31937 Roo.QuickTips.disable();
31943 * Sets the height and width of this editor.
31944 * @param {Number} width The new width
31945 * @param {Number} height The new height
31947 setSize : function(w, h){
31948 this.field.setSize(w, h);
31955 * Realigns the editor to the bound field based on the current alignment config value.
31957 realign : function(){
31958 this.el.alignTo(this.boundEl, this.alignment);
31962 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31963 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31965 completeEdit : function(remainVisible){
31969 var v = this.getValue();
31970 if(this.revertInvalid !== false && !this.field.isValid()){
31971 v = this.startValue;
31972 this.cancelEdit(true);
31974 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31975 this.editing = false;
31979 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31980 this.editing = false;
31981 if(this.updateEl && this.boundEl){
31982 this.boundEl.update(v);
31984 if(remainVisible !== true){
31987 this.fireEvent("complete", this, v, this.startValue);
31992 onShow : function(){
31994 if(this.hideEl !== false){
31995 this.boundEl.hide();
31998 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31999 this.fixIEFocus = true;
32000 this.deferredFocus.defer(50, this);
32002 this.field.focus();
32004 this.fireEvent("startedit", this.boundEl, this.startValue);
32007 deferredFocus : function(){
32009 this.field.focus();
32014 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
32015 * reverted to the original starting value.
32016 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
32017 * cancel (defaults to false)
32019 cancelEdit : function(remainVisible){
32021 this.setValue(this.startValue);
32022 if(remainVisible !== true){
32029 onBlur : function(){
32030 if(this.allowBlur !== true && this.editing){
32031 this.completeEdit();
32036 onHide : function(){
32038 this.completeEdit();
32042 if(this.field.collapse){
32043 this.field.collapse();
32046 if(this.hideEl !== false){
32047 this.boundEl.show();
32050 Roo.QuickTips.enable();
32055 * Sets the data value of the editor
32056 * @param {Mixed} value Any valid value supported by the underlying field
32058 setValue : function(v){
32059 this.field.setValue(v);
32063 * Gets the data value of the editor
32064 * @return {Mixed} The data value
32066 getValue : function(){
32067 return this.field.getValue();
32071 * Ext JS Library 1.1.1
32072 * Copyright(c) 2006-2007, Ext JS, LLC.
32074 * Originally Released Under LGPL - original licence link has changed is not relivant.
32077 * <script type="text/javascript">
32081 * @class Roo.BasicDialog
32082 * @extends Roo.util.Observable
32083 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32085 var dlg = new Roo.BasicDialog("my-dlg", {
32094 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32095 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32096 dlg.addButton('Cancel', dlg.hide, dlg);
32099 <b>A Dialog should always be a direct child of the body element.</b>
32100 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32101 * @cfg {String} title Default text to display in the title bar (defaults to null)
32102 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32103 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32104 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32105 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32106 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32107 * (defaults to null with no animation)
32108 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32109 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32110 * property for valid values (defaults to 'all')
32111 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32112 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32113 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32114 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32115 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32116 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32117 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32118 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32119 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32120 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32121 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32122 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32123 * draggable = true (defaults to false)
32124 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32125 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32126 * shadow (defaults to false)
32127 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32128 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32129 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32130 * @cfg {Array} buttons Array of buttons
32131 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32133 * Create a new BasicDialog.
32134 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32135 * @param {Object} config Configuration options
32137 Roo.BasicDialog = function(el, config){
32138 this.el = Roo.get(el);
32139 var dh = Roo.DomHelper;
32140 if(!this.el && config && config.autoCreate){
32141 if(typeof config.autoCreate == "object"){
32142 if(!config.autoCreate.id){
32143 config.autoCreate.id = el;
32145 this.el = dh.append(document.body,
32146 config.autoCreate, true);
32148 this.el = dh.append(document.body,
32149 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32153 el.setDisplayed(true);
32154 el.hide = this.hideAction;
32156 el.addClass("x-dlg");
32158 Roo.apply(this, config);
32160 this.proxy = el.createProxy("x-dlg-proxy");
32161 this.proxy.hide = this.hideAction;
32162 this.proxy.setOpacity(.5);
32166 el.setWidth(config.width);
32169 el.setHeight(config.height);
32171 this.size = el.getSize();
32172 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32173 this.xy = [config.x,config.y];
32175 this.xy = el.getCenterXY(true);
32177 /** The header element @type Roo.Element */
32178 this.header = el.child("> .x-dlg-hd");
32179 /** The body element @type Roo.Element */
32180 this.body = el.child("> .x-dlg-bd");
32181 /** The footer element @type Roo.Element */
32182 this.footer = el.child("> .x-dlg-ft");
32185 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32188 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32191 this.header.unselectable();
32193 this.header.update(this.title);
32195 // this element allows the dialog to be focused for keyboard event
32196 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32197 this.focusEl.swallowEvent("click", true);
32199 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32201 // wrap the body and footer for special rendering
32202 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32204 this.bwrap.dom.appendChild(this.footer.dom);
32207 this.bg = this.el.createChild({
32208 tag: "div", cls:"x-dlg-bg",
32209 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32211 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32214 if(this.autoScroll !== false && !this.autoTabs){
32215 this.body.setStyle("overflow", "auto");
32218 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32220 if(this.closable !== false){
32221 this.el.addClass("x-dlg-closable");
32222 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32223 this.close.on("click", this.closeClick, this);
32224 this.close.addClassOnOver("x-dlg-close-over");
32226 if(this.collapsible !== false){
32227 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32228 this.collapseBtn.on("click", this.collapseClick, this);
32229 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32230 this.header.on("dblclick", this.collapseClick, this);
32232 if(this.resizable !== false){
32233 this.el.addClass("x-dlg-resizable");
32234 this.resizer = new Roo.Resizable(el, {
32235 minWidth: this.minWidth || 80,
32236 minHeight:this.minHeight || 80,
32237 handles: this.resizeHandles || "all",
32240 this.resizer.on("beforeresize", this.beforeResize, this);
32241 this.resizer.on("resize", this.onResize, this);
32243 if(this.draggable !== false){
32244 el.addClass("x-dlg-draggable");
32245 if (!this.proxyDrag) {
32246 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32249 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32251 dd.setHandleElId(this.header.id);
32252 dd.endDrag = this.endMove.createDelegate(this);
32253 dd.startDrag = this.startMove.createDelegate(this);
32254 dd.onDrag = this.onDrag.createDelegate(this);
32259 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32260 this.mask.enableDisplayMode("block");
32262 this.el.addClass("x-dlg-modal");
32265 this.shadow = new Roo.Shadow({
32266 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32267 offset : this.shadowOffset
32270 this.shadowOffset = 0;
32272 if(Roo.useShims && this.shim !== false){
32273 this.shim = this.el.createShim();
32274 this.shim.hide = this.hideAction;
32282 if (this.buttons) {
32283 var bts= this.buttons;
32285 Roo.each(bts, function(b) {
32294 * Fires when a key is pressed
32295 * @param {Roo.BasicDialog} this
32296 * @param {Roo.EventObject} e
32301 * Fires when this dialog is moved by the user.
32302 * @param {Roo.BasicDialog} this
32303 * @param {Number} x The new page X
32304 * @param {Number} y The new page Y
32309 * Fires when this dialog is resized by the user.
32310 * @param {Roo.BasicDialog} this
32311 * @param {Number} width The new width
32312 * @param {Number} height The new height
32316 * @event beforehide
32317 * Fires before this dialog is hidden.
32318 * @param {Roo.BasicDialog} this
32320 "beforehide" : true,
32323 * Fires when this dialog is hidden.
32324 * @param {Roo.BasicDialog} this
32328 * @event beforeshow
32329 * Fires before this dialog is shown.
32330 * @param {Roo.BasicDialog} this
32332 "beforeshow" : true,
32335 * Fires when this dialog is shown.
32336 * @param {Roo.BasicDialog} this
32340 el.on("keydown", this.onKeyDown, this);
32341 el.on("mousedown", this.toFront, this);
32342 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32344 Roo.DialogManager.register(this);
32345 Roo.BasicDialog.superclass.constructor.call(this);
32348 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32349 shadowOffset: Roo.isIE ? 6 : 5,
32352 minButtonWidth: 75,
32353 defaultButton: null,
32354 buttonAlign: "right",
32359 * Sets the dialog title text
32360 * @param {String} text The title text to display
32361 * @return {Roo.BasicDialog} this
32363 setTitle : function(text){
32364 this.header.update(text);
32369 closeClick : function(){
32374 collapseClick : function(){
32375 this[this.collapsed ? "expand" : "collapse"]();
32379 * Collapses the dialog to its minimized state (only the title bar is visible).
32380 * Equivalent to the user clicking the collapse dialog button.
32382 collapse : function(){
32383 if(!this.collapsed){
32384 this.collapsed = true;
32385 this.el.addClass("x-dlg-collapsed");
32386 this.restoreHeight = this.el.getHeight();
32387 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32392 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32393 * clicking the expand dialog button.
32395 expand : function(){
32396 if(this.collapsed){
32397 this.collapsed = false;
32398 this.el.removeClass("x-dlg-collapsed");
32399 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32404 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32405 * @return {Roo.TabPanel} The tabs component
32407 initTabs : function(){
32408 var tabs = this.getTabs();
32409 while(tabs.getTab(0)){
32412 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32414 tabs.addTab(Roo.id(dom), dom.title);
32422 beforeResize : function(){
32423 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32427 onResize : function(){
32428 this.refreshSize();
32429 this.syncBodyHeight();
32430 this.adjustAssets();
32432 this.fireEvent("resize", this, this.size.width, this.size.height);
32436 onKeyDown : function(e){
32437 if(this.isVisible()){
32438 this.fireEvent("keydown", this, e);
32443 * Resizes the dialog.
32444 * @param {Number} width
32445 * @param {Number} height
32446 * @return {Roo.BasicDialog} this
32448 resizeTo : function(width, height){
32449 this.el.setSize(width, height);
32450 this.size = {width: width, height: height};
32451 this.syncBodyHeight();
32452 if(this.fixedcenter){
32455 if(this.isVisible()){
32456 this.constrainXY();
32457 this.adjustAssets();
32459 this.fireEvent("resize", this, width, height);
32465 * Resizes the dialog to fit the specified content size.
32466 * @param {Number} width
32467 * @param {Number} height
32468 * @return {Roo.BasicDialog} this
32470 setContentSize : function(w, h){
32471 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32472 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32473 //if(!this.el.isBorderBox()){
32474 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32475 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32478 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32479 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32481 this.resizeTo(w, h);
32486 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32487 * executed in response to a particular key being pressed while the dialog is active.
32488 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32489 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32490 * @param {Function} fn The function to call
32491 * @param {Object} scope (optional) The scope of the function
32492 * @return {Roo.BasicDialog} this
32494 addKeyListener : function(key, fn, scope){
32495 var keyCode, shift, ctrl, alt;
32496 if(typeof key == "object" && !(key instanceof Array)){
32497 keyCode = key["key"];
32498 shift = key["shift"];
32499 ctrl = key["ctrl"];
32504 var handler = function(dlg, e){
32505 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32506 var k = e.getKey();
32507 if(keyCode instanceof Array){
32508 for(var i = 0, len = keyCode.length; i < len; i++){
32509 if(keyCode[i] == k){
32510 fn.call(scope || window, dlg, k, e);
32516 fn.call(scope || window, dlg, k, e);
32521 this.on("keydown", handler);
32526 * Returns the TabPanel component (creates it if it doesn't exist).
32527 * Note: If you wish to simply check for the existence of tabs without creating them,
32528 * check for a null 'tabs' property.
32529 * @return {Roo.TabPanel} The tabs component
32531 getTabs : function(){
32533 this.el.addClass("x-dlg-auto-tabs");
32534 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32535 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32541 * Adds a button to the footer section of the dialog.
32542 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32543 * object or a valid Roo.DomHelper element config
32544 * @param {Function} handler The function called when the button is clicked
32545 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32546 * @return {Roo.Button} The new button
32548 addButton : function(config, handler, scope){
32549 var dh = Roo.DomHelper;
32551 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32553 if(!this.btnContainer){
32554 var tb = this.footer.createChild({
32556 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32557 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32559 this.btnContainer = tb.firstChild.firstChild.firstChild;
32564 minWidth: this.minButtonWidth,
32567 if(typeof config == "string"){
32568 bconfig.text = config;
32571 bconfig.dhconfig = config;
32573 Roo.apply(bconfig, config);
32577 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32578 bconfig.position = Math.max(0, bconfig.position);
32579 fc = this.btnContainer.childNodes[bconfig.position];
32582 var btn = new Roo.Button(
32584 this.btnContainer.insertBefore(document.createElement("td"),fc)
32585 : this.btnContainer.appendChild(document.createElement("td")),
32586 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32589 this.syncBodyHeight();
32592 * Array of all the buttons that have been added to this dialog via addButton
32597 this.buttons.push(btn);
32602 * Sets the default button to be focused when the dialog is displayed.
32603 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32604 * @return {Roo.BasicDialog} this
32606 setDefaultButton : function(btn){
32607 this.defaultButton = btn;
32612 getHeaderFooterHeight : function(safe){
32615 height += this.header.getHeight();
32618 var fm = this.footer.getMargins();
32619 height += (this.footer.getHeight()+fm.top+fm.bottom);
32621 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32622 height += this.centerBg.getPadding("tb");
32627 syncBodyHeight : function()
32629 var bd = this.body, // the text
32630 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32632 var height = this.size.height - this.getHeaderFooterHeight(false);
32633 bd.setHeight(height-bd.getMargins("tb"));
32634 var hh = this.header.getHeight();
32635 var h = this.size.height-hh;
32638 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32639 bw.setHeight(h-cb.getPadding("tb"));
32641 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32642 bd.setWidth(bw.getWidth(true));
32644 this.tabs.syncHeight();
32646 this.tabs.el.repaint();
32652 * Restores the previous state of the dialog if Roo.state is configured.
32653 * @return {Roo.BasicDialog} this
32655 restoreState : function(){
32656 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32657 if(box && box.width){
32658 this.xy = [box.x, box.y];
32659 this.resizeTo(box.width, box.height);
32665 beforeShow : function(){
32667 if(this.fixedcenter){
32668 this.xy = this.el.getCenterXY(true);
32671 Roo.get(document.body).addClass("x-body-masked");
32672 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32675 this.constrainXY();
32679 animShow : function(){
32680 var b = Roo.get(this.animateTarget).getBox();
32681 this.proxy.setSize(b.width, b.height);
32682 this.proxy.setLocation(b.x, b.y);
32684 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32685 true, .35, this.showEl.createDelegate(this));
32689 * Shows the dialog.
32690 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32691 * @return {Roo.BasicDialog} this
32693 show : function(animateTarget){
32694 if (this.fireEvent("beforeshow", this) === false){
32697 if(this.syncHeightBeforeShow){
32698 this.syncBodyHeight();
32699 }else if(this.firstShow){
32700 this.firstShow = false;
32701 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32703 this.animateTarget = animateTarget || this.animateTarget;
32704 if(!this.el.isVisible()){
32706 if(this.animateTarget && Roo.get(this.animateTarget)){
32716 showEl : function(){
32718 this.el.setXY(this.xy);
32720 this.adjustAssets(true);
32723 // IE peekaboo bug - fix found by Dave Fenwick
32727 this.fireEvent("show", this);
32731 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32732 * dialog itself will receive focus.
32734 focus : function(){
32735 if(this.defaultButton){
32736 this.defaultButton.focus();
32738 this.focusEl.focus();
32743 constrainXY : function(){
32744 if(this.constraintoviewport !== false){
32745 if(!this.viewSize){
32746 if(this.container){
32747 var s = this.container.getSize();
32748 this.viewSize = [s.width, s.height];
32750 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32753 var s = Roo.get(this.container||document).getScroll();
32755 var x = this.xy[0], y = this.xy[1];
32756 var w = this.size.width, h = this.size.height;
32757 var vw = this.viewSize[0], vh = this.viewSize[1];
32758 // only move it if it needs it
32760 // first validate right/bottom
32761 if(x + w > vw+s.left){
32765 if(y + h > vh+s.top){
32769 // then make sure top/left isn't negative
32781 if(this.isVisible()){
32782 this.el.setLocation(x, y);
32783 this.adjustAssets();
32790 onDrag : function(){
32791 if(!this.proxyDrag){
32792 this.xy = this.el.getXY();
32793 this.adjustAssets();
32798 adjustAssets : function(doShow){
32799 var x = this.xy[0], y = this.xy[1];
32800 var w = this.size.width, h = this.size.height;
32801 if(doShow === true){
32803 this.shadow.show(this.el);
32809 if(this.shadow && this.shadow.isVisible()){
32810 this.shadow.show(this.el);
32812 if(this.shim && this.shim.isVisible()){
32813 this.shim.setBounds(x, y, w, h);
32818 adjustViewport : function(w, h){
32820 w = Roo.lib.Dom.getViewWidth();
32821 h = Roo.lib.Dom.getViewHeight();
32824 this.viewSize = [w, h];
32825 if(this.modal && this.mask.isVisible()){
32826 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32827 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32829 if(this.isVisible()){
32830 this.constrainXY();
32835 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32836 * shadow, proxy, mask, etc.) Also removes all event listeners.
32837 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32839 destroy : function(removeEl){
32840 if(this.isVisible()){
32841 this.animateTarget = null;
32844 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32846 this.tabs.destroy(removeEl);
32859 for(var i = 0, len = this.buttons.length; i < len; i++){
32860 this.buttons[i].destroy();
32863 this.el.removeAllListeners();
32864 if(removeEl === true){
32865 this.el.update("");
32868 Roo.DialogManager.unregister(this);
32872 startMove : function(){
32873 if(this.proxyDrag){
32876 if(this.constraintoviewport !== false){
32877 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32882 endMove : function(){
32883 if(!this.proxyDrag){
32884 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32886 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32889 this.refreshSize();
32890 this.adjustAssets();
32892 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32896 * Brings this dialog to the front of any other visible dialogs
32897 * @return {Roo.BasicDialog} this
32899 toFront : function(){
32900 Roo.DialogManager.bringToFront(this);
32905 * Sends this dialog to the back (under) of any other visible dialogs
32906 * @return {Roo.BasicDialog} this
32908 toBack : function(){
32909 Roo.DialogManager.sendToBack(this);
32914 * Centers this dialog in the viewport
32915 * @return {Roo.BasicDialog} this
32917 center : function(){
32918 var xy = this.el.getCenterXY(true);
32919 this.moveTo(xy[0], xy[1]);
32924 * Moves the dialog's top-left corner to the specified point
32925 * @param {Number} x
32926 * @param {Number} y
32927 * @return {Roo.BasicDialog} this
32929 moveTo : function(x, y){
32931 if(this.isVisible()){
32932 this.el.setXY(this.xy);
32933 this.adjustAssets();
32939 * Aligns the dialog to the specified element
32940 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32941 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32942 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32943 * @return {Roo.BasicDialog} this
32945 alignTo : function(element, position, offsets){
32946 this.xy = this.el.getAlignToXY(element, position, offsets);
32947 if(this.isVisible()){
32948 this.el.setXY(this.xy);
32949 this.adjustAssets();
32955 * Anchors an element to another element and realigns it when the window is resized.
32956 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32957 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32958 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32959 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32960 * is a number, it is used as the buffer delay (defaults to 50ms).
32961 * @return {Roo.BasicDialog} this
32963 anchorTo : function(el, alignment, offsets, monitorScroll){
32964 var action = function(){
32965 this.alignTo(el, alignment, offsets);
32967 Roo.EventManager.onWindowResize(action, this);
32968 var tm = typeof monitorScroll;
32969 if(tm != 'undefined'){
32970 Roo.EventManager.on(window, 'scroll', action, this,
32971 {buffer: tm == 'number' ? monitorScroll : 50});
32978 * Returns true if the dialog is visible
32979 * @return {Boolean}
32981 isVisible : function(){
32982 return this.el.isVisible();
32986 animHide : function(callback){
32987 var b = Roo.get(this.animateTarget).getBox();
32989 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32991 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32992 this.hideEl.createDelegate(this, [callback]));
32996 * Hides the dialog.
32997 * @param {Function} callback (optional) Function to call when the dialog is hidden
32998 * @return {Roo.BasicDialog} this
33000 hide : function(callback){
33001 if (this.fireEvent("beforehide", this) === false){
33005 this.shadow.hide();
33010 // sometimes animateTarget seems to get set.. causing problems...
33011 // this just double checks..
33012 if(this.animateTarget && Roo.get(this.animateTarget)) {
33013 this.animHide(callback);
33016 this.hideEl(callback);
33022 hideEl : function(callback){
33026 Roo.get(document.body).removeClass("x-body-masked");
33028 this.fireEvent("hide", this);
33029 if(typeof callback == "function"){
33035 hideAction : function(){
33036 this.setLeft("-10000px");
33037 this.setTop("-10000px");
33038 this.setStyle("visibility", "hidden");
33042 refreshSize : function(){
33043 this.size = this.el.getSize();
33044 this.xy = this.el.getXY();
33045 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
33049 // z-index is managed by the DialogManager and may be overwritten at any time
33050 setZIndex : function(index){
33052 this.mask.setStyle("z-index", index);
33055 this.shim.setStyle("z-index", ++index);
33058 this.shadow.setZIndex(++index);
33060 this.el.setStyle("z-index", ++index);
33062 this.proxy.setStyle("z-index", ++index);
33065 this.resizer.proxy.setStyle("z-index", ++index);
33068 this.lastZIndex = index;
33072 * Returns the element for this dialog
33073 * @return {Roo.Element} The underlying dialog Element
33075 getEl : function(){
33081 * @class Roo.DialogManager
33082 * Provides global access to BasicDialogs that have been created and
33083 * support for z-indexing (layering) multiple open dialogs.
33085 Roo.DialogManager = function(){
33087 var accessList = [];
33091 var sortDialogs = function(d1, d2){
33092 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33096 var orderDialogs = function(){
33097 accessList.sort(sortDialogs);
33098 var seed = Roo.DialogManager.zseed;
33099 for(var i = 0, len = accessList.length; i < len; i++){
33100 var dlg = accessList[i];
33102 dlg.setZIndex(seed + (i*10));
33109 * The starting z-index for BasicDialogs (defaults to 9000)
33110 * @type Number The z-index value
33115 register : function(dlg){
33116 list[dlg.id] = dlg;
33117 accessList.push(dlg);
33121 unregister : function(dlg){
33122 delete list[dlg.id];
33125 if(!accessList.indexOf){
33126 for( i = 0, len = accessList.length; i < len; i++){
33127 if(accessList[i] == dlg){
33128 accessList.splice(i, 1);
33133 i = accessList.indexOf(dlg);
33135 accessList.splice(i, 1);
33141 * Gets a registered dialog by id
33142 * @param {String/Object} id The id of the dialog or a dialog
33143 * @return {Roo.BasicDialog} this
33145 get : function(id){
33146 return typeof id == "object" ? id : list[id];
33150 * Brings the specified dialog to the front
33151 * @param {String/Object} dlg The id of the dialog or a dialog
33152 * @return {Roo.BasicDialog} this
33154 bringToFront : function(dlg){
33155 dlg = this.get(dlg);
33158 dlg._lastAccess = new Date().getTime();
33165 * Sends the specified dialog to the back
33166 * @param {String/Object} dlg The id of the dialog or a dialog
33167 * @return {Roo.BasicDialog} this
33169 sendToBack : function(dlg){
33170 dlg = this.get(dlg);
33171 dlg._lastAccess = -(new Date().getTime());
33177 * Hides all dialogs
33179 hideAll : function(){
33180 for(var id in list){
33181 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33190 * @class Roo.LayoutDialog
33191 * @extends Roo.BasicDialog
33192 * Dialog which provides adjustments for working with a layout in a Dialog.
33193 * Add your necessary layout config options to the dialog's config.<br>
33194 * Example usage (including a nested layout):
33197 dialog = new Roo.LayoutDialog("download-dlg", {
33206 // layout config merges with the dialog config
33208 tabPosition: "top",
33209 alwaysShowTabs: true
33212 dialog.addKeyListener(27, dialog.hide, dialog);
33213 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33214 dialog.addButton("Build It!", this.getDownload, this);
33216 // we can even add nested layouts
33217 var innerLayout = new Roo.BorderLayout("dl-inner", {
33227 innerLayout.beginUpdate();
33228 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33229 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33230 innerLayout.endUpdate(true);
33232 var layout = dialog.getLayout();
33233 layout.beginUpdate();
33234 layout.add("center", new Roo.ContentPanel("standard-panel",
33235 {title: "Download the Source", fitToFrame:true}));
33236 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33237 {title: "Build your own roo.js"}));
33238 layout.getRegion("center").showPanel(sp);
33239 layout.endUpdate();
33243 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33244 * @param {Object} config configuration options
33246 Roo.LayoutDialog = function(el, cfg){
33249 if (typeof(cfg) == 'undefined') {
33250 config = Roo.apply({}, el);
33251 // not sure why we use documentElement here.. - it should always be body.
33252 // IE7 borks horribly if we use documentElement.
33253 // webkit also does not like documentElement - it creates a body element...
33254 el = Roo.get( document.body || document.documentElement ).createChild();
33255 //config.autoCreate = true;
33259 config.autoTabs = false;
33260 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33261 this.body.setStyle({overflow:"hidden", position:"relative"});
33262 this.layout = new Roo.BorderLayout(this.body.dom, config);
33263 this.layout.monitorWindowResize = false;
33264 this.el.addClass("x-dlg-auto-layout");
33265 // fix case when center region overwrites center function
33266 this.center = Roo.BasicDialog.prototype.center;
33267 this.on("show", this.layout.layout, this.layout, true);
33268 if (config.items) {
33269 var xitems = config.items;
33270 delete config.items;
33271 Roo.each(xitems, this.addxtype, this);
33276 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33278 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33281 endUpdate : function(){
33282 this.layout.endUpdate();
33286 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33289 beginUpdate : function(){
33290 this.layout.beginUpdate();
33294 * Get the BorderLayout for this dialog
33295 * @return {Roo.BorderLayout}
33297 getLayout : function(){
33298 return this.layout;
33301 showEl : function(){
33302 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33304 this.layout.layout();
33309 // Use the syncHeightBeforeShow config option to control this automatically
33310 syncBodyHeight : function(){
33311 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33312 if(this.layout){this.layout.layout();}
33316 * Add an xtype element (actually adds to the layout.)
33317 * @return {Object} xdata xtype object data.
33320 addxtype : function(c) {
33321 return this.layout.addxtype(c);
33325 * Ext JS Library 1.1.1
33326 * Copyright(c) 2006-2007, Ext JS, LLC.
33328 * Originally Released Under LGPL - original licence link has changed is not relivant.
33331 * <script type="text/javascript">
33335 * @class Roo.MessageBox
33336 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33340 Roo.Msg.alert('Status', 'Changes saved successfully.');
33342 // Prompt for user data:
33343 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33345 // process text value...
33349 // Show a dialog using config options:
33351 title:'Save Changes?',
33352 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33353 buttons: Roo.Msg.YESNOCANCEL,
33360 Roo.MessageBox = function(){
33361 var dlg, opt, mask, waitTimer;
33362 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33363 var buttons, activeTextEl, bwidth;
33366 var handleButton = function(button){
33368 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33372 var handleHide = function(){
33373 if(opt && opt.cls){
33374 dlg.el.removeClass(opt.cls);
33377 Roo.TaskMgr.stop(waitTimer);
33383 var updateButtons = function(b){
33386 buttons["ok"].hide();
33387 buttons["cancel"].hide();
33388 buttons["yes"].hide();
33389 buttons["no"].hide();
33390 dlg.footer.dom.style.display = 'none';
33393 dlg.footer.dom.style.display = '';
33394 for(var k in buttons){
33395 if(typeof buttons[k] != "function"){
33398 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33399 width += buttons[k].el.getWidth()+15;
33409 var handleEsc = function(d, k, e){
33410 if(opt && opt.closable !== false){
33420 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33421 * @return {Roo.BasicDialog} The BasicDialog element
33423 getDialog : function(){
33425 dlg = new Roo.BasicDialog("x-msg-box", {
33430 constraintoviewport:false,
33432 collapsible : false,
33435 width:400, height:100,
33436 buttonAlign:"center",
33437 closeClick : function(){
33438 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33439 handleButton("no");
33441 handleButton("cancel");
33445 dlg.on("hide", handleHide);
33447 dlg.addKeyListener(27, handleEsc);
33449 var bt = this.buttonText;
33450 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33451 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33452 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33453 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33454 bodyEl = dlg.body.createChild({
33456 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>'
33458 msgEl = bodyEl.dom.firstChild;
33459 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33460 textboxEl.enableDisplayMode();
33461 textboxEl.addKeyListener([10,13], function(){
33462 if(dlg.isVisible() && opt && opt.buttons){
33463 if(opt.buttons.ok){
33464 handleButton("ok");
33465 }else if(opt.buttons.yes){
33466 handleButton("yes");
33470 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33471 textareaEl.enableDisplayMode();
33472 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33473 progressEl.enableDisplayMode();
33474 var pf = progressEl.dom.firstChild;
33476 pp = Roo.get(pf.firstChild);
33477 pp.setHeight(pf.offsetHeight);
33485 * Updates the message box body text
33486 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33487 * the XHTML-compliant non-breaking space character '&#160;')
33488 * @return {Roo.MessageBox} This message box
33490 updateText : function(text){
33491 if(!dlg.isVisible() && !opt.width){
33492 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33494 msgEl.innerHTML = text || ' ';
33496 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33497 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33499 Math.min(opt.width || cw , this.maxWidth),
33500 Math.max(opt.minWidth || this.minWidth, bwidth)
33503 activeTextEl.setWidth(w);
33505 if(dlg.isVisible()){
33506 dlg.fixedcenter = false;
33508 // to big, make it scroll. = But as usual stupid IE does not support
33511 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33512 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33513 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33515 bodyEl.dom.style.height = '';
33516 bodyEl.dom.style.overflowY = '';
33519 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33521 bodyEl.dom.style.overflowX = '';
33524 dlg.setContentSize(w, bodyEl.getHeight());
33525 if(dlg.isVisible()){
33526 dlg.fixedcenter = true;
33532 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33533 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33534 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33535 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33536 * @return {Roo.MessageBox} This message box
33538 updateProgress : function(value, text){
33540 this.updateText(text);
33542 if (pp) { // weird bug on my firefox - for some reason this is not defined
33543 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33549 * Returns true if the message box is currently displayed
33550 * @return {Boolean} True if the message box is visible, else false
33552 isVisible : function(){
33553 return dlg && dlg.isVisible();
33557 * Hides the message box if it is displayed
33560 if(this.isVisible()){
33566 * Displays a new message box, or reinitializes an existing message box, based on the config options
33567 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33568 * The following config object properties are supported:
33570 Property Type Description
33571 ---------- --------------- ------------------------------------------------------------------------------------
33572 animEl String/Element An id or Element from which the message box should animate as it opens and
33573 closes (defaults to undefined)
33574 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33575 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33576 closable Boolean False to hide the top-right close button (defaults to true). Note that
33577 progress and wait dialogs will ignore this property and always hide the
33578 close button as they can only be closed programmatically.
33579 cls String A custom CSS class to apply to the message box element
33580 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33581 displayed (defaults to 75)
33582 fn Function A callback function to execute after closing the dialog. The arguments to the
33583 function will be btn (the name of the button that was clicked, if applicable,
33584 e.g. "ok"), and text (the value of the active text field, if applicable).
33585 Progress and wait dialogs will ignore this option since they do not respond to
33586 user actions and can only be closed programmatically, so any required function
33587 should be called by the same code after it closes the dialog.
33588 icon String A CSS class that provides a background image to be used as an icon for
33589 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33590 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33591 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33592 modal Boolean False to allow user interaction with the page while the message box is
33593 displayed (defaults to true)
33594 msg String A string that will replace the existing message box body text (defaults
33595 to the XHTML-compliant non-breaking space character ' ')
33596 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33597 progress Boolean True to display a progress bar (defaults to false)
33598 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33599 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33600 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33601 title String The title text
33602 value String The string value to set into the active textbox element if displayed
33603 wait Boolean True to display a progress bar (defaults to false)
33604 width Number The width of the dialog in pixels
33611 msg: 'Please enter your address:',
33613 buttons: Roo.MessageBox.OKCANCEL,
33616 animEl: 'addAddressBtn'
33619 * @param {Object} config Configuration options
33620 * @return {Roo.MessageBox} This message box
33622 show : function(options)
33625 // this causes nightmares if you show one dialog after another
33626 // especially on callbacks..
33628 if(this.isVisible()){
33631 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33632 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33633 Roo.log("New Dialog Message:" + options.msg )
33634 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33635 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33638 var d = this.getDialog();
33640 d.setTitle(opt.title || " ");
33641 d.close.setDisplayed(opt.closable !== false);
33642 activeTextEl = textboxEl;
33643 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33648 textareaEl.setHeight(typeof opt.multiline == "number" ?
33649 opt.multiline : this.defaultTextHeight);
33650 activeTextEl = textareaEl;
33659 progressEl.setDisplayed(opt.progress === true);
33660 this.updateProgress(0);
33661 activeTextEl.dom.value = opt.value || "";
33663 dlg.setDefaultButton(activeTextEl);
33665 var bs = opt.buttons;
33668 db = buttons["ok"];
33669 }else if(bs && bs.yes){
33670 db = buttons["yes"];
33672 dlg.setDefaultButton(db);
33674 bwidth = updateButtons(opt.buttons);
33675 this.updateText(opt.msg);
33677 d.el.addClass(opt.cls);
33679 d.proxyDrag = opt.proxyDrag === true;
33680 d.modal = opt.modal !== false;
33681 d.mask = opt.modal !== false ? mask : false;
33682 if(!d.isVisible()){
33683 // force it to the end of the z-index stack so it gets a cursor in FF
33684 document.body.appendChild(dlg.el.dom);
33685 d.animateTarget = null;
33686 d.show(options.animEl);
33692 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33693 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33694 * and closing the message box when the process is complete.
33695 * @param {String} title The title bar text
33696 * @param {String} msg The message box body text
33697 * @return {Roo.MessageBox} This message box
33699 progress : function(title, msg){
33706 minWidth: this.minProgressWidth,
33713 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33714 * If a callback function is passed it will be called after the user clicks the button, and the
33715 * id of the button that was clicked will be passed as the only parameter to the callback
33716 * (could also be the top-right close button).
33717 * @param {String} title The title bar text
33718 * @param {String} msg The message box body text
33719 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33720 * @param {Object} scope (optional) The scope of the callback function
33721 * @return {Roo.MessageBox} This message box
33723 alert : function(title, msg, fn, scope){
33736 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33737 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33738 * You are responsible for closing the message box when the process is complete.
33739 * @param {String} msg The message box body text
33740 * @param {String} title (optional) The title bar text
33741 * @return {Roo.MessageBox} This message box
33743 wait : function(msg, title){
33754 waitTimer = Roo.TaskMgr.start({
33756 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33764 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33765 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33766 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33767 * @param {String} title The title bar text
33768 * @param {String} msg The message box body text
33769 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33770 * @param {Object} scope (optional) The scope of the callback function
33771 * @return {Roo.MessageBox} This message box
33773 confirm : function(title, msg, fn, scope){
33777 buttons: this.YESNO,
33786 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33787 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33788 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33789 * (could also be the top-right close button) and the text that was entered will be passed as the two
33790 * parameters to the callback.
33791 * @param {String} title The title bar text
33792 * @param {String} msg The message box body text
33793 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33794 * @param {Object} scope (optional) The scope of the callback function
33795 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33796 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33797 * @return {Roo.MessageBox} This message box
33799 prompt : function(title, msg, fn, scope, multiline){
33803 buttons: this.OKCANCEL,
33808 multiline: multiline,
33815 * Button config that displays a single OK button
33820 * Button config that displays Yes and No buttons
33823 YESNO : {yes:true, no:true},
33825 * Button config that displays OK and Cancel buttons
33828 OKCANCEL : {ok:true, cancel:true},
33830 * Button config that displays Yes, No and Cancel buttons
33833 YESNOCANCEL : {yes:true, no:true, cancel:true},
33836 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33839 defaultTextHeight : 75,
33841 * The maximum width in pixels of the message box (defaults to 600)
33846 * The minimum width in pixels of the message box (defaults to 100)
33851 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33852 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33855 minProgressWidth : 250,
33857 * An object containing the default button text strings that can be overriden for localized language support.
33858 * Supported properties are: ok, cancel, yes and no.
33859 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33872 * Shorthand for {@link Roo.MessageBox}
33874 Roo.Msg = Roo.MessageBox;/*
33876 * Ext JS Library 1.1.1
33877 * Copyright(c) 2006-2007, Ext JS, LLC.
33879 * Originally Released Under LGPL - original licence link has changed is not relivant.
33882 * <script type="text/javascript">
33885 * @class Roo.QuickTips
33886 * Provides attractive and customizable tooltips for any element.
33889 Roo.QuickTips = function(){
33890 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33891 var ce, bd, xy, dd;
33892 var visible = false, disabled = true, inited = false;
33893 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33895 var onOver = function(e){
33899 var t = e.getTarget();
33900 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33903 if(ce && t == ce.el){
33904 clearTimeout(hideProc);
33907 if(t && tagEls[t.id]){
33908 tagEls[t.id].el = t;
33909 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33912 var ttp, et = Roo.fly(t);
33913 var ns = cfg.namespace;
33914 if(tm.interceptTitles && t.title){
33917 t.removeAttribute("title");
33918 e.preventDefault();
33920 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33923 showProc = show.defer(tm.showDelay, tm, [{
33925 text: ttp.replace(/\\n/g,'<br/>'),
33926 width: et.getAttributeNS(ns, cfg.width),
33927 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33928 title: et.getAttributeNS(ns, cfg.title),
33929 cls: et.getAttributeNS(ns, cfg.cls)
33934 var onOut = function(e){
33935 clearTimeout(showProc);
33936 var t = e.getTarget();
33937 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33938 hideProc = setTimeout(hide, tm.hideDelay);
33942 var onMove = function(e){
33948 if(tm.trackMouse && ce){
33953 var onDown = function(e){
33954 clearTimeout(showProc);
33955 clearTimeout(hideProc);
33957 if(tm.hideOnClick){
33960 tm.enable.defer(100, tm);
33965 var getPad = function(){
33966 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33969 var show = function(o){
33973 clearTimeout(dismissProc);
33975 if(removeCls){ // in case manually hidden
33976 el.removeClass(removeCls);
33980 el.addClass(ce.cls);
33981 removeCls = ce.cls;
33984 tipTitle.update(ce.title);
33987 tipTitle.update('');
33990 el.dom.style.width = tm.maxWidth+'px';
33991 //tipBody.dom.style.width = '';
33992 tipBodyText.update(o.text);
33993 var p = getPad(), w = ce.width;
33995 var td = tipBodyText.dom;
33996 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33997 if(aw > tm.maxWidth){
33999 }else if(aw < tm.minWidth){
34005 //tipBody.setWidth(w);
34006 el.setWidth(parseInt(w, 10) + p);
34007 if(ce.autoHide === false){
34008 close.setDisplayed(true);
34013 close.setDisplayed(false);
34019 el.avoidY = xy[1]-18;
34024 el.setStyle("visibility", "visible");
34025 el.fadeIn({callback: afterShow});
34031 var afterShow = function(){
34035 if(tm.autoDismiss && ce.autoHide !== false){
34036 dismissProc = setTimeout(hide, tm.autoDismissDelay);
34041 var hide = function(noanim){
34042 clearTimeout(dismissProc);
34043 clearTimeout(hideProc);
34045 if(el.isVisible()){
34047 if(noanim !== true && tm.animate){
34048 el.fadeOut({callback: afterHide});
34055 var afterHide = function(){
34058 el.removeClass(removeCls);
34065 * @cfg {Number} minWidth
34066 * The minimum width of the quick tip (defaults to 40)
34070 * @cfg {Number} maxWidth
34071 * The maximum width of the quick tip (defaults to 300)
34075 * @cfg {Boolean} interceptTitles
34076 * True to automatically use the element's DOM title value if available (defaults to false)
34078 interceptTitles : false,
34080 * @cfg {Boolean} trackMouse
34081 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34083 trackMouse : false,
34085 * @cfg {Boolean} hideOnClick
34086 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34088 hideOnClick : true,
34090 * @cfg {Number} showDelay
34091 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
34095 * @cfg {Number} hideDelay
34096 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34100 * @cfg {Boolean} autoHide
34101 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34102 * Used in conjunction with hideDelay.
34107 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34108 * (defaults to true). Used in conjunction with autoDismissDelay.
34110 autoDismiss : true,
34113 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34115 autoDismissDelay : 5000,
34117 * @cfg {Boolean} animate
34118 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34123 * @cfg {String} title
34124 * Title text to display (defaults to ''). This can be any valid HTML markup.
34128 * @cfg {String} text
34129 * Body text to display (defaults to ''). This can be any valid HTML markup.
34133 * @cfg {String} cls
34134 * A CSS class to apply to the base quick tip element (defaults to '').
34138 * @cfg {Number} width
34139 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34140 * minWidth or maxWidth.
34145 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34146 * or display QuickTips in a page.
34149 tm = Roo.QuickTips;
34150 cfg = tm.tagConfig;
34152 if(!Roo.isReady){ // allow calling of init() before onReady
34153 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34156 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34157 el.fxDefaults = {stopFx: true};
34158 // maximum custom styling
34159 //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>');
34160 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>');
34161 tipTitle = el.child('h3');
34162 tipTitle.enableDisplayMode("block");
34163 tipBody = el.child('div.x-tip-bd');
34164 tipBodyText = el.child('div.x-tip-bd-inner');
34165 //bdLeft = el.child('div.x-tip-bd-left');
34166 //bdRight = el.child('div.x-tip-bd-right');
34167 close = el.child('div.x-tip-close');
34168 close.enableDisplayMode("block");
34169 close.on("click", hide);
34170 var d = Roo.get(document);
34171 d.on("mousedown", onDown);
34172 d.on("mouseover", onOver);
34173 d.on("mouseout", onOut);
34174 d.on("mousemove", onMove);
34175 esc = d.addKeyListener(27, hide);
34178 dd = el.initDD("default", null, {
34179 onDrag : function(){
34183 dd.setHandleElId(tipTitle.id);
34192 * Configures a new quick tip instance and assigns it to a target element. The following config options
34195 Property Type Description
34196 ---------- --------------------- ------------------------------------------------------------------------
34197 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34199 * @param {Object} config The config object
34201 register : function(config){
34202 var cs = config instanceof Array ? config : arguments;
34203 for(var i = 0, len = cs.length; i < len; i++) {
34205 var target = c.target;
34207 if(target instanceof Array){
34208 for(var j = 0, jlen = target.length; j < jlen; j++){
34209 tagEls[target[j]] = c;
34212 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34219 * Removes this quick tip from its element and destroys it.
34220 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34222 unregister : function(el){
34223 delete tagEls[Roo.id(el)];
34227 * Enable this quick tip.
34229 enable : function(){
34230 if(inited && disabled){
34232 if(locks.length < 1){
34239 * Disable this quick tip.
34241 disable : function(){
34243 clearTimeout(showProc);
34244 clearTimeout(hideProc);
34245 clearTimeout(dismissProc);
34253 * Returns true if the quick tip is enabled, else false.
34255 isEnabled : function(){
34261 namespace : "roo", // was ext?? this may break..
34262 alt_namespace : "ext",
34263 attribute : "qtip",
34273 // backwards compat
34274 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34276 * Ext JS Library 1.1.1
34277 * Copyright(c) 2006-2007, Ext JS, LLC.
34279 * Originally Released Under LGPL - original licence link has changed is not relivant.
34282 * <script type="text/javascript">
34287 * @class Roo.tree.TreePanel
34288 * @extends Roo.data.Tree
34290 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34291 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34292 * @cfg {Boolean} enableDD true to enable drag and drop
34293 * @cfg {Boolean} enableDrag true to enable just drag
34294 * @cfg {Boolean} enableDrop true to enable just drop
34295 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34296 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34297 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34298 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34299 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34300 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34301 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34302 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34303 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34304 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34305 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34306 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34307 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34308 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34309 * @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>
34310 * @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>
34313 * @param {String/HTMLElement/Element} el The container element
34314 * @param {Object} config
34316 Roo.tree.TreePanel = function(el, config){
34318 var loader = false;
34320 root = config.root;
34321 delete config.root;
34323 if (config.loader) {
34324 loader = config.loader;
34325 delete config.loader;
34328 Roo.apply(this, config);
34329 Roo.tree.TreePanel.superclass.constructor.call(this);
34330 this.el = Roo.get(el);
34331 this.el.addClass('x-tree');
34332 //console.log(root);
34334 this.setRootNode( Roo.factory(root, Roo.tree));
34337 this.loader = Roo.factory(loader, Roo.tree);
34340 * Read-only. The id of the container element becomes this TreePanel's id.
34342 this.id = this.el.id;
34345 * @event beforeload
34346 * Fires before a node is loaded, return false to cancel
34347 * @param {Node} node The node being loaded
34349 "beforeload" : true,
34352 * Fires when a node is loaded
34353 * @param {Node} node The node that was loaded
34357 * @event textchange
34358 * Fires when the text for a node is changed
34359 * @param {Node} node The node
34360 * @param {String} text The new text
34361 * @param {String} oldText The old text
34363 "textchange" : true,
34365 * @event beforeexpand
34366 * Fires before a node is expanded, return false to cancel.
34367 * @param {Node} node The node
34368 * @param {Boolean} deep
34369 * @param {Boolean} anim
34371 "beforeexpand" : true,
34373 * @event beforecollapse
34374 * Fires before a node is collapsed, return false to cancel.
34375 * @param {Node} node The node
34376 * @param {Boolean} deep
34377 * @param {Boolean} anim
34379 "beforecollapse" : true,
34382 * Fires when a node is expanded
34383 * @param {Node} node The node
34387 * @event disabledchange
34388 * Fires when the disabled status of a node changes
34389 * @param {Node} node The node
34390 * @param {Boolean} disabled
34392 "disabledchange" : true,
34395 * Fires when a node is collapsed
34396 * @param {Node} node The node
34400 * @event beforeclick
34401 * Fires before click processing on a node. Return false to cancel the default action.
34402 * @param {Node} node The node
34403 * @param {Roo.EventObject} e The event object
34405 "beforeclick":true,
34407 * @event checkchange
34408 * Fires when a node with a checkbox's checked property changes
34409 * @param {Node} this This node
34410 * @param {Boolean} checked
34412 "checkchange":true,
34415 * Fires when a node is clicked
34416 * @param {Node} node The node
34417 * @param {Roo.EventObject} e The event object
34422 * Fires when a node is double clicked
34423 * @param {Node} node The node
34424 * @param {Roo.EventObject} e The event object
34428 * @event contextmenu
34429 * Fires when a node is right clicked
34430 * @param {Node} node The node
34431 * @param {Roo.EventObject} e The event object
34433 "contextmenu":true,
34435 * @event beforechildrenrendered
34436 * Fires right before the child nodes for a node are rendered
34437 * @param {Node} node The node
34439 "beforechildrenrendered":true,
34442 * Fires when a node starts being dragged
34443 * @param {Roo.tree.TreePanel} this
34444 * @param {Roo.tree.TreeNode} node
34445 * @param {event} e The raw browser event
34447 "startdrag" : true,
34450 * Fires when a drag operation is complete
34451 * @param {Roo.tree.TreePanel} this
34452 * @param {Roo.tree.TreeNode} node
34453 * @param {event} e The raw browser event
34458 * Fires when a dragged node is dropped on a valid DD target
34459 * @param {Roo.tree.TreePanel} this
34460 * @param {Roo.tree.TreeNode} node
34461 * @param {DD} dd The dd it was dropped on
34462 * @param {event} e The raw browser event
34466 * @event beforenodedrop
34467 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34468 * passed to handlers has the following properties:<br />
34469 * <ul style="padding:5px;padding-left:16px;">
34470 * <li>tree - The TreePanel</li>
34471 * <li>target - The node being targeted for the drop</li>
34472 * <li>data - The drag data from the drag source</li>
34473 * <li>point - The point of the drop - append, above or below</li>
34474 * <li>source - The drag source</li>
34475 * <li>rawEvent - Raw mouse event</li>
34476 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34477 * to be inserted by setting them on this object.</li>
34478 * <li>cancel - Set this to true to cancel the drop.</li>
34480 * @param {Object} dropEvent
34482 "beforenodedrop" : true,
34485 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34486 * passed to handlers has the following properties:<br />
34487 * <ul style="padding:5px;padding-left:16px;">
34488 * <li>tree - The TreePanel</li>
34489 * <li>target - The node being targeted for the drop</li>
34490 * <li>data - The drag data from the drag source</li>
34491 * <li>point - The point of the drop - append, above or below</li>
34492 * <li>source - The drag source</li>
34493 * <li>rawEvent - Raw mouse event</li>
34494 * <li>dropNode - Dropped node(s).</li>
34496 * @param {Object} dropEvent
34500 * @event nodedragover
34501 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34502 * passed to handlers has the following properties:<br />
34503 * <ul style="padding:5px;padding-left:16px;">
34504 * <li>tree - The TreePanel</li>
34505 * <li>target - The node being targeted for the drop</li>
34506 * <li>data - The drag data from the drag source</li>
34507 * <li>point - The point of the drop - append, above or below</li>
34508 * <li>source - The drag source</li>
34509 * <li>rawEvent - Raw mouse event</li>
34510 * <li>dropNode - Drop node(s) provided by the source.</li>
34511 * <li>cancel - Set this to true to signal drop not allowed.</li>
34513 * @param {Object} dragOverEvent
34515 "nodedragover" : true,
34517 * @event appendnode
34518 * Fires when append node to the tree
34519 * @param {Roo.tree.TreePanel} this
34520 * @param {Roo.tree.TreeNode} node
34521 * @param {Number} index The index of the newly appended node
34523 "appendnode" : true
34526 if(this.singleExpand){
34527 this.on("beforeexpand", this.restrictExpand, this);
34530 this.editor.tree = this;
34531 this.editor = Roo.factory(this.editor, Roo.tree);
34534 if (this.selModel) {
34535 this.selModel = Roo.factory(this.selModel, Roo.tree);
34539 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34540 rootVisible : true,
34541 animate: Roo.enableFx,
34544 hlDrop : Roo.enableFx,
34548 rendererTip: false,
34550 restrictExpand : function(node){
34551 var p = node.parentNode;
34553 if(p.expandedChild && p.expandedChild.parentNode == p){
34554 p.expandedChild.collapse();
34556 p.expandedChild = node;
34560 // private override
34561 setRootNode : function(node){
34562 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34563 if(!this.rootVisible){
34564 node.ui = new Roo.tree.RootTreeNodeUI(node);
34570 * Returns the container element for this TreePanel
34572 getEl : function(){
34577 * Returns the default TreeLoader for this TreePanel
34579 getLoader : function(){
34580 return this.loader;
34586 expandAll : function(){
34587 this.root.expand(true);
34591 * Collapse all nodes
34593 collapseAll : function(){
34594 this.root.collapse(true);
34598 * Returns the selection model used by this TreePanel
34600 getSelectionModel : function(){
34601 if(!this.selModel){
34602 this.selModel = new Roo.tree.DefaultSelectionModel();
34604 return this.selModel;
34608 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34609 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34610 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34613 getChecked : function(a, startNode){
34614 startNode = startNode || this.root;
34616 var f = function(){
34617 if(this.attributes.checked){
34618 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34621 startNode.cascade(f);
34626 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34627 * @param {String} path
34628 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34629 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34630 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34632 expandPath : function(path, attr, callback){
34633 attr = attr || "id";
34634 var keys = path.split(this.pathSeparator);
34635 var curNode = this.root;
34636 if(curNode.attributes[attr] != keys[1]){ // invalid root
34638 callback(false, null);
34643 var f = function(){
34644 if(++index == keys.length){
34646 callback(true, curNode);
34650 var c = curNode.findChild(attr, keys[index]);
34653 callback(false, curNode);
34658 c.expand(false, false, f);
34660 curNode.expand(false, false, f);
34664 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34665 * @param {String} path
34666 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34667 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34668 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34670 selectPath : function(path, attr, callback){
34671 attr = attr || "id";
34672 var keys = path.split(this.pathSeparator);
34673 var v = keys.pop();
34674 if(keys.length > 0){
34675 var f = function(success, node){
34676 if(success && node){
34677 var n = node.findChild(attr, v);
34683 }else if(callback){
34684 callback(false, n);
34688 callback(false, n);
34692 this.expandPath(keys.join(this.pathSeparator), attr, f);
34694 this.root.select();
34696 callback(true, this.root);
34701 getTreeEl : function(){
34706 * Trigger rendering of this TreePanel
34708 render : function(){
34709 if (this.innerCt) {
34710 return this; // stop it rendering more than once!!
34713 this.innerCt = this.el.createChild({tag:"ul",
34714 cls:"x-tree-root-ct " +
34715 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34717 if(this.containerScroll){
34718 Roo.dd.ScrollManager.register(this.el);
34720 if((this.enableDD || this.enableDrop) && !this.dropZone){
34722 * The dropZone used by this tree if drop is enabled
34723 * @type Roo.tree.TreeDropZone
34725 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34726 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34729 if((this.enableDD || this.enableDrag) && !this.dragZone){
34731 * The dragZone used by this tree if drag is enabled
34732 * @type Roo.tree.TreeDragZone
34734 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34735 ddGroup: this.ddGroup || "TreeDD",
34736 scroll: this.ddScroll
34739 this.getSelectionModel().init(this);
34741 Roo.log("ROOT not set in tree");
34744 this.root.render();
34745 if(!this.rootVisible){
34746 this.root.renderChildren();
34752 * Ext JS Library 1.1.1
34753 * Copyright(c) 2006-2007, Ext JS, LLC.
34755 * Originally Released Under LGPL - original licence link has changed is not relivant.
34758 * <script type="text/javascript">
34763 * @class Roo.tree.DefaultSelectionModel
34764 * @extends Roo.util.Observable
34765 * The default single selection for a TreePanel.
34766 * @param {Object} cfg Configuration
34768 Roo.tree.DefaultSelectionModel = function(cfg){
34769 this.selNode = null;
34775 * @event selectionchange
34776 * Fires when the selected node changes
34777 * @param {DefaultSelectionModel} this
34778 * @param {TreeNode} node the new selection
34780 "selectionchange" : true,
34783 * @event beforeselect
34784 * Fires before the selected node changes, return false to cancel the change
34785 * @param {DefaultSelectionModel} this
34786 * @param {TreeNode} node the new selection
34787 * @param {TreeNode} node the old selection
34789 "beforeselect" : true
34792 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34795 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34796 init : function(tree){
34798 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34799 tree.on("click", this.onNodeClick, this);
34802 onNodeClick : function(node, e){
34803 if (e.ctrlKey && this.selNode == node) {
34804 this.unselect(node);
34812 * @param {TreeNode} node The node to select
34813 * @return {TreeNode} The selected node
34815 select : function(node){
34816 var last = this.selNode;
34817 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34819 last.ui.onSelectedChange(false);
34821 this.selNode = node;
34822 node.ui.onSelectedChange(true);
34823 this.fireEvent("selectionchange", this, node, last);
34830 * @param {TreeNode} node The node to unselect
34832 unselect : function(node){
34833 if(this.selNode == node){
34834 this.clearSelections();
34839 * Clear all selections
34841 clearSelections : function(){
34842 var n = this.selNode;
34844 n.ui.onSelectedChange(false);
34845 this.selNode = null;
34846 this.fireEvent("selectionchange", this, null);
34852 * Get the selected node
34853 * @return {TreeNode} The selected node
34855 getSelectedNode : function(){
34856 return this.selNode;
34860 * Returns true if the node is selected
34861 * @param {TreeNode} node The node to check
34862 * @return {Boolean}
34864 isSelected : function(node){
34865 return this.selNode == node;
34869 * Selects the node above the selected node in the tree, intelligently walking the nodes
34870 * @return TreeNode The new selection
34872 selectPrevious : function(){
34873 var s = this.selNode || this.lastSelNode;
34877 var ps = s.previousSibling;
34879 if(!ps.isExpanded() || ps.childNodes.length < 1){
34880 return this.select(ps);
34882 var lc = ps.lastChild;
34883 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34886 return this.select(lc);
34888 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34889 return this.select(s.parentNode);
34895 * Selects the node above the selected node in the tree, intelligently walking the nodes
34896 * @return TreeNode The new selection
34898 selectNext : function(){
34899 var s = this.selNode || this.lastSelNode;
34903 if(s.firstChild && s.isExpanded()){
34904 return this.select(s.firstChild);
34905 }else if(s.nextSibling){
34906 return this.select(s.nextSibling);
34907 }else if(s.parentNode){
34909 s.parentNode.bubble(function(){
34910 if(this.nextSibling){
34911 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34920 onKeyDown : function(e){
34921 var s = this.selNode || this.lastSelNode;
34922 // undesirable, but required
34927 var k = e.getKey();
34935 this.selectPrevious();
34938 e.preventDefault();
34939 if(s.hasChildNodes()){
34940 if(!s.isExpanded()){
34942 }else if(s.firstChild){
34943 this.select(s.firstChild, e);
34948 e.preventDefault();
34949 if(s.hasChildNodes() && s.isExpanded()){
34951 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34952 this.select(s.parentNode, e);
34960 * @class Roo.tree.MultiSelectionModel
34961 * @extends Roo.util.Observable
34962 * Multi selection for a TreePanel.
34963 * @param {Object} cfg Configuration
34965 Roo.tree.MultiSelectionModel = function(){
34966 this.selNodes = [];
34970 * @event selectionchange
34971 * Fires when the selected nodes change
34972 * @param {MultiSelectionModel} this
34973 * @param {Array} nodes Array of the selected nodes
34975 "selectionchange" : true
34977 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34981 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34982 init : function(tree){
34984 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34985 tree.on("click", this.onNodeClick, this);
34988 onNodeClick : function(node, e){
34989 this.select(node, e, e.ctrlKey);
34994 * @param {TreeNode} node The node to select
34995 * @param {EventObject} e (optional) An event associated with the selection
34996 * @param {Boolean} keepExisting True to retain existing selections
34997 * @return {TreeNode} The selected node
34999 select : function(node, e, keepExisting){
35000 if(keepExisting !== true){
35001 this.clearSelections(true);
35003 if(this.isSelected(node)){
35004 this.lastSelNode = node;
35007 this.selNodes.push(node);
35008 this.selMap[node.id] = node;
35009 this.lastSelNode = node;
35010 node.ui.onSelectedChange(true);
35011 this.fireEvent("selectionchange", this, this.selNodes);
35017 * @param {TreeNode} node The node to unselect
35019 unselect : function(node){
35020 if(this.selMap[node.id]){
35021 node.ui.onSelectedChange(false);
35022 var sn = this.selNodes;
35025 index = sn.indexOf(node);
35027 for(var i = 0, len = sn.length; i < len; i++){
35035 this.selNodes.splice(index, 1);
35037 delete this.selMap[node.id];
35038 this.fireEvent("selectionchange", this, this.selNodes);
35043 * Clear all selections
35045 clearSelections : function(suppressEvent){
35046 var sn = this.selNodes;
35048 for(var i = 0, len = sn.length; i < len; i++){
35049 sn[i].ui.onSelectedChange(false);
35051 this.selNodes = [];
35053 if(suppressEvent !== true){
35054 this.fireEvent("selectionchange", this, this.selNodes);
35060 * Returns true if the node is selected
35061 * @param {TreeNode} node The node to check
35062 * @return {Boolean}
35064 isSelected : function(node){
35065 return this.selMap[node.id] ? true : false;
35069 * Returns an array of the selected nodes
35072 getSelectedNodes : function(){
35073 return this.selNodes;
35076 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35078 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35080 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35083 * Ext JS Library 1.1.1
35084 * Copyright(c) 2006-2007, Ext JS, LLC.
35086 * Originally Released Under LGPL - original licence link has changed is not relivant.
35089 * <script type="text/javascript">
35093 * @class Roo.tree.TreeNode
35094 * @extends Roo.data.Node
35095 * @cfg {String} text The text for this node
35096 * @cfg {Boolean} expanded true to start the node expanded
35097 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35098 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35099 * @cfg {Boolean} disabled true to start the node disabled
35100 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35101 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35102 * @cfg {String} cls A css class to be added to the node
35103 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35104 * @cfg {String} href URL of the link used for the node (defaults to #)
35105 * @cfg {String} hrefTarget target frame for the link
35106 * @cfg {String} qtip An Ext QuickTip for the node
35107 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35108 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35109 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35110 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35111 * (defaults to undefined with no checkbox rendered)
35113 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35115 Roo.tree.TreeNode = function(attributes){
35116 attributes = attributes || {};
35117 if(typeof attributes == "string"){
35118 attributes = {text: attributes};
35120 this.childrenRendered = false;
35121 this.rendered = false;
35122 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35123 this.expanded = attributes.expanded === true;
35124 this.isTarget = attributes.isTarget !== false;
35125 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35126 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35129 * Read-only. The text for this node. To change it use setText().
35132 this.text = attributes.text;
35134 * True if this node is disabled.
35137 this.disabled = attributes.disabled === true;
35141 * @event textchange
35142 * Fires when the text for this node is changed
35143 * @param {Node} this This node
35144 * @param {String} text The new text
35145 * @param {String} oldText The old text
35147 "textchange" : true,
35149 * @event beforeexpand
35150 * Fires before this node is expanded, return false to cancel.
35151 * @param {Node} this This node
35152 * @param {Boolean} deep
35153 * @param {Boolean} anim
35155 "beforeexpand" : true,
35157 * @event beforecollapse
35158 * Fires before this node is collapsed, return false to cancel.
35159 * @param {Node} this This node
35160 * @param {Boolean} deep
35161 * @param {Boolean} anim
35163 "beforecollapse" : true,
35166 * Fires when this node is expanded
35167 * @param {Node} this This node
35171 * @event disabledchange
35172 * Fires when the disabled status of this node changes
35173 * @param {Node} this This node
35174 * @param {Boolean} disabled
35176 "disabledchange" : true,
35179 * Fires when this node is collapsed
35180 * @param {Node} this This node
35184 * @event beforeclick
35185 * Fires before click processing. Return false to cancel the default action.
35186 * @param {Node} this This node
35187 * @param {Roo.EventObject} e The event object
35189 "beforeclick":true,
35191 * @event checkchange
35192 * Fires when a node with a checkbox's checked property changes
35193 * @param {Node} this This node
35194 * @param {Boolean} checked
35196 "checkchange":true,
35199 * Fires when this node is clicked
35200 * @param {Node} this This node
35201 * @param {Roo.EventObject} e The event object
35206 * Fires when this node is double clicked
35207 * @param {Node} this This node
35208 * @param {Roo.EventObject} e The event object
35212 * @event contextmenu
35213 * Fires when this node is right clicked
35214 * @param {Node} this This node
35215 * @param {Roo.EventObject} e The event object
35217 "contextmenu":true,
35219 * @event beforechildrenrendered
35220 * Fires right before the child nodes for this node are rendered
35221 * @param {Node} this This node
35223 "beforechildrenrendered":true
35226 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35229 * Read-only. The UI for this node
35232 this.ui = new uiClass(this);
35234 // finally support items[]
35235 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35240 Roo.each(this.attributes.items, function(c) {
35241 this.appendChild(Roo.factory(c,Roo.Tree));
35243 delete this.attributes.items;
35248 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35249 preventHScroll: true,
35251 * Returns true if this node is expanded
35252 * @return {Boolean}
35254 isExpanded : function(){
35255 return this.expanded;
35259 * Returns the UI object for this node
35260 * @return {TreeNodeUI}
35262 getUI : function(){
35266 // private override
35267 setFirstChild : function(node){
35268 var of = this.firstChild;
35269 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35270 if(this.childrenRendered && of && node != of){
35271 of.renderIndent(true, true);
35274 this.renderIndent(true, true);
35278 // private override
35279 setLastChild : function(node){
35280 var ol = this.lastChild;
35281 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35282 if(this.childrenRendered && ol && node != ol){
35283 ol.renderIndent(true, true);
35286 this.renderIndent(true, true);
35290 // these methods are overridden to provide lazy rendering support
35291 // private override
35292 appendChild : function()
35294 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35295 if(node && this.childrenRendered){
35298 this.ui.updateExpandIcon();
35302 // private override
35303 removeChild : function(node){
35304 this.ownerTree.getSelectionModel().unselect(node);
35305 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35306 // if it's been rendered remove dom node
35307 if(this.childrenRendered){
35310 if(this.childNodes.length < 1){
35311 this.collapse(false, false);
35313 this.ui.updateExpandIcon();
35315 if(!this.firstChild) {
35316 this.childrenRendered = false;
35321 // private override
35322 insertBefore : function(node, refNode){
35323 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35324 if(newNode && refNode && this.childrenRendered){
35327 this.ui.updateExpandIcon();
35332 * Sets the text for this node
35333 * @param {String} text
35335 setText : function(text){
35336 var oldText = this.text;
35338 this.attributes.text = text;
35339 if(this.rendered){ // event without subscribing
35340 this.ui.onTextChange(this, text, oldText);
35342 this.fireEvent("textchange", this, text, oldText);
35346 * Triggers selection of this node
35348 select : function(){
35349 this.getOwnerTree().getSelectionModel().select(this);
35353 * Triggers deselection of this node
35355 unselect : function(){
35356 this.getOwnerTree().getSelectionModel().unselect(this);
35360 * Returns true if this node is selected
35361 * @return {Boolean}
35363 isSelected : function(){
35364 return this.getOwnerTree().getSelectionModel().isSelected(this);
35368 * Expand this node.
35369 * @param {Boolean} deep (optional) True to expand all children as well
35370 * @param {Boolean} anim (optional) false to cancel the default animation
35371 * @param {Function} callback (optional) A callback to be called when
35372 * expanding this node completes (does not wait for deep expand to complete).
35373 * Called with 1 parameter, this node.
35375 expand : function(deep, anim, callback){
35376 if(!this.expanded){
35377 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35380 if(!this.childrenRendered){
35381 this.renderChildren();
35383 this.expanded = true;
35385 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35386 this.ui.animExpand(function(){
35387 this.fireEvent("expand", this);
35388 if(typeof callback == "function"){
35392 this.expandChildNodes(true);
35394 }.createDelegate(this));
35398 this.fireEvent("expand", this);
35399 if(typeof callback == "function"){
35404 if(typeof callback == "function"){
35409 this.expandChildNodes(true);
35413 isHiddenRoot : function(){
35414 return this.isRoot && !this.getOwnerTree().rootVisible;
35418 * Collapse this node.
35419 * @param {Boolean} deep (optional) True to collapse all children as well
35420 * @param {Boolean} anim (optional) false to cancel the default animation
35422 collapse : function(deep, anim){
35423 if(this.expanded && !this.isHiddenRoot()){
35424 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35427 this.expanded = false;
35428 if((this.getOwnerTree().animate && anim !== false) || anim){
35429 this.ui.animCollapse(function(){
35430 this.fireEvent("collapse", this);
35432 this.collapseChildNodes(true);
35434 }.createDelegate(this));
35437 this.ui.collapse();
35438 this.fireEvent("collapse", this);
35442 var cs = this.childNodes;
35443 for(var i = 0, len = cs.length; i < len; i++) {
35444 cs[i].collapse(true, false);
35450 delayedExpand : function(delay){
35451 if(!this.expandProcId){
35452 this.expandProcId = this.expand.defer(delay, this);
35457 cancelExpand : function(){
35458 if(this.expandProcId){
35459 clearTimeout(this.expandProcId);
35461 this.expandProcId = false;
35465 * Toggles expanded/collapsed state of the node
35467 toggle : function(){
35476 * Ensures all parent nodes are expanded
35478 ensureVisible : function(callback){
35479 var tree = this.getOwnerTree();
35480 tree.expandPath(this.parentNode.getPath(), false, function(){
35481 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35482 Roo.callback(callback);
35483 }.createDelegate(this));
35487 * Expand all child nodes
35488 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35490 expandChildNodes : function(deep){
35491 var cs = this.childNodes;
35492 for(var i = 0, len = cs.length; i < len; i++) {
35493 cs[i].expand(deep);
35498 * Collapse all child nodes
35499 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35501 collapseChildNodes : function(deep){
35502 var cs = this.childNodes;
35503 for(var i = 0, len = cs.length; i < len; i++) {
35504 cs[i].collapse(deep);
35509 * Disables this node
35511 disable : function(){
35512 this.disabled = true;
35514 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35515 this.ui.onDisableChange(this, true);
35517 this.fireEvent("disabledchange", this, true);
35521 * Enables this node
35523 enable : function(){
35524 this.disabled = false;
35525 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35526 this.ui.onDisableChange(this, false);
35528 this.fireEvent("disabledchange", this, false);
35532 renderChildren : function(suppressEvent){
35533 if(suppressEvent !== false){
35534 this.fireEvent("beforechildrenrendered", this);
35536 var cs = this.childNodes;
35537 for(var i = 0, len = cs.length; i < len; i++){
35538 cs[i].render(true);
35540 this.childrenRendered = true;
35544 sort : function(fn, scope){
35545 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35546 if(this.childrenRendered){
35547 var cs = this.childNodes;
35548 for(var i = 0, len = cs.length; i < len; i++){
35549 cs[i].render(true);
35555 render : function(bulkRender){
35556 this.ui.render(bulkRender);
35557 if(!this.rendered){
35558 this.rendered = true;
35560 this.expanded = false;
35561 this.expand(false, false);
35567 renderIndent : function(deep, refresh){
35569 this.ui.childIndent = null;
35571 this.ui.renderIndent();
35572 if(deep === true && this.childrenRendered){
35573 var cs = this.childNodes;
35574 for(var i = 0, len = cs.length; i < len; i++){
35575 cs[i].renderIndent(true, refresh);
35581 * Ext JS Library 1.1.1
35582 * Copyright(c) 2006-2007, Ext JS, LLC.
35584 * Originally Released Under LGPL - original licence link has changed is not relivant.
35587 * <script type="text/javascript">
35591 * @class Roo.tree.AsyncTreeNode
35592 * @extends Roo.tree.TreeNode
35593 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35595 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35597 Roo.tree.AsyncTreeNode = function(config){
35598 this.loaded = false;
35599 this.loading = false;
35600 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35602 * @event beforeload
35603 * Fires before this node is loaded, return false to cancel
35604 * @param {Node} this This node
35606 this.addEvents({'beforeload':true, 'load': true});
35609 * Fires when this node is loaded
35610 * @param {Node} this This node
35613 * The loader used by this node (defaults to using the tree's defined loader)
35618 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35619 expand : function(deep, anim, callback){
35620 if(this.loading){ // if an async load is already running, waiting til it's done
35622 var f = function(){
35623 if(!this.loading){ // done loading
35624 clearInterval(timer);
35625 this.expand(deep, anim, callback);
35627 }.createDelegate(this);
35628 timer = setInterval(f, 200);
35632 if(this.fireEvent("beforeload", this) === false){
35635 this.loading = true;
35636 this.ui.beforeLoad(this);
35637 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35639 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35643 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35647 * Returns true if this node is currently loading
35648 * @return {Boolean}
35650 isLoading : function(){
35651 return this.loading;
35654 loadComplete : function(deep, anim, callback){
35655 this.loading = false;
35656 this.loaded = true;
35657 this.ui.afterLoad(this);
35658 this.fireEvent("load", this);
35659 this.expand(deep, anim, callback);
35663 * Returns true if this node has been loaded
35664 * @return {Boolean}
35666 isLoaded : function(){
35667 return this.loaded;
35670 hasChildNodes : function(){
35671 if(!this.isLeaf() && !this.loaded){
35674 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35679 * Trigger a reload for this node
35680 * @param {Function} callback
35682 reload : function(callback){
35683 this.collapse(false, false);
35684 while(this.firstChild){
35685 this.removeChild(this.firstChild);
35687 this.childrenRendered = false;
35688 this.loaded = false;
35689 if(this.isHiddenRoot()){
35690 this.expanded = false;
35692 this.expand(false, false, callback);
35696 * Ext JS Library 1.1.1
35697 * Copyright(c) 2006-2007, Ext JS, LLC.
35699 * Originally Released Under LGPL - original licence link has changed is not relivant.
35702 * <script type="text/javascript">
35706 * @class Roo.tree.TreeNodeUI
35708 * @param {Object} node The node to render
35709 * The TreeNode UI implementation is separate from the
35710 * tree implementation. Unless you are customizing the tree UI,
35711 * you should never have to use this directly.
35713 Roo.tree.TreeNodeUI = function(node){
35715 this.rendered = false;
35716 this.animating = false;
35717 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35720 Roo.tree.TreeNodeUI.prototype = {
35721 removeChild : function(node){
35723 this.ctNode.removeChild(node.ui.getEl());
35727 beforeLoad : function(){
35728 this.addClass("x-tree-node-loading");
35731 afterLoad : function(){
35732 this.removeClass("x-tree-node-loading");
35735 onTextChange : function(node, text, oldText){
35737 this.textNode.innerHTML = text;
35741 onDisableChange : function(node, state){
35742 this.disabled = state;
35744 this.addClass("x-tree-node-disabled");
35746 this.removeClass("x-tree-node-disabled");
35750 onSelectedChange : function(state){
35753 this.addClass("x-tree-selected");
35756 this.removeClass("x-tree-selected");
35760 onMove : function(tree, node, oldParent, newParent, index, refNode){
35761 this.childIndent = null;
35763 var targetNode = newParent.ui.getContainer();
35764 if(!targetNode){//target not rendered
35765 this.holder = document.createElement("div");
35766 this.holder.appendChild(this.wrap);
35769 var insertBefore = refNode ? refNode.ui.getEl() : null;
35771 targetNode.insertBefore(this.wrap, insertBefore);
35773 targetNode.appendChild(this.wrap);
35775 this.node.renderIndent(true);
35779 addClass : function(cls){
35781 Roo.fly(this.elNode).addClass(cls);
35785 removeClass : function(cls){
35787 Roo.fly(this.elNode).removeClass(cls);
35791 remove : function(){
35793 this.holder = document.createElement("div");
35794 this.holder.appendChild(this.wrap);
35798 fireEvent : function(){
35799 return this.node.fireEvent.apply(this.node, arguments);
35802 initEvents : function(){
35803 this.node.on("move", this.onMove, this);
35804 var E = Roo.EventManager;
35805 var a = this.anchor;
35807 var el = Roo.fly(a, '_treeui');
35809 if(Roo.isOpera){ // opera render bug ignores the CSS
35810 el.setStyle("text-decoration", "none");
35813 el.on("click", this.onClick, this);
35814 el.on("dblclick", this.onDblClick, this);
35817 Roo.EventManager.on(this.checkbox,
35818 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35821 el.on("contextmenu", this.onContextMenu, this);
35823 var icon = Roo.fly(this.iconNode);
35824 icon.on("click", this.onClick, this);
35825 icon.on("dblclick", this.onDblClick, this);
35826 icon.on("contextmenu", this.onContextMenu, this);
35827 E.on(this.ecNode, "click", this.ecClick, this, true);
35829 if(this.node.disabled){
35830 this.addClass("x-tree-node-disabled");
35832 if(this.node.hidden){
35833 this.addClass("x-tree-node-disabled");
35835 var ot = this.node.getOwnerTree();
35836 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35837 if(dd && (!this.node.isRoot || ot.rootVisible)){
35838 Roo.dd.Registry.register(this.elNode, {
35840 handles: this.getDDHandles(),
35846 getDDHandles : function(){
35847 return [this.iconNode, this.textNode];
35852 this.wrap.style.display = "none";
35858 this.wrap.style.display = "";
35862 onContextMenu : function(e){
35863 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35864 e.preventDefault();
35866 this.fireEvent("contextmenu", this.node, e);
35870 onClick : function(e){
35875 if(this.fireEvent("beforeclick", this.node, e) !== false){
35876 if(!this.disabled && this.node.attributes.href){
35877 this.fireEvent("click", this.node, e);
35880 e.preventDefault();
35885 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35886 this.node.toggle();
35889 this.fireEvent("click", this.node, e);
35895 onDblClick : function(e){
35896 e.preventDefault();
35901 this.toggleCheck();
35903 if(!this.animating && this.node.hasChildNodes()){
35904 this.node.toggle();
35906 this.fireEvent("dblclick", this.node, e);
35909 onCheckChange : function(){
35910 var checked = this.checkbox.checked;
35911 this.node.attributes.checked = checked;
35912 this.fireEvent('checkchange', this.node, checked);
35915 ecClick : function(e){
35916 if(!this.animating && this.node.hasChildNodes()){
35917 this.node.toggle();
35921 startDrop : function(){
35922 this.dropping = true;
35925 // delayed drop so the click event doesn't get fired on a drop
35926 endDrop : function(){
35927 setTimeout(function(){
35928 this.dropping = false;
35929 }.createDelegate(this), 50);
35932 expand : function(){
35933 this.updateExpandIcon();
35934 this.ctNode.style.display = "";
35937 focus : function(){
35938 if(!this.node.preventHScroll){
35939 try{this.anchor.focus();
35941 }else if(!Roo.isIE){
35943 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35944 var l = noscroll.scrollLeft;
35945 this.anchor.focus();
35946 noscroll.scrollLeft = l;
35951 toggleCheck : function(value){
35952 var cb = this.checkbox;
35954 cb.checked = (value === undefined ? !cb.checked : value);
35960 this.anchor.blur();
35964 animExpand : function(callback){
35965 var ct = Roo.get(this.ctNode);
35967 if(!this.node.hasChildNodes()){
35968 this.updateExpandIcon();
35969 this.ctNode.style.display = "";
35970 Roo.callback(callback);
35973 this.animating = true;
35974 this.updateExpandIcon();
35977 callback : function(){
35978 this.animating = false;
35979 Roo.callback(callback);
35982 duration: this.node.ownerTree.duration || .25
35986 highlight : function(){
35987 var tree = this.node.getOwnerTree();
35988 Roo.fly(this.wrap).highlight(
35989 tree.hlColor || "C3DAF9",
35990 {endColor: tree.hlBaseColor}
35994 collapse : function(){
35995 this.updateExpandIcon();
35996 this.ctNode.style.display = "none";
35999 animCollapse : function(callback){
36000 var ct = Roo.get(this.ctNode);
36001 ct.enableDisplayMode('block');
36004 this.animating = true;
36005 this.updateExpandIcon();
36008 callback : function(){
36009 this.animating = false;
36010 Roo.callback(callback);
36013 duration: this.node.ownerTree.duration || .25
36017 getContainer : function(){
36018 return this.ctNode;
36021 getEl : function(){
36025 appendDDGhost : function(ghostNode){
36026 ghostNode.appendChild(this.elNode.cloneNode(true));
36029 getDDRepairXY : function(){
36030 return Roo.lib.Dom.getXY(this.iconNode);
36033 onRender : function(){
36037 render : function(bulkRender){
36038 var n = this.node, a = n.attributes;
36039 var targetNode = n.parentNode ?
36040 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
36042 if(!this.rendered){
36043 this.rendered = true;
36045 this.renderElements(n, a, targetNode, bulkRender);
36048 if(this.textNode.setAttributeNS){
36049 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
36051 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
36054 this.textNode.setAttribute("ext:qtip", a.qtip);
36056 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
36059 }else if(a.qtipCfg){
36060 a.qtipCfg.target = Roo.id(this.textNode);
36061 Roo.QuickTips.register(a.qtipCfg);
36064 if(!this.node.expanded){
36065 this.updateExpandIcon();
36068 if(bulkRender === true) {
36069 targetNode.appendChild(this.wrap);
36074 renderElements : function(n, a, targetNode, bulkRender)
36076 // add some indent caching, this helps performance when rendering a large tree
36077 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36078 var t = n.getOwnerTree();
36079 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36080 if (typeof(n.attributes.html) != 'undefined') {
36081 txt = n.attributes.html;
36083 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36084 var cb = typeof a.checked == 'boolean';
36085 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36086 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36087 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36088 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36089 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
36090 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
36091 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
36092 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
36093 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
36094 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36097 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36098 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36099 n.nextSibling.ui.getEl(), buf.join(""));
36101 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36104 this.elNode = this.wrap.childNodes[0];
36105 this.ctNode = this.wrap.childNodes[1];
36106 var cs = this.elNode.childNodes;
36107 this.indentNode = cs[0];
36108 this.ecNode = cs[1];
36109 this.iconNode = cs[2];
36112 this.checkbox = cs[3];
36115 this.anchor = cs[index];
36116 this.textNode = cs[index].firstChild;
36119 getAnchor : function(){
36120 return this.anchor;
36123 getTextEl : function(){
36124 return this.textNode;
36127 getIconEl : function(){
36128 return this.iconNode;
36131 isChecked : function(){
36132 return this.checkbox ? this.checkbox.checked : false;
36135 updateExpandIcon : function(){
36137 var n = this.node, c1, c2;
36138 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36139 var hasChild = n.hasChildNodes();
36143 c1 = "x-tree-node-collapsed";
36144 c2 = "x-tree-node-expanded";
36147 c1 = "x-tree-node-expanded";
36148 c2 = "x-tree-node-collapsed";
36151 this.removeClass("x-tree-node-leaf");
36152 this.wasLeaf = false;
36154 if(this.c1 != c1 || this.c2 != c2){
36155 Roo.fly(this.elNode).replaceClass(c1, c2);
36156 this.c1 = c1; this.c2 = c2;
36159 // this changes non-leafs into leafs if they have no children.
36160 // it's not very rational behaviour..
36162 if(!this.wasLeaf && this.node.leaf){
36163 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36166 this.wasLeaf = true;
36169 var ecc = "x-tree-ec-icon "+cls;
36170 if(this.ecc != ecc){
36171 this.ecNode.className = ecc;
36177 getChildIndent : function(){
36178 if(!this.childIndent){
36182 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36184 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36186 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36191 this.childIndent = buf.join("");
36193 return this.childIndent;
36196 renderIndent : function(){
36199 var p = this.node.parentNode;
36201 indent = p.ui.getChildIndent();
36203 if(this.indentMarkup != indent){ // don't rerender if not required
36204 this.indentNode.innerHTML = indent;
36205 this.indentMarkup = indent;
36207 this.updateExpandIcon();
36212 Roo.tree.RootTreeNodeUI = function(){
36213 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36215 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36216 render : function(){
36217 if(!this.rendered){
36218 var targetNode = this.node.ownerTree.innerCt.dom;
36219 this.node.expanded = true;
36220 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36221 this.wrap = this.ctNode = targetNode.firstChild;
36224 collapse : function(){
36226 expand : function(){
36230 * Ext JS Library 1.1.1
36231 * Copyright(c) 2006-2007, Ext JS, LLC.
36233 * Originally Released Under LGPL - original licence link has changed is not relivant.
36236 * <script type="text/javascript">
36239 * @class Roo.tree.TreeLoader
36240 * @extends Roo.util.Observable
36241 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36242 * nodes from a specified URL. The response must be a javascript Array definition
36243 * who's elements are node definition objects. eg:
36248 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36249 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36256 * The old style respose with just an array is still supported, but not recommended.
36259 * A server request is sent, and child nodes are loaded only when a node is expanded.
36260 * The loading node's id is passed to the server under the parameter name "node" to
36261 * enable the server to produce the correct child nodes.
36263 * To pass extra parameters, an event handler may be attached to the "beforeload"
36264 * event, and the parameters specified in the TreeLoader's baseParams property:
36266 myTreeLoader.on("beforeload", function(treeLoader, node) {
36267 this.baseParams.category = node.attributes.category;
36272 * This would pass an HTTP parameter called "category" to the server containing
36273 * the value of the Node's "category" attribute.
36275 * Creates a new Treeloader.
36276 * @param {Object} config A config object containing config properties.
36278 Roo.tree.TreeLoader = function(config){
36279 this.baseParams = {};
36280 this.requestMethod = "POST";
36281 Roo.apply(this, config);
36286 * @event beforeload
36287 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36288 * @param {Object} This TreeLoader object.
36289 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36290 * @param {Object} callback The callback function specified in the {@link #load} call.
36295 * Fires when the node has been successfuly loaded.
36296 * @param {Object} This TreeLoader object.
36297 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36298 * @param {Object} response The response object containing the data from the server.
36302 * @event loadexception
36303 * Fires if the network request failed.
36304 * @param {Object} This TreeLoader object.
36305 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36306 * @param {Object} response The response object containing the data from the server.
36308 loadexception : true,
36311 * Fires before a node is created, enabling you to return custom Node types
36312 * @param {Object} This TreeLoader object.
36313 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36318 Roo.tree.TreeLoader.superclass.constructor.call(this);
36321 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36323 * @cfg {String} dataUrl The URL from which to request a Json string which
36324 * specifies an array of node definition object representing the child nodes
36328 * @cfg {String} requestMethod either GET or POST
36329 * defaults to POST (due to BC)
36333 * @cfg {Object} baseParams (optional) An object containing properties which
36334 * specify HTTP parameters to be passed to each request for child nodes.
36337 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36338 * created by this loader. If the attributes sent by the server have an attribute in this object,
36339 * they take priority.
36342 * @cfg {Object} uiProviders (optional) An object containing properties which
36344 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36345 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36346 * <i>uiProvider</i> attribute of a returned child node is a string rather
36347 * than a reference to a TreeNodeUI implementation, this that string value
36348 * is used as a property name in the uiProviders object. You can define the provider named
36349 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36354 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36355 * child nodes before loading.
36357 clearOnLoad : true,
36360 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36361 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36362 * Grid query { data : [ .....] }
36367 * @cfg {String} queryParam (optional)
36368 * Name of the query as it will be passed on the querystring (defaults to 'node')
36369 * eg. the request will be ?node=[id]
36376 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36377 * This is called automatically when a node is expanded, but may be used to reload
36378 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36379 * @param {Roo.tree.TreeNode} node
36380 * @param {Function} callback
36382 load : function(node, callback){
36383 if(this.clearOnLoad){
36384 while(node.firstChild){
36385 node.removeChild(node.firstChild);
36388 if(node.attributes.children){ // preloaded json children
36389 var cs = node.attributes.children;
36390 for(var i = 0, len = cs.length; i < len; i++){
36391 node.appendChild(this.createNode(cs[i]));
36393 if(typeof callback == "function"){
36396 }else if(this.dataUrl){
36397 this.requestData(node, callback);
36401 getParams: function(node){
36402 var buf = [], bp = this.baseParams;
36403 for(var key in bp){
36404 if(typeof bp[key] != "function"){
36405 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36408 var n = this.queryParam === false ? 'node' : this.queryParam;
36409 buf.push(n + "=", encodeURIComponent(node.id));
36410 return buf.join("");
36413 requestData : function(node, callback){
36414 if(this.fireEvent("beforeload", this, node, callback) !== false){
36415 this.transId = Roo.Ajax.request({
36416 method:this.requestMethod,
36417 url: this.dataUrl||this.url,
36418 success: this.handleResponse,
36419 failure: this.handleFailure,
36421 argument: {callback: callback, node: node},
36422 params: this.getParams(node)
36425 // if the load is cancelled, make sure we notify
36426 // the node that we are done
36427 if(typeof callback == "function"){
36433 isLoading : function(){
36434 return this.transId ? true : false;
36437 abort : function(){
36438 if(this.isLoading()){
36439 Roo.Ajax.abort(this.transId);
36444 createNode : function(attr)
36446 // apply baseAttrs, nice idea Corey!
36447 if(this.baseAttrs){
36448 Roo.applyIf(attr, this.baseAttrs);
36450 if(this.applyLoader !== false){
36451 attr.loader = this;
36453 // uiProvider = depreciated..
36455 if(typeof(attr.uiProvider) == 'string'){
36456 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36457 /** eval:var:attr */ eval(attr.uiProvider);
36459 if(typeof(this.uiProviders['default']) != 'undefined') {
36460 attr.uiProvider = this.uiProviders['default'];
36463 this.fireEvent('create', this, attr);
36465 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36467 new Roo.tree.TreeNode(attr) :
36468 new Roo.tree.AsyncTreeNode(attr));
36471 processResponse : function(response, node, callback)
36473 var json = response.responseText;
36476 var o = Roo.decode(json);
36478 if (this.root === false && typeof(o.success) != undefined) {
36479 this.root = 'data'; // the default behaviour for list like data..
36482 if (this.root !== false && !o.success) {
36483 // it's a failure condition.
36484 var a = response.argument;
36485 this.fireEvent("loadexception", this, a.node, response);
36486 Roo.log("Load failed - should have a handler really");
36492 if (this.root !== false) {
36496 for(var i = 0, len = o.length; i < len; i++){
36497 var n = this.createNode(o[i]);
36499 node.appendChild(n);
36502 if(typeof callback == "function"){
36503 callback(this, node);
36506 this.handleFailure(response);
36510 handleResponse : function(response){
36511 this.transId = false;
36512 var a = response.argument;
36513 this.processResponse(response, a.node, a.callback);
36514 this.fireEvent("load", this, a.node, response);
36517 handleFailure : function(response)
36519 // should handle failure better..
36520 this.transId = false;
36521 var a = response.argument;
36522 this.fireEvent("loadexception", this, a.node, response);
36523 if(typeof a.callback == "function"){
36524 a.callback(this, a.node);
36529 * Ext JS Library 1.1.1
36530 * Copyright(c) 2006-2007, Ext JS, LLC.
36532 * Originally Released Under LGPL - original licence link has changed is not relivant.
36535 * <script type="text/javascript">
36539 * @class Roo.tree.TreeFilter
36540 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36541 * @param {TreePanel} tree
36542 * @param {Object} config (optional)
36544 Roo.tree.TreeFilter = function(tree, config){
36546 this.filtered = {};
36547 Roo.apply(this, config);
36550 Roo.tree.TreeFilter.prototype = {
36557 * Filter the data by a specific attribute.
36558 * @param {String/RegExp} value Either string that the attribute value
36559 * should start with or a RegExp to test against the attribute
36560 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36561 * @param {TreeNode} startNode (optional) The node to start the filter at.
36563 filter : function(value, attr, startNode){
36564 attr = attr || "text";
36566 if(typeof value == "string"){
36567 var vlen = value.length;
36568 // auto clear empty filter
36569 if(vlen == 0 && this.clearBlank){
36573 value = value.toLowerCase();
36575 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36577 }else if(value.exec){ // regex?
36579 return value.test(n.attributes[attr]);
36582 throw 'Illegal filter type, must be string or regex';
36584 this.filterBy(f, null, startNode);
36588 * Filter by a function. The passed function will be called with each
36589 * node in the tree (or from the startNode). If the function returns true, the node is kept
36590 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36591 * @param {Function} fn The filter function
36592 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36594 filterBy : function(fn, scope, startNode){
36595 startNode = startNode || this.tree.root;
36596 if(this.autoClear){
36599 var af = this.filtered, rv = this.reverse;
36600 var f = function(n){
36601 if(n == startNode){
36607 var m = fn.call(scope || n, n);
36615 startNode.cascade(f);
36618 if(typeof id != "function"){
36620 if(n && n.parentNode){
36621 n.parentNode.removeChild(n);
36629 * Clears the current filter. Note: with the "remove" option
36630 * set a filter cannot be cleared.
36632 clear : function(){
36634 var af = this.filtered;
36636 if(typeof id != "function"){
36643 this.filtered = {};
36648 * Ext JS Library 1.1.1
36649 * Copyright(c) 2006-2007, Ext JS, LLC.
36651 * Originally Released Under LGPL - original licence link has changed is not relivant.
36654 * <script type="text/javascript">
36659 * @class Roo.tree.TreeSorter
36660 * Provides sorting of nodes in a TreePanel
36662 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36663 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36664 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36665 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36666 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36667 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36669 * @param {TreePanel} tree
36670 * @param {Object} config
36672 Roo.tree.TreeSorter = function(tree, config){
36673 Roo.apply(this, config);
36674 tree.on("beforechildrenrendered", this.doSort, this);
36675 tree.on("append", this.updateSort, this);
36676 tree.on("insert", this.updateSort, this);
36678 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36679 var p = this.property || "text";
36680 var sortType = this.sortType;
36681 var fs = this.folderSort;
36682 var cs = this.caseSensitive === true;
36683 var leafAttr = this.leafAttr || 'leaf';
36685 this.sortFn = function(n1, n2){
36687 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36690 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36694 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36695 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36697 return dsc ? +1 : -1;
36699 return dsc ? -1 : +1;
36706 Roo.tree.TreeSorter.prototype = {
36707 doSort : function(node){
36708 node.sort(this.sortFn);
36711 compareNodes : function(n1, n2){
36712 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36715 updateSort : function(tree, node){
36716 if(node.childrenRendered){
36717 this.doSort.defer(1, this, [node]);
36722 * Ext JS Library 1.1.1
36723 * Copyright(c) 2006-2007, Ext JS, LLC.
36725 * Originally Released Under LGPL - original licence link has changed is not relivant.
36728 * <script type="text/javascript">
36731 if(Roo.dd.DropZone){
36733 Roo.tree.TreeDropZone = function(tree, config){
36734 this.allowParentInsert = false;
36735 this.allowContainerDrop = false;
36736 this.appendOnly = false;
36737 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36739 this.lastInsertClass = "x-tree-no-status";
36740 this.dragOverData = {};
36743 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36744 ddGroup : "TreeDD",
36747 expandDelay : 1000,
36749 expandNode : function(node){
36750 if(node.hasChildNodes() && !node.isExpanded()){
36751 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36755 queueExpand : function(node){
36756 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36759 cancelExpand : function(){
36760 if(this.expandProcId){
36761 clearTimeout(this.expandProcId);
36762 this.expandProcId = false;
36766 isValidDropPoint : function(n, pt, dd, e, data){
36767 if(!n || !data){ return false; }
36768 var targetNode = n.node;
36769 var dropNode = data.node;
36770 // default drop rules
36771 if(!(targetNode && targetNode.isTarget && pt)){
36774 if(pt == "append" && targetNode.allowChildren === false){
36777 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36780 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36783 // reuse the object
36784 var overEvent = this.dragOverData;
36785 overEvent.tree = this.tree;
36786 overEvent.target = targetNode;
36787 overEvent.data = data;
36788 overEvent.point = pt;
36789 overEvent.source = dd;
36790 overEvent.rawEvent = e;
36791 overEvent.dropNode = dropNode;
36792 overEvent.cancel = false;
36793 var result = this.tree.fireEvent("nodedragover", overEvent);
36794 return overEvent.cancel === false && result !== false;
36797 getDropPoint : function(e, n, dd)
36801 return tn.allowChildren !== false ? "append" : false; // always append for root
36803 var dragEl = n.ddel;
36804 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36805 var y = Roo.lib.Event.getPageY(e);
36806 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36808 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36809 var noAppend = tn.allowChildren === false;
36810 if(this.appendOnly || tn.parentNode.allowChildren === false){
36811 return noAppend ? false : "append";
36813 var noBelow = false;
36814 if(!this.allowParentInsert){
36815 noBelow = tn.hasChildNodes() && tn.isExpanded();
36817 var q = (b - t) / (noAppend ? 2 : 3);
36818 if(y >= t && y < (t + q)){
36820 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36827 onNodeEnter : function(n, dd, e, data)
36829 this.cancelExpand();
36832 onNodeOver : function(n, dd, e, data)
36835 var pt = this.getDropPoint(e, n, dd);
36838 // auto node expand check
36839 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36840 this.queueExpand(node);
36841 }else if(pt != "append"){
36842 this.cancelExpand();
36845 // set the insert point style on the target node
36846 var returnCls = this.dropNotAllowed;
36847 if(this.isValidDropPoint(n, pt, dd, e, data)){
36852 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36853 cls = "x-tree-drag-insert-above";
36854 }else if(pt == "below"){
36855 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36856 cls = "x-tree-drag-insert-below";
36858 returnCls = "x-tree-drop-ok-append";
36859 cls = "x-tree-drag-append";
36861 if(this.lastInsertClass != cls){
36862 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36863 this.lastInsertClass = cls;
36870 onNodeOut : function(n, dd, e, data){
36872 this.cancelExpand();
36873 this.removeDropIndicators(n);
36876 onNodeDrop : function(n, dd, e, data){
36877 var point = this.getDropPoint(e, n, dd);
36878 var targetNode = n.node;
36879 targetNode.ui.startDrop();
36880 if(!this.isValidDropPoint(n, point, dd, e, data)){
36881 targetNode.ui.endDrop();
36884 // first try to find the drop node
36885 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36888 target: targetNode,
36893 dropNode: dropNode,
36896 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36897 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36898 targetNode.ui.endDrop();
36901 // allow target changing
36902 targetNode = dropEvent.target;
36903 if(point == "append" && !targetNode.isExpanded()){
36904 targetNode.expand(false, null, function(){
36905 this.completeDrop(dropEvent);
36906 }.createDelegate(this));
36908 this.completeDrop(dropEvent);
36913 completeDrop : function(de){
36914 var ns = de.dropNode, p = de.point, t = de.target;
36915 if(!(ns instanceof Array)){
36919 for(var i = 0, len = ns.length; i < len; i++){
36922 t.parentNode.insertBefore(n, t);
36923 }else if(p == "below"){
36924 t.parentNode.insertBefore(n, t.nextSibling);
36930 if(this.tree.hlDrop){
36934 this.tree.fireEvent("nodedrop", de);
36937 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36938 if(this.tree.hlDrop){
36939 dropNode.ui.focus();
36940 dropNode.ui.highlight();
36942 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36945 getTree : function(){
36949 removeDropIndicators : function(n){
36952 Roo.fly(el).removeClass([
36953 "x-tree-drag-insert-above",
36954 "x-tree-drag-insert-below",
36955 "x-tree-drag-append"]);
36956 this.lastInsertClass = "_noclass";
36960 beforeDragDrop : function(target, e, id){
36961 this.cancelExpand();
36965 afterRepair : function(data){
36966 if(data && Roo.enableFx){
36967 data.node.ui.highlight();
36977 * Ext JS Library 1.1.1
36978 * Copyright(c) 2006-2007, Ext JS, LLC.
36980 * Originally Released Under LGPL - original licence link has changed is not relivant.
36983 * <script type="text/javascript">
36987 if(Roo.dd.DragZone){
36988 Roo.tree.TreeDragZone = function(tree, config){
36989 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36993 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36994 ddGroup : "TreeDD",
36996 onBeforeDrag : function(data, e){
36998 return n && n.draggable && !n.disabled;
37002 onInitDrag : function(e){
37003 var data = this.dragData;
37004 this.tree.getSelectionModel().select(data.node);
37005 this.proxy.update("");
37006 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
37007 this.tree.fireEvent("startdrag", this.tree, data.node, e);
37010 getRepairXY : function(e, data){
37011 return data.node.ui.getDDRepairXY();
37014 onEndDrag : function(data, e){
37015 this.tree.fireEvent("enddrag", this.tree, data.node, e);
37020 onValidDrop : function(dd, e, id){
37021 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
37025 beforeInvalidDrop : function(e, id){
37026 // this scrolls the original position back into view
37027 var sm = this.tree.getSelectionModel();
37028 sm.clearSelections();
37029 sm.select(this.dragData.node);
37034 * Ext JS Library 1.1.1
37035 * Copyright(c) 2006-2007, Ext JS, LLC.
37037 * Originally Released Under LGPL - original licence link has changed is not relivant.
37040 * <script type="text/javascript">
37043 * @class Roo.tree.TreeEditor
37044 * @extends Roo.Editor
37045 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
37046 * as the editor field.
37048 * @param {Object} config (used to be the tree panel.)
37049 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
37051 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
37052 * @cfg {Roo.form.TextField|Object} field The field configuration
37056 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
37059 if (oldconfig) { // old style..
37060 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
37063 tree = config.tree;
37064 config.field = config.field || {};
37065 config.field.xtype = 'TextField';
37066 field = Roo.factory(config.field, Roo.form);
37068 config = config || {};
37073 * @event beforenodeedit
37074 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37075 * false from the handler of this event.
37076 * @param {Editor} this
37077 * @param {Roo.tree.Node} node
37079 "beforenodeedit" : true
37083 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37087 tree.on('beforeclick', this.beforeNodeClick, this);
37088 tree.getTreeEl().on('mousedown', this.hide, this);
37089 this.on('complete', this.updateNode, this);
37090 this.on('beforestartedit', this.fitToTree, this);
37091 this.on('startedit', this.bindScroll, this, {delay:10});
37092 this.on('specialkey', this.onSpecialKey, this);
37095 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
37097 * @cfg {String} alignment
37098 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37104 * @cfg {Boolean} hideEl
37105 * True to hide the bound element while the editor is displayed (defaults to false)
37109 * @cfg {String} cls
37110 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37112 cls: "x-small-editor x-tree-editor",
37114 * @cfg {Boolean} shim
37115 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37121 * @cfg {Number} maxWidth
37122 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37123 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37124 * scroll and client offsets into account prior to each edit.
37131 fitToTree : function(ed, el){
37132 var td = this.tree.getTreeEl().dom, nd = el.dom;
37133 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37134 td.scrollLeft = nd.offsetLeft;
37138 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37139 this.setSize(w, '');
37141 return this.fireEvent('beforenodeedit', this, this.editNode);
37146 triggerEdit : function(node){
37147 this.completeEdit();
37148 this.editNode = node;
37149 this.startEdit(node.ui.textNode, node.text);
37153 bindScroll : function(){
37154 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37158 beforeNodeClick : function(node, e){
37159 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37160 this.lastClick = new Date();
37161 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37163 this.triggerEdit(node);
37170 updateNode : function(ed, value){
37171 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37172 this.editNode.setText(value);
37176 onHide : function(){
37177 Roo.tree.TreeEditor.superclass.onHide.call(this);
37179 this.editNode.ui.focus();
37184 onSpecialKey : function(field, e){
37185 var k = e.getKey();
37189 }else if(k == e.ENTER && !e.hasModifier()){
37191 this.completeEdit();
37194 });//<Script type="text/javascript">
37197 * Ext JS Library 1.1.1
37198 * Copyright(c) 2006-2007, Ext JS, LLC.
37200 * Originally Released Under LGPL - original licence link has changed is not relivant.
37203 * <script type="text/javascript">
37207 * Not documented??? - probably should be...
37210 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37211 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37213 renderElements : function(n, a, targetNode, bulkRender){
37214 //consel.log("renderElements?");
37215 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37217 var t = n.getOwnerTree();
37218 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37220 var cols = t.columns;
37221 var bw = t.borderWidth;
37223 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37224 var cb = typeof a.checked == "boolean";
37225 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37226 var colcls = 'x-t-' + tid + '-c0';
37228 '<li class="x-tree-node">',
37231 '<div class="x-tree-node-el ', a.cls,'">',
37233 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37236 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37237 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37238 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37239 (a.icon ? ' x-tree-node-inline-icon' : ''),
37240 (a.iconCls ? ' '+a.iconCls : ''),
37241 '" unselectable="on" />',
37242 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37243 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37245 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37246 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37247 '<span unselectable="on" qtip="' + tx + '">',
37251 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37252 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37254 for(var i = 1, len = cols.length; i < len; i++){
37256 colcls = 'x-t-' + tid + '-c' +i;
37257 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37258 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37259 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37265 '<div class="x-clear"></div></div>',
37266 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37269 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37270 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37271 n.nextSibling.ui.getEl(), buf.join(""));
37273 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37275 var el = this.wrap.firstChild;
37277 this.elNode = el.firstChild;
37278 this.ranchor = el.childNodes[1];
37279 this.ctNode = this.wrap.childNodes[1];
37280 var cs = el.firstChild.childNodes;
37281 this.indentNode = cs[0];
37282 this.ecNode = cs[1];
37283 this.iconNode = cs[2];
37286 this.checkbox = cs[3];
37289 this.anchor = cs[index];
37291 this.textNode = cs[index].firstChild;
37293 //el.on("click", this.onClick, this);
37294 //el.on("dblclick", this.onDblClick, this);
37297 // console.log(this);
37299 initEvents : function(){
37300 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37303 var a = this.ranchor;
37305 var el = Roo.get(a);
37307 if(Roo.isOpera){ // opera render bug ignores the CSS
37308 el.setStyle("text-decoration", "none");
37311 el.on("click", this.onClick, this);
37312 el.on("dblclick", this.onDblClick, this);
37313 el.on("contextmenu", this.onContextMenu, this);
37317 /*onSelectedChange : function(state){
37320 this.addClass("x-tree-selected");
37323 this.removeClass("x-tree-selected");
37326 addClass : function(cls){
37328 Roo.fly(this.elRow).addClass(cls);
37334 removeClass : function(cls){
37336 Roo.fly(this.elRow).removeClass(cls);
37342 });//<Script type="text/javascript">
37346 * Ext JS Library 1.1.1
37347 * Copyright(c) 2006-2007, Ext JS, LLC.
37349 * Originally Released Under LGPL - original licence link has changed is not relivant.
37352 * <script type="text/javascript">
37357 * @class Roo.tree.ColumnTree
37358 * @extends Roo.data.TreePanel
37359 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37360 * @cfg {int} borderWidth compined right/left border allowance
37362 * @param {String/HTMLElement/Element} el The container element
37363 * @param {Object} config
37365 Roo.tree.ColumnTree = function(el, config)
37367 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37371 * Fire this event on a container when it resizes
37372 * @param {int} w Width
37373 * @param {int} h Height
37377 this.on('resize', this.onResize, this);
37380 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37384 borderWidth: Roo.isBorderBox ? 0 : 2,
37387 render : function(){
37388 // add the header.....
37390 Roo.tree.ColumnTree.superclass.render.apply(this);
37392 this.el.addClass('x-column-tree');
37394 this.headers = this.el.createChild(
37395 {cls:'x-tree-headers'},this.innerCt.dom);
37397 var cols = this.columns, c;
37398 var totalWidth = 0;
37400 var len = cols.length;
37401 for(var i = 0; i < len; i++){
37403 totalWidth += c.width;
37404 this.headEls.push(this.headers.createChild({
37405 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37407 cls:'x-tree-hd-text',
37410 style:'width:'+(c.width-this.borderWidth)+'px;'
37413 this.headers.createChild({cls:'x-clear'});
37414 // prevent floats from wrapping when clipped
37415 this.headers.setWidth(totalWidth);
37416 //this.innerCt.setWidth(totalWidth);
37417 this.innerCt.setStyle({ overflow: 'auto' });
37418 this.onResize(this.width, this.height);
37422 onResize : function(w,h)
37427 this.innerCt.setWidth(this.width);
37428 this.innerCt.setHeight(this.height-20);
37431 var cols = this.columns, c;
37432 var totalWidth = 0;
37434 var len = cols.length;
37435 for(var i = 0; i < len; i++){
37437 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37438 // it's the expander..
37439 expEl = this.headEls[i];
37442 totalWidth += c.width;
37446 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37448 this.headers.setWidth(w-20);
37457 * Ext JS Library 1.1.1
37458 * Copyright(c) 2006-2007, Ext JS, LLC.
37460 * Originally Released Under LGPL - original licence link has changed is not relivant.
37463 * <script type="text/javascript">
37467 * @class Roo.menu.Menu
37468 * @extends Roo.util.Observable
37469 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37470 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37472 * Creates a new Menu
37473 * @param {Object} config Configuration options
37475 Roo.menu.Menu = function(config){
37477 Roo.menu.Menu.superclass.constructor.call(this, config);
37479 this.id = this.id || Roo.id();
37482 * @event beforeshow
37483 * Fires before this menu is displayed
37484 * @param {Roo.menu.Menu} this
37488 * @event beforehide
37489 * Fires before this menu is hidden
37490 * @param {Roo.menu.Menu} this
37495 * Fires after this menu is displayed
37496 * @param {Roo.menu.Menu} this
37501 * Fires after this menu is hidden
37502 * @param {Roo.menu.Menu} this
37507 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37508 * @param {Roo.menu.Menu} this
37509 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37510 * @param {Roo.EventObject} e
37515 * Fires when the mouse is hovering over this menu
37516 * @param {Roo.menu.Menu} this
37517 * @param {Roo.EventObject} e
37518 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37523 * Fires when the mouse exits this menu
37524 * @param {Roo.menu.Menu} this
37525 * @param {Roo.EventObject} e
37526 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37531 * Fires when a menu item contained in this menu is clicked
37532 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37533 * @param {Roo.EventObject} e
37537 if (this.registerMenu) {
37538 Roo.menu.MenuMgr.register(this);
37541 var mis = this.items;
37542 this.items = new Roo.util.MixedCollection();
37544 this.add.apply(this, mis);
37548 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37550 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37554 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37555 * for bottom-right shadow (defaults to "sides")
37559 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37560 * this menu (defaults to "tl-tr?")
37562 subMenuAlign : "tl-tr?",
37564 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37565 * relative to its element of origin (defaults to "tl-bl?")
37567 defaultAlign : "tl-bl?",
37569 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37571 allowOtherMenus : false,
37573 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37575 registerMenu : true,
37580 render : function(){
37584 var el = this.el = new Roo.Layer({
37586 shadow:this.shadow,
37588 parentEl: this.parentEl || document.body,
37592 this.keyNav = new Roo.menu.MenuNav(this);
37595 el.addClass("x-menu-plain");
37598 el.addClass(this.cls);
37600 // generic focus element
37601 this.focusEl = el.createChild({
37602 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37604 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37605 //disabling touch- as it's causing issues ..
37606 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37607 ul.on('click' , this.onClick, this);
37610 ul.on("mouseover", this.onMouseOver, this);
37611 ul.on("mouseout", this.onMouseOut, this);
37612 this.items.each(function(item){
37617 var li = document.createElement("li");
37618 li.className = "x-menu-list-item";
37619 ul.dom.appendChild(li);
37620 item.render(li, this);
37627 autoWidth : function(){
37628 var el = this.el, ul = this.ul;
37632 var w = this.width;
37635 }else if(Roo.isIE){
37636 el.setWidth(this.minWidth);
37637 var t = el.dom.offsetWidth; // force recalc
37638 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37643 delayAutoWidth : function(){
37646 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37648 this.awTask.delay(20);
37653 findTargetItem : function(e){
37654 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37655 if(t && t.menuItemId){
37656 return this.items.get(t.menuItemId);
37661 onClick : function(e){
37662 Roo.log("menu.onClick");
37663 var t = this.findTargetItem(e);
37668 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37669 if(t == this.activeItem && t.shouldDeactivate(e)){
37670 this.activeItem.deactivate();
37671 delete this.activeItem;
37675 this.setActiveItem(t, true);
37683 this.fireEvent("click", this, t, e);
37687 setActiveItem : function(item, autoExpand){
37688 if(item != this.activeItem){
37689 if(this.activeItem){
37690 this.activeItem.deactivate();
37692 this.activeItem = item;
37693 item.activate(autoExpand);
37694 }else if(autoExpand){
37700 tryActivate : function(start, step){
37701 var items = this.items;
37702 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37703 var item = items.get(i);
37704 if(!item.disabled && item.canActivate){
37705 this.setActiveItem(item, false);
37713 onMouseOver : function(e){
37715 if(t = this.findTargetItem(e)){
37716 if(t.canActivate && !t.disabled){
37717 this.setActiveItem(t, true);
37720 this.fireEvent("mouseover", this, e, t);
37724 onMouseOut : function(e){
37726 if(t = this.findTargetItem(e)){
37727 if(t == this.activeItem && t.shouldDeactivate(e)){
37728 this.activeItem.deactivate();
37729 delete this.activeItem;
37732 this.fireEvent("mouseout", this, e, t);
37736 * Read-only. Returns true if the menu is currently displayed, else false.
37739 isVisible : function(){
37740 return this.el && !this.hidden;
37744 * Displays this menu relative to another element
37745 * @param {String/HTMLElement/Roo.Element} element The element to align to
37746 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37747 * the element (defaults to this.defaultAlign)
37748 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37750 show : function(el, pos, parentMenu){
37751 this.parentMenu = parentMenu;
37755 this.fireEvent("beforeshow", this);
37756 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37760 * Displays this menu at a specific xy position
37761 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37762 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37764 showAt : function(xy, parentMenu, /* private: */_e){
37765 this.parentMenu = parentMenu;
37770 this.fireEvent("beforeshow", this);
37771 xy = this.el.adjustForConstraints(xy);
37775 this.hidden = false;
37777 this.fireEvent("show", this);
37780 focus : function(){
37782 this.doFocus.defer(50, this);
37786 doFocus : function(){
37788 this.focusEl.focus();
37793 * Hides this menu and optionally all parent menus
37794 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37796 hide : function(deep){
37797 if(this.el && this.isVisible()){
37798 this.fireEvent("beforehide", this);
37799 if(this.activeItem){
37800 this.activeItem.deactivate();
37801 this.activeItem = null;
37804 this.hidden = true;
37805 this.fireEvent("hide", this);
37807 if(deep === true && this.parentMenu){
37808 this.parentMenu.hide(true);
37813 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37814 * Any of the following are valid:
37816 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37817 * <li>An HTMLElement object which will be converted to a menu item</li>
37818 * <li>A menu item config object that will be created as a new menu item</li>
37819 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37820 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37825 var menu = new Roo.menu.Menu();
37827 // Create a menu item to add by reference
37828 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37830 // Add a bunch of items at once using different methods.
37831 // Only the last item added will be returned.
37832 var item = menu.add(
37833 menuItem, // add existing item by ref
37834 'Dynamic Item', // new TextItem
37835 '-', // new separator
37836 { text: 'Config Item' } // new item by config
37839 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37840 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37843 var a = arguments, l = a.length, item;
37844 for(var i = 0; i < l; i++){
37846 if ((typeof(el) == "object") && el.xtype && el.xns) {
37847 el = Roo.factory(el, Roo.menu);
37850 if(el.render){ // some kind of Item
37851 item = this.addItem(el);
37852 }else if(typeof el == "string"){ // string
37853 if(el == "separator" || el == "-"){
37854 item = this.addSeparator();
37856 item = this.addText(el);
37858 }else if(el.tagName || el.el){ // element
37859 item = this.addElement(el);
37860 }else if(typeof el == "object"){ // must be menu item config?
37861 item = this.addMenuItem(el);
37868 * Returns this menu's underlying {@link Roo.Element} object
37869 * @return {Roo.Element} The element
37871 getEl : function(){
37879 * Adds a separator bar to the menu
37880 * @return {Roo.menu.Item} The menu item that was added
37882 addSeparator : function(){
37883 return this.addItem(new Roo.menu.Separator());
37887 * Adds an {@link Roo.Element} object to the menu
37888 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37889 * @return {Roo.menu.Item} The menu item that was added
37891 addElement : function(el){
37892 return this.addItem(new Roo.menu.BaseItem(el));
37896 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37897 * @param {Roo.menu.Item} item The menu item to add
37898 * @return {Roo.menu.Item} The menu item that was added
37900 addItem : function(item){
37901 this.items.add(item);
37903 var li = document.createElement("li");
37904 li.className = "x-menu-list-item";
37905 this.ul.dom.appendChild(li);
37906 item.render(li, this);
37907 this.delayAutoWidth();
37913 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37914 * @param {Object} config A MenuItem config object
37915 * @return {Roo.menu.Item} The menu item that was added
37917 addMenuItem : function(config){
37918 if(!(config instanceof Roo.menu.Item)){
37919 if(typeof config.checked == "boolean"){ // must be check menu item config?
37920 config = new Roo.menu.CheckItem(config);
37922 config = new Roo.menu.Item(config);
37925 return this.addItem(config);
37929 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37930 * @param {String} text The text to display in the menu item
37931 * @return {Roo.menu.Item} The menu item that was added
37933 addText : function(text){
37934 return this.addItem(new Roo.menu.TextItem({ text : text }));
37938 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37939 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37940 * @param {Roo.menu.Item} item The menu item to add
37941 * @return {Roo.menu.Item} The menu item that was added
37943 insert : function(index, item){
37944 this.items.insert(index, item);
37946 var li = document.createElement("li");
37947 li.className = "x-menu-list-item";
37948 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37949 item.render(li, this);
37950 this.delayAutoWidth();
37956 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37957 * @param {Roo.menu.Item} item The menu item to remove
37959 remove : function(item){
37960 this.items.removeKey(item.id);
37965 * Removes and destroys all items in the menu
37967 removeAll : function(){
37969 while(f = this.items.first()){
37975 // MenuNav is a private utility class used internally by the Menu
37976 Roo.menu.MenuNav = function(menu){
37977 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37978 this.scope = this.menu = menu;
37981 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37982 doRelay : function(e, h){
37983 var k = e.getKey();
37984 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37985 this.menu.tryActivate(0, 1);
37988 return h.call(this.scope || this, e, this.menu);
37991 up : function(e, m){
37992 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37993 m.tryActivate(m.items.length-1, -1);
37997 down : function(e, m){
37998 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37999 m.tryActivate(0, 1);
38003 right : function(e, m){
38005 m.activeItem.expandMenu(true);
38009 left : function(e, m){
38011 if(m.parentMenu && m.parentMenu.activeItem){
38012 m.parentMenu.activeItem.activate();
38016 enter : function(e, m){
38018 e.stopPropagation();
38019 m.activeItem.onClick(e);
38020 m.fireEvent("click", this, m.activeItem);
38026 * Ext JS Library 1.1.1
38027 * Copyright(c) 2006-2007, Ext JS, LLC.
38029 * Originally Released Under LGPL - original licence link has changed is not relivant.
38032 * <script type="text/javascript">
38036 * @class Roo.menu.MenuMgr
38037 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
38040 Roo.menu.MenuMgr = function(){
38041 var menus, active, groups = {}, attached = false, lastShow = new Date();
38043 // private - called when first menu is created
38046 active = new Roo.util.MixedCollection();
38047 Roo.get(document).addKeyListener(27, function(){
38048 if(active.length > 0){
38055 function hideAll(){
38056 if(active && active.length > 0){
38057 var c = active.clone();
38058 c.each(function(m){
38065 function onHide(m){
38067 if(active.length < 1){
38068 Roo.get(document).un("mousedown", onMouseDown);
38074 function onShow(m){
38075 var last = active.last();
38076 lastShow = new Date();
38079 Roo.get(document).on("mousedown", onMouseDown);
38083 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38084 m.parentMenu.activeChild = m;
38085 }else if(last && last.isVisible()){
38086 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
38091 function onBeforeHide(m){
38093 m.activeChild.hide();
38095 if(m.autoHideTimer){
38096 clearTimeout(m.autoHideTimer);
38097 delete m.autoHideTimer;
38102 function onBeforeShow(m){
38103 var pm = m.parentMenu;
38104 if(!pm && !m.allowOtherMenus){
38106 }else if(pm && pm.activeChild && active != m){
38107 pm.activeChild.hide();
38112 function onMouseDown(e){
38113 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38119 function onBeforeCheck(mi, state){
38121 var g = groups[mi.group];
38122 for(var i = 0, l = g.length; i < l; i++){
38124 g[i].setChecked(false);
38133 * Hides all menus that are currently visible
38135 hideAll : function(){
38140 register : function(menu){
38144 menus[menu.id] = menu;
38145 menu.on("beforehide", onBeforeHide);
38146 menu.on("hide", onHide);
38147 menu.on("beforeshow", onBeforeShow);
38148 menu.on("show", onShow);
38149 var g = menu.group;
38150 if(g && menu.events["checkchange"]){
38154 groups[g].push(menu);
38155 menu.on("checkchange", onCheck);
38160 * Returns a {@link Roo.menu.Menu} object
38161 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38162 * be used to generate and return a new Menu instance.
38164 get : function(menu){
38165 if(typeof menu == "string"){ // menu id
38166 return menus[menu];
38167 }else if(menu.events){ // menu instance
38169 }else if(typeof menu.length == 'number'){ // array of menu items?
38170 return new Roo.menu.Menu({items:menu});
38171 }else{ // otherwise, must be a config
38172 return new Roo.menu.Menu(menu);
38177 unregister : function(menu){
38178 delete menus[menu.id];
38179 menu.un("beforehide", onBeforeHide);
38180 menu.un("hide", onHide);
38181 menu.un("beforeshow", onBeforeShow);
38182 menu.un("show", onShow);
38183 var g = menu.group;
38184 if(g && menu.events["checkchange"]){
38185 groups[g].remove(menu);
38186 menu.un("checkchange", onCheck);
38191 registerCheckable : function(menuItem){
38192 var g = menuItem.group;
38197 groups[g].push(menuItem);
38198 menuItem.on("beforecheckchange", onBeforeCheck);
38203 unregisterCheckable : function(menuItem){
38204 var g = menuItem.group;
38206 groups[g].remove(menuItem);
38207 menuItem.un("beforecheckchange", onBeforeCheck);
38213 * Ext JS Library 1.1.1
38214 * Copyright(c) 2006-2007, Ext JS, LLC.
38216 * Originally Released Under LGPL - original licence link has changed is not relivant.
38219 * <script type="text/javascript">
38224 * @class Roo.menu.BaseItem
38225 * @extends Roo.Component
38226 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38227 * management and base configuration options shared by all menu components.
38229 * Creates a new BaseItem
38230 * @param {Object} config Configuration options
38232 Roo.menu.BaseItem = function(config){
38233 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38238 * Fires when this item is clicked
38239 * @param {Roo.menu.BaseItem} this
38240 * @param {Roo.EventObject} e
38245 * Fires when this item is activated
38246 * @param {Roo.menu.BaseItem} this
38250 * @event deactivate
38251 * Fires when this item is deactivated
38252 * @param {Roo.menu.BaseItem} this
38258 this.on("click", this.handler, this.scope, true);
38262 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38264 * @cfg {Function} handler
38265 * A function that will handle the click event of this menu item (defaults to undefined)
38268 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38270 canActivate : false,
38273 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38278 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38280 activeClass : "x-menu-item-active",
38282 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38284 hideOnClick : true,
38286 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38291 ctype: "Roo.menu.BaseItem",
38294 actionMode : "container",
38297 render : function(container, parentMenu){
38298 this.parentMenu = parentMenu;
38299 Roo.menu.BaseItem.superclass.render.call(this, container);
38300 this.container.menuItemId = this.id;
38304 onRender : function(container, position){
38305 this.el = Roo.get(this.el);
38306 container.dom.appendChild(this.el.dom);
38310 onClick : function(e){
38311 if(!this.disabled && this.fireEvent("click", this, e) !== false
38312 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38313 this.handleClick(e);
38320 activate : function(){
38324 var li = this.container;
38325 li.addClass(this.activeClass);
38326 this.region = li.getRegion().adjust(2, 2, -2, -2);
38327 this.fireEvent("activate", this);
38332 deactivate : function(){
38333 this.container.removeClass(this.activeClass);
38334 this.fireEvent("deactivate", this);
38338 shouldDeactivate : function(e){
38339 return !this.region || !this.region.contains(e.getPoint());
38343 handleClick : function(e){
38344 if(this.hideOnClick){
38345 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38350 expandMenu : function(autoActivate){
38355 hideMenu : function(){
38360 * Ext JS Library 1.1.1
38361 * Copyright(c) 2006-2007, Ext JS, LLC.
38363 * Originally Released Under LGPL - original licence link has changed is not relivant.
38366 * <script type="text/javascript">
38370 * @class Roo.menu.Adapter
38371 * @extends Roo.menu.BaseItem
38372 * 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.
38373 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38375 * Creates a new Adapter
38376 * @param {Object} config Configuration options
38378 Roo.menu.Adapter = function(component, config){
38379 Roo.menu.Adapter.superclass.constructor.call(this, config);
38380 this.component = component;
38382 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38384 canActivate : true,
38387 onRender : function(container, position){
38388 this.component.render(container);
38389 this.el = this.component.getEl();
38393 activate : function(){
38397 this.component.focus();
38398 this.fireEvent("activate", this);
38403 deactivate : function(){
38404 this.fireEvent("deactivate", this);
38408 disable : function(){
38409 this.component.disable();
38410 Roo.menu.Adapter.superclass.disable.call(this);
38414 enable : function(){
38415 this.component.enable();
38416 Roo.menu.Adapter.superclass.enable.call(this);
38420 * Ext JS Library 1.1.1
38421 * Copyright(c) 2006-2007, Ext JS, LLC.
38423 * Originally Released Under LGPL - original licence link has changed is not relivant.
38426 * <script type="text/javascript">
38430 * @class Roo.menu.TextItem
38431 * @extends Roo.menu.BaseItem
38432 * Adds a static text string to a menu, usually used as either a heading or group separator.
38433 * Note: old style constructor with text is still supported.
38436 * Creates a new TextItem
38437 * @param {Object} cfg Configuration
38439 Roo.menu.TextItem = function(cfg){
38440 if (typeof(cfg) == 'string') {
38443 Roo.apply(this,cfg);
38446 Roo.menu.TextItem.superclass.constructor.call(this);
38449 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38451 * @cfg {String} text Text to show on item.
38456 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38458 hideOnClick : false,
38460 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38462 itemCls : "x-menu-text",
38465 onRender : function(){
38466 var s = document.createElement("span");
38467 s.className = this.itemCls;
38468 s.innerHTML = this.text;
38470 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38474 * Ext JS Library 1.1.1
38475 * Copyright(c) 2006-2007, Ext JS, LLC.
38477 * Originally Released Under LGPL - original licence link has changed is not relivant.
38480 * <script type="text/javascript">
38484 * @class Roo.menu.Separator
38485 * @extends Roo.menu.BaseItem
38486 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38487 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38489 * @param {Object} config Configuration options
38491 Roo.menu.Separator = function(config){
38492 Roo.menu.Separator.superclass.constructor.call(this, config);
38495 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38497 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38499 itemCls : "x-menu-sep",
38501 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38503 hideOnClick : false,
38506 onRender : function(li){
38507 var s = document.createElement("span");
38508 s.className = this.itemCls;
38509 s.innerHTML = " ";
38511 li.addClass("x-menu-sep-li");
38512 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38516 * Ext JS Library 1.1.1
38517 * Copyright(c) 2006-2007, Ext JS, LLC.
38519 * Originally Released Under LGPL - original licence link has changed is not relivant.
38522 * <script type="text/javascript">
38525 * @class Roo.menu.Item
38526 * @extends Roo.menu.BaseItem
38527 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38528 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38529 * activation and click handling.
38531 * Creates a new Item
38532 * @param {Object} config Configuration options
38534 Roo.menu.Item = function(config){
38535 Roo.menu.Item.superclass.constructor.call(this, config);
38537 this.menu = Roo.menu.MenuMgr.get(this.menu);
38540 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38543 * @cfg {String} text
38544 * The text to show on the menu item.
38548 * @cfg {String} HTML to render in menu
38549 * The text to show on the menu item (HTML version).
38553 * @cfg {String} icon
38554 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38558 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38560 itemCls : "x-menu-item",
38562 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38564 canActivate : true,
38566 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38569 // doc'd in BaseItem
38573 ctype: "Roo.menu.Item",
38576 onRender : function(container, position){
38577 var el = document.createElement("a");
38578 el.hideFocus = true;
38579 el.unselectable = "on";
38580 el.href = this.href || "#";
38581 if(this.hrefTarget){
38582 el.target = this.hrefTarget;
38584 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38586 var html = this.html.length ? this.html : String.format('{0}',this.text);
38588 el.innerHTML = String.format(
38589 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38590 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38592 Roo.menu.Item.superclass.onRender.call(this, container, position);
38596 * Sets the text to display in this menu item
38597 * @param {String} text The text to display
38598 * @param {Boolean} isHTML true to indicate text is pure html.
38600 setText : function(text, isHTML){
38608 var html = this.html.length ? this.html : String.format('{0}',this.text);
38610 this.el.update(String.format(
38611 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38612 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38613 this.parentMenu.autoWidth();
38618 handleClick : function(e){
38619 if(!this.href){ // if no link defined, stop the event automatically
38622 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38626 activate : function(autoExpand){
38627 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38637 shouldDeactivate : function(e){
38638 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38639 if(this.menu && this.menu.isVisible()){
38640 return !this.menu.getEl().getRegion().contains(e.getPoint());
38648 deactivate : function(){
38649 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38654 expandMenu : function(autoActivate){
38655 if(!this.disabled && this.menu){
38656 clearTimeout(this.hideTimer);
38657 delete this.hideTimer;
38658 if(!this.menu.isVisible() && !this.showTimer){
38659 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38660 }else if (this.menu.isVisible() && autoActivate){
38661 this.menu.tryActivate(0, 1);
38667 deferExpand : function(autoActivate){
38668 delete this.showTimer;
38669 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38671 this.menu.tryActivate(0, 1);
38676 hideMenu : function(){
38677 clearTimeout(this.showTimer);
38678 delete this.showTimer;
38679 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38680 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38685 deferHide : function(){
38686 delete this.hideTimer;
38691 * Ext JS Library 1.1.1
38692 * Copyright(c) 2006-2007, Ext JS, LLC.
38694 * Originally Released Under LGPL - original licence link has changed is not relivant.
38697 * <script type="text/javascript">
38701 * @class Roo.menu.CheckItem
38702 * @extends Roo.menu.Item
38703 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38705 * Creates a new CheckItem
38706 * @param {Object} config Configuration options
38708 Roo.menu.CheckItem = function(config){
38709 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38712 * @event beforecheckchange
38713 * Fires before the checked value is set, providing an opportunity to cancel if needed
38714 * @param {Roo.menu.CheckItem} this
38715 * @param {Boolean} checked The new checked value that will be set
38717 "beforecheckchange" : true,
38719 * @event checkchange
38720 * Fires after the checked value has been set
38721 * @param {Roo.menu.CheckItem} this
38722 * @param {Boolean} checked The checked value that was set
38724 "checkchange" : true
38726 if(this.checkHandler){
38727 this.on('checkchange', this.checkHandler, this.scope);
38730 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38732 * @cfg {String} group
38733 * All check items with the same group name will automatically be grouped into a single-select
38734 * radio button group (defaults to '')
38737 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38739 itemCls : "x-menu-item x-menu-check-item",
38741 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38743 groupClass : "x-menu-group-item",
38746 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38747 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38748 * initialized with checked = true will be rendered as checked.
38753 ctype: "Roo.menu.CheckItem",
38756 onRender : function(c){
38757 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38759 this.el.addClass(this.groupClass);
38761 Roo.menu.MenuMgr.registerCheckable(this);
38763 this.checked = false;
38764 this.setChecked(true, true);
38769 destroy : function(){
38771 Roo.menu.MenuMgr.unregisterCheckable(this);
38773 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38777 * Set the checked state of this item
38778 * @param {Boolean} checked The new checked value
38779 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38781 setChecked : function(state, suppressEvent){
38782 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38783 if(this.container){
38784 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38786 this.checked = state;
38787 if(suppressEvent !== true){
38788 this.fireEvent("checkchange", this, state);
38794 handleClick : function(e){
38795 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38796 this.setChecked(!this.checked);
38798 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38802 * Ext JS Library 1.1.1
38803 * Copyright(c) 2006-2007, Ext JS, LLC.
38805 * Originally Released Under LGPL - original licence link has changed is not relivant.
38808 * <script type="text/javascript">
38812 * @class Roo.menu.DateItem
38813 * @extends Roo.menu.Adapter
38814 * A menu item that wraps the {@link Roo.DatPicker} component.
38816 * Creates a new DateItem
38817 * @param {Object} config Configuration options
38819 Roo.menu.DateItem = function(config){
38820 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38821 /** The Roo.DatePicker object @type Roo.DatePicker */
38822 this.picker = this.component;
38823 this.addEvents({select: true});
38825 this.picker.on("render", function(picker){
38826 picker.getEl().swallowEvent("click");
38827 picker.container.addClass("x-menu-date-item");
38830 this.picker.on("select", this.onSelect, this);
38833 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38835 onSelect : function(picker, date){
38836 this.fireEvent("select", this, date, picker);
38837 Roo.menu.DateItem.superclass.handleClick.call(this);
38841 * Ext JS Library 1.1.1
38842 * Copyright(c) 2006-2007, Ext JS, LLC.
38844 * Originally Released Under LGPL - original licence link has changed is not relivant.
38847 * <script type="text/javascript">
38851 * @class Roo.menu.ColorItem
38852 * @extends Roo.menu.Adapter
38853 * A menu item that wraps the {@link Roo.ColorPalette} component.
38855 * Creates a new ColorItem
38856 * @param {Object} config Configuration options
38858 Roo.menu.ColorItem = function(config){
38859 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38860 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38861 this.palette = this.component;
38862 this.relayEvents(this.palette, ["select"]);
38863 if(this.selectHandler){
38864 this.on('select', this.selectHandler, this.scope);
38867 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38869 * Ext JS Library 1.1.1
38870 * Copyright(c) 2006-2007, Ext JS, LLC.
38872 * Originally Released Under LGPL - original licence link has changed is not relivant.
38875 * <script type="text/javascript">
38880 * @class Roo.menu.DateMenu
38881 * @extends Roo.menu.Menu
38882 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38884 * Creates a new DateMenu
38885 * @param {Object} config Configuration options
38887 Roo.menu.DateMenu = function(config){
38888 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38890 var di = new Roo.menu.DateItem(config);
38893 * The {@link Roo.DatePicker} instance for this DateMenu
38896 this.picker = di.picker;
38899 * @param {DatePicker} picker
38900 * @param {Date} date
38902 this.relayEvents(di, ["select"]);
38903 this.on('beforeshow', function(){
38905 this.picker.hideMonthPicker(false);
38909 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38913 * Ext JS Library 1.1.1
38914 * Copyright(c) 2006-2007, Ext JS, LLC.
38916 * Originally Released Under LGPL - original licence link has changed is not relivant.
38919 * <script type="text/javascript">
38924 * @class Roo.menu.ColorMenu
38925 * @extends Roo.menu.Menu
38926 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38928 * Creates a new ColorMenu
38929 * @param {Object} config Configuration options
38931 Roo.menu.ColorMenu = function(config){
38932 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38934 var ci = new Roo.menu.ColorItem(config);
38937 * The {@link Roo.ColorPalette} instance for this ColorMenu
38938 * @type ColorPalette
38940 this.palette = ci.palette;
38943 * @param {ColorPalette} palette
38944 * @param {String} color
38946 this.relayEvents(ci, ["select"]);
38948 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38950 * Ext JS Library 1.1.1
38951 * Copyright(c) 2006-2007, Ext JS, LLC.
38953 * Originally Released Under LGPL - original licence link has changed is not relivant.
38956 * <script type="text/javascript">
38960 * @class Roo.form.TextItem
38961 * @extends Roo.BoxComponent
38962 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38964 * Creates a new TextItem
38965 * @param {Object} config Configuration options
38967 Roo.form.TextItem = function(config){
38968 Roo.form.TextItem.superclass.constructor.call(this, config);
38971 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
38974 * @cfg {String} tag the tag for this item (default div)
38978 * @cfg {String} html the content for this item
38982 getAutoCreate : function()
38995 onRender : function(ct, position)
38997 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
39000 var cfg = this.getAutoCreate();
39002 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39004 if (!cfg.name.length) {
39007 this.el = ct.createChild(cfg, position);
39012 * @param {String} html update the Contents of the element.
39014 setHTML : function(html)
39016 this.fieldEl.dom.innerHTML = html;
39021 * Ext JS Library 1.1.1
39022 * Copyright(c) 2006-2007, Ext JS, LLC.
39024 * Originally Released Under LGPL - original licence link has changed is not relivant.
39027 * <script type="text/javascript">
39031 * @class Roo.form.Field
39032 * @extends Roo.BoxComponent
39033 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39035 * Creates a new Field
39036 * @param {Object} config Configuration options
39038 Roo.form.Field = function(config){
39039 Roo.form.Field.superclass.constructor.call(this, config);
39042 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
39044 * @cfg {String} fieldLabel Label to use when rendering a form.
39047 * @cfg {String} qtip Mouse over tip
39051 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
39053 invalidClass : "x-form-invalid",
39055 * @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")
39057 invalidText : "The value in this field is invalid",
39059 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
39061 focusClass : "x-form-focus",
39063 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
39064 automatic validation (defaults to "keyup").
39066 validationEvent : "keyup",
39068 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
39070 validateOnBlur : true,
39072 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39074 validationDelay : 250,
39076 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39077 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39079 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39081 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39083 fieldClass : "x-form-field",
39085 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
39088 ----------- ----------------------------------------------------------------------
39089 qtip Display a quick tip when the user hovers over the field
39090 title Display a default browser title attribute popup
39091 under Add a block div beneath the field containing the error text
39092 side Add an error icon to the right of the field with a popup on hover
39093 [element id] Add the error text directly to the innerHTML of the specified element
39096 msgTarget : 'qtip',
39098 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39103 * @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.
39108 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39113 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39115 inputType : undefined,
39118 * @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).
39120 tabIndex : undefined,
39123 isFormField : true,
39128 * @property {Roo.Element} fieldEl
39129 * Element Containing the rendered Field (with label etc.)
39132 * @cfg {Mixed} value A value to initialize this field with.
39137 * @cfg {String} name The field's HTML name attribute.
39140 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39143 loadedValue : false,
39147 initComponent : function(){
39148 Roo.form.Field.superclass.initComponent.call(this);
39152 * Fires when this field receives input focus.
39153 * @param {Roo.form.Field} this
39158 * Fires when this field loses input focus.
39159 * @param {Roo.form.Field} this
39163 * @event specialkey
39164 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39165 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39166 * @param {Roo.form.Field} this
39167 * @param {Roo.EventObject} e The event object
39172 * Fires just before the field blurs if the field value has changed.
39173 * @param {Roo.form.Field} this
39174 * @param {Mixed} newValue The new value
39175 * @param {Mixed} oldValue The original value
39180 * Fires after the field has been marked as invalid.
39181 * @param {Roo.form.Field} this
39182 * @param {String} msg The validation message
39187 * Fires after the field has been validated with no errors.
39188 * @param {Roo.form.Field} this
39193 * Fires after the key up
39194 * @param {Roo.form.Field} this
39195 * @param {Roo.EventObject} e The event Object
39202 * Returns the name attribute of the field if available
39203 * @return {String} name The field name
39205 getName: function(){
39206 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39210 onRender : function(ct, position){
39211 Roo.form.Field.superclass.onRender.call(this, ct, position);
39213 var cfg = this.getAutoCreate();
39215 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39217 if (!cfg.name.length) {
39220 if(this.inputType){
39221 cfg.type = this.inputType;
39223 this.el = ct.createChild(cfg, position);
39225 var type = this.el.dom.type;
39227 if(type == 'password'){
39230 this.el.addClass('x-form-'+type);
39233 this.el.dom.readOnly = true;
39235 if(this.tabIndex !== undefined){
39236 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39239 this.el.addClass([this.fieldClass, this.cls]);
39244 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39245 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39246 * @return {Roo.form.Field} this
39248 applyTo : function(target){
39249 this.allowDomMove = false;
39250 this.el = Roo.get(target);
39251 this.render(this.el.dom.parentNode);
39256 initValue : function(){
39257 if(this.value !== undefined){
39258 this.setValue(this.value);
39259 }else if(this.el.dom.value.length > 0){
39260 this.setValue(this.el.dom.value);
39265 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39266 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39268 isDirty : function() {
39269 if(this.disabled) {
39272 return String(this.getValue()) !== String(this.originalValue);
39276 * stores the current value in loadedValue
39278 resetHasChanged : function()
39280 this.loadedValue = String(this.getValue());
39283 * checks the current value against the 'loaded' value.
39284 * Note - will return false if 'resetHasChanged' has not been called first.
39286 hasChanged : function()
39288 if(this.disabled || this.readOnly) {
39291 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39297 afterRender : function(){
39298 Roo.form.Field.superclass.afterRender.call(this);
39303 fireKey : function(e){
39304 //Roo.log('field ' + e.getKey());
39305 if(e.isNavKeyPress()){
39306 this.fireEvent("specialkey", this, e);
39311 * Resets the current field value to the originally loaded value and clears any validation messages
39313 reset : function(){
39314 this.setValue(this.resetValue);
39315 this.originalValue = this.getValue();
39316 this.clearInvalid();
39320 initEvents : function(){
39321 // safari killled keypress - so keydown is now used..
39322 this.el.on("keydown" , this.fireKey, this);
39323 this.el.on("focus", this.onFocus, this);
39324 this.el.on("blur", this.onBlur, this);
39325 this.el.relayEvent('keyup', this);
39327 // reference to original value for reset
39328 this.originalValue = this.getValue();
39329 this.resetValue = this.getValue();
39333 onFocus : function(){
39334 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39335 this.el.addClass(this.focusClass);
39337 if(!this.hasFocus){
39338 this.hasFocus = true;
39339 this.startValue = this.getValue();
39340 this.fireEvent("focus", this);
39344 beforeBlur : Roo.emptyFn,
39347 onBlur : function(){
39349 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39350 this.el.removeClass(this.focusClass);
39352 this.hasFocus = false;
39353 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39356 var v = this.getValue();
39357 if(String(v) !== String(this.startValue)){
39358 this.fireEvent('change', this, v, this.startValue);
39360 this.fireEvent("blur", this);
39364 * Returns whether or not the field value is currently valid
39365 * @param {Boolean} preventMark True to disable marking the field invalid
39366 * @return {Boolean} True if the value is valid, else false
39368 isValid : function(preventMark){
39372 var restore = this.preventMark;
39373 this.preventMark = preventMark === true;
39374 var v = this.validateValue(this.processValue(this.getRawValue()));
39375 this.preventMark = restore;
39380 * Validates the field value
39381 * @return {Boolean} True if the value is valid, else false
39383 validate : function(){
39384 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39385 this.clearInvalid();
39391 processValue : function(value){
39396 // Subclasses should provide the validation implementation by overriding this
39397 validateValue : function(value){
39402 * Mark this field as invalid
39403 * @param {String} msg The validation message
39405 markInvalid : function(msg){
39406 if(!this.rendered || this.preventMark){ // not rendered
39410 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39412 obj.el.addClass(this.invalidClass);
39413 msg = msg || this.invalidText;
39414 switch(this.msgTarget){
39416 obj.el.dom.qtip = msg;
39417 obj.el.dom.qclass = 'x-form-invalid-tip';
39418 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39419 Roo.QuickTips.enable();
39423 this.el.dom.title = msg;
39427 var elp = this.el.findParent('.x-form-element', 5, true);
39428 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39429 this.errorEl.setWidth(elp.getWidth(true)-20);
39431 this.errorEl.update(msg);
39432 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39435 if(!this.errorIcon){
39436 var elp = this.el.findParent('.x-form-element', 5, true);
39437 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39439 this.alignErrorIcon();
39440 this.errorIcon.dom.qtip = msg;
39441 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39442 this.errorIcon.show();
39443 this.on('resize', this.alignErrorIcon, this);
39446 var t = Roo.getDom(this.msgTarget);
39448 t.style.display = this.msgDisplay;
39451 this.fireEvent('invalid', this, msg);
39455 alignErrorIcon : function(){
39456 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39460 * Clear any invalid styles/messages for this field
39462 clearInvalid : function(){
39463 if(!this.rendered || this.preventMark){ // not rendered
39466 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39468 obj.el.removeClass(this.invalidClass);
39469 switch(this.msgTarget){
39471 obj.el.dom.qtip = '';
39474 this.el.dom.title = '';
39478 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39482 if(this.errorIcon){
39483 this.errorIcon.dom.qtip = '';
39484 this.errorIcon.hide();
39485 this.un('resize', this.alignErrorIcon, this);
39489 var t = Roo.getDom(this.msgTarget);
39491 t.style.display = 'none';
39494 this.fireEvent('valid', this);
39498 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39499 * @return {Mixed} value The field value
39501 getRawValue : function(){
39502 var v = this.el.getValue();
39508 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39509 * @return {Mixed} value The field value
39511 getValue : function(){
39512 var v = this.el.getValue();
39518 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39519 * @param {Mixed} value The value to set
39521 setRawValue : function(v){
39522 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39526 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39527 * @param {Mixed} value The value to set
39529 setValue : function(v){
39532 this.el.dom.value = (v === null || v === undefined ? '' : v);
39537 adjustSize : function(w, h){
39538 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39539 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39543 adjustWidth : function(tag, w){
39544 tag = tag.toLowerCase();
39545 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39546 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39547 if(tag == 'input'){
39550 if(tag == 'textarea'){
39553 }else if(Roo.isOpera){
39554 if(tag == 'input'){
39557 if(tag == 'textarea'){
39567 // anything other than normal should be considered experimental
39568 Roo.form.Field.msgFx = {
39570 show: function(msgEl, f){
39571 msgEl.setDisplayed('block');
39574 hide : function(msgEl, f){
39575 msgEl.setDisplayed(false).update('');
39580 show: function(msgEl, f){
39581 msgEl.slideIn('t', {stopFx:true});
39584 hide : function(msgEl, f){
39585 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39590 show: function(msgEl, f){
39591 msgEl.fixDisplay();
39592 msgEl.alignTo(f.el, 'tl-tr');
39593 msgEl.slideIn('l', {stopFx:true});
39596 hide : function(msgEl, f){
39597 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39602 * Ext JS Library 1.1.1
39603 * Copyright(c) 2006-2007, Ext JS, LLC.
39605 * Originally Released Under LGPL - original licence link has changed is not relivant.
39608 * <script type="text/javascript">
39613 * @class Roo.form.TextField
39614 * @extends Roo.form.Field
39615 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39616 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39618 * Creates a new TextField
39619 * @param {Object} config Configuration options
39621 Roo.form.TextField = function(config){
39622 Roo.form.TextField.superclass.constructor.call(this, config);
39626 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39627 * according to the default logic, but this event provides a hook for the developer to apply additional
39628 * logic at runtime to resize the field if needed.
39629 * @param {Roo.form.Field} this This text field
39630 * @param {Number} width The new field width
39636 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39638 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39642 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39646 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39650 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39654 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39658 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39660 disableKeyFilter : false,
39662 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39666 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39670 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39672 maxLength : Number.MAX_VALUE,
39674 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39676 minLengthText : "The minimum length for this field is {0}",
39678 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39680 maxLengthText : "The maximum length for this field is {0}",
39682 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39684 selectOnFocus : false,
39686 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39688 allowLeadingSpace : false,
39690 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39692 blankText : "This field is required",
39694 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39695 * If available, this function will be called only after the basic validators all return true, and will be passed the
39696 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39700 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39701 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39702 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39706 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39710 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39716 initEvents : function()
39718 if (this.emptyText) {
39719 this.el.attr('placeholder', this.emptyText);
39722 Roo.form.TextField.superclass.initEvents.call(this);
39723 if(this.validationEvent == 'keyup'){
39724 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39725 this.el.on('keyup', this.filterValidation, this);
39727 else if(this.validationEvent !== false){
39728 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39731 if(this.selectOnFocus){
39732 this.on("focus", this.preFocus, this);
39734 if (!this.allowLeadingSpace) {
39735 this.on('blur', this.cleanLeadingSpace, this);
39738 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39739 this.el.on("keypress", this.filterKeys, this);
39742 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39743 this.el.on("click", this.autoSize, this);
39745 if(this.el.is('input[type=password]') && Roo.isSafari){
39746 this.el.on('keydown', this.SafariOnKeyDown, this);
39750 processValue : function(value){
39751 if(this.stripCharsRe){
39752 var newValue = value.replace(this.stripCharsRe, '');
39753 if(newValue !== value){
39754 this.setRawValue(newValue);
39761 filterValidation : function(e){
39762 if(!e.isNavKeyPress()){
39763 this.validationTask.delay(this.validationDelay);
39768 onKeyUp : function(e){
39769 if(!e.isNavKeyPress()){
39773 // private - clean the leading white space
39774 cleanLeadingSpace : function(e)
39776 if ( this.inputType == 'file') {
39780 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39783 * Resets the current field value to the originally-loaded value and clears any validation messages.
39786 reset : function(){
39787 Roo.form.TextField.superclass.reset.call(this);
39791 preFocus : function(){
39793 if(this.selectOnFocus){
39794 this.el.dom.select();
39800 filterKeys : function(e){
39801 var k = e.getKey();
39802 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39805 var c = e.getCharCode(), cc = String.fromCharCode(c);
39806 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39809 if(!this.maskRe.test(cc)){
39814 setValue : function(v){
39816 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39822 * Validates a value according to the field's validation rules and marks the field as invalid
39823 * if the validation fails
39824 * @param {Mixed} value The value to validate
39825 * @return {Boolean} True if the value is valid, else false
39827 validateValue : function(value){
39828 if(value.length < 1) { // if it's blank
39829 if(this.allowBlank){
39830 this.clearInvalid();
39833 this.markInvalid(this.blankText);
39837 if(value.length < this.minLength){
39838 this.markInvalid(String.format(this.minLengthText, this.minLength));
39841 if(value.length > this.maxLength){
39842 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39846 var vt = Roo.form.VTypes;
39847 if(!vt[this.vtype](value, this)){
39848 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39852 if(typeof this.validator == "function"){
39853 var msg = this.validator(value);
39855 this.markInvalid(msg);
39859 if(this.regex && !this.regex.test(value)){
39860 this.markInvalid(this.regexText);
39867 * Selects text in this field
39868 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39869 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39871 selectText : function(start, end){
39872 var v = this.getRawValue();
39874 start = start === undefined ? 0 : start;
39875 end = end === undefined ? v.length : end;
39876 var d = this.el.dom;
39877 if(d.setSelectionRange){
39878 d.setSelectionRange(start, end);
39879 }else if(d.createTextRange){
39880 var range = d.createTextRange();
39881 range.moveStart("character", start);
39882 range.moveEnd("character", v.length-end);
39889 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39890 * This only takes effect if grow = true, and fires the autosize event.
39892 autoSize : function(){
39893 if(!this.grow || !this.rendered){
39897 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39900 var v = el.dom.value;
39901 var d = document.createElement('div');
39902 d.appendChild(document.createTextNode(v));
39906 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39907 this.el.setWidth(w);
39908 this.fireEvent("autosize", this, w);
39912 SafariOnKeyDown : function(event)
39914 // this is a workaround for a password hang bug on chrome/ webkit.
39916 var isSelectAll = false;
39918 if(this.el.dom.selectionEnd > 0){
39919 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39921 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39922 event.preventDefault();
39927 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39929 event.preventDefault();
39930 // this is very hacky as keydown always get's upper case.
39932 var cc = String.fromCharCode(event.getCharCode());
39935 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39943 * Ext JS Library 1.1.1
39944 * Copyright(c) 2006-2007, Ext JS, LLC.
39946 * Originally Released Under LGPL - original licence link has changed is not relivant.
39949 * <script type="text/javascript">
39953 * @class Roo.form.Hidden
39954 * @extends Roo.form.TextField
39955 * Simple Hidden element used on forms
39957 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39960 * Creates a new Hidden form element.
39961 * @param {Object} config Configuration options
39966 // easy hidden field...
39967 Roo.form.Hidden = function(config){
39968 Roo.form.Hidden.superclass.constructor.call(this, config);
39971 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39973 inputType: 'hidden',
39976 labelSeparator: '',
39978 itemCls : 'x-form-item-display-none'
39986 * Ext JS Library 1.1.1
39987 * Copyright(c) 2006-2007, Ext JS, LLC.
39989 * Originally Released Under LGPL - original licence link has changed is not relivant.
39992 * <script type="text/javascript">
39996 * @class Roo.form.TriggerField
39997 * @extends Roo.form.TextField
39998 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39999 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
40000 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
40001 * for which you can provide a custom implementation. For example:
40003 var trigger = new Roo.form.TriggerField();
40004 trigger.onTriggerClick = myTriggerFn;
40005 trigger.applyTo('my-field');
40008 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
40009 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
40010 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40011 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
40013 * Create a new TriggerField.
40014 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
40015 * to the base TextField)
40017 Roo.form.TriggerField = function(config){
40018 this.mimicing = false;
40019 Roo.form.TriggerField.superclass.constructor.call(this, config);
40022 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
40024 * @cfg {String} triggerClass A CSS class to apply to the trigger
40027 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40028 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
40030 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
40032 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
40036 /** @cfg {Boolean} grow @hide */
40037 /** @cfg {Number} growMin @hide */
40038 /** @cfg {Number} growMax @hide */
40044 autoSize: Roo.emptyFn,
40048 deferHeight : true,
40051 actionMode : 'wrap',
40053 onResize : function(w, h){
40054 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
40055 if(typeof w == 'number'){
40056 var x = w - this.trigger.getWidth();
40057 this.el.setWidth(this.adjustWidth('input', x));
40058 this.trigger.setStyle('left', x+'px');
40063 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40066 getResizeEl : function(){
40071 getPositionEl : function(){
40076 alignErrorIcon : function(){
40077 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40081 onRender : function(ct, position){
40082 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40083 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
40084 this.trigger = this.wrap.createChild(this.triggerConfig ||
40085 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
40086 if(this.hideTrigger){
40087 this.trigger.setDisplayed(false);
40089 this.initTrigger();
40091 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
40096 initTrigger : function(){
40097 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40098 this.trigger.addClassOnOver('x-form-trigger-over');
40099 this.trigger.addClassOnClick('x-form-trigger-click');
40103 onDestroy : function(){
40105 this.trigger.removeAllListeners();
40106 this.trigger.remove();
40109 this.wrap.remove();
40111 Roo.form.TriggerField.superclass.onDestroy.call(this);
40115 onFocus : function(){
40116 Roo.form.TriggerField.superclass.onFocus.call(this);
40117 if(!this.mimicing){
40118 this.wrap.addClass('x-trigger-wrap-focus');
40119 this.mimicing = true;
40120 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40121 if(this.monitorTab){
40122 this.el.on("keydown", this.checkTab, this);
40128 checkTab : function(e){
40129 if(e.getKey() == e.TAB){
40130 this.triggerBlur();
40135 onBlur : function(){
40140 mimicBlur : function(e, t){
40141 if(!this.wrap.contains(t) && this.validateBlur()){
40142 this.triggerBlur();
40147 triggerBlur : function(){
40148 this.mimicing = false;
40149 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40150 if(this.monitorTab){
40151 this.el.un("keydown", this.checkTab, this);
40153 this.wrap.removeClass('x-trigger-wrap-focus');
40154 Roo.form.TriggerField.superclass.onBlur.call(this);
40158 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40159 validateBlur : function(e, t){
40164 onDisable : function(){
40165 Roo.form.TriggerField.superclass.onDisable.call(this);
40167 this.wrap.addClass('x-item-disabled');
40172 onEnable : function(){
40173 Roo.form.TriggerField.superclass.onEnable.call(this);
40175 this.wrap.removeClass('x-item-disabled');
40180 onShow : function(){
40181 var ae = this.getActionEl();
40184 ae.dom.style.display = '';
40185 ae.dom.style.visibility = 'visible';
40191 onHide : function(){
40192 var ae = this.getActionEl();
40193 ae.dom.style.display = 'none';
40197 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40198 * by an implementing function.
40200 * @param {EventObject} e
40202 onTriggerClick : Roo.emptyFn
40205 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40206 // to be extended by an implementing class. For an example of implementing this class, see the custom
40207 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40208 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40209 initComponent : function(){
40210 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40212 this.triggerConfig = {
40213 tag:'span', cls:'x-form-twin-triggers', cn:[
40214 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40215 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40219 getTrigger : function(index){
40220 return this.triggers[index];
40223 initTrigger : function(){
40224 var ts = this.trigger.select('.x-form-trigger', true);
40225 this.wrap.setStyle('overflow', 'hidden');
40226 var triggerField = this;
40227 ts.each(function(t, all, index){
40228 t.hide = function(){
40229 var w = triggerField.wrap.getWidth();
40230 this.dom.style.display = 'none';
40231 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40233 t.show = function(){
40234 var w = triggerField.wrap.getWidth();
40235 this.dom.style.display = '';
40236 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40238 var triggerIndex = 'Trigger'+(index+1);
40240 if(this['hide'+triggerIndex]){
40241 t.dom.style.display = 'none';
40243 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40244 t.addClassOnOver('x-form-trigger-over');
40245 t.addClassOnClick('x-form-trigger-click');
40247 this.triggers = ts.elements;
40250 onTrigger1Click : Roo.emptyFn,
40251 onTrigger2Click : Roo.emptyFn
40254 * Ext JS Library 1.1.1
40255 * Copyright(c) 2006-2007, Ext JS, LLC.
40257 * Originally Released Under LGPL - original licence link has changed is not relivant.
40260 * <script type="text/javascript">
40264 * @class Roo.form.TextArea
40265 * @extends Roo.form.TextField
40266 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40267 * support for auto-sizing.
40269 * Creates a new TextArea
40270 * @param {Object} config Configuration options
40272 Roo.form.TextArea = function(config){
40273 Roo.form.TextArea.superclass.constructor.call(this, config);
40274 // these are provided exchanges for backwards compat
40275 // minHeight/maxHeight were replaced by growMin/growMax to be
40276 // compatible with TextField growing config values
40277 if(this.minHeight !== undefined){
40278 this.growMin = this.minHeight;
40280 if(this.maxHeight !== undefined){
40281 this.growMax = this.maxHeight;
40285 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40287 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40291 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40295 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40296 * in the field (equivalent to setting overflow: hidden, defaults to false)
40298 preventScrollbars: false,
40300 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40301 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40305 onRender : function(ct, position){
40307 this.defaultAutoCreate = {
40309 style:"width:300px;height:60px;",
40310 autocomplete: "new-password"
40313 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40315 this.textSizeEl = Roo.DomHelper.append(document.body, {
40316 tag: "pre", cls: "x-form-grow-sizer"
40318 if(this.preventScrollbars){
40319 this.el.setStyle("overflow", "hidden");
40321 this.el.setHeight(this.growMin);
40325 onDestroy : function(){
40326 if(this.textSizeEl){
40327 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40329 Roo.form.TextArea.superclass.onDestroy.call(this);
40333 onKeyUp : function(e){
40334 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40340 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40341 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40343 autoSize : function(){
40344 if(!this.grow || !this.textSizeEl){
40348 var v = el.dom.value;
40349 var ts = this.textSizeEl;
40352 ts.appendChild(document.createTextNode(v));
40355 Roo.fly(ts).setWidth(this.el.getWidth());
40357 v = "  ";
40360 v = v.replace(/\n/g, '<p> </p>');
40362 v += " \n ";
40365 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40366 if(h != this.lastHeight){
40367 this.lastHeight = h;
40368 this.el.setHeight(h);
40369 this.fireEvent("autosize", this, h);
40374 * Ext JS Library 1.1.1
40375 * Copyright(c) 2006-2007, Ext JS, LLC.
40377 * Originally Released Under LGPL - original licence link has changed is not relivant.
40380 * <script type="text/javascript">
40385 * @class Roo.form.NumberField
40386 * @extends Roo.form.TextField
40387 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40389 * Creates a new NumberField
40390 * @param {Object} config Configuration options
40392 Roo.form.NumberField = function(config){
40393 Roo.form.NumberField.superclass.constructor.call(this, config);
40396 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40398 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40400 fieldClass: "x-form-field x-form-num-field",
40402 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40404 allowDecimals : true,
40406 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40408 decimalSeparator : ".",
40410 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40412 decimalPrecision : 2,
40414 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40416 allowNegative : true,
40418 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40420 minValue : Number.NEGATIVE_INFINITY,
40422 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40424 maxValue : Number.MAX_VALUE,
40426 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40428 minText : "The minimum value for this field is {0}",
40430 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40432 maxText : "The maximum value for this field is {0}",
40434 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40435 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40437 nanText : "{0} is not a valid number",
40440 initEvents : function(){
40441 Roo.form.NumberField.superclass.initEvents.call(this);
40442 var allowed = "0123456789";
40443 if(this.allowDecimals){
40444 allowed += this.decimalSeparator;
40446 if(this.allowNegative){
40449 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40450 var keyPress = function(e){
40451 var k = e.getKey();
40452 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40455 var c = e.getCharCode();
40456 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40460 this.el.on("keypress", keyPress, this);
40464 validateValue : function(value){
40465 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40468 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40471 var num = this.parseValue(value);
40473 this.markInvalid(String.format(this.nanText, value));
40476 if(num < this.minValue){
40477 this.markInvalid(String.format(this.minText, this.minValue));
40480 if(num > this.maxValue){
40481 this.markInvalid(String.format(this.maxText, this.maxValue));
40487 getValue : function(){
40488 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40492 parseValue : function(value){
40493 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40494 return isNaN(value) ? '' : value;
40498 fixPrecision : function(value){
40499 var nan = isNaN(value);
40500 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40501 return nan ? '' : value;
40503 return parseFloat(value).toFixed(this.decimalPrecision);
40506 setValue : function(v){
40507 v = this.fixPrecision(v);
40508 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40512 decimalPrecisionFcn : function(v){
40513 return Math.floor(v);
40516 beforeBlur : function(){
40517 var v = this.parseValue(this.getRawValue());
40524 * Ext JS Library 1.1.1
40525 * Copyright(c) 2006-2007, Ext JS, LLC.
40527 * Originally Released Under LGPL - original licence link has changed is not relivant.
40530 * <script type="text/javascript">
40534 * @class Roo.form.DateField
40535 * @extends Roo.form.TriggerField
40536 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40538 * Create a new DateField
40539 * @param {Object} config
40541 Roo.form.DateField = function(config)
40543 Roo.form.DateField.superclass.constructor.call(this, config);
40549 * Fires when a date is selected
40550 * @param {Roo.form.DateField} combo This combo box
40551 * @param {Date} date The date selected
40558 if(typeof this.minValue == "string") {
40559 this.minValue = this.parseDate(this.minValue);
40561 if(typeof this.maxValue == "string") {
40562 this.maxValue = this.parseDate(this.maxValue);
40564 this.ddMatch = null;
40565 if(this.disabledDates){
40566 var dd = this.disabledDates;
40568 for(var i = 0; i < dd.length; i++){
40570 if(i != dd.length-1) {
40574 this.ddMatch = new RegExp(re + ")");
40578 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40580 * @cfg {String} format
40581 * The default date format string which can be overriden for localization support. The format must be
40582 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40586 * @cfg {String} altFormats
40587 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40588 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40590 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40592 * @cfg {Array} disabledDays
40593 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40595 disabledDays : null,
40597 * @cfg {String} disabledDaysText
40598 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40600 disabledDaysText : "Disabled",
40602 * @cfg {Array} disabledDates
40603 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40604 * expression so they are very powerful. Some examples:
40606 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40607 * <li>["03/08", "09/16"] would disable those days for every year</li>
40608 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40609 * <li>["03/../2006"] would disable every day in March 2006</li>
40610 * <li>["^03"] would disable every day in every March</li>
40612 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40613 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40615 disabledDates : null,
40617 * @cfg {String} disabledDatesText
40618 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40620 disabledDatesText : "Disabled",
40622 * @cfg {Date/String} minValue
40623 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40624 * valid format (defaults to null).
40628 * @cfg {Date/String} maxValue
40629 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40630 * valid format (defaults to null).
40634 * @cfg {String} minText
40635 * The error text to display when the date in the cell is before minValue (defaults to
40636 * 'The date in this field must be after {minValue}').
40638 minText : "The date in this field must be equal to or after {0}",
40640 * @cfg {String} maxText
40641 * The error text to display when the date in the cell is after maxValue (defaults to
40642 * 'The date in this field must be before {maxValue}').
40644 maxText : "The date in this field must be equal to or before {0}",
40646 * @cfg {String} invalidText
40647 * The error text to display when the date in the field is invalid (defaults to
40648 * '{value} is not a valid date - it must be in the format {format}').
40650 invalidText : "{0} is not a valid date - it must be in the format {1}",
40652 * @cfg {String} triggerClass
40653 * An additional CSS class used to style the trigger button. The trigger will always get the
40654 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40655 * which displays a calendar icon).
40657 triggerClass : 'x-form-date-trigger',
40661 * @cfg {Boolean} useIso
40662 * if enabled, then the date field will use a hidden field to store the
40663 * real value as iso formated date. default (false)
40667 * @cfg {String/Object} autoCreate
40668 * A DomHelper element spec, or true for a default element spec (defaults to
40669 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40672 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40675 hiddenField: false,
40677 onRender : function(ct, position)
40679 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40681 //this.el.dom.removeAttribute('name');
40682 Roo.log("Changing name?");
40683 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40684 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40686 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40687 // prevent input submission
40688 this.hiddenName = this.name;
40695 validateValue : function(value)
40697 value = this.formatDate(value);
40698 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40699 Roo.log('super failed');
40702 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40705 var svalue = value;
40706 value = this.parseDate(value);
40708 Roo.log('parse date failed' + svalue);
40709 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40712 var time = value.getTime();
40713 if(this.minValue && time < this.minValue.getTime()){
40714 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40717 if(this.maxValue && time > this.maxValue.getTime()){
40718 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40721 if(this.disabledDays){
40722 var day = value.getDay();
40723 for(var i = 0; i < this.disabledDays.length; i++) {
40724 if(day === this.disabledDays[i]){
40725 this.markInvalid(this.disabledDaysText);
40730 var fvalue = this.formatDate(value);
40731 if(this.ddMatch && this.ddMatch.test(fvalue)){
40732 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40739 // Provides logic to override the default TriggerField.validateBlur which just returns true
40740 validateBlur : function(){
40741 return !this.menu || !this.menu.isVisible();
40744 getName: function()
40746 // returns hidden if it's set..
40747 if (!this.rendered) {return ''};
40748 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40753 * Returns the current date value of the date field.
40754 * @return {Date} The date value
40756 getValue : function(){
40758 return this.hiddenField ?
40759 this.hiddenField.value :
40760 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40764 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40765 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40766 * (the default format used is "m/d/y").
40769 //All of these calls set the same date value (May 4, 2006)
40771 //Pass a date object:
40772 var dt = new Date('5/4/06');
40773 dateField.setValue(dt);
40775 //Pass a date string (default format):
40776 dateField.setValue('5/4/06');
40778 //Pass a date string (custom format):
40779 dateField.format = 'Y-m-d';
40780 dateField.setValue('2006-5-4');
40782 * @param {String/Date} date The date or valid date string
40784 setValue : function(date){
40785 if (this.hiddenField) {
40786 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40788 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40789 // make sure the value field is always stored as a date..
40790 this.value = this.parseDate(date);
40796 parseDate : function(value){
40797 if(!value || value instanceof Date){
40800 var v = Date.parseDate(value, this.format);
40801 if (!v && this.useIso) {
40802 v = Date.parseDate(value, 'Y-m-d');
40804 if(!v && this.altFormats){
40805 if(!this.altFormatsArray){
40806 this.altFormatsArray = this.altFormats.split("|");
40808 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40809 v = Date.parseDate(value, this.altFormatsArray[i]);
40816 formatDate : function(date, fmt){
40817 return (!date || !(date instanceof Date)) ?
40818 date : date.dateFormat(fmt || this.format);
40823 select: function(m, d){
40826 this.fireEvent('select', this, d);
40828 show : function(){ // retain focus styling
40832 this.focus.defer(10, this);
40833 var ml = this.menuListeners;
40834 this.menu.un("select", ml.select, this);
40835 this.menu.un("show", ml.show, this);
40836 this.menu.un("hide", ml.hide, this);
40841 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40842 onTriggerClick : function(){
40846 if(this.menu == null){
40847 this.menu = new Roo.menu.DateMenu();
40849 Roo.apply(this.menu.picker, {
40850 showClear: this.allowBlank,
40851 minDate : this.minValue,
40852 maxDate : this.maxValue,
40853 disabledDatesRE : this.ddMatch,
40854 disabledDatesText : this.disabledDatesText,
40855 disabledDays : this.disabledDays,
40856 disabledDaysText : this.disabledDaysText,
40857 format : this.useIso ? 'Y-m-d' : this.format,
40858 minText : String.format(this.minText, this.formatDate(this.minValue)),
40859 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40861 this.menu.on(Roo.apply({}, this.menuListeners, {
40864 this.menu.picker.setValue(this.getValue() || new Date());
40865 this.menu.show(this.el, "tl-bl?");
40868 beforeBlur : function(){
40869 var v = this.parseDate(this.getRawValue());
40879 isDirty : function() {
40880 if(this.disabled) {
40884 if(typeof(this.startValue) === 'undefined'){
40888 return String(this.getValue()) !== String(this.startValue);
40892 cleanLeadingSpace : function(e)
40899 * Ext JS Library 1.1.1
40900 * Copyright(c) 2006-2007, Ext JS, LLC.
40902 * Originally Released Under LGPL - original licence link has changed is not relivant.
40905 * <script type="text/javascript">
40909 * @class Roo.form.MonthField
40910 * @extends Roo.form.TriggerField
40911 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40913 * Create a new MonthField
40914 * @param {Object} config
40916 Roo.form.MonthField = function(config){
40918 Roo.form.MonthField.superclass.constructor.call(this, config);
40924 * Fires when a date is selected
40925 * @param {Roo.form.MonthFieeld} combo This combo box
40926 * @param {Date} date The date selected
40933 if(typeof this.minValue == "string") {
40934 this.minValue = this.parseDate(this.minValue);
40936 if(typeof this.maxValue == "string") {
40937 this.maxValue = this.parseDate(this.maxValue);
40939 this.ddMatch = null;
40940 if(this.disabledDates){
40941 var dd = this.disabledDates;
40943 for(var i = 0; i < dd.length; i++){
40945 if(i != dd.length-1) {
40949 this.ddMatch = new RegExp(re + ")");
40953 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40955 * @cfg {String} format
40956 * The default date format string which can be overriden for localization support. The format must be
40957 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40961 * @cfg {String} altFormats
40962 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40963 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40965 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40967 * @cfg {Array} disabledDays
40968 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40970 disabledDays : [0,1,2,3,4,5,6],
40972 * @cfg {String} disabledDaysText
40973 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40975 disabledDaysText : "Disabled",
40977 * @cfg {Array} disabledDates
40978 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40979 * expression so they are very powerful. Some examples:
40981 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40982 * <li>["03/08", "09/16"] would disable those days for every year</li>
40983 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40984 * <li>["03/../2006"] would disable every day in March 2006</li>
40985 * <li>["^03"] would disable every day in every March</li>
40987 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40988 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40990 disabledDates : null,
40992 * @cfg {String} disabledDatesText
40993 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40995 disabledDatesText : "Disabled",
40997 * @cfg {Date/String} minValue
40998 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40999 * valid format (defaults to null).
41003 * @cfg {Date/String} maxValue
41004 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41005 * valid format (defaults to null).
41009 * @cfg {String} minText
41010 * The error text to display when the date in the cell is before minValue (defaults to
41011 * 'The date in this field must be after {minValue}').
41013 minText : "The date in this field must be equal to or after {0}",
41015 * @cfg {String} maxTextf
41016 * The error text to display when the date in the cell is after maxValue (defaults to
41017 * 'The date in this field must be before {maxValue}').
41019 maxText : "The date in this field must be equal to or before {0}",
41021 * @cfg {String} invalidText
41022 * The error text to display when the date in the field is invalid (defaults to
41023 * '{value} is not a valid date - it must be in the format {format}').
41025 invalidText : "{0} is not a valid date - it must be in the format {1}",
41027 * @cfg {String} triggerClass
41028 * An additional CSS class used to style the trigger button. The trigger will always get the
41029 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41030 * which displays a calendar icon).
41032 triggerClass : 'x-form-date-trigger',
41036 * @cfg {Boolean} useIso
41037 * if enabled, then the date field will use a hidden field to store the
41038 * real value as iso formated date. default (true)
41042 * @cfg {String/Object} autoCreate
41043 * A DomHelper element spec, or true for a default element spec (defaults to
41044 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41047 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
41050 hiddenField: false,
41052 hideMonthPicker : false,
41054 onRender : function(ct, position)
41056 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
41058 this.el.dom.removeAttribute('name');
41059 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41061 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41062 // prevent input submission
41063 this.hiddenName = this.name;
41070 validateValue : function(value)
41072 value = this.formatDate(value);
41073 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41076 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41079 var svalue = value;
41080 value = this.parseDate(value);
41082 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41085 var time = value.getTime();
41086 if(this.minValue && time < this.minValue.getTime()){
41087 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41090 if(this.maxValue && time > this.maxValue.getTime()){
41091 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41094 /*if(this.disabledDays){
41095 var day = value.getDay();
41096 for(var i = 0; i < this.disabledDays.length; i++) {
41097 if(day === this.disabledDays[i]){
41098 this.markInvalid(this.disabledDaysText);
41104 var fvalue = this.formatDate(value);
41105 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41106 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41114 // Provides logic to override the default TriggerField.validateBlur which just returns true
41115 validateBlur : function(){
41116 return !this.menu || !this.menu.isVisible();
41120 * Returns the current date value of the date field.
41121 * @return {Date} The date value
41123 getValue : function(){
41127 return this.hiddenField ?
41128 this.hiddenField.value :
41129 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41133 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41134 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41135 * (the default format used is "m/d/y").
41138 //All of these calls set the same date value (May 4, 2006)
41140 //Pass a date object:
41141 var dt = new Date('5/4/06');
41142 monthField.setValue(dt);
41144 //Pass a date string (default format):
41145 monthField.setValue('5/4/06');
41147 //Pass a date string (custom format):
41148 monthField.format = 'Y-m-d';
41149 monthField.setValue('2006-5-4');
41151 * @param {String/Date} date The date or valid date string
41153 setValue : function(date){
41154 Roo.log('month setValue' + date);
41155 // can only be first of month..
41157 var val = this.parseDate(date);
41159 if (this.hiddenField) {
41160 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41162 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41163 this.value = this.parseDate(date);
41167 parseDate : function(value){
41168 if(!value || value instanceof Date){
41169 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41172 var v = Date.parseDate(value, this.format);
41173 if (!v && this.useIso) {
41174 v = Date.parseDate(value, 'Y-m-d');
41178 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41182 if(!v && this.altFormats){
41183 if(!this.altFormatsArray){
41184 this.altFormatsArray = this.altFormats.split("|");
41186 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41187 v = Date.parseDate(value, this.altFormatsArray[i]);
41194 formatDate : function(date, fmt){
41195 return (!date || !(date instanceof Date)) ?
41196 date : date.dateFormat(fmt || this.format);
41201 select: function(m, d){
41203 this.fireEvent('select', this, d);
41205 show : function(){ // retain focus styling
41209 this.focus.defer(10, this);
41210 var ml = this.menuListeners;
41211 this.menu.un("select", ml.select, this);
41212 this.menu.un("show", ml.show, this);
41213 this.menu.un("hide", ml.hide, this);
41217 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41218 onTriggerClick : function(){
41222 if(this.menu == null){
41223 this.menu = new Roo.menu.DateMenu();
41227 Roo.apply(this.menu.picker, {
41229 showClear: this.allowBlank,
41230 minDate : this.minValue,
41231 maxDate : this.maxValue,
41232 disabledDatesRE : this.ddMatch,
41233 disabledDatesText : this.disabledDatesText,
41235 format : this.useIso ? 'Y-m-d' : this.format,
41236 minText : String.format(this.minText, this.formatDate(this.minValue)),
41237 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41240 this.menu.on(Roo.apply({}, this.menuListeners, {
41248 // hide month picker get's called when we called by 'before hide';
41250 var ignorehide = true;
41251 p.hideMonthPicker = function(disableAnim){
41255 if(this.monthPicker){
41256 Roo.log("hideMonthPicker called");
41257 if(disableAnim === true){
41258 this.monthPicker.hide();
41260 this.monthPicker.slideOut('t', {duration:.2});
41261 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41262 p.fireEvent("select", this, this.value);
41268 Roo.log('picker set value');
41269 Roo.log(this.getValue());
41270 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41271 m.show(this.el, 'tl-bl?');
41272 ignorehide = false;
41273 // this will trigger hideMonthPicker..
41276 // hidden the day picker
41277 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41283 p.showMonthPicker.defer(100, p);
41289 beforeBlur : function(){
41290 var v = this.parseDate(this.getRawValue());
41296 /** @cfg {Boolean} grow @hide */
41297 /** @cfg {Number} growMin @hide */
41298 /** @cfg {Number} growMax @hide */
41305 * Ext JS Library 1.1.1
41306 * Copyright(c) 2006-2007, Ext JS, LLC.
41308 * Originally Released Under LGPL - original licence link has changed is not relivant.
41311 * <script type="text/javascript">
41316 * @class Roo.form.ComboBox
41317 * @extends Roo.form.TriggerField
41318 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41320 * Create a new ComboBox.
41321 * @param {Object} config Configuration options
41323 Roo.form.ComboBox = function(config){
41324 Roo.form.ComboBox.superclass.constructor.call(this, config);
41328 * Fires when the dropdown list is expanded
41329 * @param {Roo.form.ComboBox} combo This combo box
41334 * Fires when the dropdown list is collapsed
41335 * @param {Roo.form.ComboBox} combo This combo box
41339 * @event beforeselect
41340 * Fires before a list item is selected. Return false to cancel the selection.
41341 * @param {Roo.form.ComboBox} combo This combo box
41342 * @param {Roo.data.Record} record The data record returned from the underlying store
41343 * @param {Number} index The index of the selected item in the dropdown list
41345 'beforeselect' : true,
41348 * Fires when a list item is selected
41349 * @param {Roo.form.ComboBox} combo This combo box
41350 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41351 * @param {Number} index The index of the selected item in the dropdown list
41355 * @event beforequery
41356 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41357 * The event object passed has these properties:
41358 * @param {Roo.form.ComboBox} combo This combo box
41359 * @param {String} query The query
41360 * @param {Boolean} forceAll true to force "all" query
41361 * @param {Boolean} cancel true to cancel the query
41362 * @param {Object} e The query event object
41364 'beforequery': true,
41367 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41368 * @param {Roo.form.ComboBox} combo This combo box
41373 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41374 * @param {Roo.form.ComboBox} combo This combo box
41375 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41381 if(this.transform){
41382 this.allowDomMove = false;
41383 var s = Roo.getDom(this.transform);
41384 if(!this.hiddenName){
41385 this.hiddenName = s.name;
41388 this.mode = 'local';
41389 var d = [], opts = s.options;
41390 for(var i = 0, len = opts.length;i < len; i++){
41392 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41394 this.value = value;
41396 d.push([value, o.text]);
41398 this.store = new Roo.data.SimpleStore({
41400 fields: ['value', 'text'],
41403 this.valueField = 'value';
41404 this.displayField = 'text';
41406 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41407 if(!this.lazyRender){
41408 this.target = true;
41409 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41410 s.parentNode.removeChild(s); // remove it
41411 this.render(this.el.parentNode);
41413 s.parentNode.removeChild(s); // remove it
41418 this.store = Roo.factory(this.store, Roo.data);
41421 this.selectedIndex = -1;
41422 if(this.mode == 'local'){
41423 if(config.queryDelay === undefined){
41424 this.queryDelay = 10;
41426 if(config.minChars === undefined){
41432 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41434 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41437 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41438 * rendering into an Roo.Editor, defaults to false)
41441 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41442 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41445 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41448 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41449 * the dropdown list (defaults to undefined, with no header element)
41453 * @cfg {String/Roo.Template} tpl The template to use to render the output
41457 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41459 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41461 listWidth: undefined,
41463 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41464 * mode = 'remote' or 'text' if mode = 'local')
41466 displayField: undefined,
41468 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41469 * mode = 'remote' or 'value' if mode = 'local').
41470 * Note: use of a valueField requires the user make a selection
41471 * in order for a value to be mapped.
41473 valueField: undefined,
41477 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41478 * field's data value (defaults to the underlying DOM element's name)
41480 hiddenName: undefined,
41482 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41486 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41488 selectedClass: 'x-combo-selected',
41490 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41491 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41492 * which displays a downward arrow icon).
41494 triggerClass : 'x-form-arrow-trigger',
41496 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41500 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41501 * anchor positions (defaults to 'tl-bl')
41503 listAlign: 'tl-bl?',
41505 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41509 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41510 * query specified by the allQuery config option (defaults to 'query')
41512 triggerAction: 'query',
41514 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41515 * (defaults to 4, does not apply if editable = false)
41519 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41520 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41524 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41525 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41529 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41530 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41534 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41535 * when editable = true (defaults to false)
41537 selectOnFocus:false,
41539 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41541 queryParam: 'query',
41543 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41544 * when mode = 'remote' (defaults to 'Loading...')
41546 loadingText: 'Loading...',
41548 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41552 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41556 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41557 * traditional select (defaults to true)
41561 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41565 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41569 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41570 * listWidth has a higher value)
41574 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41575 * allow the user to set arbitrary text into the field (defaults to false)
41577 forceSelection:false,
41579 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41580 * if typeAhead = true (defaults to 250)
41582 typeAheadDelay : 250,
41584 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41585 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41587 valueNotFoundText : undefined,
41589 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41591 blockFocus : false,
41594 * @cfg {Boolean} disableClear Disable showing of clear button.
41596 disableClear : false,
41598 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41600 alwaysQuery : false,
41606 // element that contains real text value.. (when hidden is used..)
41609 onRender : function(ct, position)
41611 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41613 if(this.hiddenName){
41614 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41616 this.hiddenField.value =
41617 this.hiddenValue !== undefined ? this.hiddenValue :
41618 this.value !== undefined ? this.value : '';
41620 // prevent input submission
41621 this.el.dom.removeAttribute('name');
41627 this.el.dom.setAttribute('autocomplete', 'off');
41630 var cls = 'x-combo-list';
41632 this.list = new Roo.Layer({
41633 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41636 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41637 this.list.setWidth(lw);
41638 this.list.swallowEvent('mousewheel');
41639 this.assetHeight = 0;
41642 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41643 this.assetHeight += this.header.getHeight();
41646 this.innerList = this.list.createChild({cls:cls+'-inner'});
41647 this.innerList.on('mouseover', this.onViewOver, this);
41648 this.innerList.on('mousemove', this.onViewMove, this);
41649 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41651 if(this.allowBlank && !this.pageSize && !this.disableClear){
41652 this.footer = this.list.createChild({cls:cls+'-ft'});
41653 this.pageTb = new Roo.Toolbar(this.footer);
41657 this.footer = this.list.createChild({cls:cls+'-ft'});
41658 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41659 {pageSize: this.pageSize});
41663 if (this.pageTb && this.allowBlank && !this.disableClear) {
41665 this.pageTb.add(new Roo.Toolbar.Fill(), {
41666 cls: 'x-btn-icon x-btn-clear',
41668 handler: function()
41671 _this.clearValue();
41672 _this.onSelect(false, -1);
41677 this.assetHeight += this.footer.getHeight();
41682 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41685 this.view = new Roo.View(this.innerList, this.tpl, {
41688 selectedClass: this.selectedClass
41691 this.view.on('click', this.onViewClick, this);
41693 this.store.on('beforeload', this.onBeforeLoad, this);
41694 this.store.on('load', this.onLoad, this);
41695 this.store.on('loadexception', this.onLoadException, this);
41697 if(this.resizable){
41698 this.resizer = new Roo.Resizable(this.list, {
41699 pinned:true, handles:'se'
41701 this.resizer.on('resize', function(r, w, h){
41702 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41703 this.listWidth = w;
41704 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41705 this.restrictHeight();
41707 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41709 if(!this.editable){
41710 this.editable = true;
41711 this.setEditable(false);
41715 if (typeof(this.events.add.listeners) != 'undefined') {
41717 this.addicon = this.wrap.createChild(
41718 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41720 this.addicon.on('click', function(e) {
41721 this.fireEvent('add', this);
41724 if (typeof(this.events.edit.listeners) != 'undefined') {
41726 this.editicon = this.wrap.createChild(
41727 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41728 if (this.addicon) {
41729 this.editicon.setStyle('margin-left', '40px');
41731 this.editicon.on('click', function(e) {
41733 // we fire even if inothing is selected..
41734 this.fireEvent('edit', this, this.lastData );
41744 initEvents : function(){
41745 Roo.form.ComboBox.superclass.initEvents.call(this);
41747 this.keyNav = new Roo.KeyNav(this.el, {
41748 "up" : function(e){
41749 this.inKeyMode = true;
41753 "down" : function(e){
41754 if(!this.isExpanded()){
41755 this.onTriggerClick();
41757 this.inKeyMode = true;
41762 "enter" : function(e){
41763 this.onViewClick();
41767 "esc" : function(e){
41771 "tab" : function(e){
41772 this.onViewClick(false);
41773 this.fireEvent("specialkey", this, e);
41779 doRelay : function(foo, bar, hname){
41780 if(hname == 'down' || this.scope.isExpanded()){
41781 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41788 this.queryDelay = Math.max(this.queryDelay || 10,
41789 this.mode == 'local' ? 10 : 250);
41790 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41791 if(this.typeAhead){
41792 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41794 if(this.editable !== false){
41795 this.el.on("keyup", this.onKeyUp, this);
41797 if(this.forceSelection){
41798 this.on('blur', this.doForce, this);
41802 onDestroy : function(){
41804 this.view.setStore(null);
41805 this.view.el.removeAllListeners();
41806 this.view.el.remove();
41807 this.view.purgeListeners();
41810 this.list.destroy();
41813 this.store.un('beforeload', this.onBeforeLoad, this);
41814 this.store.un('load', this.onLoad, this);
41815 this.store.un('loadexception', this.onLoadException, this);
41817 Roo.form.ComboBox.superclass.onDestroy.call(this);
41821 fireKey : function(e){
41822 if(e.isNavKeyPress() && !this.list.isVisible()){
41823 this.fireEvent("specialkey", this, e);
41828 onResize: function(w, h){
41829 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41831 if(typeof w != 'number'){
41832 // we do not handle it!?!?
41835 var tw = this.trigger.getWidth();
41836 tw += this.addicon ? this.addicon.getWidth() : 0;
41837 tw += this.editicon ? this.editicon.getWidth() : 0;
41839 this.el.setWidth( this.adjustWidth('input', x));
41841 this.trigger.setStyle('left', x+'px');
41843 if(this.list && this.listWidth === undefined){
41844 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41845 this.list.setWidth(lw);
41846 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41854 * Allow or prevent the user from directly editing the field text. If false is passed,
41855 * the user will only be able to select from the items defined in the dropdown list. This method
41856 * is the runtime equivalent of setting the 'editable' config option at config time.
41857 * @param {Boolean} value True to allow the user to directly edit the field text
41859 setEditable : function(value){
41860 if(value == this.editable){
41863 this.editable = value;
41865 this.el.dom.setAttribute('readOnly', true);
41866 this.el.on('mousedown', this.onTriggerClick, this);
41867 this.el.addClass('x-combo-noedit');
41869 this.el.dom.setAttribute('readOnly', false);
41870 this.el.un('mousedown', this.onTriggerClick, this);
41871 this.el.removeClass('x-combo-noedit');
41876 onBeforeLoad : function(){
41877 if(!this.hasFocus){
41880 this.innerList.update(this.loadingText ?
41881 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41882 this.restrictHeight();
41883 this.selectedIndex = -1;
41887 onLoad : function(){
41888 if(!this.hasFocus){
41891 if(this.store.getCount() > 0){
41893 this.restrictHeight();
41894 if(this.lastQuery == this.allQuery){
41896 this.el.dom.select();
41898 if(!this.selectByValue(this.value, true)){
41899 this.select(0, true);
41903 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41904 this.taTask.delay(this.typeAheadDelay);
41908 this.onEmptyResults();
41913 onLoadException : function()
41916 Roo.log(this.store.reader.jsonData);
41917 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41918 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41924 onTypeAhead : function(){
41925 if(this.store.getCount() > 0){
41926 var r = this.store.getAt(0);
41927 var newValue = r.data[this.displayField];
41928 var len = newValue.length;
41929 var selStart = this.getRawValue().length;
41930 if(selStart != len){
41931 this.setRawValue(newValue);
41932 this.selectText(selStart, newValue.length);
41938 onSelect : function(record, index){
41939 if(this.fireEvent('beforeselect', this, record, index) !== false){
41940 this.setFromData(index > -1 ? record.data : false);
41942 this.fireEvent('select', this, record, index);
41947 * Returns the currently selected field value or empty string if no value is set.
41948 * @return {String} value The selected value
41950 getValue : function(){
41951 if(this.valueField){
41952 return typeof this.value != 'undefined' ? this.value : '';
41954 return Roo.form.ComboBox.superclass.getValue.call(this);
41958 * Clears any text/value currently set in the field
41960 clearValue : function(){
41961 if(this.hiddenField){
41962 this.hiddenField.value = '';
41965 this.setRawValue('');
41966 this.lastSelectionText = '';
41971 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41972 * will be displayed in the field. If the value does not match the data value of an existing item,
41973 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41974 * Otherwise the field will be blank (although the value will still be set).
41975 * @param {String} value The value to match
41977 setValue : function(v){
41979 if(this.valueField){
41980 var r = this.findRecord(this.valueField, v);
41982 text = r.data[this.displayField];
41983 }else if(this.valueNotFoundText !== undefined){
41984 text = this.valueNotFoundText;
41987 this.lastSelectionText = text;
41988 if(this.hiddenField){
41989 this.hiddenField.value = v;
41991 Roo.form.ComboBox.superclass.setValue.call(this, text);
41995 * @property {Object} the last set data for the element
42000 * Sets the value of the field based on a object which is related to the record format for the store.
42001 * @param {Object} value the value to set as. or false on reset?
42003 setFromData : function(o){
42004 var dv = ''; // display value
42005 var vv = ''; // value value..
42007 if (this.displayField) {
42008 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
42010 // this is an error condition!!!
42011 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
42014 if(this.valueField){
42015 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
42017 if(this.hiddenField){
42018 this.hiddenField.value = vv;
42020 this.lastSelectionText = dv;
42021 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42025 // no hidden field.. - we store the value in 'value', but still display
42026 // display field!!!!
42027 this.lastSelectionText = dv;
42028 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42034 reset : function(){
42035 // overridden so that last data is reset..
42036 this.setValue(this.resetValue);
42037 this.originalValue = this.getValue();
42038 this.clearInvalid();
42039 this.lastData = false;
42041 this.view.clearSelections();
42045 findRecord : function(prop, value){
42047 if(this.store.getCount() > 0){
42048 this.store.each(function(r){
42049 if(r.data[prop] == value){
42059 getName: function()
42061 // returns hidden if it's set..
42062 if (!this.rendered) {return ''};
42063 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42067 onViewMove : function(e, t){
42068 this.inKeyMode = false;
42072 onViewOver : function(e, t){
42073 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42076 var item = this.view.findItemFromChild(t);
42078 var index = this.view.indexOf(item);
42079 this.select(index, false);
42084 onViewClick : function(doFocus)
42086 var index = this.view.getSelectedIndexes()[0];
42087 var r = this.store.getAt(index);
42089 this.onSelect(r, index);
42091 if(doFocus !== false && !this.blockFocus){
42097 restrictHeight : function(){
42098 this.innerList.dom.style.height = '';
42099 var inner = this.innerList.dom;
42100 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42101 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42102 this.list.beginUpdate();
42103 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42104 this.list.alignTo(this.el, this.listAlign);
42105 this.list.endUpdate();
42109 onEmptyResults : function(){
42114 * Returns true if the dropdown list is expanded, else false.
42116 isExpanded : function(){
42117 return this.list.isVisible();
42121 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42122 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42123 * @param {String} value The data value of the item to select
42124 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42125 * selected item if it is not currently in view (defaults to true)
42126 * @return {Boolean} True if the value matched an item in the list, else false
42128 selectByValue : function(v, scrollIntoView){
42129 if(v !== undefined && v !== null){
42130 var r = this.findRecord(this.valueField || this.displayField, v);
42132 this.select(this.store.indexOf(r), scrollIntoView);
42140 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42141 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42142 * @param {Number} index The zero-based index of the list item to select
42143 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42144 * selected item if it is not currently in view (defaults to true)
42146 select : function(index, scrollIntoView){
42147 this.selectedIndex = index;
42148 this.view.select(index);
42149 if(scrollIntoView !== false){
42150 var el = this.view.getNode(index);
42152 this.innerList.scrollChildIntoView(el, false);
42158 selectNext : function(){
42159 var ct = this.store.getCount();
42161 if(this.selectedIndex == -1){
42163 }else if(this.selectedIndex < ct-1){
42164 this.select(this.selectedIndex+1);
42170 selectPrev : function(){
42171 var ct = this.store.getCount();
42173 if(this.selectedIndex == -1){
42175 }else if(this.selectedIndex != 0){
42176 this.select(this.selectedIndex-1);
42182 onKeyUp : function(e){
42183 if(this.editable !== false && !e.isSpecialKey()){
42184 this.lastKey = e.getKey();
42185 this.dqTask.delay(this.queryDelay);
42190 validateBlur : function(){
42191 return !this.list || !this.list.isVisible();
42195 initQuery : function(){
42196 this.doQuery(this.getRawValue());
42200 doForce : function(){
42201 if(this.el.dom.value.length > 0){
42202 this.el.dom.value =
42203 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42209 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42210 * query allowing the query action to be canceled if needed.
42211 * @param {String} query The SQL query to execute
42212 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42213 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42214 * saved in the current store (defaults to false)
42216 doQuery : function(q, forceAll){
42217 if(q === undefined || q === null){
42222 forceAll: forceAll,
42226 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42230 forceAll = qe.forceAll;
42231 if(forceAll === true || (q.length >= this.minChars)){
42232 if(this.lastQuery != q || this.alwaysQuery){
42233 this.lastQuery = q;
42234 if(this.mode == 'local'){
42235 this.selectedIndex = -1;
42237 this.store.clearFilter();
42239 this.store.filter(this.displayField, q);
42243 this.store.baseParams[this.queryParam] = q;
42245 params: this.getParams(q)
42250 this.selectedIndex = -1;
42257 getParams : function(q){
42259 //p[this.queryParam] = q;
42262 p.limit = this.pageSize;
42268 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42270 collapse : function(){
42271 if(!this.isExpanded()){
42275 Roo.get(document).un('mousedown', this.collapseIf, this);
42276 Roo.get(document).un('mousewheel', this.collapseIf, this);
42277 if (!this.editable) {
42278 Roo.get(document).un('keydown', this.listKeyPress, this);
42280 this.fireEvent('collapse', this);
42284 collapseIf : function(e){
42285 if(!e.within(this.wrap) && !e.within(this.list)){
42291 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42293 expand : function(){
42294 if(this.isExpanded() || !this.hasFocus){
42297 this.list.alignTo(this.el, this.listAlign);
42299 Roo.get(document).on('mousedown', this.collapseIf, this);
42300 Roo.get(document).on('mousewheel', this.collapseIf, this);
42301 if (!this.editable) {
42302 Roo.get(document).on('keydown', this.listKeyPress, this);
42305 this.fireEvent('expand', this);
42309 // Implements the default empty TriggerField.onTriggerClick function
42310 onTriggerClick : function(){
42314 if(this.isExpanded()){
42316 if (!this.blockFocus) {
42321 this.hasFocus = true;
42322 if(this.triggerAction == 'all') {
42323 this.doQuery(this.allQuery, true);
42325 this.doQuery(this.getRawValue());
42327 if (!this.blockFocus) {
42332 listKeyPress : function(e)
42334 //Roo.log('listkeypress');
42335 // scroll to first matching element based on key pres..
42336 if (e.isSpecialKey()) {
42339 var k = String.fromCharCode(e.getKey()).toUpperCase();
42342 var csel = this.view.getSelectedNodes();
42343 var cselitem = false;
42345 var ix = this.view.indexOf(csel[0]);
42346 cselitem = this.store.getAt(ix);
42347 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42353 this.store.each(function(v) {
42355 // start at existing selection.
42356 if (cselitem.id == v.id) {
42362 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42363 match = this.store.indexOf(v);
42368 if (match === false) {
42369 return true; // no more action?
42372 this.view.select(match);
42373 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42374 sn.scrollIntoView(sn.dom.parentNode, false);
42378 * @cfg {Boolean} grow
42382 * @cfg {Number} growMin
42386 * @cfg {Number} growMax
42394 * Copyright(c) 2010-2012, Roo J Solutions Limited
42401 * @class Roo.form.ComboBoxArray
42402 * @extends Roo.form.TextField
42403 * A facebook style adder... for lists of email / people / countries etc...
42404 * pick multiple items from a combo box, and shows each one.
42406 * Fred [x] Brian [x] [Pick another |v]
42409 * For this to work: it needs various extra information
42410 * - normal combo problay has
42412 * + displayField, valueField
42414 * For our purpose...
42417 * If we change from 'extends' to wrapping...
42424 * Create a new ComboBoxArray.
42425 * @param {Object} config Configuration options
42429 Roo.form.ComboBoxArray = function(config)
42433 * @event beforeremove
42434 * Fires before remove the value from the list
42435 * @param {Roo.form.ComboBoxArray} _self This combo box array
42436 * @param {Roo.form.ComboBoxArray.Item} item removed item
42438 'beforeremove' : true,
42441 * Fires when remove the value from the list
42442 * @param {Roo.form.ComboBoxArray} _self This combo box array
42443 * @param {Roo.form.ComboBoxArray.Item} item removed item
42450 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42452 this.items = new Roo.util.MixedCollection(false);
42454 // construct the child combo...
42464 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42467 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42472 // behavies liek a hiddne field
42473 inputType: 'hidden',
42475 * @cfg {Number} width The width of the box that displays the selected element
42482 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42486 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42488 hiddenName : false,
42490 * @cfg {String} seperator The value seperator normally ','
42494 // private the array of items that are displayed..
42496 // private - the hidden field el.
42498 // private - the filed el..
42501 //validateValue : function() { return true; }, // all values are ok!
42502 //onAddClick: function() { },
42504 onRender : function(ct, position)
42507 // create the standard hidden element
42508 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42511 // give fake names to child combo;
42512 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42513 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42515 this.combo = Roo.factory(this.combo, Roo.form);
42516 this.combo.onRender(ct, position);
42517 if (typeof(this.combo.width) != 'undefined') {
42518 this.combo.onResize(this.combo.width,0);
42521 this.combo.initEvents();
42523 // assigned so form know we need to do this..
42524 this.store = this.combo.store;
42525 this.valueField = this.combo.valueField;
42526 this.displayField = this.combo.displayField ;
42529 this.combo.wrap.addClass('x-cbarray-grp');
42531 var cbwrap = this.combo.wrap.createChild(
42532 {tag: 'div', cls: 'x-cbarray-cb'},
42537 this.hiddenEl = this.combo.wrap.createChild({
42538 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42540 this.el = this.combo.wrap.createChild({
42541 tag: 'input', type:'hidden' , name: this.name, value : ''
42543 // this.el.dom.removeAttribute("name");
42546 this.outerWrap = this.combo.wrap;
42547 this.wrap = cbwrap;
42549 this.outerWrap.setWidth(this.width);
42550 this.outerWrap.dom.removeChild(this.el.dom);
42552 this.wrap.dom.appendChild(this.el.dom);
42553 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42554 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42556 this.combo.trigger.setStyle('position','relative');
42557 this.combo.trigger.setStyle('left', '0px');
42558 this.combo.trigger.setStyle('top', '2px');
42560 this.combo.el.setStyle('vertical-align', 'text-bottom');
42562 //this.trigger.setStyle('vertical-align', 'top');
42564 // this should use the code from combo really... on('add' ....)
42568 this.adder = this.outerWrap.createChild(
42569 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42571 this.adder.on('click', function(e) {
42572 _t.fireEvent('adderclick', this, e);
42576 //this.adder.on('click', this.onAddClick, _t);
42579 this.combo.on('select', function(cb, rec, ix) {
42580 this.addItem(rec.data);
42583 cb.el.dom.value = '';
42584 //cb.lastData = rec.data;
42593 getName: function()
42595 // returns hidden if it's set..
42596 if (!this.rendered) {return ''};
42597 return this.hiddenName ? this.hiddenName : this.name;
42602 onResize: function(w, h){
42605 // not sure if this is needed..
42606 //this.combo.onResize(w,h);
42608 if(typeof w != 'number'){
42609 // we do not handle it!?!?
42612 var tw = this.combo.trigger.getWidth();
42613 tw += this.addicon ? this.addicon.getWidth() : 0;
42614 tw += this.editicon ? this.editicon.getWidth() : 0;
42616 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42618 this.combo.trigger.setStyle('left', '0px');
42620 if(this.list && this.listWidth === undefined){
42621 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42622 this.list.setWidth(lw);
42623 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42630 addItem: function(rec)
42632 var valueField = this.combo.valueField;
42633 var displayField = this.combo.displayField;
42635 if (this.items.indexOfKey(rec[valueField]) > -1) {
42636 //console.log("GOT " + rec.data.id);
42640 var x = new Roo.form.ComboBoxArray.Item({
42641 //id : rec[this.idField],
42643 displayField : displayField ,
42644 tipField : displayField ,
42648 this.items.add(rec[valueField],x);
42649 // add it before the element..
42650 this.updateHiddenEl();
42651 x.render(this.outerWrap, this.wrap.dom);
42652 // add the image handler..
42655 updateHiddenEl : function()
42658 if (!this.hiddenEl) {
42662 var idField = this.combo.valueField;
42664 this.items.each(function(f) {
42665 ar.push(f.data[idField]);
42667 this.hiddenEl.dom.value = ar.join(this.seperator);
42673 this.items.clear();
42675 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42679 this.el.dom.value = '';
42680 if (this.hiddenEl) {
42681 this.hiddenEl.dom.value = '';
42685 getValue: function()
42687 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42689 setValue: function(v) // not a valid action - must use addItems..
42694 if (this.store.isLocal && (typeof(v) == 'string')) {
42695 // then we can use the store to find the values..
42696 // comma seperated at present.. this needs to allow JSON based encoding..
42697 this.hiddenEl.value = v;
42699 Roo.each(v.split(this.seperator), function(k) {
42700 Roo.log("CHECK " + this.valueField + ',' + k);
42701 var li = this.store.query(this.valueField, k);
42706 add[this.valueField] = k;
42707 add[this.displayField] = li.item(0).data[this.displayField];
42713 if (typeof(v) == 'object' ) {
42714 // then let's assume it's an array of objects..
42715 Roo.each(v, function(l) {
42717 if (typeof(l) == 'string') {
42719 add[this.valueField] = l;
42720 add[this.displayField] = l
42729 setFromData: function(v)
42731 // this recieves an object, if setValues is called.
42733 this.el.dom.value = v[this.displayField];
42734 this.hiddenEl.dom.value = v[this.valueField];
42735 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42738 var kv = v[this.valueField];
42739 var dv = v[this.displayField];
42740 kv = typeof(kv) != 'string' ? '' : kv;
42741 dv = typeof(dv) != 'string' ? '' : dv;
42744 var keys = kv.split(this.seperator);
42745 var display = dv.split(this.seperator);
42746 for (var i = 0 ; i < keys.length; i++) {
42748 add[this.valueField] = keys[i];
42749 add[this.displayField] = display[i];
42757 * Validates the combox array value
42758 * @return {Boolean} True if the value is valid, else false
42760 validate : function(){
42761 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42762 this.clearInvalid();
42768 validateValue : function(value){
42769 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42777 isDirty : function() {
42778 if(this.disabled) {
42783 var d = Roo.decode(String(this.originalValue));
42785 return String(this.getValue()) !== String(this.originalValue);
42788 var originalValue = [];
42790 for (var i = 0; i < d.length; i++){
42791 originalValue.push(d[i][this.valueField]);
42794 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42803 * @class Roo.form.ComboBoxArray.Item
42804 * @extends Roo.BoxComponent
42805 * A selected item in the list
42806 * Fred [x] Brian [x] [Pick another |v]
42809 * Create a new item.
42810 * @param {Object} config Configuration options
42813 Roo.form.ComboBoxArray.Item = function(config) {
42814 config.id = Roo.id();
42815 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42818 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42821 displayField : false,
42825 defaultAutoCreate : {
42827 cls: 'x-cbarray-item',
42834 src : Roo.BLANK_IMAGE_URL ,
42842 onRender : function(ct, position)
42844 Roo.form.Field.superclass.onRender.call(this, ct, position);
42847 var cfg = this.getAutoCreate();
42848 this.el = ct.createChild(cfg, position);
42851 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42853 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42854 this.cb.renderer(this.data) :
42855 String.format('{0}',this.data[this.displayField]);
42858 this.el.child('div').dom.setAttribute('qtip',
42859 String.format('{0}',this.data[this.tipField])
42862 this.el.child('img').on('click', this.remove, this);
42866 remove : function()
42868 if(this.cb.disabled){
42872 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42873 this.cb.items.remove(this);
42874 this.el.child('img').un('click', this.remove, this);
42876 this.cb.updateHiddenEl();
42878 this.cb.fireEvent('remove', this.cb, this);
42883 * RooJS Library 1.1.1
42884 * Copyright(c) 2008-2011 Alan Knowles
42891 * @class Roo.form.ComboNested
42892 * @extends Roo.form.ComboBox
42893 * A combobox for that allows selection of nested items in a list,
42908 * Create a new ComboNested
42909 * @param {Object} config Configuration options
42911 Roo.form.ComboNested = function(config){
42912 Roo.form.ComboCheck.superclass.constructor.call(this, config);
42913 // should verify some data...
42915 // hiddenName = required..
42916 // displayField = required
42917 // valudField == required
42918 var req= [ 'hiddenName', 'displayField', 'valueField' ];
42920 Roo.each(req, function(e) {
42921 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
42922 throw "Roo.form.ComboNested : missing value for: " + e;
42929 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
42932 * @config {Number} max Number of columns to show
42937 list : null, // the outermost div..
42938 innerLists : null, // the
42942 loadingChildren : false,
42944 onRender : function(ct, position)
42946 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
42948 if(this.hiddenName){
42949 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42951 this.hiddenField.value =
42952 this.hiddenValue !== undefined ? this.hiddenValue :
42953 this.value !== undefined ? this.value : '';
42955 // prevent input submission
42956 this.el.dom.removeAttribute('name');
42962 this.el.dom.setAttribute('autocomplete', 'off');
42965 var cls = 'x-combo-list';
42967 this.list = new Roo.Layer({
42968 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
42971 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
42972 this.list.setWidth(lw);
42973 this.list.swallowEvent('mousewheel');
42974 this.assetHeight = 0;
42977 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
42978 this.assetHeight += this.header.getHeight();
42980 this.innerLists = [];
42983 for (var i =0 ; i < this.maxColumns; i++) {
42984 this.onRenderList( cls, i);
42987 // always needs footer, as we are going to have an 'OK' button.
42988 this.footer = this.list.createChild({cls:cls+'-ft'});
42989 this.pageTb = new Roo.Toolbar(this.footer);
42994 handler: function()
43000 if ( this.allowBlank && !this.disableClear) {
43002 this.pageTb.add(new Roo.Toolbar.Fill(), {
43003 cls: 'x-btn-icon x-btn-clear',
43005 handler: function()
43008 _this.clearValue();
43009 _this.onSelect(false, -1);
43014 this.assetHeight += this.footer.getHeight();
43018 onRenderList : function ( cls, i)
43021 var lw = Math.floor(
43022 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43025 this.list.setWidth(lw); // default to '1'
43027 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
43028 //il.on('mouseover', this.onViewOver, this, { list: i });
43029 //il.on('mousemove', this.onViewMove, this, { list: i });
43031 il.setStyle({ 'overflow-x' : 'hidden'});
43034 this.tpl = new Roo.Template({
43035 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
43036 isEmpty: function (value, allValues) {
43038 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
43039 return dl ? 'has-children' : 'no-children'
43044 var store = this.store;
43046 store = new Roo.data.SimpleStore({
43047 //fields : this.store.reader.meta.fields,
43048 reader : this.store.reader,
43052 this.stores[i] = store;
43054 var view = this.views[i] = new Roo.View(
43060 selectedClass: this.selectedClass
43063 view.getEl().setWidth(lw);
43064 view.getEl().setStyle({
43065 position: i < 1 ? 'relative' : 'absolute',
43067 left: (i * lw ) + 'px',
43068 display : i > 0 ? 'none' : 'block'
43070 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
43071 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
43072 //view.on('click', this.onViewClick, this, { list : i });
43074 store.on('beforeload', this.onBeforeLoad, this);
43075 store.on('load', this.onLoad, this, { list : i});
43076 store.on('loadexception', this.onLoadException, this);
43078 // hide the other vies..
43084 restrictHeight : function()
43087 Roo.each(this.innerLists, function(il,i) {
43088 var el = this.views[i].getEl();
43089 el.dom.style.height = '';
43090 var inner = el.dom;
43091 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
43092 // only adjust heights on other ones..
43093 mh = Math.max(h, mh);
43096 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43097 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43104 this.list.beginUpdate();
43105 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43106 this.list.alignTo(this.el, this.listAlign);
43107 this.list.endUpdate();
43112 // -- store handlers..
43114 onBeforeLoad : function()
43116 if(!this.hasFocus){
43119 this.innerLists[0].update(this.loadingText ?
43120 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43121 this.restrictHeight();
43122 this.selectedIndex = -1;
43125 onLoad : function(a,b,c,d)
43127 if (!this.loadingChildren) {
43128 // then we are loading the top level. - hide the children
43129 for (var i = 1;i < this.views.length; i++) {
43130 this.views[i].getEl().setStyle({ display : 'none' });
43132 var lw = Math.floor(
43133 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43136 this.list.setWidth(lw); // default to '1'
43140 if(!this.hasFocus){
43144 if(this.store.getCount() > 0) {
43146 this.restrictHeight();
43148 this.onEmptyResults();
43151 if (!this.loadingChildren) {
43152 this.selectActive();
43155 this.stores[1].loadData([]);
43156 this.stores[2].loadData([]);
43165 onLoadException : function()
43168 Roo.log(this.store.reader.jsonData);
43169 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43170 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43175 // no cleaning of leading spaces on blur here.
43176 cleanLeadingSpace : function(e) { },
43179 onSelectChange : function (view, sels, opts )
43181 var ix = view.getSelectedIndexes();
43183 if (opts.list > this.maxColumns - 2) {
43184 if (view.store.getCount()< 1) {
43185 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43189 // used to clear ?? but if we are loading unselected
43190 this.setFromData(view.store.getAt(ix[0]).data);
43199 // this get's fired when trigger opens..
43200 // this.setFromData({});
43201 var str = this.stores[opts.list+1];
43202 str.data.clear(); // removeall wihtout the fire events..
43206 var rec = view.store.getAt(ix[0]);
43208 this.setFromData(rec.data);
43209 this.fireEvent('select', this, rec, ix[0]);
43211 var lw = Math.floor(
43213 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43214 ) / this.maxColumns
43216 this.loadingChildren = true;
43217 this.stores[opts.list+1].loadDataFromChildren( rec );
43218 this.loadingChildren = false;
43219 var dl = this.stores[opts.list+1]. getTotalCount();
43221 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43223 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43224 for (var i = opts.list+2; i < this.views.length;i++) {
43225 this.views[i].getEl().setStyle({ display : 'none' });
43228 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43229 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43231 if (this.isLoading) {
43232 // this.selectActive(opts.list);
43240 onDoubleClick : function()
43242 this.collapse(); //??
43250 recordToStack : function(store, prop, value, stack)
43252 var cstore = new Roo.data.SimpleStore({
43253 //fields : this.store.reader.meta.fields, // we need array reader.. for
43254 reader : this.store.reader,
43258 var record = false;
43260 if(store.getCount() < 1){
43263 store.each(function(r){
43264 if(r.data[prop] == value){
43269 if (r.data.cn && r.data.cn.length) {
43270 cstore.loadDataFromChildren( r);
43271 var cret = _this.recordToStack(cstore, prop, value, stack);
43272 if (cret !== false) {
43281 if (record == false) {
43284 stack.unshift(srec);
43289 * find the stack of stores that match our value.
43294 selectActive : function ()
43296 // if store is not loaded, then we will need to wait for that to happen first.
43298 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43299 for (var i = 0; i < stack.length; i++ ) {
43300 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43312 * Ext JS Library 1.1.1
43313 * Copyright(c) 2006-2007, Ext JS, LLC.
43315 * Originally Released Under LGPL - original licence link has changed is not relivant.
43318 * <script type="text/javascript">
43321 * @class Roo.form.Checkbox
43322 * @extends Roo.form.Field
43323 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43325 * Creates a new Checkbox
43326 * @param {Object} config Configuration options
43328 Roo.form.Checkbox = function(config){
43329 Roo.form.Checkbox.superclass.constructor.call(this, config);
43333 * Fires when the checkbox is checked or unchecked.
43334 * @param {Roo.form.Checkbox} this This checkbox
43335 * @param {Boolean} checked The new checked value
43341 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43343 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43345 focusClass : undefined,
43347 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43349 fieldClass: "x-form-field",
43351 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43355 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43356 * {tag: "input", type: "checkbox", autocomplete: "off"})
43358 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43360 * @cfg {String} boxLabel The text that appears beside the checkbox
43364 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43368 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43370 valueOff: '0', // value when not checked..
43372 actionMode : 'viewEl',
43375 itemCls : 'x-menu-check-item x-form-item',
43376 groupClass : 'x-menu-group-item',
43377 inputType : 'hidden',
43380 inSetChecked: false, // check that we are not calling self...
43382 inputElement: false, // real input element?
43383 basedOn: false, // ????
43385 isFormField: true, // not sure where this is needed!!!!
43387 onResize : function(){
43388 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43389 if(!this.boxLabel){
43390 this.el.alignTo(this.wrap, 'c-c');
43394 initEvents : function(){
43395 Roo.form.Checkbox.superclass.initEvents.call(this);
43396 this.el.on("click", this.onClick, this);
43397 this.el.on("change", this.onClick, this);
43401 getResizeEl : function(){
43405 getPositionEl : function(){
43410 onRender : function(ct, position){
43411 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43413 if(this.inputValue !== undefined){
43414 this.el.dom.value = this.inputValue;
43417 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43418 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43419 var viewEl = this.wrap.createChild({
43420 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43421 this.viewEl = viewEl;
43422 this.wrap.on('click', this.onClick, this);
43424 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43425 this.el.on('propertychange', this.setFromHidden, this); //ie
43430 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43431 // viewEl.on('click', this.onClick, this);
43433 //if(this.checked){
43434 this.setChecked(this.checked);
43436 //this.checked = this.el.dom;
43442 initValue : Roo.emptyFn,
43445 * Returns the checked state of the checkbox.
43446 * @return {Boolean} True if checked, else false
43448 getValue : function(){
43450 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43452 return this.valueOff;
43457 onClick : function(){
43458 if (this.disabled) {
43461 this.setChecked(!this.checked);
43463 //if(this.el.dom.checked != this.checked){
43464 // this.setValue(this.el.dom.checked);
43469 * Sets the checked state of the checkbox.
43470 * On is always based on a string comparison between inputValue and the param.
43471 * @param {Boolean/String} value - the value to set
43472 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43474 setValue : function(v,suppressEvent){
43477 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43478 //if(this.el && this.el.dom){
43479 // this.el.dom.checked = this.checked;
43480 // this.el.dom.defaultChecked = this.checked;
43482 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43483 //this.fireEvent("check", this, this.checked);
43486 setChecked : function(state,suppressEvent)
43488 if (this.inSetChecked) {
43489 this.checked = state;
43495 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43497 this.checked = state;
43498 if(suppressEvent !== true){
43499 this.fireEvent('check', this, state);
43501 this.inSetChecked = true;
43502 this.el.dom.value = state ? this.inputValue : this.valueOff;
43503 this.inSetChecked = false;
43506 // handle setting of hidden value by some other method!!?!?
43507 setFromHidden: function()
43512 //console.log("SET FROM HIDDEN");
43513 //alert('setFrom hidden');
43514 this.setValue(this.el.dom.value);
43517 onDestroy : function()
43520 Roo.get(this.viewEl).remove();
43523 Roo.form.Checkbox.superclass.onDestroy.call(this);
43526 setBoxLabel : function(str)
43528 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43533 * Ext JS Library 1.1.1
43534 * Copyright(c) 2006-2007, Ext JS, LLC.
43536 * Originally Released Under LGPL - original licence link has changed is not relivant.
43539 * <script type="text/javascript">
43543 * @class Roo.form.Radio
43544 * @extends Roo.form.Checkbox
43545 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43546 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43548 * Creates a new Radio
43549 * @param {Object} config Configuration options
43551 Roo.form.Radio = function(){
43552 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43554 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43555 inputType: 'radio',
43558 * If this radio is part of a group, it will return the selected value
43561 getGroupValue : function(){
43562 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43566 onRender : function(ct, position){
43567 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43569 if(this.inputValue !== undefined){
43570 this.el.dom.value = this.inputValue;
43573 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43574 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43575 //var viewEl = this.wrap.createChild({
43576 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43577 //this.viewEl = viewEl;
43578 //this.wrap.on('click', this.onClick, this);
43580 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43581 //this.el.on('propertychange', this.setFromHidden, this); //ie
43586 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43587 // viewEl.on('click', this.onClick, this);
43590 this.el.dom.checked = 'checked' ;
43596 });//<script type="text/javascript">
43599 * Based Ext JS Library 1.1.1
43600 * Copyright(c) 2006-2007, Ext JS, LLC.
43606 * @class Roo.HtmlEditorCore
43607 * @extends Roo.Component
43608 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43610 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43613 Roo.HtmlEditorCore = function(config){
43616 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43621 * @event initialize
43622 * Fires when the editor is fully initialized (including the iframe)
43623 * @param {Roo.HtmlEditorCore} this
43628 * Fires when the editor is first receives the focus. Any insertion must wait
43629 * until after this event.
43630 * @param {Roo.HtmlEditorCore} this
43634 * @event beforesync
43635 * Fires before the textarea is updated with content from the editor iframe. Return false
43636 * to cancel the sync.
43637 * @param {Roo.HtmlEditorCore} this
43638 * @param {String} html
43642 * @event beforepush
43643 * Fires before the iframe editor is updated with content from the textarea. Return false
43644 * to cancel the push.
43645 * @param {Roo.HtmlEditorCore} this
43646 * @param {String} html
43651 * Fires when the textarea is updated with content from the editor iframe.
43652 * @param {Roo.HtmlEditorCore} this
43653 * @param {String} html
43658 * Fires when the iframe editor is updated with content from the textarea.
43659 * @param {Roo.HtmlEditorCore} this
43660 * @param {String} html
43665 * @event editorevent
43666 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43667 * @param {Roo.HtmlEditorCore} this
43673 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43675 // defaults : white / black...
43676 this.applyBlacklists();
43683 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43687 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43693 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43698 * @cfg {Number} height (in pixels)
43702 * @cfg {Number} width (in pixels)
43707 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43710 stylesheets: false,
43715 // private properties
43716 validationEvent : false,
43718 initialized : false,
43720 sourceEditMode : false,
43721 onFocus : Roo.emptyFn,
43723 hideMode:'offsets',
43727 // blacklist + whitelisted elements..
43734 * Protected method that will not generally be called directly. It
43735 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43736 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43738 getDocMarkup : function(){
43742 // inherit styels from page...??
43743 if (this.stylesheets === false) {
43745 Roo.get(document.head).select('style').each(function(node) {
43746 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43749 Roo.get(document.head).select('link').each(function(node) {
43750 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43753 } else if (!this.stylesheets.length) {
43755 st = '<style type="text/css">' +
43756 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43759 for (var i in this.stylesheets) {
43760 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43765 st += '<style type="text/css">' +
43766 'IMG { cursor: pointer } ' +
43769 var cls = 'roo-htmleditor-body';
43771 if(this.bodyCls.length){
43772 cls += ' ' + this.bodyCls;
43775 return '<html><head>' + st +
43776 //<style type="text/css">' +
43777 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43779 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43783 onRender : function(ct, position)
43786 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43787 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43790 this.el.dom.style.border = '0 none';
43791 this.el.dom.setAttribute('tabIndex', -1);
43792 this.el.addClass('x-hidden hide');
43796 if(Roo.isIE){ // fix IE 1px bogus margin
43797 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43801 this.frameId = Roo.id();
43805 var iframe = this.owner.wrap.createChild({
43807 cls: 'form-control', // bootstrap..
43809 name: this.frameId,
43810 frameBorder : 'no',
43811 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43816 this.iframe = iframe.dom;
43818 this.assignDocWin();
43820 this.doc.designMode = 'on';
43823 this.doc.write(this.getDocMarkup());
43827 var task = { // must defer to wait for browser to be ready
43829 //console.log("run task?" + this.doc.readyState);
43830 this.assignDocWin();
43831 if(this.doc.body || this.doc.readyState == 'complete'){
43833 this.doc.designMode="on";
43837 Roo.TaskMgr.stop(task);
43838 this.initEditor.defer(10, this);
43845 Roo.TaskMgr.start(task);
43850 onResize : function(w, h)
43852 Roo.log('resize: ' +w + ',' + h );
43853 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43857 if(typeof w == 'number'){
43859 this.iframe.style.width = w + 'px';
43861 if(typeof h == 'number'){
43863 this.iframe.style.height = h + 'px';
43865 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43872 * Toggles the editor between standard and source edit mode.
43873 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43875 toggleSourceEdit : function(sourceEditMode){
43877 this.sourceEditMode = sourceEditMode === true;
43879 if(this.sourceEditMode){
43881 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43884 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43885 //this.iframe.className = '';
43888 //this.setSize(this.owner.wrap.getSize());
43889 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43896 * Protected method that will not generally be called directly. If you need/want
43897 * custom HTML cleanup, this is the method you should override.
43898 * @param {String} html The HTML to be cleaned
43899 * return {String} The cleaned HTML
43901 cleanHtml : function(html){
43902 html = String(html);
43903 if(html.length > 5){
43904 if(Roo.isSafari){ // strip safari nonsense
43905 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43908 if(html == ' '){
43915 * HTML Editor -> Textarea
43916 * Protected method that will not generally be called directly. Syncs the contents
43917 * of the editor iframe with the textarea.
43919 syncValue : function(){
43920 if(this.initialized){
43921 var bd = (this.doc.body || this.doc.documentElement);
43922 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43923 var html = bd.innerHTML;
43925 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43926 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43928 html = '<div style="'+m[0]+'">' + html + '</div>';
43931 html = this.cleanHtml(html);
43932 // fix up the special chars.. normaly like back quotes in word...
43933 // however we do not want to do this with chinese..
43934 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
43936 var cc = match.charCodeAt();
43938 // Get the character value, handling surrogate pairs
43939 if (match.length == 2) {
43940 // It's a surrogate pair, calculate the Unicode code point
43941 var high = match.charCodeAt(0) - 0xD800;
43942 var low = match.charCodeAt(1) - 0xDC00;
43943 cc = (high * 0x400) + low + 0x10000;
43945 (cc >= 0x4E00 && cc < 0xA000 ) ||
43946 (cc >= 0x3400 && cc < 0x4E00 ) ||
43947 (cc >= 0xf900 && cc < 0xfb00 )
43952 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
43953 return "&#" + cc + ";";
43960 if(this.owner.fireEvent('beforesync', this, html) !== false){
43961 this.el.dom.value = html;
43962 this.owner.fireEvent('sync', this, html);
43968 * Protected method that will not generally be called directly. Pushes the value of the textarea
43969 * into the iframe editor.
43971 pushValue : function(){
43972 if(this.initialized){
43973 var v = this.el.dom.value.trim();
43975 // if(v.length < 1){
43979 if(this.owner.fireEvent('beforepush', this, v) !== false){
43980 var d = (this.doc.body || this.doc.documentElement);
43982 this.cleanUpPaste();
43983 this.el.dom.value = d.innerHTML;
43984 this.owner.fireEvent('push', this, v);
43990 deferFocus : function(){
43991 this.focus.defer(10, this);
43995 focus : function(){
43996 if(this.win && !this.sourceEditMode){
44003 assignDocWin: function()
44005 var iframe = this.iframe;
44008 this.doc = iframe.contentWindow.document;
44009 this.win = iframe.contentWindow;
44011 // if (!Roo.get(this.frameId)) {
44014 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44015 // this.win = Roo.get(this.frameId).dom.contentWindow;
44017 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
44021 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44022 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
44027 initEditor : function(){
44028 //console.log("INIT EDITOR");
44029 this.assignDocWin();
44033 this.doc.designMode="on";
44035 this.doc.write(this.getDocMarkup());
44038 var dbody = (this.doc.body || this.doc.documentElement);
44039 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
44040 // this copies styles from the containing element into thsi one..
44041 // not sure why we need all of this..
44042 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
44044 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
44045 //ss['background-attachment'] = 'fixed'; // w3c
44046 dbody.bgProperties = 'fixed'; // ie
44047 //Roo.DomHelper.applyStyles(dbody, ss);
44048 Roo.EventManager.on(this.doc, {
44049 //'mousedown': this.onEditorEvent,
44050 'mouseup': this.onEditorEvent,
44051 'dblclick': this.onEditorEvent,
44052 'click': this.onEditorEvent,
44053 'keyup': this.onEditorEvent,
44058 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
44060 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
44061 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
44063 this.initialized = true;
44065 this.owner.fireEvent('initialize', this);
44070 onDestroy : function(){
44076 //for (var i =0; i < this.toolbars.length;i++) {
44077 // // fixme - ask toolbars for heights?
44078 // this.toolbars[i].onDestroy();
44081 //this.wrap.dom.innerHTML = '';
44082 //this.wrap.remove();
44087 onFirstFocus : function(){
44089 this.assignDocWin();
44092 this.activated = true;
44095 if(Roo.isGecko){ // prevent silly gecko errors
44097 var s = this.win.getSelection();
44098 if(!s.focusNode || s.focusNode.nodeType != 3){
44099 var r = s.getRangeAt(0);
44100 r.selectNodeContents((this.doc.body || this.doc.documentElement));
44105 this.execCmd('useCSS', true);
44106 this.execCmd('styleWithCSS', false);
44109 this.owner.fireEvent('activate', this);
44113 adjustFont: function(btn){
44114 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44115 //if(Roo.isSafari){ // safari
44118 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44119 if(Roo.isSafari){ // safari
44120 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44121 v = (v < 10) ? 10 : v;
44122 v = (v > 48) ? 48 : v;
44123 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44128 v = Math.max(1, v+adjust);
44130 this.execCmd('FontSize', v );
44133 onEditorEvent : function(e)
44135 this.owner.fireEvent('editorevent', this, e);
44136 // this.updateToolbar();
44137 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44140 insertTag : function(tg)
44142 // could be a bit smarter... -> wrap the current selected tRoo..
44143 if (tg.toLowerCase() == 'span' ||
44144 tg.toLowerCase() == 'code' ||
44145 tg.toLowerCase() == 'sup' ||
44146 tg.toLowerCase() == 'sub'
44149 range = this.createRange(this.getSelection());
44150 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44151 wrappingNode.appendChild(range.extractContents());
44152 range.insertNode(wrappingNode);
44159 this.execCmd("formatblock", tg);
44163 insertText : function(txt)
44167 var range = this.createRange();
44168 range.deleteContents();
44169 //alert(Sender.getAttribute('label'));
44171 range.insertNode(this.doc.createTextNode(txt));
44177 * Executes a Midas editor command on the editor document and performs necessary focus and
44178 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44179 * @param {String} cmd The Midas command
44180 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44182 relayCmd : function(cmd, value){
44184 this.execCmd(cmd, value);
44185 this.owner.fireEvent('editorevent', this);
44186 //this.updateToolbar();
44187 this.owner.deferFocus();
44191 * Executes a Midas editor command directly on the editor document.
44192 * For visual commands, you should use {@link #relayCmd} instead.
44193 * <b>This should only be called after the editor is initialized.</b>
44194 * @param {String} cmd The Midas command
44195 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44197 execCmd : function(cmd, value){
44198 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44205 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44207 * @param {String} text | dom node..
44209 insertAtCursor : function(text)
44212 if(!this.activated){
44218 var r = this.doc.selection.createRange();
44229 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44233 // from jquery ui (MIT licenced)
44235 var win = this.win;
44237 if (win.getSelection && win.getSelection().getRangeAt) {
44238 range = win.getSelection().getRangeAt(0);
44239 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44240 range.insertNode(node);
44241 } else if (win.document.selection && win.document.selection.createRange) {
44242 // no firefox support
44243 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44244 win.document.selection.createRange().pasteHTML(txt);
44246 // no firefox support
44247 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44248 this.execCmd('InsertHTML', txt);
44257 mozKeyPress : function(e){
44259 var c = e.getCharCode(), cmd;
44262 c = String.fromCharCode(c).toLowerCase();
44276 this.cleanUpPaste.defer(100, this);
44284 e.preventDefault();
44292 fixKeys : function(){ // load time branching for fastest keydown performance
44294 return function(e){
44295 var k = e.getKey(), r;
44298 r = this.doc.selection.createRange();
44301 r.pasteHTML('    ');
44308 r = this.doc.selection.createRange();
44310 var target = r.parentElement();
44311 if(!target || target.tagName.toLowerCase() != 'li'){
44313 r.pasteHTML('<br />');
44319 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44320 this.cleanUpPaste.defer(100, this);
44326 }else if(Roo.isOpera){
44327 return function(e){
44328 var k = e.getKey();
44332 this.execCmd('InsertHTML','    ');
44335 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44336 this.cleanUpPaste.defer(100, this);
44341 }else if(Roo.isSafari){
44342 return function(e){
44343 var k = e.getKey();
44347 this.execCmd('InsertText','\t');
44351 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44352 this.cleanUpPaste.defer(100, this);
44360 getAllAncestors: function()
44362 var p = this.getSelectedNode();
44365 a.push(p); // push blank onto stack..
44366 p = this.getParentElement();
44370 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44374 a.push(this.doc.body);
44378 lastSelNode : false,
44381 getSelection : function()
44383 this.assignDocWin();
44384 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44387 getSelectedNode: function()
44389 // this may only work on Gecko!!!
44391 // should we cache this!!!!
44396 var range = this.createRange(this.getSelection()).cloneRange();
44399 var parent = range.parentElement();
44401 var testRange = range.duplicate();
44402 testRange.moveToElementText(parent);
44403 if (testRange.inRange(range)) {
44406 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44409 parent = parent.parentElement;
44414 // is ancestor a text element.
44415 var ac = range.commonAncestorContainer;
44416 if (ac.nodeType == 3) {
44417 ac = ac.parentNode;
44420 var ar = ac.childNodes;
44423 var other_nodes = [];
44424 var has_other_nodes = false;
44425 for (var i=0;i<ar.length;i++) {
44426 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44429 // fullly contained node.
44431 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44436 // probably selected..
44437 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44438 other_nodes.push(ar[i]);
44442 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44447 has_other_nodes = true;
44449 if (!nodes.length && other_nodes.length) {
44450 nodes= other_nodes;
44452 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44458 createRange: function(sel)
44460 // this has strange effects when using with
44461 // top toolbar - not sure if it's a great idea.
44462 //this.editor.contentWindow.focus();
44463 if (typeof sel != "undefined") {
44465 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44467 return this.doc.createRange();
44470 return this.doc.createRange();
44473 getParentElement: function()
44476 this.assignDocWin();
44477 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44479 var range = this.createRange(sel);
44482 var p = range.commonAncestorContainer;
44483 while (p.nodeType == 3) { // text node
44494 * Range intersection.. the hard stuff...
44498 * [ -- selected range --- ]
44502 * if end is before start or hits it. fail.
44503 * if start is after end or hits it fail.
44505 * if either hits (but other is outside. - then it's not
44511 // @see http://www.thismuchiknow.co.uk/?p=64.
44512 rangeIntersectsNode : function(range, node)
44514 var nodeRange = node.ownerDocument.createRange();
44516 nodeRange.selectNode(node);
44518 nodeRange.selectNodeContents(node);
44521 var rangeStartRange = range.cloneRange();
44522 rangeStartRange.collapse(true);
44524 var rangeEndRange = range.cloneRange();
44525 rangeEndRange.collapse(false);
44527 var nodeStartRange = nodeRange.cloneRange();
44528 nodeStartRange.collapse(true);
44530 var nodeEndRange = nodeRange.cloneRange();
44531 nodeEndRange.collapse(false);
44533 return rangeStartRange.compareBoundaryPoints(
44534 Range.START_TO_START, nodeEndRange) == -1 &&
44535 rangeEndRange.compareBoundaryPoints(
44536 Range.START_TO_START, nodeStartRange) == 1;
44540 rangeCompareNode : function(range, node)
44542 var nodeRange = node.ownerDocument.createRange();
44544 nodeRange.selectNode(node);
44546 nodeRange.selectNodeContents(node);
44550 range.collapse(true);
44552 nodeRange.collapse(true);
44554 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44555 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44557 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44559 var nodeIsBefore = ss == 1;
44560 var nodeIsAfter = ee == -1;
44562 if (nodeIsBefore && nodeIsAfter) {
44565 if (!nodeIsBefore && nodeIsAfter) {
44566 return 1; //right trailed.
44569 if (nodeIsBefore && !nodeIsAfter) {
44570 return 2; // left trailed.
44576 // private? - in a new class?
44577 cleanUpPaste : function()
44579 // cleans up the whole document..
44580 Roo.log('cleanuppaste');
44582 this.cleanUpChildren(this.doc.body);
44583 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44584 if (clean != this.doc.body.innerHTML) {
44585 this.doc.body.innerHTML = clean;
44590 cleanWordChars : function(input) {// change the chars to hex code
44591 var he = Roo.HtmlEditorCore;
44593 var output = input;
44594 Roo.each(he.swapCodes, function(sw) {
44595 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44597 output = output.replace(swapper, sw[1]);
44604 cleanUpChildren : function (n)
44606 if (!n.childNodes.length) {
44609 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44610 this.cleanUpChild(n.childNodes[i]);
44617 cleanUpChild : function (node)
44620 //console.log(node);
44621 if (node.nodeName == "#text") {
44622 // clean up silly Windows -- stuff?
44625 if (node.nodeName == "#comment") {
44626 node.parentNode.removeChild(node);
44627 // clean up silly Windows -- stuff?
44630 var lcname = node.tagName.toLowerCase();
44631 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44632 // whitelist of tags..
44634 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44636 node.parentNode.removeChild(node);
44641 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44643 // spans with no attributes - just remove them..
44644 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44645 remove_keep_children = true;
44648 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44649 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44651 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44652 // remove_keep_children = true;
44655 if (remove_keep_children) {
44656 this.cleanUpChildren(node);
44657 // inserts everything just before this node...
44658 while (node.childNodes.length) {
44659 var cn = node.childNodes[0];
44660 node.removeChild(cn);
44661 node.parentNode.insertBefore(cn, node);
44663 node.parentNode.removeChild(node);
44667 if (!node.attributes || !node.attributes.length) {
44672 this.cleanUpChildren(node);
44676 function cleanAttr(n,v)
44679 if (v.match(/^\./) || v.match(/^\//)) {
44682 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44685 if (v.match(/^#/)) {
44688 if (v.match(/^\{/)) { // allow template editing.
44691 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44692 node.removeAttribute(n);
44696 var cwhite = this.cwhite;
44697 var cblack = this.cblack;
44699 function cleanStyle(n,v)
44701 if (v.match(/expression/)) { //XSS?? should we even bother..
44702 node.removeAttribute(n);
44706 var parts = v.split(/;/);
44709 Roo.each(parts, function(p) {
44710 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44714 var l = p.split(':').shift().replace(/\s+/g,'');
44715 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44717 if ( cwhite.length && cblack.indexOf(l) > -1) {
44718 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44719 //node.removeAttribute(n);
44723 // only allow 'c whitelisted system attributes'
44724 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44725 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44726 //node.removeAttribute(n);
44736 if (clean.length) {
44737 node.setAttribute(n, clean.join(';'));
44739 node.removeAttribute(n);
44745 for (var i = node.attributes.length-1; i > -1 ; i--) {
44746 var a = node.attributes[i];
44749 if (a.name.toLowerCase().substr(0,2)=='on') {
44750 node.removeAttribute(a.name);
44753 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44754 node.removeAttribute(a.name);
44757 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44758 cleanAttr(a.name,a.value); // fixme..
44761 if (a.name == 'style') {
44762 cleanStyle(a.name,a.value);
44765 /// clean up MS crap..
44766 // tecnically this should be a list of valid class'es..
44769 if (a.name == 'class') {
44770 if (a.value.match(/^Mso/)) {
44771 node.removeAttribute('class');
44774 if (a.value.match(/^body$/)) {
44775 node.removeAttribute('class');
44786 this.cleanUpChildren(node);
44792 * Clean up MS wordisms...
44794 cleanWord : function(node)
44797 this.cleanWord(this.doc.body);
44802 node.nodeName == 'SPAN' &&
44803 !node.hasAttributes() &&
44804 node.childNodes.length == 1 &&
44805 node.firstChild.nodeName == "#text"
44807 var textNode = node.firstChild;
44808 node.removeChild(textNode);
44809 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44810 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44812 node.parentNode.insertBefore(textNode, node);
44813 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44814 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44816 node.parentNode.removeChild(node);
44819 if (node.nodeName == "#text") {
44820 // clean up silly Windows -- stuff?
44823 if (node.nodeName == "#comment") {
44824 node.parentNode.removeChild(node);
44825 // clean up silly Windows -- stuff?
44829 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44830 node.parentNode.removeChild(node);
44833 //Roo.log(node.tagName);
44834 // remove - but keep children..
44835 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44836 //Roo.log('-- removed');
44837 while (node.childNodes.length) {
44838 var cn = node.childNodes[0];
44839 node.removeChild(cn);
44840 node.parentNode.insertBefore(cn, node);
44841 // move node to parent - and clean it..
44842 this.cleanWord(cn);
44844 node.parentNode.removeChild(node);
44845 /// no need to iterate chidlren = it's got none..
44846 //this.iterateChildren(node, this.cleanWord);
44850 if (node.className.length) {
44852 var cn = node.className.split(/\W+/);
44854 Roo.each(cn, function(cls) {
44855 if (cls.match(/Mso[a-zA-Z]+/)) {
44860 node.className = cna.length ? cna.join(' ') : '';
44862 node.removeAttribute("class");
44866 if (node.hasAttribute("lang")) {
44867 node.removeAttribute("lang");
44870 if (node.hasAttribute("style")) {
44872 var styles = node.getAttribute("style").split(";");
44874 Roo.each(styles, function(s) {
44875 if (!s.match(/:/)) {
44878 var kv = s.split(":");
44879 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44882 // what ever is left... we allow.
44885 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44886 if (!nstyle.length) {
44887 node.removeAttribute('style');
44890 this.iterateChildren(node, this.cleanWord);
44896 * iterateChildren of a Node, calling fn each time, using this as the scole..
44897 * @param {DomNode} node node to iterate children of.
44898 * @param {Function} fn method of this class to call on each item.
44900 iterateChildren : function(node, fn)
44902 if (!node.childNodes.length) {
44905 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44906 fn.call(this, node.childNodes[i])
44912 * cleanTableWidths.
44914 * Quite often pasting from word etc.. results in tables with column and widths.
44915 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44918 cleanTableWidths : function(node)
44923 this.cleanTableWidths(this.doc.body);
44928 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44931 Roo.log(node.tagName);
44932 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44933 this.iterateChildren(node, this.cleanTableWidths);
44936 if (node.hasAttribute('width')) {
44937 node.removeAttribute('width');
44941 if (node.hasAttribute("style")) {
44944 var styles = node.getAttribute("style").split(";");
44946 Roo.each(styles, function(s) {
44947 if (!s.match(/:/)) {
44950 var kv = s.split(":");
44951 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
44954 // what ever is left... we allow.
44957 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44958 if (!nstyle.length) {
44959 node.removeAttribute('style');
44963 this.iterateChildren(node, this.cleanTableWidths);
44971 domToHTML : function(currentElement, depth, nopadtext) {
44973 depth = depth || 0;
44974 nopadtext = nopadtext || false;
44976 if (!currentElement) {
44977 return this.domToHTML(this.doc.body);
44980 //Roo.log(currentElement);
44982 var allText = false;
44983 var nodeName = currentElement.nodeName;
44984 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44986 if (nodeName == '#text') {
44988 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44993 if (nodeName != 'BODY') {
44996 // Prints the node tagName, such as <A>, <IMG>, etc
44999 for(i = 0; i < currentElement.attributes.length;i++) {
45001 var aname = currentElement.attributes.item(i).name;
45002 if (!currentElement.attributes.item(i).value.length) {
45005 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
45008 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
45017 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
45020 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
45025 // Traverse the tree
45027 var currentElementChild = currentElement.childNodes.item(i);
45028 var allText = true;
45029 var innerHTML = '';
45031 while (currentElementChild) {
45032 // Formatting code (indent the tree so it looks nice on the screen)
45033 var nopad = nopadtext;
45034 if (lastnode == 'SPAN') {
45038 if (currentElementChild.nodeName == '#text') {
45039 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
45040 toadd = nopadtext ? toadd : toadd.trim();
45041 if (!nopad && toadd.length > 80) {
45042 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
45044 innerHTML += toadd;
45047 currentElementChild = currentElement.childNodes.item(i);
45053 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
45055 // Recursively traverse the tree structure of the child node
45056 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
45057 lastnode = currentElementChild.nodeName;
45059 currentElementChild=currentElement.childNodes.item(i);
45065 // The remaining code is mostly for formatting the tree
45066 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
45071 ret+= "</"+tagName+">";
45077 applyBlacklists : function()
45079 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
45080 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
45084 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
45085 if (b.indexOf(tag) > -1) {
45088 this.white.push(tag);
45092 Roo.each(w, function(tag) {
45093 if (b.indexOf(tag) > -1) {
45096 if (this.white.indexOf(tag) > -1) {
45099 this.white.push(tag);
45104 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
45105 if (w.indexOf(tag) > -1) {
45108 this.black.push(tag);
45112 Roo.each(b, function(tag) {
45113 if (w.indexOf(tag) > -1) {
45116 if (this.black.indexOf(tag) > -1) {
45119 this.black.push(tag);
45124 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45125 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45129 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45130 if (b.indexOf(tag) > -1) {
45133 this.cwhite.push(tag);
45137 Roo.each(w, function(tag) {
45138 if (b.indexOf(tag) > -1) {
45141 if (this.cwhite.indexOf(tag) > -1) {
45144 this.cwhite.push(tag);
45149 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45150 if (w.indexOf(tag) > -1) {
45153 this.cblack.push(tag);
45157 Roo.each(b, function(tag) {
45158 if (w.indexOf(tag) > -1) {
45161 if (this.cblack.indexOf(tag) > -1) {
45164 this.cblack.push(tag);
45169 setStylesheets : function(stylesheets)
45171 if(typeof(stylesheets) == 'string'){
45172 Roo.get(this.iframe.contentDocument.head).createChild({
45174 rel : 'stylesheet',
45183 Roo.each(stylesheets, function(s) {
45188 Roo.get(_this.iframe.contentDocument.head).createChild({
45190 rel : 'stylesheet',
45199 removeStylesheets : function()
45203 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45208 setStyle : function(style)
45210 Roo.get(this.iframe.contentDocument.head).createChild({
45219 // hide stuff that is not compatible
45233 * @event specialkey
45237 * @cfg {String} fieldClass @hide
45240 * @cfg {String} focusClass @hide
45243 * @cfg {String} autoCreate @hide
45246 * @cfg {String} inputType @hide
45249 * @cfg {String} invalidClass @hide
45252 * @cfg {String} invalidText @hide
45255 * @cfg {String} msgFx @hide
45258 * @cfg {String} validateOnBlur @hide
45262 Roo.HtmlEditorCore.white = [
45263 'area', 'br', 'img', 'input', 'hr', 'wbr',
45265 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45266 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45267 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45268 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45269 'table', 'ul', 'xmp',
45271 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45274 'dir', 'menu', 'ol', 'ul', 'dl',
45280 Roo.HtmlEditorCore.black = [
45281 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45283 'base', 'basefont', 'bgsound', 'blink', 'body',
45284 'frame', 'frameset', 'head', 'html', 'ilayer',
45285 'iframe', 'layer', 'link', 'meta', 'object',
45286 'script', 'style' ,'title', 'xml' // clean later..
45288 Roo.HtmlEditorCore.clean = [
45289 'script', 'style', 'title', 'xml'
45291 Roo.HtmlEditorCore.remove = [
45296 Roo.HtmlEditorCore.ablack = [
45300 Roo.HtmlEditorCore.aclean = [
45301 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45305 Roo.HtmlEditorCore.pwhite= [
45306 'http', 'https', 'mailto'
45309 // white listed style attributes.
45310 Roo.HtmlEditorCore.cwhite= [
45311 // 'text-align', /// default is to allow most things..
45317 // black listed style attributes.
45318 Roo.HtmlEditorCore.cblack= [
45319 // 'font-size' -- this can be set by the project
45323 Roo.HtmlEditorCore.swapCodes =[
45324 [ 8211, "–" ],
45325 [ 8212, "—" ],
45334 //<script type="text/javascript">
45337 * Ext JS Library 1.1.1
45338 * Copyright(c) 2006-2007, Ext JS, LLC.
45344 Roo.form.HtmlEditor = function(config){
45348 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45350 if (!this.toolbars) {
45351 this.toolbars = [];
45353 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45359 * @class Roo.form.HtmlEditor
45360 * @extends Roo.form.Field
45361 * Provides a lightweight HTML Editor component.
45363 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45365 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45366 * supported by this editor.</b><br/><br/>
45367 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45368 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45370 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45372 * @cfg {Boolean} clearUp
45376 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45381 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45386 * @cfg {Number} height (in pixels)
45390 * @cfg {Number} width (in pixels)
45395 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45398 stylesheets: false,
45402 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45407 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45413 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45418 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45426 // private properties
45427 validationEvent : false,
45429 initialized : false,
45432 onFocus : Roo.emptyFn,
45434 hideMode:'offsets',
45436 actionMode : 'container', // defaults to hiding it...
45438 defaultAutoCreate : { // modified by initCompnoent..
45440 style:"width:500px;height:300px;",
45441 autocomplete: "new-password"
45445 initComponent : function(){
45448 * @event initialize
45449 * Fires when the editor is fully initialized (including the iframe)
45450 * @param {HtmlEditor} this
45455 * Fires when the editor is first receives the focus. Any insertion must wait
45456 * until after this event.
45457 * @param {HtmlEditor} this
45461 * @event beforesync
45462 * Fires before the textarea is updated with content from the editor iframe. Return false
45463 * to cancel the sync.
45464 * @param {HtmlEditor} this
45465 * @param {String} html
45469 * @event beforepush
45470 * Fires before the iframe editor is updated with content from the textarea. Return false
45471 * to cancel the push.
45472 * @param {HtmlEditor} this
45473 * @param {String} html
45478 * Fires when the textarea is updated with content from the editor iframe.
45479 * @param {HtmlEditor} this
45480 * @param {String} html
45485 * Fires when the iframe editor is updated with content from the textarea.
45486 * @param {HtmlEditor} this
45487 * @param {String} html
45491 * @event editmodechange
45492 * Fires when the editor switches edit modes
45493 * @param {HtmlEditor} this
45494 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45496 editmodechange: true,
45498 * @event editorevent
45499 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45500 * @param {HtmlEditor} this
45504 * @event firstfocus
45505 * Fires when on first focus - needed by toolbars..
45506 * @param {HtmlEditor} this
45511 * Auto save the htmlEditor value as a file into Events
45512 * @param {HtmlEditor} this
45516 * @event savedpreview
45517 * preview the saved version of htmlEditor
45518 * @param {HtmlEditor} this
45520 savedpreview: true,
45523 * @event stylesheetsclick
45524 * Fires when press the Sytlesheets button
45525 * @param {Roo.HtmlEditorCore} this
45527 stylesheetsclick: true
45529 this.defaultAutoCreate = {
45531 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45532 autocomplete: "new-password"
45537 * Protected method that will not generally be called directly. It
45538 * is called when the editor creates its toolbar. Override this method if you need to
45539 * add custom toolbar buttons.
45540 * @param {HtmlEditor} editor
45542 createToolbar : function(editor){
45543 Roo.log("create toolbars");
45544 if (!editor.toolbars || !editor.toolbars.length) {
45545 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45548 for (var i =0 ; i < editor.toolbars.length;i++) {
45549 editor.toolbars[i] = Roo.factory(
45550 typeof(editor.toolbars[i]) == 'string' ?
45551 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45552 Roo.form.HtmlEditor);
45553 editor.toolbars[i].init(editor);
45561 onRender : function(ct, position)
45564 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45566 this.wrap = this.el.wrap({
45567 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45570 this.editorcore.onRender(ct, position);
45572 if (this.resizable) {
45573 this.resizeEl = new Roo.Resizable(this.wrap, {
45577 minHeight : this.height,
45578 height: this.height,
45579 handles : this.resizable,
45582 resize : function(r, w, h) {
45583 _t.onResize(w,h); // -something
45589 this.createToolbar(this);
45593 this.setSize(this.wrap.getSize());
45595 if (this.resizeEl) {
45596 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45597 // should trigger onReize..
45600 this.keyNav = new Roo.KeyNav(this.el, {
45602 "tab" : function(e){
45603 e.preventDefault();
45605 var value = this.getValue();
45607 var start = this.el.dom.selectionStart;
45608 var end = this.el.dom.selectionEnd;
45612 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45613 this.el.dom.setSelectionRange(end + 1, end + 1);
45617 var f = value.substring(0, start).split("\t");
45619 if(f.pop().length != 0){
45623 this.setValue(f.join("\t") + value.substring(end));
45624 this.el.dom.setSelectionRange(start - 1, start - 1);
45628 "home" : function(e){
45629 e.preventDefault();
45631 var curr = this.el.dom.selectionStart;
45632 var lines = this.getValue().split("\n");
45639 this.el.dom.setSelectionRange(0, 0);
45645 for (var i = 0; i < lines.length;i++) {
45646 pos += lines[i].length;
45656 pos -= lines[i].length;
45662 this.el.dom.setSelectionRange(pos, pos);
45666 this.el.dom.selectionStart = pos;
45667 this.el.dom.selectionEnd = curr;
45670 "end" : function(e){
45671 e.preventDefault();
45673 var curr = this.el.dom.selectionStart;
45674 var lines = this.getValue().split("\n");
45681 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45687 for (var i = 0; i < lines.length;i++) {
45689 pos += lines[i].length;
45703 this.el.dom.setSelectionRange(pos, pos);
45707 this.el.dom.selectionStart = curr;
45708 this.el.dom.selectionEnd = pos;
45713 doRelay : function(foo, bar, hname){
45714 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45720 // if(this.autosave && this.w){
45721 // this.autoSaveFn = setInterval(this.autosave, 1000);
45726 onResize : function(w, h)
45728 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45733 if(typeof w == 'number'){
45734 var aw = w - this.wrap.getFrameWidth('lr');
45735 this.el.setWidth(this.adjustWidth('textarea', aw));
45738 if(typeof h == 'number'){
45740 for (var i =0; i < this.toolbars.length;i++) {
45741 // fixme - ask toolbars for heights?
45742 tbh += this.toolbars[i].tb.el.getHeight();
45743 if (this.toolbars[i].footer) {
45744 tbh += this.toolbars[i].footer.el.getHeight();
45751 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45752 ah -= 5; // knock a few pixes off for look..
45754 this.el.setHeight(this.adjustWidth('textarea', ah));
45758 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45759 this.editorcore.onResize(ew,eh);
45764 * Toggles the editor between standard and source edit mode.
45765 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45767 toggleSourceEdit : function(sourceEditMode)
45769 this.editorcore.toggleSourceEdit(sourceEditMode);
45771 if(this.editorcore.sourceEditMode){
45772 Roo.log('editor - showing textarea');
45775 // Roo.log(this.syncValue());
45776 this.editorcore.syncValue();
45777 this.el.removeClass('x-hidden');
45778 this.el.dom.removeAttribute('tabIndex');
45781 for (var i = 0; i < this.toolbars.length; i++) {
45782 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45783 this.toolbars[i].tb.hide();
45784 this.toolbars[i].footer.hide();
45789 Roo.log('editor - hiding textarea');
45791 // Roo.log(this.pushValue());
45792 this.editorcore.pushValue();
45794 this.el.addClass('x-hidden');
45795 this.el.dom.setAttribute('tabIndex', -1);
45797 for (var i = 0; i < this.toolbars.length; i++) {
45798 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45799 this.toolbars[i].tb.show();
45800 this.toolbars[i].footer.show();
45804 //this.deferFocus();
45807 this.setSize(this.wrap.getSize());
45808 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45810 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45813 // private (for BoxComponent)
45814 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45816 // private (for BoxComponent)
45817 getResizeEl : function(){
45821 // private (for BoxComponent)
45822 getPositionEl : function(){
45827 initEvents : function(){
45828 this.originalValue = this.getValue();
45832 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45835 markInvalid : Roo.emptyFn,
45837 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45840 clearInvalid : Roo.emptyFn,
45842 setValue : function(v){
45843 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45844 this.editorcore.pushValue();
45849 deferFocus : function(){
45850 this.focus.defer(10, this);
45854 focus : function(){
45855 this.editorcore.focus();
45861 onDestroy : function(){
45867 for (var i =0; i < this.toolbars.length;i++) {
45868 // fixme - ask toolbars for heights?
45869 this.toolbars[i].onDestroy();
45872 this.wrap.dom.innerHTML = '';
45873 this.wrap.remove();
45878 onFirstFocus : function(){
45879 //Roo.log("onFirstFocus");
45880 this.editorcore.onFirstFocus();
45881 for (var i =0; i < this.toolbars.length;i++) {
45882 this.toolbars[i].onFirstFocus();
45888 syncValue : function()
45890 this.editorcore.syncValue();
45893 pushValue : function()
45895 this.editorcore.pushValue();
45898 setStylesheets : function(stylesheets)
45900 this.editorcore.setStylesheets(stylesheets);
45903 removeStylesheets : function()
45905 this.editorcore.removeStylesheets();
45909 // hide stuff that is not compatible
45923 * @event specialkey
45927 * @cfg {String} fieldClass @hide
45930 * @cfg {String} focusClass @hide
45933 * @cfg {String} autoCreate @hide
45936 * @cfg {String} inputType @hide
45939 * @cfg {String} invalidClass @hide
45942 * @cfg {String} invalidText @hide
45945 * @cfg {String} msgFx @hide
45948 * @cfg {String} validateOnBlur @hide
45952 // <script type="text/javascript">
45955 * Ext JS Library 1.1.1
45956 * Copyright(c) 2006-2007, Ext JS, LLC.
45962 * @class Roo.form.HtmlEditorToolbar1
45967 new Roo.form.HtmlEditor({
45970 new Roo.form.HtmlEditorToolbar1({
45971 disable : { fonts: 1 , format: 1, ..., ... , ...],
45977 * @cfg {Object} disable List of elements to disable..
45978 * @cfg {Array} btns List of additional buttons.
45982 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45985 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45988 Roo.apply(this, config);
45990 // default disabled, based on 'good practice'..
45991 this.disable = this.disable || {};
45992 Roo.applyIf(this.disable, {
45995 specialElements : true
45999 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46000 // dont call parent... till later.
46003 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
46010 editorcore : false,
46012 * @cfg {Object} disable List of toolbar elements to disable
46019 * @cfg {String} createLinkText The default text for the create link prompt
46021 createLinkText : 'Please enter the URL for the link:',
46023 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
46025 defaultLinkValue : 'http:/'+'/',
46029 * @cfg {Array} fontFamilies An array of available font families
46047 // "á" , ?? a acute?
46052 "°" // , // degrees
46054 // "é" , // e ecute
46055 // "ú" , // u ecute?
46058 specialElements : [
46060 text: "Insert Table",
46063 ihtml : '<table><tr><td>Cell</td></tr></table>'
46067 text: "Insert Image",
46070 ihtml : '<img src="about:blank"/>'
46079 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
46080 "input:submit", "input:button", "select", "textarea", "label" ],
46083 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
46085 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
46094 * @cfg {String} defaultFont default font to use.
46096 defaultFont: 'tahoma',
46098 fontSelect : false,
46101 formatCombo : false,
46103 init : function(editor)
46105 this.editor = editor;
46106 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46107 var editorcore = this.editorcore;
46111 var fid = editorcore.frameId;
46113 function btn(id, toggle, handler){
46114 var xid = fid + '-'+ id ;
46118 cls : 'x-btn-icon x-edit-'+id,
46119 enableToggle:toggle !== false,
46120 scope: _t, // was editor...
46121 handler:handler||_t.relayBtnCmd,
46122 clickEvent:'mousedown',
46123 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46130 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46132 // stop form submits
46133 tb.el.on('click', function(e){
46134 e.preventDefault(); // what does this do?
46137 if(!this.disable.font) { // && !Roo.isSafari){
46138 /* why no safari for fonts
46139 editor.fontSelect = tb.el.createChild({
46142 cls:'x-font-select',
46143 html: this.createFontOptions()
46146 editor.fontSelect.on('change', function(){
46147 var font = editor.fontSelect.dom.value;
46148 editor.relayCmd('fontname', font);
46149 editor.deferFocus();
46153 editor.fontSelect.dom,
46159 if(!this.disable.formats){
46160 this.formatCombo = new Roo.form.ComboBox({
46161 store: new Roo.data.SimpleStore({
46164 data : this.formats // from states.js
46168 //autoCreate : {tag: "div", size: "20"},
46169 displayField:'tag',
46173 triggerAction: 'all',
46174 emptyText:'Add tag',
46175 selectOnFocus:true,
46178 'select': function(c, r, i) {
46179 editorcore.insertTag(r.get('tag'));
46185 tb.addField(this.formatCombo);
46189 if(!this.disable.format){
46194 btn('strikethrough')
46197 if(!this.disable.fontSize){
46202 btn('increasefontsize', false, editorcore.adjustFont),
46203 btn('decreasefontsize', false, editorcore.adjustFont)
46208 if(!this.disable.colors){
46211 id:editorcore.frameId +'-forecolor',
46212 cls:'x-btn-icon x-edit-forecolor',
46213 clickEvent:'mousedown',
46214 tooltip: this.buttonTips['forecolor'] || undefined,
46216 menu : new Roo.menu.ColorMenu({
46217 allowReselect: true,
46218 focus: Roo.emptyFn,
46221 selectHandler: function(cp, color){
46222 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46223 editor.deferFocus();
46226 clickEvent:'mousedown'
46229 id:editorcore.frameId +'backcolor',
46230 cls:'x-btn-icon x-edit-backcolor',
46231 clickEvent:'mousedown',
46232 tooltip: this.buttonTips['backcolor'] || undefined,
46234 menu : new Roo.menu.ColorMenu({
46235 focus: Roo.emptyFn,
46238 allowReselect: true,
46239 selectHandler: function(cp, color){
46241 editorcore.execCmd('useCSS', false);
46242 editorcore.execCmd('hilitecolor', color);
46243 editorcore.execCmd('useCSS', true);
46244 editor.deferFocus();
46246 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46247 Roo.isSafari || Roo.isIE ? '#'+color : color);
46248 editor.deferFocus();
46252 clickEvent:'mousedown'
46257 // now add all the items...
46260 if(!this.disable.alignments){
46263 btn('justifyleft'),
46264 btn('justifycenter'),
46265 btn('justifyright')
46269 //if(!Roo.isSafari){
46270 if(!this.disable.links){
46273 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46277 if(!this.disable.lists){
46280 btn('insertorderedlist'),
46281 btn('insertunorderedlist')
46284 if(!this.disable.sourceEdit){
46287 btn('sourceedit', true, function(btn){
46288 this.toggleSourceEdit(btn.pressed);
46295 // special menu.. - needs to be tidied up..
46296 if (!this.disable.special) {
46299 cls: 'x-edit-none',
46305 for (var i =0; i < this.specialChars.length; i++) {
46306 smenu.menu.items.push({
46308 html: this.specialChars[i],
46309 handler: function(a,b) {
46310 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46311 //editor.insertAtCursor(a.html);
46325 if (!this.disable.cleanStyles) {
46327 cls: 'x-btn-icon x-btn-clear',
46333 for (var i =0; i < this.cleanStyles.length; i++) {
46334 cmenu.menu.items.push({
46335 actiontype : this.cleanStyles[i],
46336 html: 'Remove ' + this.cleanStyles[i],
46337 handler: function(a,b) {
46340 var c = Roo.get(editorcore.doc.body);
46341 c.select('[style]').each(function(s) {
46342 s.dom.style.removeProperty(a.actiontype);
46344 editorcore.syncValue();
46349 cmenu.menu.items.push({
46350 actiontype : 'tablewidths',
46351 html: 'Remove Table Widths',
46352 handler: function(a,b) {
46353 editorcore.cleanTableWidths();
46354 editorcore.syncValue();
46358 cmenu.menu.items.push({
46359 actiontype : 'word',
46360 html: 'Remove MS Word Formating',
46361 handler: function(a,b) {
46362 editorcore.cleanWord();
46363 editorcore.syncValue();
46368 cmenu.menu.items.push({
46369 actiontype : 'all',
46370 html: 'Remove All Styles',
46371 handler: function(a,b) {
46373 var c = Roo.get(editorcore.doc.body);
46374 c.select('[style]').each(function(s) {
46375 s.dom.removeAttribute('style');
46377 editorcore.syncValue();
46382 cmenu.menu.items.push({
46383 actiontype : 'all',
46384 html: 'Remove All CSS Classes',
46385 handler: function(a,b) {
46387 var c = Roo.get(editorcore.doc.body);
46388 c.select('[class]').each(function(s) {
46389 s.dom.removeAttribute('class');
46391 editorcore.cleanWord();
46392 editorcore.syncValue();
46397 cmenu.menu.items.push({
46398 actiontype : 'tidy',
46399 html: 'Tidy HTML Source',
46400 handler: function(a,b) {
46401 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46402 editorcore.syncValue();
46411 if (!this.disable.specialElements) {
46414 cls: 'x-edit-none',
46419 for (var i =0; i < this.specialElements.length; i++) {
46420 semenu.menu.items.push(
46422 handler: function(a,b) {
46423 editor.insertAtCursor(this.ihtml);
46425 }, this.specialElements[i])
46437 for(var i =0; i< this.btns.length;i++) {
46438 var b = Roo.factory(this.btns[i],Roo.form);
46439 b.cls = 'x-edit-none';
46441 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46442 b.cls += ' x-init-enable';
46445 b.scope = editorcore;
46453 // disable everything...
46455 this.tb.items.each(function(item){
46458 item.id != editorcore.frameId+ '-sourceedit' &&
46459 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46465 this.rendered = true;
46467 // the all the btns;
46468 editor.on('editorevent', this.updateToolbar, this);
46469 // other toolbars need to implement this..
46470 //editor.on('editmodechange', this.updateToolbar, this);
46474 relayBtnCmd : function(btn) {
46475 this.editorcore.relayCmd(btn.cmd);
46477 // private used internally
46478 createLink : function(){
46479 Roo.log("create link?");
46480 var url = prompt(this.createLinkText, this.defaultLinkValue);
46481 if(url && url != 'http:/'+'/'){
46482 this.editorcore.relayCmd('createlink', url);
46488 * Protected method that will not generally be called directly. It triggers
46489 * a toolbar update by reading the markup state of the current selection in the editor.
46491 updateToolbar: function(){
46493 if(!this.editorcore.activated){
46494 this.editor.onFirstFocus();
46498 var btns = this.tb.items.map,
46499 doc = this.editorcore.doc,
46500 frameId = this.editorcore.frameId;
46502 if(!this.disable.font && !Roo.isSafari){
46504 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46505 if(name != this.fontSelect.dom.value){
46506 this.fontSelect.dom.value = name;
46510 if(!this.disable.format){
46511 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46512 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46513 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46514 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46516 if(!this.disable.alignments){
46517 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46518 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46519 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46521 if(!Roo.isSafari && !this.disable.lists){
46522 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46523 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46526 var ans = this.editorcore.getAllAncestors();
46527 if (this.formatCombo) {
46530 var store = this.formatCombo.store;
46531 this.formatCombo.setValue("");
46532 for (var i =0; i < ans.length;i++) {
46533 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46535 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46543 // hides menus... - so this cant be on a menu...
46544 Roo.menu.MenuMgr.hideAll();
46546 //this.editorsyncValue();
46550 createFontOptions : function(){
46551 var buf = [], fs = this.fontFamilies, ff, lc;
46555 for(var i = 0, len = fs.length; i< len; i++){
46557 lc = ff.toLowerCase();
46559 '<option value="',lc,'" style="font-family:',ff,';"',
46560 (this.defaultFont == lc ? ' selected="true">' : '>'),
46565 return buf.join('');
46568 toggleSourceEdit : function(sourceEditMode){
46570 Roo.log("toolbar toogle");
46571 if(sourceEditMode === undefined){
46572 sourceEditMode = !this.sourceEditMode;
46574 this.sourceEditMode = sourceEditMode === true;
46575 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46576 // just toggle the button?
46577 if(btn.pressed !== this.sourceEditMode){
46578 btn.toggle(this.sourceEditMode);
46582 if(sourceEditMode){
46583 Roo.log("disabling buttons");
46584 this.tb.items.each(function(item){
46585 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46591 Roo.log("enabling buttons");
46592 if(this.editorcore.initialized){
46593 this.tb.items.each(function(item){
46599 Roo.log("calling toggole on editor");
46600 // tell the editor that it's been pressed..
46601 this.editor.toggleSourceEdit(sourceEditMode);
46605 * Object collection of toolbar tooltips for the buttons in the editor. The key
46606 * is the command id associated with that button and the value is a valid QuickTips object.
46611 title: 'Bold (Ctrl+B)',
46612 text: 'Make the selected text bold.',
46613 cls: 'x-html-editor-tip'
46616 title: 'Italic (Ctrl+I)',
46617 text: 'Make the selected text italic.',
46618 cls: 'x-html-editor-tip'
46626 title: 'Bold (Ctrl+B)',
46627 text: 'Make the selected text bold.',
46628 cls: 'x-html-editor-tip'
46631 title: 'Italic (Ctrl+I)',
46632 text: 'Make the selected text italic.',
46633 cls: 'x-html-editor-tip'
46636 title: 'Underline (Ctrl+U)',
46637 text: 'Underline the selected text.',
46638 cls: 'x-html-editor-tip'
46641 title: 'Strikethrough',
46642 text: 'Strikethrough the selected text.',
46643 cls: 'x-html-editor-tip'
46645 increasefontsize : {
46646 title: 'Grow Text',
46647 text: 'Increase the font size.',
46648 cls: 'x-html-editor-tip'
46650 decreasefontsize : {
46651 title: 'Shrink Text',
46652 text: 'Decrease the font size.',
46653 cls: 'x-html-editor-tip'
46656 title: 'Text Highlight Color',
46657 text: 'Change the background color of the selected text.',
46658 cls: 'x-html-editor-tip'
46661 title: 'Font Color',
46662 text: 'Change the color of the selected text.',
46663 cls: 'x-html-editor-tip'
46666 title: 'Align Text Left',
46667 text: 'Align text to the left.',
46668 cls: 'x-html-editor-tip'
46671 title: 'Center Text',
46672 text: 'Center text in the editor.',
46673 cls: 'x-html-editor-tip'
46676 title: 'Align Text Right',
46677 text: 'Align text to the right.',
46678 cls: 'x-html-editor-tip'
46680 insertunorderedlist : {
46681 title: 'Bullet List',
46682 text: 'Start a bulleted list.',
46683 cls: 'x-html-editor-tip'
46685 insertorderedlist : {
46686 title: 'Numbered List',
46687 text: 'Start a numbered list.',
46688 cls: 'x-html-editor-tip'
46691 title: 'Hyperlink',
46692 text: 'Make the selected text a hyperlink.',
46693 cls: 'x-html-editor-tip'
46696 title: 'Source Edit',
46697 text: 'Switch to source editing mode.',
46698 cls: 'x-html-editor-tip'
46702 onDestroy : function(){
46705 this.tb.items.each(function(item){
46707 item.menu.removeAll();
46709 item.menu.el.destroy();
46717 onFirstFocus: function() {
46718 this.tb.items.each(function(item){
46727 // <script type="text/javascript">
46730 * Ext JS Library 1.1.1
46731 * Copyright(c) 2006-2007, Ext JS, LLC.
46738 * @class Roo.form.HtmlEditor.ToolbarContext
46743 new Roo.form.HtmlEditor({
46746 { xtype: 'ToolbarStandard', styles : {} }
46747 { xtype: 'ToolbarContext', disable : {} }
46753 * @config : {Object} disable List of elements to disable.. (not done yet.)
46754 * @config : {Object} styles Map of styles available.
46758 Roo.form.HtmlEditor.ToolbarContext = function(config)
46761 Roo.apply(this, config);
46762 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46763 // dont call parent... till later.
46764 this.styles = this.styles || {};
46769 Roo.form.HtmlEditor.ToolbarContext.types = {
46781 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46847 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46852 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46862 style : 'fontFamily',
46863 displayField: 'display',
46864 optname : 'font-family',
46913 // should we really allow this??
46914 // should this just be
46925 style : 'fontFamily',
46926 displayField: 'display',
46927 optname : 'font-family',
46934 style : 'fontFamily',
46935 displayField: 'display',
46936 optname : 'font-family',
46943 style : 'fontFamily',
46944 displayField: 'display',
46945 optname : 'font-family',
46956 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
46957 Roo.form.HtmlEditor.ToolbarContext.stores = false;
46959 Roo.form.HtmlEditor.ToolbarContext.options = {
46961 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
46962 [ 'Courier New', 'Courier New'],
46963 [ 'Tahoma', 'Tahoma'],
46964 [ 'Times New Roman,serif', 'Times'],
46965 [ 'Verdana','Verdana' ]
46969 // fixme - these need to be configurable..
46972 //Roo.form.HtmlEditor.ToolbarContext.types
46975 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46982 editorcore : false,
46984 * @cfg {Object} disable List of toolbar elements to disable
46989 * @cfg {Object} styles List of styles
46990 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46992 * These must be defined in the page, so they get rendered correctly..
47003 init : function(editor)
47005 this.editor = editor;
47006 this.editorcore = editor.editorcore ? editor.editorcore : editor;
47007 var editorcore = this.editorcore;
47009 var fid = editorcore.frameId;
47011 function btn(id, toggle, handler){
47012 var xid = fid + '-'+ id ;
47016 cls : 'x-btn-icon x-edit-'+id,
47017 enableToggle:toggle !== false,
47018 scope: editorcore, // was editor...
47019 handler:handler||editorcore.relayBtnCmd,
47020 clickEvent:'mousedown',
47021 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47025 // create a new element.
47026 var wdiv = editor.wrap.createChild({
47028 }, editor.wrap.dom.firstChild.nextSibling, true);
47030 // can we do this more than once??
47032 // stop form submits
47035 // disable everything...
47036 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47037 this.toolbars = {};
47039 for (var i in ty) {
47041 this.toolbars[i] = this.buildToolbar(ty[i],i);
47043 this.tb = this.toolbars.BODY;
47045 this.buildFooter();
47046 this.footer.show();
47047 editor.on('hide', function( ) { this.footer.hide() }, this);
47048 editor.on('show', function( ) { this.footer.show() }, this);
47051 this.rendered = true;
47053 // the all the btns;
47054 editor.on('editorevent', this.updateToolbar, this);
47055 // other toolbars need to implement this..
47056 //editor.on('editmodechange', this.updateToolbar, this);
47062 * Protected method that will not generally be called directly. It triggers
47063 * a toolbar update by reading the markup state of the current selection in the editor.
47065 * Note you can force an update by calling on('editorevent', scope, false)
47067 updateToolbar: function(editor,ev,sel){
47070 // capture mouse up - this is handy for selecting images..
47071 // perhaps should go somewhere else...
47072 if(!this.editorcore.activated){
47073 this.editor.onFirstFocus();
47079 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
47080 // selectNode - might want to handle IE?
47082 (ev.type == 'mouseup' || ev.type == 'click' ) &&
47083 ev.target && ev.target.tagName == 'IMG') {
47084 // they have click on an image...
47085 // let's see if we can change the selection...
47088 var nodeRange = sel.ownerDocument.createRange();
47090 nodeRange.selectNode(sel);
47092 nodeRange.selectNodeContents(sel);
47094 //nodeRange.collapse(true);
47095 var s = this.editorcore.win.getSelection();
47096 s.removeAllRanges();
47097 s.addRange(nodeRange);
47101 var updateFooter = sel ? false : true;
47104 var ans = this.editorcore.getAllAncestors();
47107 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47110 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47111 sel = sel ? sel : this.editorcore.doc.body;
47112 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47115 // pick a menu that exists..
47116 var tn = sel.tagName.toUpperCase();
47117 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47119 tn = sel.tagName.toUpperCase();
47121 var lastSel = this.tb.selectedNode;
47123 this.tb.selectedNode = sel;
47125 // if current menu does not match..
47127 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47130 ///console.log("show: " + tn);
47131 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47134 this.tb.items.first().el.innerHTML = tn + ': ';
47137 // update attributes
47138 if (this.tb.fields) {
47139 this.tb.fields.each(function(e) {
47141 e.setValue(sel.style[e.stylename]);
47144 e.setValue(sel.getAttribute(e.attrname));
47148 var hasStyles = false;
47149 for(var i in this.styles) {
47156 var st = this.tb.fields.item(0);
47158 st.store.removeAll();
47161 var cn = sel.className.split(/\s+/);
47164 if (this.styles['*']) {
47166 Roo.each(this.styles['*'], function(v) {
47167 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47170 if (this.styles[tn]) {
47171 Roo.each(this.styles[tn], function(v) {
47172 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47176 st.store.loadData(avs);
47180 // flag our selected Node.
47181 this.tb.selectedNode = sel;
47184 Roo.menu.MenuMgr.hideAll();
47188 if (!updateFooter) {
47189 //this.footDisp.dom.innerHTML = '';
47192 // update the footer
47196 this.footerEls = ans.reverse();
47197 Roo.each(this.footerEls, function(a,i) {
47198 if (!a) { return; }
47199 html += html.length ? ' > ' : '';
47201 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47206 var sz = this.footDisp.up('td').getSize();
47207 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47208 this.footDisp.dom.style.marginLeft = '5px';
47210 this.footDisp.dom.style.overflow = 'hidden';
47212 this.footDisp.dom.innerHTML = html;
47214 //this.editorsyncValue();
47221 onDestroy : function(){
47224 this.tb.items.each(function(item){
47226 item.menu.removeAll();
47228 item.menu.el.destroy();
47236 onFirstFocus: function() {
47237 // need to do this for all the toolbars..
47238 this.tb.items.each(function(item){
47242 buildToolbar: function(tlist, nm)
47244 var editor = this.editor;
47245 var editorcore = this.editorcore;
47246 // create a new element.
47247 var wdiv = editor.wrap.createChild({
47249 }, editor.wrap.dom.firstChild.nextSibling, true);
47252 var tb = new Roo.Toolbar(wdiv);
47255 tb.add(nm+ ": ");
47258 for(var i in this.styles) {
47263 if (styles && styles.length) {
47265 // this needs a multi-select checkbox...
47266 tb.addField( new Roo.form.ComboBox({
47267 store: new Roo.data.SimpleStore({
47269 fields: ['val', 'selected'],
47272 name : '-roo-edit-className',
47273 attrname : 'className',
47274 displayField: 'val',
47278 triggerAction: 'all',
47279 emptyText:'Select Style',
47280 selectOnFocus:true,
47283 'select': function(c, r, i) {
47284 // initial support only for on class per el..
47285 tb.selectedNode.className = r ? r.get('val') : '';
47286 editorcore.syncValue();
47293 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47294 var tbops = tbc.options;
47296 for (var i in tlist) {
47298 var item = tlist[i];
47299 tb.add(item.title + ": ");
47302 //optname == used so you can configure the options available..
47303 var opts = item.opts ? item.opts : false;
47304 if (item.optname) {
47305 opts = tbops[item.optname];
47310 // opts == pulldown..
47311 tb.addField( new Roo.form.ComboBox({
47312 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47314 fields: ['val', 'display'],
47317 name : '-roo-edit-' + i,
47319 stylename : item.style ? item.style : false,
47320 displayField: item.displayField ? item.displayField : 'val',
47321 valueField : 'val',
47323 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47325 triggerAction: 'all',
47326 emptyText:'Select',
47327 selectOnFocus:true,
47328 width: item.width ? item.width : 130,
47330 'select': function(c, r, i) {
47332 tb.selectedNode.style[c.stylename] = r.get('val');
47335 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47344 tb.addField( new Roo.form.TextField({
47347 //allowBlank:false,
47352 tb.addField( new Roo.form.TextField({
47353 name: '-roo-edit-' + i,
47360 'change' : function(f, nv, ov) {
47361 tb.selectedNode.setAttribute(f.attrname, nv);
47362 editorcore.syncValue();
47375 text: 'Stylesheets',
47378 click : function ()
47380 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47388 text: 'Remove Tag',
47391 click : function ()
47394 // undo does not work.
47396 var sn = tb.selectedNode;
47398 var pn = sn.parentNode;
47400 var stn = sn.childNodes[0];
47401 var en = sn.childNodes[sn.childNodes.length - 1 ];
47402 while (sn.childNodes.length) {
47403 var node = sn.childNodes[0];
47404 sn.removeChild(node);
47406 pn.insertBefore(node, sn);
47409 pn.removeChild(sn);
47410 var range = editorcore.createRange();
47412 range.setStart(stn,0);
47413 range.setEnd(en,0); //????
47414 //range.selectNode(sel);
47417 var selection = editorcore.getSelection();
47418 selection.removeAllRanges();
47419 selection.addRange(range);
47423 //_this.updateToolbar(null, null, pn);
47424 _this.updateToolbar(null, null, null);
47425 _this.footDisp.dom.innerHTML = '';
47435 tb.el.on('click', function(e){
47436 e.preventDefault(); // what does this do?
47438 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47441 // dont need to disable them... as they will get hidden
47446 buildFooter : function()
47449 var fel = this.editor.wrap.createChild();
47450 this.footer = new Roo.Toolbar(fel);
47451 // toolbar has scrolly on left / right?
47452 var footDisp= new Roo.Toolbar.Fill();
47458 handler : function() {
47459 _t.footDisp.scrollTo('left',0,true)
47463 this.footer.add( footDisp );
47468 handler : function() {
47470 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47474 var fel = Roo.get(footDisp.el);
47475 fel.addClass('x-editor-context');
47476 this.footDispWrap = fel;
47477 this.footDispWrap.overflow = 'hidden';
47479 this.footDisp = fel.createChild();
47480 this.footDispWrap.on('click', this.onContextClick, this)
47484 onContextClick : function (ev,dom)
47486 ev.preventDefault();
47487 var cn = dom.className;
47489 if (!cn.match(/x-ed-loc-/)) {
47492 var n = cn.split('-').pop();
47493 var ans = this.footerEls;
47497 var range = this.editorcore.createRange();
47499 range.selectNodeContents(sel);
47500 //range.selectNode(sel);
47503 var selection = this.editorcore.getSelection();
47504 selection.removeAllRanges();
47505 selection.addRange(range);
47509 this.updateToolbar(null, null, sel);
47526 * Ext JS Library 1.1.1
47527 * Copyright(c) 2006-2007, Ext JS, LLC.
47529 * Originally Released Under LGPL - original licence link has changed is not relivant.
47532 * <script type="text/javascript">
47536 * @class Roo.form.BasicForm
47537 * @extends Roo.util.Observable
47538 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47540 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47541 * @param {Object} config Configuration options
47543 Roo.form.BasicForm = function(el, config){
47544 this.allItems = [];
47545 this.childForms = [];
47546 Roo.apply(this, config);
47548 * The Roo.form.Field items in this form.
47549 * @type MixedCollection
47553 this.items = new Roo.util.MixedCollection(false, function(o){
47554 return o.id || (o.id = Roo.id());
47558 * @event beforeaction
47559 * Fires before any action is performed. Return false to cancel the action.
47560 * @param {Form} this
47561 * @param {Action} action The action to be performed
47563 beforeaction: true,
47565 * @event actionfailed
47566 * Fires when an action fails.
47567 * @param {Form} this
47568 * @param {Action} action The action that failed
47570 actionfailed : true,
47572 * @event actioncomplete
47573 * Fires when an action is completed.
47574 * @param {Form} this
47575 * @param {Action} action The action that completed
47577 actioncomplete : true
47582 Roo.form.BasicForm.superclass.constructor.call(this);
47584 Roo.form.BasicForm.popover.apply();
47587 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47589 * @cfg {String} method
47590 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47593 * @cfg {DataReader} reader
47594 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47595 * This is optional as there is built-in support for processing JSON.
47598 * @cfg {DataReader} errorReader
47599 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47600 * This is completely optional as there is built-in support for processing JSON.
47603 * @cfg {String} url
47604 * The URL to use for form actions if one isn't supplied in the action options.
47607 * @cfg {Boolean} fileUpload
47608 * Set to true if this form is a file upload.
47612 * @cfg {Object} baseParams
47613 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47618 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47623 activeAction : null,
47626 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47627 * or setValues() data instead of when the form was first created.
47629 trackResetOnLoad : false,
47633 * childForms - used for multi-tab forms
47636 childForms : false,
47639 * allItems - full list of fields.
47645 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47646 * element by passing it or its id or mask the form itself by passing in true.
47649 waitMsgTarget : false,
47654 disableMask : false,
47657 * @cfg {Boolean} errorMask (true|false) default false
47662 * @cfg {Number} maskOffset Default 100
47667 initEl : function(el){
47668 this.el = Roo.get(el);
47669 this.id = this.el.id || Roo.id();
47670 this.el.on('submit', this.onSubmit, this);
47671 this.el.addClass('x-form');
47675 onSubmit : function(e){
47680 * Returns true if client-side validation on the form is successful.
47683 isValid : function(){
47685 var target = false;
47686 this.items.each(function(f){
47693 if(!target && f.el.isVisible(true)){
47698 if(this.errorMask && !valid){
47699 Roo.form.BasicForm.popover.mask(this, target);
47705 * Returns array of invalid form fields.
47709 invalidFields : function()
47712 this.items.each(function(f){
47725 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47728 isDirty : function(){
47730 this.items.each(function(f){
47740 * Returns true if any fields in this form have changed since their original load. (New version)
47744 hasChanged : function()
47747 this.items.each(function(f){
47748 if(f.hasChanged()){
47757 * Resets all hasChanged to 'false' -
47758 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47759 * So hasChanged storage is only to be used for this purpose
47762 resetHasChanged : function()
47764 this.items.each(function(f){
47765 f.resetHasChanged();
47772 * Performs a predefined action (submit or load) or custom actions you define on this form.
47773 * @param {String} actionName The name of the action type
47774 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47775 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47776 * accept other config options):
47778 Property Type Description
47779 ---------------- --------------- ----------------------------------------------------------------------------------
47780 url String The url for the action (defaults to the form's url)
47781 method String The form method to use (defaults to the form's method, or POST if not defined)
47782 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47783 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47784 validate the form on the client (defaults to false)
47786 * @return {BasicForm} this
47788 doAction : function(action, options){
47789 if(typeof action == 'string'){
47790 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47792 if(this.fireEvent('beforeaction', this, action) !== false){
47793 this.beforeAction(action);
47794 action.run.defer(100, action);
47800 * Shortcut to do a submit action.
47801 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47802 * @return {BasicForm} this
47804 submit : function(options){
47805 this.doAction('submit', options);
47810 * Shortcut to do a load action.
47811 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47812 * @return {BasicForm} this
47814 load : function(options){
47815 this.doAction('load', options);
47820 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47821 * @param {Record} record The record to edit
47822 * @return {BasicForm} this
47824 updateRecord : function(record){
47825 record.beginEdit();
47826 var fs = record.fields;
47827 fs.each(function(f){
47828 var field = this.findField(f.name);
47830 record.set(f.name, field.getValue());
47838 * Loads an Roo.data.Record into this form.
47839 * @param {Record} record The record to load
47840 * @return {BasicForm} this
47842 loadRecord : function(record){
47843 this.setValues(record.data);
47848 beforeAction : function(action){
47849 var o = action.options;
47851 if(!this.disableMask) {
47852 if(this.waitMsgTarget === true){
47853 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47854 }else if(this.waitMsgTarget){
47855 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47856 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47858 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47866 afterAction : function(action, success){
47867 this.activeAction = null;
47868 var o = action.options;
47870 if(!this.disableMask) {
47871 if(this.waitMsgTarget === true){
47873 }else if(this.waitMsgTarget){
47874 this.waitMsgTarget.unmask();
47876 Roo.MessageBox.updateProgress(1);
47877 Roo.MessageBox.hide();
47885 Roo.callback(o.success, o.scope, [this, action]);
47886 this.fireEvent('actioncomplete', this, action);
47890 // failure condition..
47891 // we have a scenario where updates need confirming.
47892 // eg. if a locking scenario exists..
47893 // we look for { errors : { needs_confirm : true }} in the response.
47895 (typeof(action.result) != 'undefined') &&
47896 (typeof(action.result.errors) != 'undefined') &&
47897 (typeof(action.result.errors.needs_confirm) != 'undefined')
47900 Roo.MessageBox.confirm(
47901 "Change requires confirmation",
47902 action.result.errorMsg,
47907 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47917 Roo.callback(o.failure, o.scope, [this, action]);
47918 // show an error message if no failed handler is set..
47919 if (!this.hasListener('actionfailed')) {
47920 Roo.MessageBox.alert("Error",
47921 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47922 action.result.errorMsg :
47923 "Saving Failed, please check your entries or try again"
47927 this.fireEvent('actionfailed', this, action);
47933 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47934 * @param {String} id The value to search for
47937 findField : function(id){
47938 var field = this.items.get(id);
47940 this.items.each(function(f){
47941 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47947 return field || null;
47951 * Add a secondary form to this one,
47952 * Used to provide tabbed forms. One form is primary, with hidden values
47953 * which mirror the elements from the other forms.
47955 * @param {Roo.form.Form} form to add.
47958 addForm : function(form)
47961 if (this.childForms.indexOf(form) > -1) {
47965 this.childForms.push(form);
47967 Roo.each(form.allItems, function (fe) {
47969 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
47970 if (this.findField(n)) { // already added..
47973 var add = new Roo.form.Hidden({
47976 add.render(this.el);
47983 * Mark fields in this form invalid in bulk.
47984 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
47985 * @return {BasicForm} this
47987 markInvalid : function(errors){
47988 if(errors instanceof Array){
47989 for(var i = 0, len = errors.length; i < len; i++){
47990 var fieldError = errors[i];
47991 var f = this.findField(fieldError.id);
47993 f.markInvalid(fieldError.msg);
47999 if(typeof errors[id] != 'function' && (field = this.findField(id))){
48000 field.markInvalid(errors[id]);
48004 Roo.each(this.childForms || [], function (f) {
48005 f.markInvalid(errors);
48012 * Set values for fields in this form in bulk.
48013 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
48014 * @return {BasicForm} this
48016 setValues : function(values){
48017 if(values instanceof Array){ // array of objects
48018 for(var i = 0, len = values.length; i < len; i++){
48020 var f = this.findField(v.id);
48022 f.setValue(v.value);
48023 if(this.trackResetOnLoad){
48024 f.originalValue = f.getValue();
48028 }else{ // object hash
48031 if(typeof values[id] != 'function' && (field = this.findField(id))){
48033 if (field.setFromData &&
48034 field.valueField &&
48035 field.displayField &&
48036 // combos' with local stores can
48037 // be queried via setValue()
48038 // to set their value..
48039 (field.store && !field.store.isLocal)
48043 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
48044 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
48045 field.setFromData(sd);
48048 field.setValue(values[id]);
48052 if(this.trackResetOnLoad){
48053 field.originalValue = field.getValue();
48058 this.resetHasChanged();
48061 Roo.each(this.childForms || [], function (f) {
48062 f.setValues(values);
48063 f.resetHasChanged();
48070 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
48071 * they are returned as an array.
48072 * @param {Boolean} asString
48075 getValues : function(asString){
48076 if (this.childForms) {
48077 // copy values from the child forms
48078 Roo.each(this.childForms, function (f) {
48079 this.setValues(f.getValues());
48084 if (typeof(FormData) != 'undefined' && asString !== true) {
48085 // this relies on a 'recent' version of chrome apparently...
48087 var fd = (new FormData(this.el.dom)).entries();
48089 var ent = fd.next();
48090 while (!ent.done) {
48091 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
48102 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
48103 if(asString === true){
48106 return Roo.urlDecode(fs);
48110 * Returns the fields in this form as an object with key/value pairs.
48111 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48114 getFieldValues : function(with_hidden)
48116 if (this.childForms) {
48117 // copy values from the child forms
48118 // should this call getFieldValues - probably not as we do not currently copy
48119 // hidden fields when we generate..
48120 Roo.each(this.childForms, function (f) {
48121 this.setValues(f.getValues());
48126 this.items.each(function(f){
48127 if (!f.getName()) {
48130 var v = f.getValue();
48131 if (f.inputType =='radio') {
48132 if (typeof(ret[f.getName()]) == 'undefined') {
48133 ret[f.getName()] = ''; // empty..
48136 if (!f.el.dom.checked) {
48140 v = f.el.dom.value;
48144 // not sure if this supported any more..
48145 if ((typeof(v) == 'object') && f.getRawValue) {
48146 v = f.getRawValue() ; // dates..
48148 // combo boxes where name != hiddenName...
48149 if (f.name != f.getName()) {
48150 ret[f.name] = f.getRawValue();
48152 ret[f.getName()] = v;
48159 * Clears all invalid messages in this form.
48160 * @return {BasicForm} this
48162 clearInvalid : function(){
48163 this.items.each(function(f){
48167 Roo.each(this.childForms || [], function (f) {
48176 * Resets this form.
48177 * @return {BasicForm} this
48179 reset : function(){
48180 this.items.each(function(f){
48184 Roo.each(this.childForms || [], function (f) {
48187 this.resetHasChanged();
48193 * Add Roo.form components to this form.
48194 * @param {Field} field1
48195 * @param {Field} field2 (optional)
48196 * @param {Field} etc (optional)
48197 * @return {BasicForm} this
48200 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48206 * Removes a field from the items collection (does NOT remove its markup).
48207 * @param {Field} field
48208 * @return {BasicForm} this
48210 remove : function(field){
48211 this.items.remove(field);
48216 * Looks at the fields in this form, checks them for an id attribute,
48217 * and calls applyTo on the existing dom element with that id.
48218 * @return {BasicForm} this
48220 render : function(){
48221 this.items.each(function(f){
48222 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48230 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48231 * @param {Object} values
48232 * @return {BasicForm} this
48234 applyToFields : function(o){
48235 this.items.each(function(f){
48242 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48243 * @param {Object} values
48244 * @return {BasicForm} this
48246 applyIfToFields : function(o){
48247 this.items.each(function(f){
48255 Roo.BasicForm = Roo.form.BasicForm;
48257 Roo.apply(Roo.form.BasicForm, {
48271 intervalID : false,
48277 if(this.isApplied){
48282 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48283 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48284 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48285 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48288 this.maskEl.top.enableDisplayMode("block");
48289 this.maskEl.left.enableDisplayMode("block");
48290 this.maskEl.bottom.enableDisplayMode("block");
48291 this.maskEl.right.enableDisplayMode("block");
48293 Roo.get(document.body).on('click', function(){
48297 Roo.get(document.body).on('touchstart', function(){
48301 this.isApplied = true
48304 mask : function(form, target)
48308 this.target = target;
48310 if(!this.form.errorMask || !target.el){
48314 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48316 var ot = this.target.el.calcOffsetsTo(scrollable);
48318 var scrollTo = ot[1] - this.form.maskOffset;
48320 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48322 scrollable.scrollTo('top', scrollTo);
48324 var el = this.target.wrap || this.target.el;
48326 var box = el.getBox();
48328 this.maskEl.top.setStyle('position', 'absolute');
48329 this.maskEl.top.setStyle('z-index', 10000);
48330 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48331 this.maskEl.top.setLeft(0);
48332 this.maskEl.top.setTop(0);
48333 this.maskEl.top.show();
48335 this.maskEl.left.setStyle('position', 'absolute');
48336 this.maskEl.left.setStyle('z-index', 10000);
48337 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48338 this.maskEl.left.setLeft(0);
48339 this.maskEl.left.setTop(box.y - this.padding);
48340 this.maskEl.left.show();
48342 this.maskEl.bottom.setStyle('position', 'absolute');
48343 this.maskEl.bottom.setStyle('z-index', 10000);
48344 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48345 this.maskEl.bottom.setLeft(0);
48346 this.maskEl.bottom.setTop(box.bottom + this.padding);
48347 this.maskEl.bottom.show();
48349 this.maskEl.right.setStyle('position', 'absolute');
48350 this.maskEl.right.setStyle('z-index', 10000);
48351 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48352 this.maskEl.right.setLeft(box.right + this.padding);
48353 this.maskEl.right.setTop(box.y - this.padding);
48354 this.maskEl.right.show();
48356 this.intervalID = window.setInterval(function() {
48357 Roo.form.BasicForm.popover.unmask();
48360 window.onwheel = function(){ return false;};
48362 (function(){ this.isMasked = true; }).defer(500, this);
48366 unmask : function()
48368 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48372 this.maskEl.top.setStyle('position', 'absolute');
48373 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48374 this.maskEl.top.hide();
48376 this.maskEl.left.setStyle('position', 'absolute');
48377 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48378 this.maskEl.left.hide();
48380 this.maskEl.bottom.setStyle('position', 'absolute');
48381 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48382 this.maskEl.bottom.hide();
48384 this.maskEl.right.setStyle('position', 'absolute');
48385 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48386 this.maskEl.right.hide();
48388 window.onwheel = function(){ return true;};
48390 if(this.intervalID){
48391 window.clearInterval(this.intervalID);
48392 this.intervalID = false;
48395 this.isMasked = false;
48403 * Ext JS Library 1.1.1
48404 * Copyright(c) 2006-2007, Ext JS, LLC.
48406 * Originally Released Under LGPL - original licence link has changed is not relivant.
48409 * <script type="text/javascript">
48413 * @class Roo.form.Form
48414 * @extends Roo.form.BasicForm
48415 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48417 * @param {Object} config Configuration options
48419 Roo.form.Form = function(config){
48421 if (config.items) {
48422 xitems = config.items;
48423 delete config.items;
48427 Roo.form.Form.superclass.constructor.call(this, null, config);
48428 this.url = this.url || this.action;
48430 this.root = new Roo.form.Layout(Roo.applyIf({
48434 this.active = this.root;
48436 * Array of all the buttons that have been added to this form via {@link addButton}
48440 this.allItems = [];
48443 * @event clientvalidation
48444 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48445 * @param {Form} this
48446 * @param {Boolean} valid true if the form has passed client-side validation
48448 clientvalidation: true,
48451 * Fires when the form is rendered
48452 * @param {Roo.form.Form} form
48457 if (this.progressUrl) {
48458 // push a hidden field onto the list of fields..
48462 name : 'UPLOAD_IDENTIFIER'
48467 Roo.each(xitems, this.addxtype, this);
48471 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48473 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48476 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48479 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48481 buttonAlign:'center',
48484 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48489 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48490 * This property cascades to child containers if not set.
48495 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48496 * fires a looping event with that state. This is required to bind buttons to the valid
48497 * state using the config value formBind:true on the button.
48499 monitorValid : false,
48502 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48507 * @cfg {String} progressUrl - Url to return progress data
48510 progressUrl : false,
48512 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48513 * sending a formdata with extra parameters - eg uploaded elements.
48519 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48520 * fields are added and the column is closed. If no fields are passed the column remains open
48521 * until end() is called.
48522 * @param {Object} config The config to pass to the column
48523 * @param {Field} field1 (optional)
48524 * @param {Field} field2 (optional)
48525 * @param {Field} etc (optional)
48526 * @return Column The column container object
48528 column : function(c){
48529 var col = new Roo.form.Column(c);
48531 if(arguments.length > 1){ // duplicate code required because of Opera
48532 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48539 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48540 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48541 * until end() is called.
48542 * @param {Object} config The config to pass to the fieldset
48543 * @param {Field} field1 (optional)
48544 * @param {Field} field2 (optional)
48545 * @param {Field} etc (optional)
48546 * @return FieldSet The fieldset container object
48548 fieldset : function(c){
48549 var fs = new Roo.form.FieldSet(c);
48551 if(arguments.length > 1){ // duplicate code required because of Opera
48552 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48559 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48560 * fields are added and the container is closed. If no fields are passed the container remains open
48561 * until end() is called.
48562 * @param {Object} config The config to pass to the Layout
48563 * @param {Field} field1 (optional)
48564 * @param {Field} field2 (optional)
48565 * @param {Field} etc (optional)
48566 * @return Layout The container object
48568 container : function(c){
48569 var l = new Roo.form.Layout(c);
48571 if(arguments.length > 1){ // duplicate code required because of Opera
48572 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48579 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48580 * @param {Object} container A Roo.form.Layout or subclass of Layout
48581 * @return {Form} this
48583 start : function(c){
48584 // cascade label info
48585 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48586 this.active.stack.push(c);
48587 c.ownerCt = this.active;
48593 * Closes the current open container
48594 * @return {Form} this
48597 if(this.active == this.root){
48600 this.active = this.active.ownerCt;
48605 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48606 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48607 * as the label of the field.
48608 * @param {Field} field1
48609 * @param {Field} field2 (optional)
48610 * @param {Field} etc. (optional)
48611 * @return {Form} this
48614 this.active.stack.push.apply(this.active.stack, arguments);
48615 this.allItems.push.apply(this.allItems,arguments);
48617 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48618 if(a[i].isFormField){
48623 Roo.form.Form.superclass.add.apply(this, r);
48633 * Find any element that has been added to a form, using it's ID or name
48634 * This can include framesets, columns etc. along with regular fields..
48635 * @param {String} id - id or name to find.
48637 * @return {Element} e - or false if nothing found.
48639 findbyId : function(id)
48645 Roo.each(this.allItems, function(f){
48646 if (f.id == id || f.name == id ){
48657 * Render this form into the passed container. This should only be called once!
48658 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48659 * @return {Form} this
48661 render : function(ct)
48667 var o = this.autoCreate || {
48669 method : this.method || 'POST',
48670 id : this.id || Roo.id()
48672 this.initEl(ct.createChild(o));
48674 this.root.render(this.el);
48678 this.items.each(function(f){
48679 f.render('x-form-el-'+f.id);
48682 if(this.buttons.length > 0){
48683 // tables are required to maintain order and for correct IE layout
48684 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48685 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48686 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48688 var tr = tb.getElementsByTagName('tr')[0];
48689 for(var i = 0, len = this.buttons.length; i < len; i++) {
48690 var b = this.buttons[i];
48691 var td = document.createElement('td');
48692 td.className = 'x-form-btn-td';
48693 b.render(tr.appendChild(td));
48696 if(this.monitorValid){ // initialize after render
48697 this.startMonitoring();
48699 this.fireEvent('rendered', this);
48704 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48705 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48706 * object or a valid Roo.DomHelper element config
48707 * @param {Function} handler The function called when the button is clicked
48708 * @param {Object} scope (optional) The scope of the handler function
48709 * @return {Roo.Button}
48711 addButton : function(config, handler, scope){
48715 minWidth: this.minButtonWidth,
48718 if(typeof config == "string"){
48721 Roo.apply(bc, config);
48723 var btn = new Roo.Button(null, bc);
48724 this.buttons.push(btn);
48729 * Adds a series of form elements (using the xtype property as the factory method.
48730 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48731 * @param {Object} config
48734 addxtype : function()
48736 var ar = Array.prototype.slice.call(arguments, 0);
48738 for(var i = 0; i < ar.length; i++) {
48740 continue; // skip -- if this happends something invalid got sent, we
48741 // should ignore it, as basically that interface element will not show up
48742 // and that should be pretty obvious!!
48745 if (Roo.form[ar[i].xtype]) {
48747 var fe = Roo.factory(ar[i], Roo.form);
48753 fe.store.form = this;
48758 this.allItems.push(fe);
48759 if (fe.items && fe.addxtype) {
48760 fe.addxtype.apply(fe, fe.items);
48770 // console.log('adding ' + ar[i].xtype);
48772 if (ar[i].xtype == 'Button') {
48773 //console.log('adding button');
48774 //console.log(ar[i]);
48775 this.addButton(ar[i]);
48776 this.allItems.push(fe);
48780 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48781 alert('end is not supported on xtype any more, use items');
48783 // //console.log('adding end');
48791 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48792 * option "monitorValid"
48794 startMonitoring : function(){
48797 Roo.TaskMgr.start({
48798 run : this.bindHandler,
48799 interval : this.monitorPoll || 200,
48806 * Stops monitoring of the valid state of this form
48808 stopMonitoring : function(){
48809 this.bound = false;
48813 bindHandler : function(){
48815 return false; // stops binding
48818 this.items.each(function(f){
48819 if(!f.isValid(true)){
48824 for(var i = 0, len = this.buttons.length; i < len; i++){
48825 var btn = this.buttons[i];
48826 if(btn.formBind === true && btn.disabled === valid){
48827 btn.setDisabled(!valid);
48830 this.fireEvent('clientvalidation', this, valid);
48844 Roo.Form = Roo.form.Form;
48847 * Ext JS Library 1.1.1
48848 * Copyright(c) 2006-2007, Ext JS, LLC.
48850 * Originally Released Under LGPL - original licence link has changed is not relivant.
48853 * <script type="text/javascript">
48856 // as we use this in bootstrap.
48857 Roo.namespace('Roo.form');
48859 * @class Roo.form.Action
48860 * Internal Class used to handle form actions
48862 * @param {Roo.form.BasicForm} el The form element or its id
48863 * @param {Object} config Configuration options
48868 // define the action interface
48869 Roo.form.Action = function(form, options){
48871 this.options = options || {};
48874 * Client Validation Failed
48877 Roo.form.Action.CLIENT_INVALID = 'client';
48879 * Server Validation Failed
48882 Roo.form.Action.SERVER_INVALID = 'server';
48884 * Connect to Server Failed
48887 Roo.form.Action.CONNECT_FAILURE = 'connect';
48889 * Reading Data from Server Failed
48892 Roo.form.Action.LOAD_FAILURE = 'load';
48894 Roo.form.Action.prototype = {
48896 failureType : undefined,
48897 response : undefined,
48898 result : undefined,
48900 // interface method
48901 run : function(options){
48905 // interface method
48906 success : function(response){
48910 // interface method
48911 handleResponse : function(response){
48915 // default connection failure
48916 failure : function(response){
48918 this.response = response;
48919 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48920 this.form.afterAction(this, false);
48923 processResponse : function(response){
48924 this.response = response;
48925 if(!response.responseText){
48928 this.result = this.handleResponse(response);
48929 return this.result;
48932 // utility functions used internally
48933 getUrl : function(appendParams){
48934 var url = this.options.url || this.form.url || this.form.el.dom.action;
48936 var p = this.getParams();
48938 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
48944 getMethod : function(){
48945 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
48948 getParams : function(){
48949 var bp = this.form.baseParams;
48950 var p = this.options.params;
48952 if(typeof p == "object"){
48953 p = Roo.urlEncode(Roo.applyIf(p, bp));
48954 }else if(typeof p == 'string' && bp){
48955 p += '&' + Roo.urlEncode(bp);
48958 p = Roo.urlEncode(bp);
48963 createCallback : function(){
48965 success: this.success,
48966 failure: this.failure,
48968 timeout: (this.form.timeout*1000),
48969 upload: this.form.fileUpload ? this.success : undefined
48974 Roo.form.Action.Submit = function(form, options){
48975 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
48978 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
48981 haveProgress : false,
48982 uploadComplete : false,
48984 // uploadProgress indicator.
48985 uploadProgress : function()
48987 if (!this.form.progressUrl) {
48991 if (!this.haveProgress) {
48992 Roo.MessageBox.progress("Uploading", "Uploading");
48994 if (this.uploadComplete) {
48995 Roo.MessageBox.hide();
48999 this.haveProgress = true;
49001 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
49003 var c = new Roo.data.Connection();
49005 url : this.form.progressUrl,
49010 success : function(req){
49011 //console.log(data);
49015 rdata = Roo.decode(req.responseText)
49017 Roo.log("Invalid data from server..");
49021 if (!rdata || !rdata.success) {
49023 Roo.MessageBox.alert(Roo.encode(rdata));
49026 var data = rdata.data;
49028 if (this.uploadComplete) {
49029 Roo.MessageBox.hide();
49034 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
49035 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
49038 this.uploadProgress.defer(2000,this);
49041 failure: function(data) {
49042 Roo.log('progress url failed ');
49053 // run get Values on the form, so it syncs any secondary forms.
49054 this.form.getValues();
49056 var o = this.options;
49057 var method = this.getMethod();
49058 var isPost = method == 'POST';
49059 if(o.clientValidation === false || this.form.isValid()){
49061 if (this.form.progressUrl) {
49062 this.form.findField('UPLOAD_IDENTIFIER').setValue(
49063 (new Date() * 1) + '' + Math.random());
49068 Roo.Ajax.request(Roo.apply(this.createCallback(), {
49069 form:this.form.el.dom,
49070 url:this.getUrl(!isPost),
49072 params:isPost ? this.getParams() : null,
49073 isUpload: this.form.fileUpload,
49074 formData : this.form.formData
49077 this.uploadProgress();
49079 }else if (o.clientValidation !== false){ // client validation failed
49080 this.failureType = Roo.form.Action.CLIENT_INVALID;
49081 this.form.afterAction(this, false);
49085 success : function(response)
49087 this.uploadComplete= true;
49088 if (this.haveProgress) {
49089 Roo.MessageBox.hide();
49093 var result = this.processResponse(response);
49094 if(result === true || result.success){
49095 this.form.afterAction(this, true);
49099 this.form.markInvalid(result.errors);
49100 this.failureType = Roo.form.Action.SERVER_INVALID;
49102 this.form.afterAction(this, false);
49104 failure : function(response)
49106 this.uploadComplete= true;
49107 if (this.haveProgress) {
49108 Roo.MessageBox.hide();
49111 this.response = response;
49112 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49113 this.form.afterAction(this, false);
49116 handleResponse : function(response){
49117 if(this.form.errorReader){
49118 var rs = this.form.errorReader.read(response);
49121 for(var i = 0, len = rs.records.length; i < len; i++) {
49122 var r = rs.records[i];
49123 errors[i] = r.data;
49126 if(errors.length < 1){
49130 success : rs.success,
49136 ret = Roo.decode(response.responseText);
49140 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49150 Roo.form.Action.Load = function(form, options){
49151 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49152 this.reader = this.form.reader;
49155 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49160 Roo.Ajax.request(Roo.apply(
49161 this.createCallback(), {
49162 method:this.getMethod(),
49163 url:this.getUrl(false),
49164 params:this.getParams()
49168 success : function(response){
49170 var result = this.processResponse(response);
49171 if(result === true || !result.success || !result.data){
49172 this.failureType = Roo.form.Action.LOAD_FAILURE;
49173 this.form.afterAction(this, false);
49176 this.form.clearInvalid();
49177 this.form.setValues(result.data);
49178 this.form.afterAction(this, true);
49181 handleResponse : function(response){
49182 if(this.form.reader){
49183 var rs = this.form.reader.read(response);
49184 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49186 success : rs.success,
49190 return Roo.decode(response.responseText);
49194 Roo.form.Action.ACTION_TYPES = {
49195 'load' : Roo.form.Action.Load,
49196 'submit' : Roo.form.Action.Submit
49199 * Ext JS Library 1.1.1
49200 * Copyright(c) 2006-2007, Ext JS, LLC.
49202 * Originally Released Under LGPL - original licence link has changed is not relivant.
49205 * <script type="text/javascript">
49209 * @class Roo.form.Layout
49210 * @extends Roo.Component
49211 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49213 * @param {Object} config Configuration options
49215 Roo.form.Layout = function(config){
49217 if (config.items) {
49218 xitems = config.items;
49219 delete config.items;
49221 Roo.form.Layout.superclass.constructor.call(this, config);
49223 Roo.each(xitems, this.addxtype, this);
49227 Roo.extend(Roo.form.Layout, Roo.Component, {
49229 * @cfg {String/Object} autoCreate
49230 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49233 * @cfg {String/Object/Function} style
49234 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49235 * a function which returns such a specification.
49238 * @cfg {String} labelAlign
49239 * Valid values are "left," "top" and "right" (defaults to "left")
49242 * @cfg {Number} labelWidth
49243 * Fixed width in pixels of all field labels (defaults to undefined)
49246 * @cfg {Boolean} clear
49247 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49251 * @cfg {String} labelSeparator
49252 * The separator to use after field labels (defaults to ':')
49254 labelSeparator : ':',
49256 * @cfg {Boolean} hideLabels
49257 * True to suppress the display of field labels in this layout (defaults to false)
49259 hideLabels : false,
49262 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49267 onRender : function(ct, position){
49268 if(this.el){ // from markup
49269 this.el = Roo.get(this.el);
49270 }else { // generate
49271 var cfg = this.getAutoCreate();
49272 this.el = ct.createChild(cfg, position);
49275 this.el.applyStyles(this.style);
49277 if(this.labelAlign){
49278 this.el.addClass('x-form-label-'+this.labelAlign);
49280 if(this.hideLabels){
49281 this.labelStyle = "display:none";
49282 this.elementStyle = "padding-left:0;";
49284 if(typeof this.labelWidth == 'number'){
49285 this.labelStyle = "width:"+this.labelWidth+"px;";
49286 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49288 if(this.labelAlign == 'top'){
49289 this.labelStyle = "width:auto;";
49290 this.elementStyle = "padding-left:0;";
49293 var stack = this.stack;
49294 var slen = stack.length;
49296 if(!this.fieldTpl){
49297 var t = new Roo.Template(
49298 '<div class="x-form-item {5}">',
49299 '<label for="{0}" style="{2}">{1}{4}</label>',
49300 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49302 '</div><div class="x-form-clear-left"></div>'
49304 t.disableFormats = true;
49306 Roo.form.Layout.prototype.fieldTpl = t;
49308 for(var i = 0; i < slen; i++) {
49309 if(stack[i].isFormField){
49310 this.renderField(stack[i]);
49312 this.renderComponent(stack[i]);
49317 this.el.createChild({cls:'x-form-clear'});
49322 renderField : function(f){
49323 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49326 f.labelStyle||this.labelStyle||'', //2
49327 this.elementStyle||'', //3
49328 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49329 f.itemCls||this.itemCls||'' //5
49330 ], true).getPrevSibling());
49334 renderComponent : function(c){
49335 c.render(c.isLayout ? this.el : this.el.createChild());
49338 * Adds a object form elements (using the xtype property as the factory method.)
49339 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49340 * @param {Object} config
49342 addxtype : function(o)
49344 // create the lement.
49345 o.form = this.form;
49346 var fe = Roo.factory(o, Roo.form);
49347 this.form.allItems.push(fe);
49348 this.stack.push(fe);
49350 if (fe.isFormField) {
49351 this.form.items.add(fe);
49359 * @class Roo.form.Column
49360 * @extends Roo.form.Layout
49361 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49363 * @param {Object} config Configuration options
49365 Roo.form.Column = function(config){
49366 Roo.form.Column.superclass.constructor.call(this, config);
49369 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49371 * @cfg {Number/String} width
49372 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49375 * @cfg {String/Object} autoCreate
49376 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49380 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49383 onRender : function(ct, position){
49384 Roo.form.Column.superclass.onRender.call(this, ct, position);
49386 this.el.setWidth(this.width);
49393 * @class Roo.form.Row
49394 * @extends Roo.form.Layout
49395 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49397 * @param {Object} config Configuration options
49401 Roo.form.Row = function(config){
49402 Roo.form.Row.superclass.constructor.call(this, config);
49405 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49407 * @cfg {Number/String} width
49408 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49411 * @cfg {Number/String} height
49412 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49414 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49418 onRender : function(ct, position){
49419 //console.log('row render');
49421 var t = new Roo.Template(
49422 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49423 '<label for="{0}" style="{2}">{1}{4}</label>',
49424 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49428 t.disableFormats = true;
49430 Roo.form.Layout.prototype.rowTpl = t;
49432 this.fieldTpl = this.rowTpl;
49434 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49435 var labelWidth = 100;
49437 if ((this.labelAlign != 'top')) {
49438 if (typeof this.labelWidth == 'number') {
49439 labelWidth = this.labelWidth
49441 this.padWidth = 20 + labelWidth;
49445 Roo.form.Column.superclass.onRender.call(this, ct, position);
49447 this.el.setWidth(this.width);
49450 this.el.setHeight(this.height);
49455 renderField : function(f){
49456 f.fieldEl = this.fieldTpl.append(this.el, [
49457 f.id, f.fieldLabel,
49458 f.labelStyle||this.labelStyle||'',
49459 this.elementStyle||'',
49460 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49461 f.itemCls||this.itemCls||'',
49462 f.width ? f.width + this.padWidth : 160 + this.padWidth
49469 * @class Roo.form.FieldSet
49470 * @extends Roo.form.Layout
49471 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49473 * @param {Object} config Configuration options
49475 Roo.form.FieldSet = function(config){
49476 Roo.form.FieldSet.superclass.constructor.call(this, config);
49479 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49481 * @cfg {String} legend
49482 * The text to display as the legend for the FieldSet (defaults to '')
49485 * @cfg {String/Object} autoCreate
49486 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49490 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49493 onRender : function(ct, position){
49494 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49496 this.setLegend(this.legend);
49501 setLegend : function(text){
49503 this.el.child('legend').update(text);
49508 * Ext JS Library 1.1.1
49509 * Copyright(c) 2006-2007, Ext JS, LLC.
49511 * Originally Released Under LGPL - original licence link has changed is not relivant.
49514 * <script type="text/javascript">
49517 * @class Roo.form.VTypes
49518 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49521 Roo.form.VTypes = function(){
49522 // closure these in so they are only created once.
49523 var alpha = /^[a-zA-Z_]+$/;
49524 var alphanum = /^[a-zA-Z0-9_]+$/;
49525 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49526 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49528 // All these messages and functions are configurable
49531 * The function used to validate email addresses
49532 * @param {String} value The email address
49534 'email' : function(v){
49535 return email.test(v);
49538 * The error text to display when the email validation function returns false
49541 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49543 * The keystroke filter mask to be applied on email input
49546 'emailMask' : /[a-z0-9_\.\-@]/i,
49549 * The function used to validate URLs
49550 * @param {String} value The URL
49552 'url' : function(v){
49553 return url.test(v);
49556 * The error text to display when the url validation function returns false
49559 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49562 * The function used to validate alpha values
49563 * @param {String} value The value
49565 'alpha' : function(v){
49566 return alpha.test(v);
49569 * The error text to display when the alpha validation function returns false
49572 'alphaText' : 'This field should only contain letters and _',
49574 * The keystroke filter mask to be applied on alpha input
49577 'alphaMask' : /[a-z_]/i,
49580 * The function used to validate alphanumeric values
49581 * @param {String} value The value
49583 'alphanum' : function(v){
49584 return alphanum.test(v);
49587 * The error text to display when the alphanumeric validation function returns false
49590 'alphanumText' : 'This field should only contain letters, numbers and _',
49592 * The keystroke filter mask to be applied on alphanumeric input
49595 'alphanumMask' : /[a-z0-9_]/i
49597 }();//<script type="text/javascript">
49600 * @class Roo.form.FCKeditor
49601 * @extends Roo.form.TextArea
49602 * Wrapper around the FCKEditor http://www.fckeditor.net
49604 * Creates a new FCKeditor
49605 * @param {Object} config Configuration options
49607 Roo.form.FCKeditor = function(config){
49608 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49611 * @event editorinit
49612 * Fired when the editor is initialized - you can add extra handlers here..
49613 * @param {FCKeditor} this
49614 * @param {Object} the FCK object.
49621 Roo.form.FCKeditor.editors = { };
49622 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49624 //defaultAutoCreate : {
49625 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49629 * @cfg {Object} fck options - see fck manual for details.
49634 * @cfg {Object} fck toolbar set (Basic or Default)
49636 toolbarSet : 'Basic',
49638 * @cfg {Object} fck BasePath
49640 basePath : '/fckeditor/',
49648 onRender : function(ct, position)
49651 this.defaultAutoCreate = {
49653 style:"width:300px;height:60px;",
49654 autocomplete: "new-password"
49657 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49660 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49661 if(this.preventScrollbars){
49662 this.el.setStyle("overflow", "hidden");
49664 this.el.setHeight(this.growMin);
49667 //console.log('onrender' + this.getId() );
49668 Roo.form.FCKeditor.editors[this.getId()] = this;
49671 this.replaceTextarea() ;
49675 getEditor : function() {
49676 return this.fckEditor;
49679 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49680 * @param {Mixed} value The value to set
49684 setValue : function(value)
49686 //console.log('setValue: ' + value);
49688 if(typeof(value) == 'undefined') { // not sure why this is happending...
49691 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49693 //if(!this.el || !this.getEditor()) {
49694 // this.value = value;
49695 //this.setValue.defer(100,this,[value]);
49699 if(!this.getEditor()) {
49703 this.getEditor().SetData(value);
49710 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49711 * @return {Mixed} value The field value
49713 getValue : function()
49716 if (this.frame && this.frame.dom.style.display == 'none') {
49717 return Roo.form.FCKeditor.superclass.getValue.call(this);
49720 if(!this.el || !this.getEditor()) {
49722 // this.getValue.defer(100,this);
49727 var value=this.getEditor().GetData();
49728 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49729 return Roo.form.FCKeditor.superclass.getValue.call(this);
49735 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49736 * @return {Mixed} value The field value
49738 getRawValue : function()
49740 if (this.frame && this.frame.dom.style.display == 'none') {
49741 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49744 if(!this.el || !this.getEditor()) {
49745 //this.getRawValue.defer(100,this);
49752 var value=this.getEditor().GetData();
49753 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49754 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49758 setSize : function(w,h) {
49762 //if (this.frame && this.frame.dom.style.display == 'none') {
49763 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49766 //if(!this.el || !this.getEditor()) {
49767 // this.setSize.defer(100,this, [w,h]);
49773 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49775 this.frame.dom.setAttribute('width', w);
49776 this.frame.dom.setAttribute('height', h);
49777 this.frame.setSize(w,h);
49781 toggleSourceEdit : function(value) {
49785 this.el.dom.style.display = value ? '' : 'none';
49786 this.frame.dom.style.display = value ? 'none' : '';
49791 focus: function(tag)
49793 if (this.frame.dom.style.display == 'none') {
49794 return Roo.form.FCKeditor.superclass.focus.call(this);
49796 if(!this.el || !this.getEditor()) {
49797 this.focus.defer(100,this, [tag]);
49804 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49805 this.getEditor().Focus();
49807 if (!this.getEditor().Selection.GetSelection()) {
49808 this.focus.defer(100,this, [tag]);
49813 var r = this.getEditor().EditorDocument.createRange();
49814 r.setStart(tgs[0],0);
49815 r.setEnd(tgs[0],0);
49816 this.getEditor().Selection.GetSelection().removeAllRanges();
49817 this.getEditor().Selection.GetSelection().addRange(r);
49818 this.getEditor().Focus();
49825 replaceTextarea : function()
49827 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49830 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49832 // We must check the elements firstly using the Id and then the name.
49833 var oTextarea = document.getElementById( this.getId() );
49835 var colElementsByName = document.getElementsByName( this.getId() ) ;
49837 oTextarea.style.display = 'none' ;
49839 if ( oTextarea.tabIndex ) {
49840 this.TabIndex = oTextarea.tabIndex ;
49843 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49844 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49845 this.frame = Roo.get(this.getId() + '___Frame')
49848 _getConfigHtml : function()
49852 for ( var o in this.fckconfig ) {
49853 sConfig += sConfig.length > 0 ? '&' : '';
49854 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49857 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49861 _getIFrameHtml : function()
49863 var sFile = 'fckeditor.html' ;
49864 /* no idea what this is about..
49867 if ( (/fcksource=true/i).test( window.top.location.search ) )
49868 sFile = 'fckeditor.original.html' ;
49873 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49874 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49877 var html = '<iframe id="' + this.getId() +
49878 '___Frame" src="' + sLink +
49879 '" width="' + this.width +
49880 '" height="' + this.height + '"' +
49881 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
49882 ' frameborder="0" scrolling="no"></iframe>' ;
49887 _insertHtmlBefore : function( html, element )
49889 if ( element.insertAdjacentHTML ) {
49891 element.insertAdjacentHTML( 'beforeBegin', html ) ;
49893 var oRange = document.createRange() ;
49894 oRange.setStartBefore( element ) ;
49895 var oFragment = oRange.createContextualFragment( html );
49896 element.parentNode.insertBefore( oFragment, element ) ;
49909 //Roo.reg('fckeditor', Roo.form.FCKeditor);
49911 function FCKeditor_OnComplete(editorInstance){
49912 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
49913 f.fckEditor = editorInstance;
49914 //console.log("loaded");
49915 f.fireEvent('editorinit', f, editorInstance);
49935 //<script type="text/javascript">
49937 * @class Roo.form.GridField
49938 * @extends Roo.form.Field
49939 * Embed a grid (or editable grid into a form)
49942 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
49944 * xgrid.store = Roo.data.Store
49945 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
49946 * xgrid.store.reader = Roo.data.JsonReader
49950 * Creates a new GridField
49951 * @param {Object} config Configuration options
49953 Roo.form.GridField = function(config){
49954 Roo.form.GridField.superclass.constructor.call(this, config);
49958 Roo.extend(Roo.form.GridField, Roo.form.Field, {
49960 * @cfg {Number} width - used to restrict width of grid..
49964 * @cfg {Number} height - used to restrict height of grid..
49968 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
49974 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49975 * {tag: "input", type: "checkbox", autocomplete: "off"})
49977 // defaultAutoCreate : { tag: 'div' },
49978 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
49980 * @cfg {String} addTitle Text to include for adding a title.
49984 onResize : function(){
49985 Roo.form.Field.superclass.onResize.apply(this, arguments);
49988 initEvents : function(){
49989 // Roo.form.Checkbox.superclass.initEvents.call(this);
49990 // has no events...
49995 getResizeEl : function(){
49999 getPositionEl : function(){
50004 onRender : function(ct, position){
50006 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
50007 var style = this.style;
50010 Roo.form.GridField.superclass.onRender.call(this, ct, position);
50011 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
50012 this.viewEl = this.wrap.createChild({ tag: 'div' });
50014 this.viewEl.applyStyles(style);
50017 this.viewEl.setWidth(this.width);
50020 this.viewEl.setHeight(this.height);
50022 //if(this.inputValue !== undefined){
50023 //this.setValue(this.value);
50026 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
50029 this.grid.render();
50030 this.grid.getDataSource().on('remove', this.refreshValue, this);
50031 this.grid.getDataSource().on('update', this.refreshValue, this);
50032 this.grid.on('afteredit', this.refreshValue, this);
50038 * Sets the value of the item.
50039 * @param {String} either an object or a string..
50041 setValue : function(v){
50043 v = v || []; // empty set..
50044 // this does not seem smart - it really only affects memoryproxy grids..
50045 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
50046 var ds = this.grid.getDataSource();
50047 // assumes a json reader..
50049 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
50050 ds.loadData( data);
50052 // clear selection so it does not get stale.
50053 if (this.grid.sm) {
50054 this.grid.sm.clearSelections();
50057 Roo.form.GridField.superclass.setValue.call(this, v);
50058 this.refreshValue();
50059 // should load data in the grid really....
50063 refreshValue: function() {
50065 this.grid.getDataSource().each(function(r) {
50068 this.el.dom.value = Roo.encode(val);
50076 * Ext JS Library 1.1.1
50077 * Copyright(c) 2006-2007, Ext JS, LLC.
50079 * Originally Released Under LGPL - original licence link has changed is not relivant.
50082 * <script type="text/javascript">
50085 * @class Roo.form.DisplayField
50086 * @extends Roo.form.Field
50087 * A generic Field to display non-editable data.
50088 * @cfg {Boolean} closable (true|false) default false
50090 * Creates a new Display Field item.
50091 * @param {Object} config Configuration options
50093 Roo.form.DisplayField = function(config){
50094 Roo.form.DisplayField.superclass.constructor.call(this, config);
50099 * Fires after the click the close btn
50100 * @param {Roo.form.DisplayField} this
50106 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50107 inputType: 'hidden',
50113 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50115 focusClass : undefined,
50117 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50119 fieldClass: 'x-form-field',
50122 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50124 valueRenderer: undefined,
50128 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50129 * {tag: "input", type: "checkbox", autocomplete: "off"})
50132 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50136 onResize : function(){
50137 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50141 initEvents : function(){
50142 // Roo.form.Checkbox.superclass.initEvents.call(this);
50143 // has no events...
50146 this.closeEl.on('click', this.onClose, this);
50152 getResizeEl : function(){
50156 getPositionEl : function(){
50161 onRender : function(ct, position){
50163 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50164 //if(this.inputValue !== undefined){
50165 this.wrap = this.el.wrap();
50167 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50170 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50173 if (this.bodyStyle) {
50174 this.viewEl.applyStyles(this.bodyStyle);
50176 //this.viewEl.setStyle('padding', '2px');
50178 this.setValue(this.value);
50183 initValue : Roo.emptyFn,
50188 onClick : function(){
50193 * Sets the checked state of the checkbox.
50194 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50196 setValue : function(v){
50198 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50199 // this might be called before we have a dom element..
50200 if (!this.viewEl) {
50203 this.viewEl.dom.innerHTML = html;
50204 Roo.form.DisplayField.superclass.setValue.call(this, v);
50208 onClose : function(e)
50210 e.preventDefault();
50212 this.fireEvent('close', this);
50221 * @class Roo.form.DayPicker
50222 * @extends Roo.form.Field
50223 * A Day picker show [M] [T] [W] ....
50225 * Creates a new Day Picker
50226 * @param {Object} config Configuration options
50228 Roo.form.DayPicker= function(config){
50229 Roo.form.DayPicker.superclass.constructor.call(this, config);
50233 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50235 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50237 focusClass : undefined,
50239 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50241 fieldClass: "x-form-field",
50244 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50245 * {tag: "input", type: "checkbox", autocomplete: "off"})
50247 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50250 actionMode : 'viewEl',
50254 inputType : 'hidden',
50257 inputElement: false, // real input element?
50258 basedOn: false, // ????
50260 isFormField: true, // not sure where this is needed!!!!
50262 onResize : function(){
50263 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50264 if(!this.boxLabel){
50265 this.el.alignTo(this.wrap, 'c-c');
50269 initEvents : function(){
50270 Roo.form.Checkbox.superclass.initEvents.call(this);
50271 this.el.on("click", this.onClick, this);
50272 this.el.on("change", this.onClick, this);
50276 getResizeEl : function(){
50280 getPositionEl : function(){
50286 onRender : function(ct, position){
50287 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50289 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50291 var r1 = '<table><tr>';
50292 var r2 = '<tr class="x-form-daypick-icons">';
50293 for (var i=0; i < 7; i++) {
50294 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50295 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50298 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50299 viewEl.select('img').on('click', this.onClick, this);
50300 this.viewEl = viewEl;
50303 // this will not work on Chrome!!!
50304 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50305 this.el.on('propertychange', this.setFromHidden, this); //ie
50313 initValue : Roo.emptyFn,
50316 * Returns the checked state of the checkbox.
50317 * @return {Boolean} True if checked, else false
50319 getValue : function(){
50320 return this.el.dom.value;
50325 onClick : function(e){
50326 //this.setChecked(!this.checked);
50327 Roo.get(e.target).toggleClass('x-menu-item-checked');
50328 this.refreshValue();
50329 //if(this.el.dom.checked != this.checked){
50330 // this.setValue(this.el.dom.checked);
50335 refreshValue : function()
50338 this.viewEl.select('img',true).each(function(e,i,n) {
50339 val += e.is(".x-menu-item-checked") ? String(n) : '';
50341 this.setValue(val, true);
50345 * Sets the checked state of the checkbox.
50346 * On is always based on a string comparison between inputValue and the param.
50347 * @param {Boolean/String} value - the value to set
50348 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50350 setValue : function(v,suppressEvent){
50351 if (!this.el.dom) {
50354 var old = this.el.dom.value ;
50355 this.el.dom.value = v;
50356 if (suppressEvent) {
50360 // update display..
50361 this.viewEl.select('img',true).each(function(e,i,n) {
50363 var on = e.is(".x-menu-item-checked");
50364 var newv = v.indexOf(String(n)) > -1;
50366 e.toggleClass('x-menu-item-checked');
50372 this.fireEvent('change', this, v, old);
50377 // handle setting of hidden value by some other method!!?!?
50378 setFromHidden: function()
50383 //console.log("SET FROM HIDDEN");
50384 //alert('setFrom hidden');
50385 this.setValue(this.el.dom.value);
50388 onDestroy : function()
50391 Roo.get(this.viewEl).remove();
50394 Roo.form.DayPicker.superclass.onDestroy.call(this);
50398 * RooJS Library 1.1.1
50399 * Copyright(c) 2008-2011 Alan Knowles
50406 * @class Roo.form.ComboCheck
50407 * @extends Roo.form.ComboBox
50408 * A combobox for multiple select items.
50410 * FIXME - could do with a reset button..
50413 * Create a new ComboCheck
50414 * @param {Object} config Configuration options
50416 Roo.form.ComboCheck = function(config){
50417 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50418 // should verify some data...
50420 // hiddenName = required..
50421 // displayField = required
50422 // valudField == required
50423 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50425 Roo.each(req, function(e) {
50426 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50427 throw "Roo.form.ComboCheck : missing value for: " + e;
50434 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50439 selectedClass: 'x-menu-item-checked',
50442 onRender : function(ct, position){
50448 var cls = 'x-combo-list';
50451 this.tpl = new Roo.Template({
50452 html : '<div class="'+cls+'-item x-menu-check-item">' +
50453 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50454 '<span>{' + this.displayField + '}</span>' +
50461 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50462 this.view.singleSelect = false;
50463 this.view.multiSelect = true;
50464 this.view.toggleSelect = true;
50465 this.pageTb.add(new Roo.Toolbar.Fill(), {
50468 handler: function()
50475 onViewOver : function(e, t){
50481 onViewClick : function(doFocus,index){
50485 select: function () {
50486 //Roo.log("SELECT CALLED");
50489 selectByValue : function(xv, scrollIntoView){
50490 var ar = this.getValueArray();
50493 Roo.each(ar, function(v) {
50494 if(v === undefined || v === null){
50497 var r = this.findRecord(this.valueField, v);
50499 sels.push(this.store.indexOf(r))
50503 this.view.select(sels);
50509 onSelect : function(record, index){
50510 // Roo.log("onselect Called");
50511 // this is only called by the clear button now..
50512 this.view.clearSelections();
50513 this.setValue('[]');
50514 if (this.value != this.valueBefore) {
50515 this.fireEvent('change', this, this.value, this.valueBefore);
50516 this.valueBefore = this.value;
50519 getValueArray : function()
50524 //Roo.log(this.value);
50525 if (typeof(this.value) == 'undefined') {
50528 var ar = Roo.decode(this.value);
50529 return ar instanceof Array ? ar : []; //?? valid?
50532 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50537 expand : function ()
50540 Roo.form.ComboCheck.superclass.expand.call(this);
50541 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50542 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50547 collapse : function(){
50548 Roo.form.ComboCheck.superclass.collapse.call(this);
50549 var sl = this.view.getSelectedIndexes();
50550 var st = this.store;
50554 Roo.each(sl, function(i) {
50556 nv.push(r.get(this.valueField));
50558 this.setValue(Roo.encode(nv));
50559 if (this.value != this.valueBefore) {
50561 this.fireEvent('change', this, this.value, this.valueBefore);
50562 this.valueBefore = this.value;
50567 setValue : function(v){
50571 var vals = this.getValueArray();
50573 Roo.each(vals, function(k) {
50574 var r = this.findRecord(this.valueField, k);
50576 tv.push(r.data[this.displayField]);
50577 }else if(this.valueNotFoundText !== undefined){
50578 tv.push( this.valueNotFoundText );
50583 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50584 this.hiddenField.value = v;
50590 * Ext JS Library 1.1.1
50591 * Copyright(c) 2006-2007, Ext JS, LLC.
50593 * Originally Released Under LGPL - original licence link has changed is not relivant.
50596 * <script type="text/javascript">
50600 * @class Roo.form.Signature
50601 * @extends Roo.form.Field
50605 * @param {Object} config Configuration options
50608 Roo.form.Signature = function(config){
50609 Roo.form.Signature.superclass.constructor.call(this, config);
50611 this.addEvents({// not in used??
50614 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50615 * @param {Roo.form.Signature} combo This combo box
50620 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50621 * @param {Roo.form.ComboBox} combo This combo box
50622 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50628 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50630 * @cfg {Object} labels Label to use when rendering a form.
50634 * confirm : "Confirm"
50639 confirm : "Confirm"
50642 * @cfg {Number} width The signature panel width (defaults to 300)
50646 * @cfg {Number} height The signature panel height (defaults to 100)
50650 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50652 allowBlank : false,
50655 // {Object} signPanel The signature SVG panel element (defaults to {})
50657 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50658 isMouseDown : false,
50659 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50660 isConfirmed : false,
50661 // {String} signatureTmp SVG mapping string (defaults to empty string)
50665 defaultAutoCreate : { // modified by initCompnoent..
50671 onRender : function(ct, position){
50673 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50675 this.wrap = this.el.wrap({
50676 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50679 this.createToolbar(this);
50680 this.signPanel = this.wrap.createChild({
50682 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50686 this.svgID = Roo.id();
50687 this.svgEl = this.signPanel.createChild({
50688 xmlns : 'http://www.w3.org/2000/svg',
50690 id : this.svgID + "-svg",
50692 height: this.height,
50693 viewBox: '0 0 '+this.width+' '+this.height,
50697 id: this.svgID + "-svg-r",
50699 height: this.height,
50704 id: this.svgID + "-svg-l",
50706 y1: (this.height*0.8), // start set the line in 80% of height
50707 x2: this.width, // end
50708 y2: (this.height*0.8), // end set the line in 80% of height
50710 'stroke-width': "1",
50711 'stroke-dasharray': "3",
50712 'shape-rendering': "crispEdges",
50713 'pointer-events': "none"
50717 id: this.svgID + "-svg-p",
50719 'stroke-width': "3",
50721 'pointer-events': 'none'
50726 this.svgBox = this.svgEl.dom.getScreenCTM();
50728 createSVG : function(){
50729 var svg = this.signPanel;
50730 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50733 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50734 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50735 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50736 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50737 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50738 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50739 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50742 isTouchEvent : function(e){
50743 return e.type.match(/^touch/);
50745 getCoords : function (e) {
50746 var pt = this.svgEl.dom.createSVGPoint();
50749 if (this.isTouchEvent(e)) {
50750 pt.x = e.targetTouches[0].clientX;
50751 pt.y = e.targetTouches[0].clientY;
50753 var a = this.svgEl.dom.getScreenCTM();
50754 var b = a.inverse();
50755 var mx = pt.matrixTransform(b);
50756 return mx.x + ',' + mx.y;
50758 //mouse event headler
50759 down : function (e) {
50760 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50761 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50763 this.isMouseDown = true;
50765 e.preventDefault();
50767 move : function (e) {
50768 if (this.isMouseDown) {
50769 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50770 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50773 e.preventDefault();
50775 up : function (e) {
50776 this.isMouseDown = false;
50777 var sp = this.signatureTmp.split(' ');
50780 if(!sp[sp.length-2].match(/^L/)){
50784 this.signatureTmp = sp.join(" ");
50787 if(this.getValue() != this.signatureTmp){
50788 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50789 this.isConfirmed = false;
50791 e.preventDefault();
50795 * Protected method that will not generally be called directly. It
50796 * is called when the editor creates its toolbar. Override this method if you need to
50797 * add custom toolbar buttons.
50798 * @param {HtmlEditor} editor
50800 createToolbar : function(editor){
50801 function btn(id, toggle, handler){
50802 var xid = fid + '-'+ id ;
50806 cls : 'x-btn-icon x-edit-'+id,
50807 enableToggle:toggle !== false,
50808 scope: editor, // was editor...
50809 handler:handler||editor.relayBtnCmd,
50810 clickEvent:'mousedown',
50811 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50817 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50821 cls : ' x-signature-btn x-signature-'+id,
50822 scope: editor, // was editor...
50823 handler: this.reset,
50824 clickEvent:'mousedown',
50825 text: this.labels.clear
50832 cls : ' x-signature-btn x-signature-'+id,
50833 scope: editor, // was editor...
50834 handler: this.confirmHandler,
50835 clickEvent:'mousedown',
50836 text: this.labels.confirm
50843 * when user is clicked confirm then show this image.....
50845 * @return {String} Image Data URI
50847 getImageDataURI : function(){
50848 var svg = this.svgEl.dom.parentNode.innerHTML;
50849 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50854 * @return {Boolean} this.isConfirmed
50856 getConfirmed : function(){
50857 return this.isConfirmed;
50861 * @return {Number} this.width
50863 getWidth : function(){
50868 * @return {Number} this.height
50870 getHeight : function(){
50871 return this.height;
50874 getSignature : function(){
50875 return this.signatureTmp;
50878 reset : function(){
50879 this.signatureTmp = '';
50880 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50881 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
50882 this.isConfirmed = false;
50883 Roo.form.Signature.superclass.reset.call(this);
50885 setSignature : function(s){
50886 this.signatureTmp = s;
50887 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50888 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
50890 this.isConfirmed = false;
50891 Roo.form.Signature.superclass.reset.call(this);
50894 // Roo.log(this.signPanel.dom.contentWindow.up())
50897 setConfirmed : function(){
50901 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
50904 confirmHandler : function(){
50905 if(!this.getSignature()){
50909 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
50910 this.setValue(this.getSignature());
50911 this.isConfirmed = true;
50913 this.fireEvent('confirm', this);
50916 // Subclasses should provide the validation implementation by overriding this
50917 validateValue : function(value){
50918 if(this.allowBlank){
50922 if(this.isConfirmed){
50929 * Ext JS Library 1.1.1
50930 * Copyright(c) 2006-2007, Ext JS, LLC.
50932 * Originally Released Under LGPL - original licence link has changed is not relivant.
50935 * <script type="text/javascript">
50940 * @class Roo.form.ComboBox
50941 * @extends Roo.form.TriggerField
50942 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
50944 * Create a new ComboBox.
50945 * @param {Object} config Configuration options
50947 Roo.form.Select = function(config){
50948 Roo.form.Select.superclass.constructor.call(this, config);
50952 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
50954 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
50957 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
50958 * rendering into an Roo.Editor, defaults to false)
50961 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
50962 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
50965 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
50968 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
50969 * the dropdown list (defaults to undefined, with no header element)
50973 * @cfg {String/Roo.Template} tpl The template to use to render the output
50977 defaultAutoCreate : {tag: "select" },
50979 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
50981 listWidth: undefined,
50983 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
50984 * mode = 'remote' or 'text' if mode = 'local')
50986 displayField: undefined,
50988 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
50989 * mode = 'remote' or 'value' if mode = 'local').
50990 * Note: use of a valueField requires the user make a selection
50991 * in order for a value to be mapped.
50993 valueField: undefined,
50997 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
50998 * field's data value (defaults to the underlying DOM element's name)
51000 hiddenName: undefined,
51002 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
51006 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
51008 selectedClass: 'x-combo-selected',
51010 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
51011 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
51012 * which displays a downward arrow icon).
51014 triggerClass : 'x-form-arrow-trigger',
51016 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
51020 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
51021 * anchor positions (defaults to 'tl-bl')
51023 listAlign: 'tl-bl?',
51025 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
51029 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
51030 * query specified by the allQuery config option (defaults to 'query')
51032 triggerAction: 'query',
51034 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
51035 * (defaults to 4, does not apply if editable = false)
51039 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
51040 * delay (typeAheadDelay) if it matches a known value (defaults to false)
51044 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
51045 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
51049 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
51050 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
51054 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
51055 * when editable = true (defaults to false)
51057 selectOnFocus:false,
51059 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
51061 queryParam: 'query',
51063 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
51064 * when mode = 'remote' (defaults to 'Loading...')
51066 loadingText: 'Loading...',
51068 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
51072 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
51076 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
51077 * traditional select (defaults to true)
51081 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
51085 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
51089 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
51090 * listWidth has a higher value)
51094 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
51095 * allow the user to set arbitrary text into the field (defaults to false)
51097 forceSelection:false,
51099 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
51100 * if typeAhead = true (defaults to 250)
51102 typeAheadDelay : 250,
51104 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
51105 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51107 valueNotFoundText : undefined,
51110 * @cfg {String} defaultValue The value displayed after loading the store.
51115 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51117 blockFocus : false,
51120 * @cfg {Boolean} disableClear Disable showing of clear button.
51122 disableClear : false,
51124 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51126 alwaysQuery : false,
51132 // element that contains real text value.. (when hidden is used..)
51135 onRender : function(ct, position){
51136 Roo.form.Field.prototype.onRender.call(this, ct, position);
51139 this.store.on('beforeload', this.onBeforeLoad, this);
51140 this.store.on('load', this.onLoad, this);
51141 this.store.on('loadexception', this.onLoadException, this);
51142 this.store.load({});
51150 initEvents : function(){
51151 //Roo.form.ComboBox.superclass.initEvents.call(this);
51155 onDestroy : function(){
51158 this.store.un('beforeload', this.onBeforeLoad, this);
51159 this.store.un('load', this.onLoad, this);
51160 this.store.un('loadexception', this.onLoadException, this);
51162 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51166 fireKey : function(e){
51167 if(e.isNavKeyPress() && !this.list.isVisible()){
51168 this.fireEvent("specialkey", this, e);
51173 onResize: function(w, h){
51181 * Allow or prevent the user from directly editing the field text. If false is passed,
51182 * the user will only be able to select from the items defined in the dropdown list. This method
51183 * is the runtime equivalent of setting the 'editable' config option at config time.
51184 * @param {Boolean} value True to allow the user to directly edit the field text
51186 setEditable : function(value){
51191 onBeforeLoad : function(){
51193 Roo.log("Select before load");
51196 this.innerList.update(this.loadingText ?
51197 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51198 //this.restrictHeight();
51199 this.selectedIndex = -1;
51203 onLoad : function(){
51206 var dom = this.el.dom;
51207 dom.innerHTML = '';
51208 var od = dom.ownerDocument;
51210 if (this.emptyText) {
51211 var op = od.createElement('option');
51212 op.setAttribute('value', '');
51213 op.innerHTML = String.format('{0}', this.emptyText);
51214 dom.appendChild(op);
51216 if(this.store.getCount() > 0){
51218 var vf = this.valueField;
51219 var df = this.displayField;
51220 this.store.data.each(function(r) {
51221 // which colmsn to use... testing - cdoe / title..
51222 var op = od.createElement('option');
51223 op.setAttribute('value', r.data[vf]);
51224 op.innerHTML = String.format('{0}', r.data[df]);
51225 dom.appendChild(op);
51227 if (typeof(this.defaultValue != 'undefined')) {
51228 this.setValue(this.defaultValue);
51233 //this.onEmptyResults();
51238 onLoadException : function()
51240 dom.innerHTML = '';
51242 Roo.log("Select on load exception");
51246 Roo.log(this.store.reader.jsonData);
51247 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51248 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51254 onTypeAhead : function(){
51259 onSelect : function(record, index){
51260 Roo.log('on select?');
51262 if(this.fireEvent('beforeselect', this, record, index) !== false){
51263 this.setFromData(index > -1 ? record.data : false);
51265 this.fireEvent('select', this, record, index);
51270 * Returns the currently selected field value or empty string if no value is set.
51271 * @return {String} value The selected value
51273 getValue : function(){
51274 var dom = this.el.dom;
51275 this.value = dom.options[dom.selectedIndex].value;
51281 * Clears any text/value currently set in the field
51283 clearValue : function(){
51285 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51290 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51291 * will be displayed in the field. If the value does not match the data value of an existing item,
51292 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51293 * Otherwise the field will be blank (although the value will still be set).
51294 * @param {String} value The value to match
51296 setValue : function(v){
51297 var d = this.el.dom;
51298 for (var i =0; i < d.options.length;i++) {
51299 if (v == d.options[i].value) {
51300 d.selectedIndex = i;
51308 * @property {Object} the last set data for the element
51313 * Sets the value of the field based on a object which is related to the record format for the store.
51314 * @param {Object} value the value to set as. or false on reset?
51316 setFromData : function(o){
51317 Roo.log('setfrom data?');
51323 reset : function(){
51327 findRecord : function(prop, value){
51332 if(this.store.getCount() > 0){
51333 this.store.each(function(r){
51334 if(r.data[prop] == value){
51344 getName: function()
51346 // returns hidden if it's set..
51347 if (!this.rendered) {return ''};
51348 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51356 onEmptyResults : function(){
51357 Roo.log('empty results');
51362 * Returns true if the dropdown list is expanded, else false.
51364 isExpanded : function(){
51369 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51370 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51371 * @param {String} value The data value of the item to select
51372 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51373 * selected item if it is not currently in view (defaults to true)
51374 * @return {Boolean} True if the value matched an item in the list, else false
51376 selectByValue : function(v, scrollIntoView){
51377 Roo.log('select By Value');
51380 if(v !== undefined && v !== null){
51381 var r = this.findRecord(this.valueField || this.displayField, v);
51383 this.select(this.store.indexOf(r), scrollIntoView);
51391 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51392 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51393 * @param {Number} index The zero-based index of the list item to select
51394 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51395 * selected item if it is not currently in view (defaults to true)
51397 select : function(index, scrollIntoView){
51398 Roo.log('select ');
51401 this.selectedIndex = index;
51402 this.view.select(index);
51403 if(scrollIntoView !== false){
51404 var el = this.view.getNode(index);
51406 this.innerList.scrollChildIntoView(el, false);
51414 validateBlur : function(){
51421 initQuery : function(){
51422 this.doQuery(this.getRawValue());
51426 doForce : function(){
51427 if(this.el.dom.value.length > 0){
51428 this.el.dom.value =
51429 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51435 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51436 * query allowing the query action to be canceled if needed.
51437 * @param {String} query The SQL query to execute
51438 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51439 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51440 * saved in the current store (defaults to false)
51442 doQuery : function(q, forceAll){
51444 Roo.log('doQuery?');
51445 if(q === undefined || q === null){
51450 forceAll: forceAll,
51454 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51458 forceAll = qe.forceAll;
51459 if(forceAll === true || (q.length >= this.minChars)){
51460 if(this.lastQuery != q || this.alwaysQuery){
51461 this.lastQuery = q;
51462 if(this.mode == 'local'){
51463 this.selectedIndex = -1;
51465 this.store.clearFilter();
51467 this.store.filter(this.displayField, q);
51471 this.store.baseParams[this.queryParam] = q;
51473 params: this.getParams(q)
51478 this.selectedIndex = -1;
51485 getParams : function(q){
51487 //p[this.queryParam] = q;
51490 p.limit = this.pageSize;
51496 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51498 collapse : function(){
51503 collapseIf : function(e){
51508 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51510 expand : function(){
51518 * @cfg {Boolean} grow
51522 * @cfg {Number} growMin
51526 * @cfg {Number} growMax
51534 setWidth : function()
51538 getResizeEl : function(){
51541 });//<script type="text/javasscript">
51545 * @class Roo.DDView
51546 * A DnD enabled version of Roo.View.
51547 * @param {Element/String} container The Element in which to create the View.
51548 * @param {String} tpl The template string used to create the markup for each element of the View
51549 * @param {Object} config The configuration properties. These include all the config options of
51550 * {@link Roo.View} plus some specific to this class.<br>
51552 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51553 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51555 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51556 .x-view-drag-insert-above {
51557 border-top:1px dotted #3366cc;
51559 .x-view-drag-insert-below {
51560 border-bottom:1px dotted #3366cc;
51566 Roo.DDView = function(container, tpl, config) {
51567 Roo.DDView.superclass.constructor.apply(this, arguments);
51568 this.getEl().setStyle("outline", "0px none");
51569 this.getEl().unselectable();
51570 if (this.dragGroup) {
51571 this.setDraggable(this.dragGroup.split(","));
51573 if (this.dropGroup) {
51574 this.setDroppable(this.dropGroup.split(","));
51576 if (this.deletable) {
51577 this.setDeletable();
51579 this.isDirtyFlag = false;
51585 Roo.extend(Roo.DDView, Roo.View, {
51586 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51587 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51588 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51589 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51593 reset: Roo.emptyFn,
51595 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51597 validate: function() {
51601 destroy: function() {
51602 this.purgeListeners();
51603 this.getEl.removeAllListeners();
51604 this.getEl().remove();
51605 if (this.dragZone) {
51606 if (this.dragZone.destroy) {
51607 this.dragZone.destroy();
51610 if (this.dropZone) {
51611 if (this.dropZone.destroy) {
51612 this.dropZone.destroy();
51617 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51618 getName: function() {
51622 /** Loads the View from a JSON string representing the Records to put into the Store. */
51623 setValue: function(v) {
51625 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51628 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51629 this.store.proxy = new Roo.data.MemoryProxy(data);
51633 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51634 getValue: function() {
51636 this.store.each(function(rec) {
51637 result += rec.id + ',';
51639 return result.substr(0, result.length - 1) + ')';
51642 getIds: function() {
51643 var i = 0, result = new Array(this.store.getCount());
51644 this.store.each(function(rec) {
51645 result[i++] = rec.id;
51650 isDirty: function() {
51651 return this.isDirtyFlag;
51655 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51656 * whole Element becomes the target, and this causes the drop gesture to append.
51658 getTargetFromEvent : function(e) {
51659 var target = e.getTarget();
51660 while ((target !== null) && (target.parentNode != this.el.dom)) {
51661 target = target.parentNode;
51664 target = this.el.dom.lastChild || this.el.dom;
51670 * Create the drag data which consists of an object which has the property "ddel" as
51671 * the drag proxy element.
51673 getDragData : function(e) {
51674 var target = this.findItemFromChild(e.getTarget());
51676 this.handleSelection(e);
51677 var selNodes = this.getSelectedNodes();
51680 copy: this.copy || (this.allowCopy && e.ctrlKey),
51684 var selectedIndices = this.getSelectedIndexes();
51685 for (var i = 0; i < selectedIndices.length; i++) {
51686 dragData.records.push(this.store.getAt(selectedIndices[i]));
51688 if (selNodes.length == 1) {
51689 dragData.ddel = target.cloneNode(true); // the div element
51691 var div = document.createElement('div'); // create the multi element drag "ghost"
51692 div.className = 'multi-proxy';
51693 for (var i = 0, len = selNodes.length; i < len; i++) {
51694 div.appendChild(selNodes[i].cloneNode(true));
51696 dragData.ddel = div;
51698 //console.log(dragData)
51699 //console.log(dragData.ddel.innerHTML)
51702 //console.log('nodragData')
51706 /** Specify to which ddGroup items in this DDView may be dragged. */
51707 setDraggable: function(ddGroup) {
51708 if (ddGroup instanceof Array) {
51709 Roo.each(ddGroup, this.setDraggable, this);
51712 if (this.dragZone) {
51713 this.dragZone.addToGroup(ddGroup);
51715 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51716 containerScroll: true,
51720 // Draggability implies selection. DragZone's mousedown selects the element.
51721 if (!this.multiSelect) { this.singleSelect = true; }
51723 // Wire the DragZone's handlers up to methods in *this*
51724 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51728 /** Specify from which ddGroup this DDView accepts drops. */
51729 setDroppable: function(ddGroup) {
51730 if (ddGroup instanceof Array) {
51731 Roo.each(ddGroup, this.setDroppable, this);
51734 if (this.dropZone) {
51735 this.dropZone.addToGroup(ddGroup);
51737 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51738 containerScroll: true,
51742 // Wire the DropZone's handlers up to methods in *this*
51743 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51744 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51745 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51746 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51747 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51751 /** Decide whether to drop above or below a View node. */
51752 getDropPoint : function(e, n, dd){
51753 if (n == this.el.dom) { return "above"; }
51754 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51755 var c = t + (b - t) / 2;
51756 var y = Roo.lib.Event.getPageY(e);
51764 onNodeEnter : function(n, dd, e, data){
51768 onNodeOver : function(n, dd, e, data){
51769 var pt = this.getDropPoint(e, n, dd);
51770 // set the insert point style on the target node
51771 var dragElClass = this.dropNotAllowed;
51774 if (pt == "above"){
51775 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51776 targetElClass = "x-view-drag-insert-above";
51778 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51779 targetElClass = "x-view-drag-insert-below";
51781 if (this.lastInsertClass != targetElClass){
51782 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51783 this.lastInsertClass = targetElClass;
51786 return dragElClass;
51789 onNodeOut : function(n, dd, e, data){
51790 this.removeDropIndicators(n);
51793 onNodeDrop : function(n, dd, e, data){
51794 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51797 var pt = this.getDropPoint(e, n, dd);
51798 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51799 if (pt == "below") { insertAt++; }
51800 for (var i = 0; i < data.records.length; i++) {
51801 var r = data.records[i];
51802 var dup = this.store.getById(r.id);
51803 if (dup && (dd != this.dragZone)) {
51804 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51807 this.store.insert(insertAt++, r.copy());
51809 data.source.isDirtyFlag = true;
51811 this.store.insert(insertAt++, r);
51813 this.isDirtyFlag = true;
51816 this.dragZone.cachedTarget = null;
51820 removeDropIndicators : function(n){
51822 Roo.fly(n).removeClass([
51823 "x-view-drag-insert-above",
51824 "x-view-drag-insert-below"]);
51825 this.lastInsertClass = "_noclass";
51830 * Utility method. Add a delete option to the DDView's context menu.
51831 * @param {String} imageUrl The URL of the "delete" icon image.
51833 setDeletable: function(imageUrl) {
51834 if (!this.singleSelect && !this.multiSelect) {
51835 this.singleSelect = true;
51837 var c = this.getContextMenu();
51838 this.contextMenu.on("itemclick", function(item) {
51841 this.remove(this.getSelectedIndexes());
51845 this.contextMenu.add({
51852 /** Return the context menu for this DDView. */
51853 getContextMenu: function() {
51854 if (!this.contextMenu) {
51855 // Create the View's context menu
51856 this.contextMenu = new Roo.menu.Menu({
51857 id: this.id + "-contextmenu"
51859 this.el.on("contextmenu", this.showContextMenu, this);
51861 return this.contextMenu;
51864 disableContextMenu: function() {
51865 if (this.contextMenu) {
51866 this.el.un("contextmenu", this.showContextMenu, this);
51870 showContextMenu: function(e, item) {
51871 item = this.findItemFromChild(e.getTarget());
51874 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51875 this.contextMenu.showAt(e.getXY());
51880 * Remove {@link Roo.data.Record}s at the specified indices.
51881 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
51883 remove: function(selectedIndices) {
51884 selectedIndices = [].concat(selectedIndices);
51885 for (var i = 0; i < selectedIndices.length; i++) {
51886 var rec = this.store.getAt(selectedIndices[i]);
51887 this.store.remove(rec);
51892 * Double click fires the event, but also, if this is draggable, and there is only one other
51893 * related DropZone, it transfers the selected node.
51895 onDblClick : function(e){
51896 var item = this.findItemFromChild(e.getTarget());
51898 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
51901 if (this.dragGroup) {
51902 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
51903 while (targets.indexOf(this.dropZone) > -1) {
51904 targets.remove(this.dropZone);
51906 if (targets.length == 1) {
51907 this.dragZone.cachedTarget = null;
51908 var el = Roo.get(targets[0].getEl());
51909 var box = el.getBox(true);
51910 targets[0].onNodeDrop(el.dom, {
51912 xy: [box.x, box.y + box.height - 1]
51913 }, null, this.getDragData(e));
51919 handleSelection: function(e) {
51920 this.dragZone.cachedTarget = null;
51921 var item = this.findItemFromChild(e.getTarget());
51923 this.clearSelections(true);
51926 if (item && (this.multiSelect || this.singleSelect)){
51927 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
51928 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
51929 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
51930 this.unselect(item);
51932 this.select(item, this.multiSelect && e.ctrlKey);
51933 this.lastSelection = item;
51938 onItemClick : function(item, index, e){
51939 if(this.fireEvent("beforeclick", this, index, item, e) === false){
51945 unselect : function(nodeInfo, suppressEvent){
51946 var node = this.getNode(nodeInfo);
51947 if(node && this.isSelected(node)){
51948 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
51949 Roo.fly(node).removeClass(this.selectedClass);
51950 this.selections.remove(node);
51951 if(!suppressEvent){
51952 this.fireEvent("selectionchange", this, this.selections);
51960 * Ext JS Library 1.1.1
51961 * Copyright(c) 2006-2007, Ext JS, LLC.
51963 * Originally Released Under LGPL - original licence link has changed is not relivant.
51966 * <script type="text/javascript">
51970 * @class Roo.LayoutManager
51971 * @extends Roo.util.Observable
51972 * Base class for layout managers.
51974 Roo.LayoutManager = function(container, config){
51975 Roo.LayoutManager.superclass.constructor.call(this);
51976 this.el = Roo.get(container);
51977 // ie scrollbar fix
51978 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
51979 document.body.scroll = "no";
51980 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
51981 this.el.position('relative');
51983 this.id = this.el.id;
51984 this.el.addClass("x-layout-container");
51985 /** false to disable window resize monitoring @type Boolean */
51986 this.monitorWindowResize = true;
51991 * Fires when a layout is performed.
51992 * @param {Roo.LayoutManager} this
51996 * @event regionresized
51997 * Fires when the user resizes a region.
51998 * @param {Roo.LayoutRegion} region The resized region
51999 * @param {Number} newSize The new size (width for east/west, height for north/south)
52001 "regionresized" : true,
52003 * @event regioncollapsed
52004 * Fires when a region is collapsed.
52005 * @param {Roo.LayoutRegion} region The collapsed region
52007 "regioncollapsed" : true,
52009 * @event regionexpanded
52010 * Fires when a region is expanded.
52011 * @param {Roo.LayoutRegion} region The expanded region
52013 "regionexpanded" : true
52015 this.updating = false;
52016 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52019 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
52021 * Returns true if this layout is currently being updated
52022 * @return {Boolean}
52024 isUpdating : function(){
52025 return this.updating;
52029 * Suspend the LayoutManager from doing auto-layouts while
52030 * making multiple add or remove calls
52032 beginUpdate : function(){
52033 this.updating = true;
52037 * Restore auto-layouts and optionally disable the manager from performing a layout
52038 * @param {Boolean} noLayout true to disable a layout update
52040 endUpdate : function(noLayout){
52041 this.updating = false;
52047 layout: function(){
52051 onRegionResized : function(region, newSize){
52052 this.fireEvent("regionresized", region, newSize);
52056 onRegionCollapsed : function(region){
52057 this.fireEvent("regioncollapsed", region);
52060 onRegionExpanded : function(region){
52061 this.fireEvent("regionexpanded", region);
52065 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
52066 * performs box-model adjustments.
52067 * @return {Object} The size as an object {width: (the width), height: (the height)}
52069 getViewSize : function(){
52071 if(this.el.dom != document.body){
52072 size = this.el.getSize();
52074 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
52076 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
52077 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
52082 * Returns the Element this layout is bound to.
52083 * @return {Roo.Element}
52085 getEl : function(){
52090 * Returns the specified region.
52091 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
52092 * @return {Roo.LayoutRegion}
52094 getRegion : function(target){
52095 return this.regions[target.toLowerCase()];
52098 onWindowResize : function(){
52099 if(this.monitorWindowResize){
52105 * Ext JS Library 1.1.1
52106 * Copyright(c) 2006-2007, Ext JS, LLC.
52108 * Originally Released Under LGPL - original licence link has changed is not relivant.
52111 * <script type="text/javascript">
52114 * @class Roo.BorderLayout
52115 * @extends Roo.LayoutManager
52116 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52117 * please see: <br><br>
52118 * <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>
52119 * <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>
52122 var layout = new Roo.BorderLayout(document.body, {
52156 preferredTabWidth: 150
52161 var CP = Roo.ContentPanel;
52163 layout.beginUpdate();
52164 layout.add("north", new CP("north", "North"));
52165 layout.add("south", new CP("south", {title: "South", closable: true}));
52166 layout.add("west", new CP("west", {title: "West"}));
52167 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52168 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52169 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52170 layout.getRegion("center").showPanel("center1");
52171 layout.endUpdate();
52174 <b>The container the layout is rendered into can be either the body element or any other element.
52175 If it is not the body element, the container needs to either be an absolute positioned element,
52176 or you will need to add "position:relative" to the css of the container. You will also need to specify
52177 the container size if it is not the body element.</b>
52180 * Create a new BorderLayout
52181 * @param {String/HTMLElement/Element} container The container this layout is bound to
52182 * @param {Object} config Configuration options
52184 Roo.BorderLayout = function(container, config){
52185 config = config || {};
52186 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52187 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52188 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52189 var target = this.factory.validRegions[i];
52190 if(config[target]){
52191 this.addRegion(target, config[target]);
52196 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52198 * Creates and adds a new region if it doesn't already exist.
52199 * @param {String} target The target region key (north, south, east, west or center).
52200 * @param {Object} config The regions config object
52201 * @return {BorderLayoutRegion} The new region
52203 addRegion : function(target, config){
52204 if(!this.regions[target]){
52205 var r = this.factory.create(target, this, config);
52206 this.bindRegion(target, r);
52208 return this.regions[target];
52212 bindRegion : function(name, r){
52213 this.regions[name] = r;
52214 r.on("visibilitychange", this.layout, this);
52215 r.on("paneladded", this.layout, this);
52216 r.on("panelremoved", this.layout, this);
52217 r.on("invalidated", this.layout, this);
52218 r.on("resized", this.onRegionResized, this);
52219 r.on("collapsed", this.onRegionCollapsed, this);
52220 r.on("expanded", this.onRegionExpanded, this);
52224 * Performs a layout update.
52226 layout : function(){
52227 if(this.updating) {
52230 var size = this.getViewSize();
52231 var w = size.width;
52232 var h = size.height;
52237 //var x = 0, y = 0;
52239 var rs = this.regions;
52240 var north = rs["north"];
52241 var south = rs["south"];
52242 var west = rs["west"];
52243 var east = rs["east"];
52244 var center = rs["center"];
52245 //if(this.hideOnLayout){ // not supported anymore
52246 //c.el.setStyle("display", "none");
52248 if(north && north.isVisible()){
52249 var b = north.getBox();
52250 var m = north.getMargins();
52251 b.width = w - (m.left+m.right);
52254 centerY = b.height + b.y + m.bottom;
52255 centerH -= centerY;
52256 north.updateBox(this.safeBox(b));
52258 if(south && south.isVisible()){
52259 var b = south.getBox();
52260 var m = south.getMargins();
52261 b.width = w - (m.left+m.right);
52263 var totalHeight = (b.height + m.top + m.bottom);
52264 b.y = h - totalHeight + m.top;
52265 centerH -= totalHeight;
52266 south.updateBox(this.safeBox(b));
52268 if(west && west.isVisible()){
52269 var b = west.getBox();
52270 var m = west.getMargins();
52271 b.height = centerH - (m.top+m.bottom);
52273 b.y = centerY + m.top;
52274 var totalWidth = (b.width + m.left + m.right);
52275 centerX += totalWidth;
52276 centerW -= totalWidth;
52277 west.updateBox(this.safeBox(b));
52279 if(east && east.isVisible()){
52280 var b = east.getBox();
52281 var m = east.getMargins();
52282 b.height = centerH - (m.top+m.bottom);
52283 var totalWidth = (b.width + m.left + m.right);
52284 b.x = w - totalWidth + m.left;
52285 b.y = centerY + m.top;
52286 centerW -= totalWidth;
52287 east.updateBox(this.safeBox(b));
52290 var m = center.getMargins();
52292 x: centerX + m.left,
52293 y: centerY + m.top,
52294 width: centerW - (m.left+m.right),
52295 height: centerH - (m.top+m.bottom)
52297 //if(this.hideOnLayout){
52298 //center.el.setStyle("display", "block");
52300 center.updateBox(this.safeBox(centerBox));
52303 this.fireEvent("layout", this);
52307 safeBox : function(box){
52308 box.width = Math.max(0, box.width);
52309 box.height = Math.max(0, box.height);
52314 * Adds a ContentPanel (or subclass) to this layout.
52315 * @param {String} target The target region key (north, south, east, west or center).
52316 * @param {Roo.ContentPanel} panel The panel to add
52317 * @return {Roo.ContentPanel} The added panel
52319 add : function(target, panel){
52321 target = target.toLowerCase();
52322 return this.regions[target].add(panel);
52326 * Remove a ContentPanel (or subclass) to this layout.
52327 * @param {String} target The target region key (north, south, east, west or center).
52328 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52329 * @return {Roo.ContentPanel} The removed panel
52331 remove : function(target, panel){
52332 target = target.toLowerCase();
52333 return this.regions[target].remove(panel);
52337 * Searches all regions for a panel with the specified id
52338 * @param {String} panelId
52339 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52341 findPanel : function(panelId){
52342 var rs = this.regions;
52343 for(var target in rs){
52344 if(typeof rs[target] != "function"){
52345 var p = rs[target].getPanel(panelId);
52355 * Searches all regions for a panel with the specified id and activates (shows) it.
52356 * @param {String/ContentPanel} panelId The panels id or the panel itself
52357 * @return {Roo.ContentPanel} The shown panel or null
52359 showPanel : function(panelId) {
52360 var rs = this.regions;
52361 for(var target in rs){
52362 var r = rs[target];
52363 if(typeof r != "function"){
52364 if(r.hasPanel(panelId)){
52365 return r.showPanel(panelId);
52373 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52374 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52376 restoreState : function(provider){
52378 provider = Roo.state.Manager;
52380 var sm = new Roo.LayoutStateManager();
52381 sm.init(this, provider);
52385 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52386 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52387 * a valid ContentPanel config object. Example:
52389 // Create the main layout
52390 var layout = new Roo.BorderLayout('main-ct', {
52401 // Create and add multiple ContentPanels at once via configs
52404 id: 'source-files',
52406 title:'Ext Source Files',
52419 * @param {Object} regions An object containing ContentPanel configs by region name
52421 batchAdd : function(regions){
52422 this.beginUpdate();
52423 for(var rname in regions){
52424 var lr = this.regions[rname];
52426 this.addTypedPanels(lr, regions[rname]);
52433 addTypedPanels : function(lr, ps){
52434 if(typeof ps == 'string'){
52435 lr.add(new Roo.ContentPanel(ps));
52437 else if(ps instanceof Array){
52438 for(var i =0, len = ps.length; i < len; i++){
52439 this.addTypedPanels(lr, ps[i]);
52442 else if(!ps.events){ // raw config?
52444 delete ps.el; // prevent conflict
52445 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52447 else { // panel object assumed!
52452 * Adds a xtype elements to the layout.
52456 xtype : 'ContentPanel',
52463 xtype : 'NestedLayoutPanel',
52469 items : [ ... list of content panels or nested layout panels.. ]
52473 * @param {Object} cfg Xtype definition of item to add.
52475 addxtype : function(cfg)
52477 // basically accepts a pannel...
52478 // can accept a layout region..!?!?
52479 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52481 if (!cfg.xtype.match(/Panel$/)) {
52486 if (typeof(cfg.region) == 'undefined') {
52487 Roo.log("Failed to add Panel, region was not set");
52491 var region = cfg.region;
52497 xitems = cfg.items;
52504 case 'ContentPanel': // ContentPanel (el, cfg)
52505 case 'ScrollPanel': // ContentPanel (el, cfg)
52507 if(cfg.autoCreate) {
52508 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52510 var el = this.el.createChild();
52511 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52514 this.add(region, ret);
52518 case 'TreePanel': // our new panel!
52519 cfg.el = this.el.createChild();
52520 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52521 this.add(region, ret);
52524 case 'NestedLayoutPanel':
52525 // create a new Layout (which is a Border Layout...
52526 var el = this.el.createChild();
52527 var clayout = cfg.layout;
52529 clayout.items = clayout.items || [];
52530 // replace this exitems with the clayout ones..
52531 xitems = clayout.items;
52534 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52535 cfg.background = false;
52537 var layout = new Roo.BorderLayout(el, clayout);
52539 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52540 //console.log('adding nested layout panel ' + cfg.toSource());
52541 this.add(region, ret);
52542 nb = {}; /// find first...
52547 // needs grid and region
52549 //var el = this.getRegion(region).el.createChild();
52550 var el = this.el.createChild();
52551 // create the grid first...
52553 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52555 if (region == 'center' && this.active ) {
52556 cfg.background = false;
52558 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52560 this.add(region, ret);
52561 if (cfg.background) {
52562 ret.on('activate', function(gp) {
52563 if (!gp.grid.rendered) {
52578 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52580 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52581 this.add(region, ret);
52584 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52588 // GridPanel (grid, cfg)
52591 this.beginUpdate();
52595 Roo.each(xitems, function(i) {
52596 region = nb && i.region ? i.region : false;
52598 var add = ret.addxtype(i);
52601 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52602 if (!i.background) {
52603 abn[region] = nb[region] ;
52610 // make the last non-background panel active..
52611 //if (nb) { Roo.log(abn); }
52614 for(var r in abn) {
52615 region = this.getRegion(r);
52617 // tried using nb[r], but it does not work..
52619 region.showPanel(abn[r]);
52630 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52631 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52632 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52633 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52636 var CP = Roo.ContentPanel;
52638 var layout = Roo.BorderLayout.create({
52642 panels: [new CP("north", "North")]
52651 panels: [new CP("west", {title: "West"})]
52660 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52669 panels: [new CP("south", {title: "South", closable: true})]
52676 preferredTabWidth: 150,
52678 new CP("center1", {title: "Close Me", closable: true}),
52679 new CP("center2", {title: "Center Panel", closable: false})
52684 layout.getRegion("center").showPanel("center1");
52689 Roo.BorderLayout.create = function(config, targetEl){
52690 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52691 layout.beginUpdate();
52692 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52693 for(var j = 0, jlen = regions.length; j < jlen; j++){
52694 var lr = regions[j];
52695 if(layout.regions[lr] && config[lr].panels){
52696 var r = layout.regions[lr];
52697 var ps = config[lr].panels;
52698 layout.addTypedPanels(r, ps);
52701 layout.endUpdate();
52706 Roo.BorderLayout.RegionFactory = {
52708 validRegions : ["north","south","east","west","center"],
52711 create : function(target, mgr, config){
52712 target = target.toLowerCase();
52713 if(config.lightweight || config.basic){
52714 return new Roo.BasicLayoutRegion(mgr, config, target);
52718 return new Roo.NorthLayoutRegion(mgr, config);
52720 return new Roo.SouthLayoutRegion(mgr, config);
52722 return new Roo.EastLayoutRegion(mgr, config);
52724 return new Roo.WestLayoutRegion(mgr, config);
52726 return new Roo.CenterLayoutRegion(mgr, config);
52728 throw 'Layout region "'+target+'" not supported.';
52732 * Ext JS Library 1.1.1
52733 * Copyright(c) 2006-2007, Ext JS, LLC.
52735 * Originally Released Under LGPL - original licence link has changed is not relivant.
52738 * <script type="text/javascript">
52742 * @class Roo.BasicLayoutRegion
52743 * @extends Roo.util.Observable
52744 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52745 * and does not have a titlebar, tabs or any other features. All it does is size and position
52746 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52748 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52750 this.position = pos;
52753 * @scope Roo.BasicLayoutRegion
52757 * @event beforeremove
52758 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52759 * @param {Roo.LayoutRegion} this
52760 * @param {Roo.ContentPanel} panel The panel
52761 * @param {Object} e The cancel event object
52763 "beforeremove" : true,
52765 * @event invalidated
52766 * Fires when the layout for this region is changed.
52767 * @param {Roo.LayoutRegion} this
52769 "invalidated" : true,
52771 * @event visibilitychange
52772 * Fires when this region is shown or hidden
52773 * @param {Roo.LayoutRegion} this
52774 * @param {Boolean} visibility true or false
52776 "visibilitychange" : true,
52778 * @event paneladded
52779 * Fires when a panel is added.
52780 * @param {Roo.LayoutRegion} this
52781 * @param {Roo.ContentPanel} panel The panel
52783 "paneladded" : true,
52785 * @event panelremoved
52786 * Fires when a panel is removed.
52787 * @param {Roo.LayoutRegion} this
52788 * @param {Roo.ContentPanel} panel The panel
52790 "panelremoved" : true,
52792 * @event beforecollapse
52793 * Fires when this region before collapse.
52794 * @param {Roo.LayoutRegion} this
52796 "beforecollapse" : true,
52799 * Fires when this region is collapsed.
52800 * @param {Roo.LayoutRegion} this
52802 "collapsed" : true,
52805 * Fires when this region is expanded.
52806 * @param {Roo.LayoutRegion} this
52811 * Fires when this region is slid into view.
52812 * @param {Roo.LayoutRegion} this
52814 "slideshow" : true,
52817 * Fires when this region slides out of view.
52818 * @param {Roo.LayoutRegion} this
52820 "slidehide" : true,
52822 * @event panelactivated
52823 * Fires when a panel is activated.
52824 * @param {Roo.LayoutRegion} this
52825 * @param {Roo.ContentPanel} panel The activated panel
52827 "panelactivated" : true,
52830 * Fires when the user resizes this region.
52831 * @param {Roo.LayoutRegion} this
52832 * @param {Number} newSize The new size (width for east/west, height for north/south)
52836 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52837 this.panels = new Roo.util.MixedCollection();
52838 this.panels.getKey = this.getPanelId.createDelegate(this);
52840 this.activePanel = null;
52841 // ensure listeners are added...
52843 if (config.listeners || config.events) {
52844 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52845 listeners : config.listeners || {},
52846 events : config.events || {}
52850 if(skipConfig !== true){
52851 this.applyConfig(config);
52855 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52856 getPanelId : function(p){
52860 applyConfig : function(config){
52861 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52862 this.config = config;
52867 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
52868 * the width, for horizontal (north, south) the height.
52869 * @param {Number} newSize The new width or height
52871 resizeTo : function(newSize){
52872 var el = this.el ? this.el :
52873 (this.activePanel ? this.activePanel.getEl() : null);
52875 switch(this.position){
52878 el.setWidth(newSize);
52879 this.fireEvent("resized", this, newSize);
52883 el.setHeight(newSize);
52884 this.fireEvent("resized", this, newSize);
52890 getBox : function(){
52891 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
52894 getMargins : function(){
52895 return this.margins;
52898 updateBox : function(box){
52900 var el = this.activePanel.getEl();
52901 el.dom.style.left = box.x + "px";
52902 el.dom.style.top = box.y + "px";
52903 this.activePanel.setSize(box.width, box.height);
52907 * Returns the container element for this region.
52908 * @return {Roo.Element}
52910 getEl : function(){
52911 return this.activePanel;
52915 * Returns true if this region is currently visible.
52916 * @return {Boolean}
52918 isVisible : function(){
52919 return this.activePanel ? true : false;
52922 setActivePanel : function(panel){
52923 panel = this.getPanel(panel);
52924 if(this.activePanel && this.activePanel != panel){
52925 this.activePanel.setActiveState(false);
52926 this.activePanel.getEl().setLeftTop(-10000,-10000);
52928 this.activePanel = panel;
52929 panel.setActiveState(true);
52931 panel.setSize(this.box.width, this.box.height);
52933 this.fireEvent("panelactivated", this, panel);
52934 this.fireEvent("invalidated");
52938 * Show the specified panel.
52939 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
52940 * @return {Roo.ContentPanel} The shown panel or null
52942 showPanel : function(panel){
52943 if(panel = this.getPanel(panel)){
52944 this.setActivePanel(panel);
52950 * Get the active panel for this region.
52951 * @return {Roo.ContentPanel} The active panel or null
52953 getActivePanel : function(){
52954 return this.activePanel;
52958 * Add the passed ContentPanel(s)
52959 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52960 * @return {Roo.ContentPanel} The panel added (if only one was added)
52962 add : function(panel){
52963 if(arguments.length > 1){
52964 for(var i = 0, len = arguments.length; i < len; i++) {
52965 this.add(arguments[i]);
52969 if(this.hasPanel(panel)){
52970 this.showPanel(panel);
52973 var el = panel.getEl();
52974 if(el.dom.parentNode != this.mgr.el.dom){
52975 this.mgr.el.dom.appendChild(el.dom);
52977 if(panel.setRegion){
52978 panel.setRegion(this);
52980 this.panels.add(panel);
52981 el.setStyle("position", "absolute");
52982 if(!panel.background){
52983 this.setActivePanel(panel);
52984 if(this.config.initialSize && this.panels.getCount()==1){
52985 this.resizeTo(this.config.initialSize);
52988 this.fireEvent("paneladded", this, panel);
52993 * Returns true if the panel is in this region.
52994 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
52995 * @return {Boolean}
52997 hasPanel : function(panel){
52998 if(typeof panel == "object"){ // must be panel obj
52999 panel = panel.getId();
53001 return this.getPanel(panel) ? true : false;
53005 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53006 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53007 * @param {Boolean} preservePanel Overrides the config preservePanel option
53008 * @return {Roo.ContentPanel} The panel that was removed
53010 remove : function(panel, preservePanel){
53011 panel = this.getPanel(panel);
53016 this.fireEvent("beforeremove", this, panel, e);
53017 if(e.cancel === true){
53020 var panelId = panel.getId();
53021 this.panels.removeKey(panelId);
53026 * Returns the panel specified or null if it's not in this region.
53027 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53028 * @return {Roo.ContentPanel}
53030 getPanel : function(id){
53031 if(typeof id == "object"){ // must be panel obj
53034 return this.panels.get(id);
53038 * Returns this regions position (north/south/east/west/center).
53041 getPosition: function(){
53042 return this.position;
53046 * Ext JS Library 1.1.1
53047 * Copyright(c) 2006-2007, Ext JS, LLC.
53049 * Originally Released Under LGPL - original licence link has changed is not relivant.
53052 * <script type="text/javascript">
53056 * @class Roo.LayoutRegion
53057 * @extends Roo.BasicLayoutRegion
53058 * This class represents a region in a layout manager.
53059 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
53060 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
53061 * @cfg {Boolean} floatable False to disable floating (defaults to true)
53062 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
53063 * @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})
53064 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
53065 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
53066 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
53067 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
53068 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
53069 * @cfg {String} title The title for the region (overrides panel titles)
53070 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
53071 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
53072 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
53073 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
53074 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
53075 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
53076 * the space available, similar to FireFox 1.5 tabs (defaults to false)
53077 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
53078 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
53079 * @cfg {Boolean} showPin True to show a pin button
53080 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
53081 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
53082 * @cfg {Boolean} disableTabTips True to disable tab tooltips
53083 * @cfg {Number} width For East/West panels
53084 * @cfg {Number} height For North/South panels
53085 * @cfg {Boolean} split To show the splitter
53086 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
53088 Roo.LayoutRegion = function(mgr, config, pos){
53089 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
53090 var dh = Roo.DomHelper;
53091 /** This region's container element
53092 * @type Roo.Element */
53093 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
53094 /** This region's title element
53095 * @type Roo.Element */
53097 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
53098 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
53099 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
53101 this.titleEl.enableDisplayMode();
53102 /** This region's title text element
53103 * @type HTMLElement */
53104 this.titleTextEl = this.titleEl.dom.firstChild;
53105 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53106 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53107 this.closeBtn.enableDisplayMode();
53108 this.closeBtn.on("click", this.closeClicked, this);
53109 this.closeBtn.hide();
53111 this.createBody(config);
53112 this.visible = true;
53113 this.collapsed = false;
53115 if(config.hideWhenEmpty){
53117 this.on("paneladded", this.validateVisibility, this);
53118 this.on("panelremoved", this.validateVisibility, this);
53120 this.applyConfig(config);
53123 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53125 createBody : function(){
53126 /** This region's body element
53127 * @type Roo.Element */
53128 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53131 applyConfig : function(c){
53132 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53133 var dh = Roo.DomHelper;
53134 if(c.titlebar !== false){
53135 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53136 this.collapseBtn.on("click", this.collapse, this);
53137 this.collapseBtn.enableDisplayMode();
53139 if(c.showPin === true || this.showPin){
53140 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53141 this.stickBtn.enableDisplayMode();
53142 this.stickBtn.on("click", this.expand, this);
53143 this.stickBtn.hide();
53146 /** This region's collapsed element
53147 * @type Roo.Element */
53148 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53149 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53151 if(c.floatable !== false){
53152 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53153 this.collapsedEl.on("click", this.collapseClick, this);
53156 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53157 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53158 id: "message", unselectable: "on", style:{"float":"left"}});
53159 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53161 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53162 this.expandBtn.on("click", this.expand, this);
53164 if(this.collapseBtn){
53165 this.collapseBtn.setVisible(c.collapsible == true);
53167 this.cmargins = c.cmargins || this.cmargins ||
53168 (this.position == "west" || this.position == "east" ?
53169 {top: 0, left: 2, right:2, bottom: 0} :
53170 {top: 2, left: 0, right:0, bottom: 2});
53171 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53172 this.bottomTabs = c.tabPosition != "top";
53173 this.autoScroll = c.autoScroll || false;
53174 if(this.autoScroll){
53175 this.bodyEl.setStyle("overflow", "auto");
53177 this.bodyEl.setStyle("overflow", "hidden");
53179 //if(c.titlebar !== false){
53180 if((!c.titlebar && !c.title) || c.titlebar === false){
53181 this.titleEl.hide();
53183 this.titleEl.show();
53185 this.titleTextEl.innerHTML = c.title;
53189 this.duration = c.duration || .30;
53190 this.slideDuration = c.slideDuration || .45;
53193 this.collapse(true);
53200 * Returns true if this region is currently visible.
53201 * @return {Boolean}
53203 isVisible : function(){
53204 return this.visible;
53208 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53209 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53211 setCollapsedTitle : function(title){
53212 title = title || " ";
53213 if(this.collapsedTitleTextEl){
53214 this.collapsedTitleTextEl.innerHTML = title;
53218 getBox : function(){
53220 if(!this.collapsed){
53221 b = this.el.getBox(false, true);
53223 b = this.collapsedEl.getBox(false, true);
53228 getMargins : function(){
53229 return this.collapsed ? this.cmargins : this.margins;
53232 highlight : function(){
53233 this.el.addClass("x-layout-panel-dragover");
53236 unhighlight : function(){
53237 this.el.removeClass("x-layout-panel-dragover");
53240 updateBox : function(box){
53242 if(!this.collapsed){
53243 this.el.dom.style.left = box.x + "px";
53244 this.el.dom.style.top = box.y + "px";
53245 this.updateBody(box.width, box.height);
53247 this.collapsedEl.dom.style.left = box.x + "px";
53248 this.collapsedEl.dom.style.top = box.y + "px";
53249 this.collapsedEl.setSize(box.width, box.height);
53252 this.tabs.autoSizeTabs();
53256 updateBody : function(w, h){
53258 this.el.setWidth(w);
53259 w -= this.el.getBorderWidth("rl");
53260 if(this.config.adjustments){
53261 w += this.config.adjustments[0];
53265 this.el.setHeight(h);
53266 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53267 h -= this.el.getBorderWidth("tb");
53268 if(this.config.adjustments){
53269 h += this.config.adjustments[1];
53271 this.bodyEl.setHeight(h);
53273 h = this.tabs.syncHeight(h);
53276 if(this.panelSize){
53277 w = w !== null ? w : this.panelSize.width;
53278 h = h !== null ? h : this.panelSize.height;
53280 if(this.activePanel){
53281 var el = this.activePanel.getEl();
53282 w = w !== null ? w : el.getWidth();
53283 h = h !== null ? h : el.getHeight();
53284 this.panelSize = {width: w, height: h};
53285 this.activePanel.setSize(w, h);
53287 if(Roo.isIE && this.tabs){
53288 this.tabs.el.repaint();
53293 * Returns the container element for this region.
53294 * @return {Roo.Element}
53296 getEl : function(){
53301 * Hides this region.
53304 if(!this.collapsed){
53305 this.el.dom.style.left = "-2000px";
53308 this.collapsedEl.dom.style.left = "-2000px";
53309 this.collapsedEl.hide();
53311 this.visible = false;
53312 this.fireEvent("visibilitychange", this, false);
53316 * Shows this region if it was previously hidden.
53319 if(!this.collapsed){
53322 this.collapsedEl.show();
53324 this.visible = true;
53325 this.fireEvent("visibilitychange", this, true);
53328 closeClicked : function(){
53329 if(this.activePanel){
53330 this.remove(this.activePanel);
53334 collapseClick : function(e){
53336 e.stopPropagation();
53339 e.stopPropagation();
53345 * Collapses this region.
53346 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53348 collapse : function(skipAnim, skipCheck){
53349 if(this.collapsed) {
53353 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53355 this.collapsed = true;
53357 this.split.el.hide();
53359 if(this.config.animate && skipAnim !== true){
53360 this.fireEvent("invalidated", this);
53361 this.animateCollapse();
53363 this.el.setLocation(-20000,-20000);
53365 this.collapsedEl.show();
53366 this.fireEvent("collapsed", this);
53367 this.fireEvent("invalidated", this);
53373 animateCollapse : function(){
53378 * Expands this region if it was previously collapsed.
53379 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53380 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53382 expand : function(e, skipAnim){
53384 e.stopPropagation();
53386 if(!this.collapsed || this.el.hasActiveFx()) {
53390 this.afterSlideIn();
53393 this.collapsed = false;
53394 if(this.config.animate && skipAnim !== true){
53395 this.animateExpand();
53399 this.split.el.show();
53401 this.collapsedEl.setLocation(-2000,-2000);
53402 this.collapsedEl.hide();
53403 this.fireEvent("invalidated", this);
53404 this.fireEvent("expanded", this);
53408 animateExpand : function(){
53412 initTabs : function()
53414 this.bodyEl.setStyle("overflow", "hidden");
53415 var ts = new Roo.TabPanel(
53418 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53419 disableTooltips: this.config.disableTabTips,
53420 toolbar : this.config.toolbar
53423 if(this.config.hideTabs){
53424 ts.stripWrap.setDisplayed(false);
53427 ts.resizeTabs = this.config.resizeTabs === true;
53428 ts.minTabWidth = this.config.minTabWidth || 40;
53429 ts.maxTabWidth = this.config.maxTabWidth || 250;
53430 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53431 ts.monitorResize = false;
53432 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53433 ts.bodyEl.addClass('x-layout-tabs-body');
53434 this.panels.each(this.initPanelAsTab, this);
53437 initPanelAsTab : function(panel){
53438 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53439 this.config.closeOnTab && panel.isClosable());
53440 if(panel.tabTip !== undefined){
53441 ti.setTooltip(panel.tabTip);
53443 ti.on("activate", function(){
53444 this.setActivePanel(panel);
53446 if(this.config.closeOnTab){
53447 ti.on("beforeclose", function(t, e){
53449 this.remove(panel);
53455 updatePanelTitle : function(panel, title){
53456 if(this.activePanel == panel){
53457 this.updateTitle(title);
53460 var ti = this.tabs.getTab(panel.getEl().id);
53462 if(panel.tabTip !== undefined){
53463 ti.setTooltip(panel.tabTip);
53468 updateTitle : function(title){
53469 if(this.titleTextEl && !this.config.title){
53470 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53474 setActivePanel : function(panel){
53475 panel = this.getPanel(panel);
53476 if(this.activePanel && this.activePanel != panel){
53477 this.activePanel.setActiveState(false);
53479 this.activePanel = panel;
53480 panel.setActiveState(true);
53481 if(this.panelSize){
53482 panel.setSize(this.panelSize.width, this.panelSize.height);
53485 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53487 this.updateTitle(panel.getTitle());
53489 this.fireEvent("invalidated", this);
53491 this.fireEvent("panelactivated", this, panel);
53495 * Shows the specified panel.
53496 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53497 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53499 showPanel : function(panel)
53501 panel = this.getPanel(panel);
53504 var tab = this.tabs.getTab(panel.getEl().id);
53505 if(tab.isHidden()){
53506 this.tabs.unhideTab(tab.id);
53510 this.setActivePanel(panel);
53517 * Get the active panel for this region.
53518 * @return {Roo.ContentPanel} The active panel or null
53520 getActivePanel : function(){
53521 return this.activePanel;
53524 validateVisibility : function(){
53525 if(this.panels.getCount() < 1){
53526 this.updateTitle(" ");
53527 this.closeBtn.hide();
53530 if(!this.isVisible()){
53537 * Adds the passed ContentPanel(s) to this region.
53538 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53539 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53541 add : function(panel){
53542 if(arguments.length > 1){
53543 for(var i = 0, len = arguments.length; i < len; i++) {
53544 this.add(arguments[i]);
53548 if(this.hasPanel(panel)){
53549 this.showPanel(panel);
53552 panel.setRegion(this);
53553 this.panels.add(panel);
53554 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53555 this.bodyEl.dom.appendChild(panel.getEl().dom);
53556 if(panel.background !== true){
53557 this.setActivePanel(panel);
53559 this.fireEvent("paneladded", this, panel);
53565 this.initPanelAsTab(panel);
53567 if(panel.background !== true){
53568 this.tabs.activate(panel.getEl().id);
53570 this.fireEvent("paneladded", this, panel);
53575 * Hides the tab for the specified panel.
53576 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53578 hidePanel : function(panel){
53579 if(this.tabs && (panel = this.getPanel(panel))){
53580 this.tabs.hideTab(panel.getEl().id);
53585 * Unhides the tab for a previously hidden panel.
53586 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53588 unhidePanel : function(panel){
53589 if(this.tabs && (panel = this.getPanel(panel))){
53590 this.tabs.unhideTab(panel.getEl().id);
53594 clearPanels : function(){
53595 while(this.panels.getCount() > 0){
53596 this.remove(this.panels.first());
53601 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53602 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53603 * @param {Boolean} preservePanel Overrides the config preservePanel option
53604 * @return {Roo.ContentPanel} The panel that was removed
53606 remove : function(panel, preservePanel){
53607 panel = this.getPanel(panel);
53612 this.fireEvent("beforeremove", this, panel, e);
53613 if(e.cancel === true){
53616 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53617 var panelId = panel.getId();
53618 this.panels.removeKey(panelId);
53620 document.body.appendChild(panel.getEl().dom);
53623 this.tabs.removeTab(panel.getEl().id);
53624 }else if (!preservePanel){
53625 this.bodyEl.dom.removeChild(panel.getEl().dom);
53627 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53628 var p = this.panels.first();
53629 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53630 tempEl.appendChild(p.getEl().dom);
53631 this.bodyEl.update("");
53632 this.bodyEl.dom.appendChild(p.getEl().dom);
53634 this.updateTitle(p.getTitle());
53636 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53637 this.setActivePanel(p);
53639 panel.setRegion(null);
53640 if(this.activePanel == panel){
53641 this.activePanel = null;
53643 if(this.config.autoDestroy !== false && preservePanel !== true){
53644 try{panel.destroy();}catch(e){}
53646 this.fireEvent("panelremoved", this, panel);
53651 * Returns the TabPanel component used by this region
53652 * @return {Roo.TabPanel}
53654 getTabs : function(){
53658 createTool : function(parentEl, className){
53659 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53660 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53661 btn.addClassOnOver("x-layout-tools-button-over");
53666 * Ext JS Library 1.1.1
53667 * Copyright(c) 2006-2007, Ext JS, LLC.
53669 * Originally Released Under LGPL - original licence link has changed is not relivant.
53672 * <script type="text/javascript">
53678 * @class Roo.SplitLayoutRegion
53679 * @extends Roo.LayoutRegion
53680 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53682 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53683 this.cursor = cursor;
53684 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53687 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53688 splitTip : "Drag to resize.",
53689 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53690 useSplitTips : false,
53692 applyConfig : function(config){
53693 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53696 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53697 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53698 /** The SplitBar for this region
53699 * @type Roo.SplitBar */
53700 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53701 this.split.on("moved", this.onSplitMove, this);
53702 this.split.useShim = config.useShim === true;
53703 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53704 if(this.useSplitTips){
53705 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53707 if(config.collapsible){
53708 this.split.el.on("dblclick", this.collapse, this);
53711 if(typeof config.minSize != "undefined"){
53712 this.split.minSize = config.minSize;
53714 if(typeof config.maxSize != "undefined"){
53715 this.split.maxSize = config.maxSize;
53717 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53718 this.hideSplitter();
53723 getHMaxSize : function(){
53724 var cmax = this.config.maxSize || 10000;
53725 var center = this.mgr.getRegion("center");
53726 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53729 getVMaxSize : function(){
53730 var cmax = this.config.maxSize || 10000;
53731 var center = this.mgr.getRegion("center");
53732 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53735 onSplitMove : function(split, newSize){
53736 this.fireEvent("resized", this, newSize);
53740 * Returns the {@link Roo.SplitBar} for this region.
53741 * @return {Roo.SplitBar}
53743 getSplitBar : function(){
53748 this.hideSplitter();
53749 Roo.SplitLayoutRegion.superclass.hide.call(this);
53752 hideSplitter : function(){
53754 this.split.el.setLocation(-2000,-2000);
53755 this.split.el.hide();
53761 this.split.el.show();
53763 Roo.SplitLayoutRegion.superclass.show.call(this);
53766 beforeSlide: function(){
53767 if(Roo.isGecko){// firefox overflow auto bug workaround
53768 this.bodyEl.clip();
53770 this.tabs.bodyEl.clip();
53772 if(this.activePanel){
53773 this.activePanel.getEl().clip();
53775 if(this.activePanel.beforeSlide){
53776 this.activePanel.beforeSlide();
53782 afterSlide : function(){
53783 if(Roo.isGecko){// firefox overflow auto bug workaround
53784 this.bodyEl.unclip();
53786 this.tabs.bodyEl.unclip();
53788 if(this.activePanel){
53789 this.activePanel.getEl().unclip();
53790 if(this.activePanel.afterSlide){
53791 this.activePanel.afterSlide();
53797 initAutoHide : function(){
53798 if(this.autoHide !== false){
53799 if(!this.autoHideHd){
53800 var st = new Roo.util.DelayedTask(this.slideIn, this);
53801 this.autoHideHd = {
53802 "mouseout": function(e){
53803 if(!e.within(this.el, true)){
53807 "mouseover" : function(e){
53813 this.el.on(this.autoHideHd);
53817 clearAutoHide : function(){
53818 if(this.autoHide !== false){
53819 this.el.un("mouseout", this.autoHideHd.mouseout);
53820 this.el.un("mouseover", this.autoHideHd.mouseover);
53824 clearMonitor : function(){
53825 Roo.get(document).un("click", this.slideInIf, this);
53828 // these names are backwards but not changed for compat
53829 slideOut : function(){
53830 if(this.isSlid || this.el.hasActiveFx()){
53833 this.isSlid = true;
53834 if(this.collapseBtn){
53835 this.collapseBtn.hide();
53837 this.closeBtnState = this.closeBtn.getStyle('display');
53838 this.closeBtn.hide();
53840 this.stickBtn.show();
53843 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53844 this.beforeSlide();
53845 this.el.setStyle("z-index", 10001);
53846 this.el.slideIn(this.getSlideAnchor(), {
53847 callback: function(){
53849 this.initAutoHide();
53850 Roo.get(document).on("click", this.slideInIf, this);
53851 this.fireEvent("slideshow", this);
53858 afterSlideIn : function(){
53859 this.clearAutoHide();
53860 this.isSlid = false;
53861 this.clearMonitor();
53862 this.el.setStyle("z-index", "");
53863 if(this.collapseBtn){
53864 this.collapseBtn.show();
53866 this.closeBtn.setStyle('display', this.closeBtnState);
53868 this.stickBtn.hide();
53870 this.fireEvent("slidehide", this);
53873 slideIn : function(cb){
53874 if(!this.isSlid || this.el.hasActiveFx()){
53878 this.isSlid = false;
53879 this.beforeSlide();
53880 this.el.slideOut(this.getSlideAnchor(), {
53881 callback: function(){
53882 this.el.setLeftTop(-10000, -10000);
53884 this.afterSlideIn();
53892 slideInIf : function(e){
53893 if(!e.within(this.el)){
53898 animateCollapse : function(){
53899 this.beforeSlide();
53900 this.el.setStyle("z-index", 20000);
53901 var anchor = this.getSlideAnchor();
53902 this.el.slideOut(anchor, {
53903 callback : function(){
53904 this.el.setStyle("z-index", "");
53905 this.collapsedEl.slideIn(anchor, {duration:.3});
53907 this.el.setLocation(-10000,-10000);
53909 this.fireEvent("collapsed", this);
53916 animateExpand : function(){
53917 this.beforeSlide();
53918 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
53919 this.el.setStyle("z-index", 20000);
53920 this.collapsedEl.hide({
53923 this.el.slideIn(this.getSlideAnchor(), {
53924 callback : function(){
53925 this.el.setStyle("z-index", "");
53928 this.split.el.show();
53930 this.fireEvent("invalidated", this);
53931 this.fireEvent("expanded", this);
53959 getAnchor : function(){
53960 return this.anchors[this.position];
53963 getCollapseAnchor : function(){
53964 return this.canchors[this.position];
53967 getSlideAnchor : function(){
53968 return this.sanchors[this.position];
53971 getAlignAdj : function(){
53972 var cm = this.cmargins;
53973 switch(this.position){
53989 getExpandAdj : function(){
53990 var c = this.collapsedEl, cm = this.cmargins;
53991 switch(this.position){
53993 return [-(cm.right+c.getWidth()+cm.left), 0];
53996 return [cm.right+c.getWidth()+cm.left, 0];
53999 return [0, -(cm.top+cm.bottom+c.getHeight())];
54002 return [0, cm.top+cm.bottom+c.getHeight()];
54008 * Ext JS Library 1.1.1
54009 * Copyright(c) 2006-2007, Ext JS, LLC.
54011 * Originally Released Under LGPL - original licence link has changed is not relivant.
54014 * <script type="text/javascript">
54017 * These classes are private internal classes
54019 Roo.CenterLayoutRegion = function(mgr, config){
54020 Roo.LayoutRegion.call(this, mgr, config, "center");
54021 this.visible = true;
54022 this.minWidth = config.minWidth || 20;
54023 this.minHeight = config.minHeight || 20;
54026 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
54028 // center panel can't be hidden
54032 // center panel can't be hidden
54035 getMinWidth: function(){
54036 return this.minWidth;
54039 getMinHeight: function(){
54040 return this.minHeight;
54045 Roo.NorthLayoutRegion = function(mgr, config){
54046 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
54048 this.split.placement = Roo.SplitBar.TOP;
54049 this.split.orientation = Roo.SplitBar.VERTICAL;
54050 this.split.el.addClass("x-layout-split-v");
54052 var size = config.initialSize || config.height;
54053 if(typeof size != "undefined"){
54054 this.el.setHeight(size);
54057 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
54058 orientation: Roo.SplitBar.VERTICAL,
54059 getBox : function(){
54060 if(this.collapsed){
54061 return this.collapsedEl.getBox();
54063 var box = this.el.getBox();
54065 box.height += this.split.el.getHeight();
54070 updateBox : function(box){
54071 if(this.split && !this.collapsed){
54072 box.height -= this.split.el.getHeight();
54073 this.split.el.setLeft(box.x);
54074 this.split.el.setTop(box.y+box.height);
54075 this.split.el.setWidth(box.width);
54077 if(this.collapsed){
54078 this.updateBody(box.width, null);
54080 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54084 Roo.SouthLayoutRegion = function(mgr, config){
54085 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
54087 this.split.placement = Roo.SplitBar.BOTTOM;
54088 this.split.orientation = Roo.SplitBar.VERTICAL;
54089 this.split.el.addClass("x-layout-split-v");
54091 var size = config.initialSize || config.height;
54092 if(typeof size != "undefined"){
54093 this.el.setHeight(size);
54096 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
54097 orientation: Roo.SplitBar.VERTICAL,
54098 getBox : function(){
54099 if(this.collapsed){
54100 return this.collapsedEl.getBox();
54102 var box = this.el.getBox();
54104 var sh = this.split.el.getHeight();
54111 updateBox : function(box){
54112 if(this.split && !this.collapsed){
54113 var sh = this.split.el.getHeight();
54116 this.split.el.setLeft(box.x);
54117 this.split.el.setTop(box.y-sh);
54118 this.split.el.setWidth(box.width);
54120 if(this.collapsed){
54121 this.updateBody(box.width, null);
54123 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54127 Roo.EastLayoutRegion = function(mgr, config){
54128 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54130 this.split.placement = Roo.SplitBar.RIGHT;
54131 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54132 this.split.el.addClass("x-layout-split-h");
54134 var size = config.initialSize || config.width;
54135 if(typeof size != "undefined"){
54136 this.el.setWidth(size);
54139 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54140 orientation: Roo.SplitBar.HORIZONTAL,
54141 getBox : function(){
54142 if(this.collapsed){
54143 return this.collapsedEl.getBox();
54145 var box = this.el.getBox();
54147 var sw = this.split.el.getWidth();
54154 updateBox : function(box){
54155 if(this.split && !this.collapsed){
54156 var sw = this.split.el.getWidth();
54158 this.split.el.setLeft(box.x);
54159 this.split.el.setTop(box.y);
54160 this.split.el.setHeight(box.height);
54163 if(this.collapsed){
54164 this.updateBody(null, box.height);
54166 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54170 Roo.WestLayoutRegion = function(mgr, config){
54171 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54173 this.split.placement = Roo.SplitBar.LEFT;
54174 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54175 this.split.el.addClass("x-layout-split-h");
54177 var size = config.initialSize || config.width;
54178 if(typeof size != "undefined"){
54179 this.el.setWidth(size);
54182 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
54183 orientation: Roo.SplitBar.HORIZONTAL,
54184 getBox : function(){
54185 if(this.collapsed){
54186 return this.collapsedEl.getBox();
54188 var box = this.el.getBox();
54190 box.width += this.split.el.getWidth();
54195 updateBox : function(box){
54196 if(this.split && !this.collapsed){
54197 var sw = this.split.el.getWidth();
54199 this.split.el.setLeft(box.x+box.width);
54200 this.split.el.setTop(box.y);
54201 this.split.el.setHeight(box.height);
54203 if(this.collapsed){
54204 this.updateBody(null, box.height);
54206 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54211 * Ext JS Library 1.1.1
54212 * Copyright(c) 2006-2007, Ext JS, LLC.
54214 * Originally Released Under LGPL - original licence link has changed is not relivant.
54217 * <script type="text/javascript">
54222 * Private internal class for reading and applying state
54224 Roo.LayoutStateManager = function(layout){
54225 // default empty state
54234 Roo.LayoutStateManager.prototype = {
54235 init : function(layout, provider){
54236 this.provider = provider;
54237 var state = provider.get(layout.id+"-layout-state");
54239 var wasUpdating = layout.isUpdating();
54241 layout.beginUpdate();
54243 for(var key in state){
54244 if(typeof state[key] != "function"){
54245 var rstate = state[key];
54246 var r = layout.getRegion(key);
54249 r.resizeTo(rstate.size);
54251 if(rstate.collapsed == true){
54254 r.expand(null, true);
54260 layout.endUpdate();
54262 this.state = state;
54264 this.layout = layout;
54265 layout.on("regionresized", this.onRegionResized, this);
54266 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54267 layout.on("regionexpanded", this.onRegionExpanded, this);
54270 storeState : function(){
54271 this.provider.set(this.layout.id+"-layout-state", this.state);
54274 onRegionResized : function(region, newSize){
54275 this.state[region.getPosition()].size = newSize;
54279 onRegionCollapsed : function(region){
54280 this.state[region.getPosition()].collapsed = true;
54284 onRegionExpanded : function(region){
54285 this.state[region.getPosition()].collapsed = false;
54290 * Ext JS Library 1.1.1
54291 * Copyright(c) 2006-2007, Ext JS, LLC.
54293 * Originally Released Under LGPL - original licence link has changed is not relivant.
54296 * <script type="text/javascript">
54299 * @class Roo.ContentPanel
54300 * @extends Roo.util.Observable
54301 * A basic ContentPanel element.
54302 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54303 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54304 * @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
54305 * @cfg {Boolean} closable True if the panel can be closed/removed
54306 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54307 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54308 * @cfg {Toolbar} toolbar A toolbar for this panel
54309 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54310 * @cfg {String} title The title for this panel
54311 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54312 * @cfg {String} url Calls {@link #setUrl} with this value
54313 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54314 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54315 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54316 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54317 * @cfg {String} style Extra style to add to the content panel
54320 * Create a new ContentPanel.
54321 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54322 * @param {String/Object} config A string to set only the title or a config object
54323 * @param {String} content (optional) Set the HTML content for this panel
54324 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54326 Roo.ContentPanel = function(el, config, content){
54330 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54334 if (config && config.parentLayout) {
54335 el = config.parentLayout.el.createChild();
54338 if(el.autoCreate){ // xtype is available if this is called from factory
54342 this.el = Roo.get(el);
54343 if(!this.el && config && config.autoCreate){
54344 if(typeof config.autoCreate == "object"){
54345 if(!config.autoCreate.id){
54346 config.autoCreate.id = config.id||el;
54348 this.el = Roo.DomHelper.append(document.body,
54349 config.autoCreate, true);
54351 this.el = Roo.DomHelper.append(document.body,
54352 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54357 this.closable = false;
54358 this.loaded = false;
54359 this.active = false;
54360 if(typeof config == "string"){
54361 this.title = config;
54363 Roo.apply(this, config);
54366 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54367 this.wrapEl = this.el.wrap();
54368 this.toolbar.container = this.el.insertSibling(false, 'before');
54369 this.toolbar = new Roo.Toolbar(this.toolbar);
54372 // xtype created footer. - not sure if will work as we normally have to render first..
54373 if (this.footer && !this.footer.el && this.footer.xtype) {
54374 if (!this.wrapEl) {
54375 this.wrapEl = this.el.wrap();
54378 this.footer.container = this.wrapEl.createChild();
54380 this.footer = Roo.factory(this.footer, Roo);
54385 this.resizeEl = Roo.get(this.resizeEl, true);
54387 this.resizeEl = this.el;
54389 // handle view.xtype
54397 * Fires when this panel is activated.
54398 * @param {Roo.ContentPanel} this
54402 * @event deactivate
54403 * Fires when this panel is activated.
54404 * @param {Roo.ContentPanel} this
54406 "deactivate" : true,
54410 * Fires when this panel is resized if fitToFrame is true.
54411 * @param {Roo.ContentPanel} this
54412 * @param {Number} width The width after any component adjustments
54413 * @param {Number} height The height after any component adjustments
54419 * Fires when this tab is created
54420 * @param {Roo.ContentPanel} this
54430 if(this.autoScroll){
54431 this.resizeEl.setStyle("overflow", "auto");
54433 // fix randome scrolling
54434 this.el.on('scroll', function() {
54435 Roo.log('fix random scolling');
54436 this.scrollTo('top',0);
54439 content = content || this.content;
54441 this.setContent(content);
54443 if(config && config.url){
54444 this.setUrl(this.url, this.params, this.loadOnce);
54449 Roo.ContentPanel.superclass.constructor.call(this);
54451 if (this.view && typeof(this.view.xtype) != 'undefined') {
54452 this.view.el = this.el.appendChild(document.createElement("div"));
54453 this.view = Roo.factory(this.view);
54454 this.view.render && this.view.render(false, '');
54458 this.fireEvent('render', this);
54461 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54463 setRegion : function(region){
54464 this.region = region;
54466 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54468 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54473 * Returns the toolbar for this Panel if one was configured.
54474 * @return {Roo.Toolbar}
54476 getToolbar : function(){
54477 return this.toolbar;
54480 setActiveState : function(active){
54481 this.active = active;
54483 this.fireEvent("deactivate", this);
54485 this.fireEvent("activate", this);
54489 * Updates this panel's element
54490 * @param {String} content The new content
54491 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54493 setContent : function(content, loadScripts){
54494 this.el.update(content, loadScripts);
54497 ignoreResize : function(w, h){
54498 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54501 this.lastSize = {width: w, height: h};
54506 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54507 * @return {Roo.UpdateManager} The UpdateManager
54509 getUpdateManager : function(){
54510 return this.el.getUpdateManager();
54513 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54514 * @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:
54517 url: "your-url.php",
54518 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54519 callback: yourFunction,
54520 scope: yourObject, //(optional scope)
54523 text: "Loading...",
54528 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54529 * 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.
54530 * @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}
54531 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54532 * @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.
54533 * @return {Roo.ContentPanel} this
54536 var um = this.el.getUpdateManager();
54537 um.update.apply(um, arguments);
54543 * 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.
54544 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54545 * @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)
54546 * @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)
54547 * @return {Roo.UpdateManager} The UpdateManager
54549 setUrl : function(url, params, loadOnce){
54550 if(this.refreshDelegate){
54551 this.removeListener("activate", this.refreshDelegate);
54553 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54554 this.on("activate", this.refreshDelegate);
54555 return this.el.getUpdateManager();
54558 _handleRefresh : function(url, params, loadOnce){
54559 if(!loadOnce || !this.loaded){
54560 var updater = this.el.getUpdateManager();
54561 updater.update(url, params, this._setLoaded.createDelegate(this));
54565 _setLoaded : function(){
54566 this.loaded = true;
54570 * Returns this panel's id
54573 getId : function(){
54578 * Returns this panel's element - used by regiosn to add.
54579 * @return {Roo.Element}
54581 getEl : function(){
54582 return this.wrapEl || this.el;
54585 adjustForComponents : function(width, height)
54587 //Roo.log('adjustForComponents ');
54588 if(this.resizeEl != this.el){
54589 width -= this.el.getFrameWidth('lr');
54590 height -= this.el.getFrameWidth('tb');
54593 var te = this.toolbar.getEl();
54594 height -= te.getHeight();
54595 te.setWidth(width);
54598 var te = this.footer.getEl();
54599 //Roo.log("footer:" + te.getHeight());
54601 height -= te.getHeight();
54602 te.setWidth(width);
54606 if(this.adjustments){
54607 width += this.adjustments[0];
54608 height += this.adjustments[1];
54610 return {"width": width, "height": height};
54613 setSize : function(width, height){
54614 if(this.fitToFrame && !this.ignoreResize(width, height)){
54615 if(this.fitContainer && this.resizeEl != this.el){
54616 this.el.setSize(width, height);
54618 var size = this.adjustForComponents(width, height);
54619 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54620 this.fireEvent('resize', this, size.width, size.height);
54625 * Returns this panel's title
54628 getTitle : function(){
54633 * Set this panel's title
54634 * @param {String} title
54636 setTitle : function(title){
54637 this.title = title;
54639 this.region.updatePanelTitle(this, title);
54644 * Returns true is this panel was configured to be closable
54645 * @return {Boolean}
54647 isClosable : function(){
54648 return this.closable;
54651 beforeSlide : function(){
54653 this.resizeEl.clip();
54656 afterSlide : function(){
54658 this.resizeEl.unclip();
54662 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54663 * Will fail silently if the {@link #setUrl} method has not been called.
54664 * This does not activate the panel, just updates its content.
54666 refresh : function(){
54667 if(this.refreshDelegate){
54668 this.loaded = false;
54669 this.refreshDelegate();
54674 * Destroys this panel
54676 destroy : function(){
54677 this.el.removeAllListeners();
54678 var tempEl = document.createElement("span");
54679 tempEl.appendChild(this.el.dom);
54680 tempEl.innerHTML = "";
54686 * form - if the content panel contains a form - this is a reference to it.
54687 * @type {Roo.form.Form}
54691 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54692 * This contains a reference to it.
54698 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54708 * @param {Object} cfg Xtype definition of item to add.
54711 addxtype : function(cfg) {
54713 if (cfg.xtype.match(/^Form$/)) {
54716 //if (this.footer) {
54717 // el = this.footer.container.insertSibling(false, 'before');
54719 el = this.el.createChild();
54722 this.form = new Roo.form.Form(cfg);
54725 if ( this.form.allItems.length) {
54726 this.form.render(el.dom);
54730 // should only have one of theses..
54731 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54732 // views.. should not be just added - used named prop 'view''
54734 cfg.el = this.el.appendChild(document.createElement("div"));
54737 var ret = new Roo.factory(cfg);
54739 ret.render && ret.render(false, ''); // render blank..
54748 * @class Roo.GridPanel
54749 * @extends Roo.ContentPanel
54751 * Create a new GridPanel.
54752 * @param {Roo.grid.Grid} grid The grid for this panel
54753 * @param {String/Object} config A string to set only the panel's title, or a config object
54755 Roo.GridPanel = function(grid, config){
54758 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54759 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54761 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54763 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54766 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54768 // xtype created footer. - not sure if will work as we normally have to render first..
54769 if (this.footer && !this.footer.el && this.footer.xtype) {
54771 this.footer.container = this.grid.getView().getFooterPanel(true);
54772 this.footer.dataSource = this.grid.dataSource;
54773 this.footer = Roo.factory(this.footer, Roo);
54777 grid.monitorWindowResize = false; // turn off autosizing
54778 grid.autoHeight = false;
54779 grid.autoWidth = false;
54781 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54784 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54785 getId : function(){
54786 return this.grid.id;
54790 * Returns the grid for this panel
54791 * @return {Roo.grid.Grid}
54793 getGrid : function(){
54797 setSize : function(width, height){
54798 if(!this.ignoreResize(width, height)){
54799 var grid = this.grid;
54800 var size = this.adjustForComponents(width, height);
54801 grid.getGridEl().setSize(size.width, size.height);
54806 beforeSlide : function(){
54807 this.grid.getView().scroller.clip();
54810 afterSlide : function(){
54811 this.grid.getView().scroller.unclip();
54814 destroy : function(){
54815 this.grid.destroy();
54817 Roo.GridPanel.superclass.destroy.call(this);
54823 * @class Roo.NestedLayoutPanel
54824 * @extends Roo.ContentPanel
54826 * Create a new NestedLayoutPanel.
54829 * @param {Roo.BorderLayout} layout The layout for this panel
54830 * @param {String/Object} config A string to set only the title or a config object
54832 Roo.NestedLayoutPanel = function(layout, config)
54834 // construct with only one argument..
54835 /* FIXME - implement nicer consturctors
54836 if (layout.layout) {
54838 layout = config.layout;
54839 delete config.layout;
54841 if (layout.xtype && !layout.getEl) {
54842 // then layout needs constructing..
54843 layout = Roo.factory(layout, Roo);
54848 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54850 layout.monitorWindowResize = false; // turn off autosizing
54851 this.layout = layout;
54852 this.layout.getEl().addClass("x-layout-nested-layout");
54859 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
54861 setSize : function(width, height){
54862 if(!this.ignoreResize(width, height)){
54863 var size = this.adjustForComponents(width, height);
54864 var el = this.layout.getEl();
54865 el.setSize(size.width, size.height);
54866 var touch = el.dom.offsetWidth;
54867 this.layout.layout();
54868 // ie requires a double layout on the first pass
54869 if(Roo.isIE && !this.initialized){
54870 this.initialized = true;
54871 this.layout.layout();
54876 // activate all subpanels if not currently active..
54878 setActiveState : function(active){
54879 this.active = active;
54881 this.fireEvent("deactivate", this);
54885 this.fireEvent("activate", this);
54886 // not sure if this should happen before or after..
54887 if (!this.layout) {
54888 return; // should not happen..
54891 for (var r in this.layout.regions) {
54892 reg = this.layout.getRegion(r);
54893 if (reg.getActivePanel()) {
54894 //reg.showPanel(reg.getActivePanel()); // force it to activate..
54895 reg.setActivePanel(reg.getActivePanel());
54898 if (!reg.panels.length) {
54901 reg.showPanel(reg.getPanel(0));
54910 * Returns the nested BorderLayout for this panel
54911 * @return {Roo.BorderLayout}
54913 getLayout : function(){
54914 return this.layout;
54918 * Adds a xtype elements to the layout of the nested panel
54922 xtype : 'ContentPanel',
54929 xtype : 'NestedLayoutPanel',
54935 items : [ ... list of content panels or nested layout panels.. ]
54939 * @param {Object} cfg Xtype definition of item to add.
54941 addxtype : function(cfg) {
54942 return this.layout.addxtype(cfg);
54947 Roo.ScrollPanel = function(el, config, content){
54948 config = config || {};
54949 config.fitToFrame = true;
54950 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
54952 this.el.dom.style.overflow = "hidden";
54953 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
54954 this.el.removeClass("x-layout-inactive-content");
54955 this.el.on("mousewheel", this.onWheel, this);
54957 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
54958 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
54959 up.unselectable(); down.unselectable();
54960 up.on("click", this.scrollUp, this);
54961 down.on("click", this.scrollDown, this);
54962 up.addClassOnOver("x-scroller-btn-over");
54963 down.addClassOnOver("x-scroller-btn-over");
54964 up.addClassOnClick("x-scroller-btn-click");
54965 down.addClassOnClick("x-scroller-btn-click");
54966 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
54968 this.resizeEl = this.el;
54969 this.el = wrap; this.up = up; this.down = down;
54972 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
54974 wheelIncrement : 5,
54975 scrollUp : function(){
54976 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
54979 scrollDown : function(){
54980 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
54983 afterScroll : function(){
54984 var el = this.resizeEl;
54985 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
54986 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54987 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
54990 setSize : function(){
54991 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
54992 this.afterScroll();
54995 onWheel : function(e){
54996 var d = e.getWheelDelta();
54997 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
54998 this.afterScroll();
55002 setContent : function(content, loadScripts){
55003 this.resizeEl.update(content, loadScripts);
55017 * @class Roo.TreePanel
55018 * @extends Roo.ContentPanel
55020 * Create a new TreePanel. - defaults to fit/scoll contents.
55021 * @param {String/Object} config A string to set only the panel's title, or a config object
55022 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
55024 Roo.TreePanel = function(config){
55025 var el = config.el;
55026 var tree = config.tree;
55027 delete config.tree;
55028 delete config.el; // hopefull!
55030 // wrapper for IE7 strict & safari scroll issue
55032 var treeEl = el.createChild();
55033 config.resizeEl = treeEl;
55037 Roo.TreePanel.superclass.constructor.call(this, el, config);
55040 this.tree = new Roo.tree.TreePanel(treeEl , tree);
55041 //console.log(tree);
55042 this.on('activate', function()
55044 if (this.tree.rendered) {
55047 //console.log('render tree');
55048 this.tree.render();
55050 // this should not be needed.. - it's actually the 'el' that resizes?
55051 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
55053 //this.on('resize', function (cp, w, h) {
55054 // this.tree.innerCt.setWidth(w);
55055 // this.tree.innerCt.setHeight(h);
55056 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
55063 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
55080 * Ext JS Library 1.1.1
55081 * Copyright(c) 2006-2007, Ext JS, LLC.
55083 * Originally Released Under LGPL - original licence link has changed is not relivant.
55086 * <script type="text/javascript">
55091 * @class Roo.ReaderLayout
55092 * @extends Roo.BorderLayout
55093 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
55094 * center region containing two nested regions (a top one for a list view and one for item preview below),
55095 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
55096 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
55097 * expedites the setup of the overall layout and regions for this common application style.
55100 var reader = new Roo.ReaderLayout();
55101 var CP = Roo.ContentPanel; // shortcut for adding
55103 reader.beginUpdate();
55104 reader.add("north", new CP("north", "North"));
55105 reader.add("west", new CP("west", {title: "West"}));
55106 reader.add("east", new CP("east", {title: "East"}));
55108 reader.regions.listView.add(new CP("listView", "List"));
55109 reader.regions.preview.add(new CP("preview", "Preview"));
55110 reader.endUpdate();
55113 * Create a new ReaderLayout
55114 * @param {Object} config Configuration options
55115 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55116 * document.body if omitted)
55118 Roo.ReaderLayout = function(config, renderTo){
55119 var c = config || {size:{}};
55120 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55121 north: c.north !== false ? Roo.apply({
55125 }, c.north) : false,
55126 west: c.west !== false ? Roo.apply({
55134 margins:{left:5,right:0,bottom:5,top:5},
55135 cmargins:{left:5,right:5,bottom:5,top:5}
55136 }, c.west) : false,
55137 east: c.east !== false ? Roo.apply({
55145 margins:{left:0,right:5,bottom:5,top:5},
55146 cmargins:{left:5,right:5,bottom:5,top:5}
55147 }, c.east) : false,
55148 center: Roo.apply({
55149 tabPosition: 'top',
55153 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55157 this.el.addClass('x-reader');
55159 this.beginUpdate();
55161 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55162 south: c.preview !== false ? Roo.apply({
55169 cmargins:{top:5,left:0, right:0, bottom:0}
55170 }, c.preview) : false,
55171 center: Roo.apply({
55177 this.add('center', new Roo.NestedLayoutPanel(inner,
55178 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55182 this.regions.preview = inner.getRegion('south');
55183 this.regions.listView = inner.getRegion('center');
55186 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55188 * Ext JS Library 1.1.1
55189 * Copyright(c) 2006-2007, Ext JS, LLC.
55191 * Originally Released Under LGPL - original licence link has changed is not relivant.
55194 * <script type="text/javascript">
55198 * @class Roo.grid.Grid
55199 * @extends Roo.util.Observable
55200 * This class represents the primary interface of a component based grid control.
55201 * <br><br>Usage:<pre><code>
55202 var grid = new Roo.grid.Grid("my-container-id", {
55205 selModel: mySelectionModel,
55206 autoSizeColumns: true,
55207 monitorWindowResize: false,
55208 trackMouseOver: true
55213 * <b>Common Problems:</b><br/>
55214 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55215 * element will correct this<br/>
55216 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55217 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55218 * are unpredictable.<br/>
55219 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55220 * grid to calculate dimensions/offsets.<br/>
55222 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55223 * The container MUST have some type of size defined for the grid to fill. The container will be
55224 * automatically set to position relative if it isn't already.
55225 * @param {Object} config A config object that sets properties on this grid.
55227 Roo.grid.Grid = function(container, config){
55228 // initialize the container
55229 this.container = Roo.get(container);
55230 this.container.update("");
55231 this.container.setStyle("overflow", "hidden");
55232 this.container.addClass('x-grid-container');
55234 this.id = this.container.id;
55236 Roo.apply(this, config);
55237 // check and correct shorthanded configs
55239 this.dataSource = this.ds;
55243 this.colModel = this.cm;
55247 this.selModel = this.sm;
55251 if (this.selModel) {
55252 this.selModel = Roo.factory(this.selModel, Roo.grid);
55253 this.sm = this.selModel;
55254 this.sm.xmodule = this.xmodule || false;
55256 if (typeof(this.colModel.config) == 'undefined') {
55257 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55258 this.cm = this.colModel;
55259 this.cm.xmodule = this.xmodule || false;
55261 if (this.dataSource) {
55262 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55263 this.ds = this.dataSource;
55264 this.ds.xmodule = this.xmodule || false;
55271 this.container.setWidth(this.width);
55275 this.container.setHeight(this.height);
55282 * The raw click event for the entire grid.
55283 * @param {Roo.EventObject} e
55288 * The raw dblclick event for the entire grid.
55289 * @param {Roo.EventObject} e
55293 * @event contextmenu
55294 * The raw contextmenu event for the entire grid.
55295 * @param {Roo.EventObject} e
55297 "contextmenu" : true,
55300 * The raw mousedown event for the entire grid.
55301 * @param {Roo.EventObject} e
55303 "mousedown" : true,
55306 * The raw mouseup event for the entire grid.
55307 * @param {Roo.EventObject} e
55312 * The raw mouseover event for the entire grid.
55313 * @param {Roo.EventObject} e
55315 "mouseover" : true,
55318 * The raw mouseout event for the entire grid.
55319 * @param {Roo.EventObject} e
55324 * The raw keypress event for the entire grid.
55325 * @param {Roo.EventObject} e
55330 * The raw keydown event for the entire grid.
55331 * @param {Roo.EventObject} e
55339 * Fires when a cell is clicked
55340 * @param {Grid} this
55341 * @param {Number} rowIndex
55342 * @param {Number} columnIndex
55343 * @param {Roo.EventObject} e
55345 "cellclick" : true,
55347 * @event celldblclick
55348 * Fires when a cell is double clicked
55349 * @param {Grid} this
55350 * @param {Number} rowIndex
55351 * @param {Number} columnIndex
55352 * @param {Roo.EventObject} e
55354 "celldblclick" : true,
55357 * Fires when a row is clicked
55358 * @param {Grid} this
55359 * @param {Number} rowIndex
55360 * @param {Roo.EventObject} e
55364 * @event rowdblclick
55365 * Fires when a row is double clicked
55366 * @param {Grid} this
55367 * @param {Number} rowIndex
55368 * @param {Roo.EventObject} e
55370 "rowdblclick" : true,
55372 * @event headerclick
55373 * Fires when a header is clicked
55374 * @param {Grid} this
55375 * @param {Number} columnIndex
55376 * @param {Roo.EventObject} e
55378 "headerclick" : true,
55380 * @event headerdblclick
55381 * Fires when a header cell is double clicked
55382 * @param {Grid} this
55383 * @param {Number} columnIndex
55384 * @param {Roo.EventObject} e
55386 "headerdblclick" : true,
55388 * @event rowcontextmenu
55389 * Fires when a row is right clicked
55390 * @param {Grid} this
55391 * @param {Number} rowIndex
55392 * @param {Roo.EventObject} e
55394 "rowcontextmenu" : true,
55396 * @event cellcontextmenu
55397 * Fires when a cell is right clicked
55398 * @param {Grid} this
55399 * @param {Number} rowIndex
55400 * @param {Number} cellIndex
55401 * @param {Roo.EventObject} e
55403 "cellcontextmenu" : true,
55405 * @event headercontextmenu
55406 * Fires when a header is right clicked
55407 * @param {Grid} this
55408 * @param {Number} columnIndex
55409 * @param {Roo.EventObject} e
55411 "headercontextmenu" : true,
55413 * @event bodyscroll
55414 * Fires when the body element is scrolled
55415 * @param {Number} scrollLeft
55416 * @param {Number} scrollTop
55418 "bodyscroll" : true,
55420 * @event columnresize
55421 * Fires when the user resizes a column
55422 * @param {Number} columnIndex
55423 * @param {Number} newSize
55425 "columnresize" : true,
55427 * @event columnmove
55428 * Fires when the user moves a column
55429 * @param {Number} oldIndex
55430 * @param {Number} newIndex
55432 "columnmove" : true,
55435 * Fires when row(s) start being dragged
55436 * @param {Grid} this
55437 * @param {Roo.GridDD} dd The drag drop object
55438 * @param {event} e The raw browser event
55440 "startdrag" : true,
55443 * Fires when a drag operation is complete
55444 * @param {Grid} this
55445 * @param {Roo.GridDD} dd The drag drop object
55446 * @param {event} e The raw browser event
55451 * Fires when dragged row(s) are dropped on a valid DD target
55452 * @param {Grid} this
55453 * @param {Roo.GridDD} dd The drag drop object
55454 * @param {String} targetId The target drag drop object
55455 * @param {event} e The raw browser event
55460 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55461 * @param {Grid} this
55462 * @param {Roo.GridDD} dd The drag drop object
55463 * @param {String} targetId The target drag drop object
55464 * @param {event} e The raw browser event
55469 * Fires when the dragged row(s) first cross another DD target while being dragged
55470 * @param {Grid} this
55471 * @param {Roo.GridDD} dd The drag drop object
55472 * @param {String} targetId The target drag drop object
55473 * @param {event} e The raw browser event
55475 "dragenter" : true,
55478 * Fires when the dragged row(s) leave another DD target while being dragged
55479 * @param {Grid} this
55480 * @param {Roo.GridDD} dd The drag drop object
55481 * @param {String} targetId The target drag drop object
55482 * @param {event} e The raw browser event
55487 * Fires when a row is rendered, so you can change add a style to it.
55488 * @param {GridView} gridview The grid view
55489 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55495 * Fires when the grid is rendered
55496 * @param {Grid} grid
55501 Roo.grid.Grid.superclass.constructor.call(this);
55503 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55506 * @cfg {String} ddGroup - drag drop group.
55509 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
55513 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55515 minColumnWidth : 25,
55518 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55519 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55520 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55522 autoSizeColumns : false,
55525 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55527 autoSizeHeaders : true,
55530 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55532 monitorWindowResize : true,
55535 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55536 * rows measured to get a columns size. Default is 0 (all rows).
55538 maxRowsToMeasure : 0,
55541 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55543 trackMouseOver : true,
55546 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55549 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
55553 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55555 enableDragDrop : false,
55558 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55560 enableColumnMove : true,
55563 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55565 enableColumnHide : true,
55568 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55570 enableRowHeightSync : false,
55573 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55578 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55580 autoHeight : false,
55583 * @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.
55585 autoExpandColumn : false,
55588 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55591 autoExpandMin : 50,
55594 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55596 autoExpandMax : 1000,
55599 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55604 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55608 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55618 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55619 * of a fixed width. Default is false.
55622 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55627 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55628 * %0 is replaced with the number of selected rows.
55630 ddText : "{0} selected row{1}",
55634 * Called once after all setup has been completed and the grid is ready to be rendered.
55635 * @return {Roo.grid.Grid} this
55637 render : function()
55639 var c = this.container;
55640 // try to detect autoHeight/width mode
55641 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55642 this.autoHeight = true;
55644 var view = this.getView();
55647 c.on("click", this.onClick, this);
55648 c.on("dblclick", this.onDblClick, this);
55649 c.on("contextmenu", this.onContextMenu, this);
55650 c.on("keydown", this.onKeyDown, this);
55652 c.on("touchstart", this.onTouchStart, this);
55655 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55657 this.getSelectionModel().init(this);
55662 this.loadMask = new Roo.LoadMask(this.container,
55663 Roo.apply({store:this.dataSource}, this.loadMask));
55667 if (this.toolbar && this.toolbar.xtype) {
55668 this.toolbar.container = this.getView().getHeaderPanel(true);
55669 this.toolbar = new Roo.Toolbar(this.toolbar);
55671 if (this.footer && this.footer.xtype) {
55672 this.footer.dataSource = this.getDataSource();
55673 this.footer.container = this.getView().getFooterPanel(true);
55674 this.footer = Roo.factory(this.footer, Roo);
55676 if (this.dropTarget && this.dropTarget.xtype) {
55677 delete this.dropTarget.xtype;
55678 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55682 this.rendered = true;
55683 this.fireEvent('render', this);
55688 * Reconfigures the grid to use a different Store and Column Model.
55689 * The View will be bound to the new objects and refreshed.
55690 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55691 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55693 reconfigure : function(dataSource, colModel){
55695 this.loadMask.destroy();
55696 this.loadMask = new Roo.LoadMask(this.container,
55697 Roo.apply({store:dataSource}, this.loadMask));
55699 this.view.bind(dataSource, colModel);
55700 this.dataSource = dataSource;
55701 this.colModel = colModel;
55702 this.view.refresh(true);
55706 * Add's a column, default at the end..
55708 * @param {int} position to add (default end)
55709 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55711 addColumns : function(pos, ar)
55714 for (var i =0;i< ar.length;i++) {
55716 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55717 this.cm.lookup[cfg.id] = cfg;
55721 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55722 pos = this.cm.config.length; //this.cm.config.push(cfg);
55724 pos = Math.max(0,pos);
55727 this.cm.config.splice.apply(this.cm.config, ar);
55731 this.view.generateRules(this.cm);
55732 this.view.refresh(true);
55740 onKeyDown : function(e){
55741 this.fireEvent("keydown", e);
55745 * Destroy this grid.
55746 * @param {Boolean} removeEl True to remove the element
55748 destroy : function(removeEl, keepListeners){
55750 this.loadMask.destroy();
55752 var c = this.container;
55753 c.removeAllListeners();
55754 this.view.destroy();
55755 this.colModel.purgeListeners();
55756 if(!keepListeners){
55757 this.purgeListeners();
55760 if(removeEl === true){
55766 processEvent : function(name, e){
55767 // does this fire select???
55768 //Roo.log('grid:processEvent ' + name);
55770 if (name != 'touchstart' ) {
55771 this.fireEvent(name, e);
55774 var t = e.getTarget();
55776 var header = v.findHeaderIndex(t);
55777 if(header !== false){
55778 var ename = name == 'touchstart' ? 'click' : name;
55780 this.fireEvent("header" + ename, this, header, e);
55782 var row = v.findRowIndex(t);
55783 var cell = v.findCellIndex(t);
55784 if (name == 'touchstart') {
55785 // first touch is always a click.
55786 // hopefull this happens after selection is updated.?
55789 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55790 var cs = this.selModel.getSelectedCell();
55791 if (row == cs[0] && cell == cs[1]){
55795 if (typeof(this.selModel.getSelections) != 'undefined') {
55796 var cs = this.selModel.getSelections();
55797 var ds = this.dataSource;
55798 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55809 this.fireEvent("row" + name, this, row, e);
55810 if(cell !== false){
55811 this.fireEvent("cell" + name, this, row, cell, e);
55818 onClick : function(e){
55819 this.processEvent("click", e);
55822 onTouchStart : function(e){
55823 this.processEvent("touchstart", e);
55827 onContextMenu : function(e, t){
55828 this.processEvent("contextmenu", e);
55832 onDblClick : function(e){
55833 this.processEvent("dblclick", e);
55837 walkCells : function(row, col, step, fn, scope){
55838 var cm = this.colModel, clen = cm.getColumnCount();
55839 var ds = this.dataSource, rlen = ds.getCount(), first = true;
55851 if(fn.call(scope || this, row, col, cm) === true){
55869 if(fn.call(scope || this, row, col, cm) === true){
55881 getSelections : function(){
55882 return this.selModel.getSelections();
55886 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
55887 * but if manual update is required this method will initiate it.
55889 autoSize : function(){
55891 this.view.layout();
55892 if(this.view.adjustForScroll){
55893 this.view.adjustForScroll();
55899 * Returns the grid's underlying element.
55900 * @return {Element} The element
55902 getGridEl : function(){
55903 return this.container;
55906 // private for compatibility, overridden by editor grid
55907 stopEditing : function(){},
55910 * Returns the grid's SelectionModel.
55911 * @return {SelectionModel}
55913 getSelectionModel : function(){
55914 if(!this.selModel){
55915 this.selModel = new Roo.grid.RowSelectionModel();
55917 return this.selModel;
55921 * Returns the grid's DataSource.
55922 * @return {DataSource}
55924 getDataSource : function(){
55925 return this.dataSource;
55929 * Returns the grid's ColumnModel.
55930 * @return {ColumnModel}
55932 getColumnModel : function(){
55933 return this.colModel;
55937 * Returns the grid's GridView object.
55938 * @return {GridView}
55940 getView : function(){
55942 this.view = new Roo.grid.GridView(this.viewConfig);
55943 this.relayEvents(this.view, [
55944 "beforerowremoved", "beforerowsinserted",
55945 "beforerefresh", "rowremoved",
55946 "rowsinserted", "rowupdated" ,"refresh"
55952 * Called to get grid's drag proxy text, by default returns this.ddText.
55953 * Override this to put something different in the dragged text.
55956 getDragDropText : function(){
55957 var count = this.selModel.getCount();
55958 return String.format(this.ddText, count, count == 1 ? '' : 's');
55963 * Ext JS Library 1.1.1
55964 * Copyright(c) 2006-2007, Ext JS, LLC.
55966 * Originally Released Under LGPL - original licence link has changed is not relivant.
55969 * <script type="text/javascript">
55972 Roo.grid.AbstractGridView = function(){
55976 "beforerowremoved" : true,
55977 "beforerowsinserted" : true,
55978 "beforerefresh" : true,
55979 "rowremoved" : true,
55980 "rowsinserted" : true,
55981 "rowupdated" : true,
55984 Roo.grid.AbstractGridView.superclass.constructor.call(this);
55987 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
55988 rowClass : "x-grid-row",
55989 cellClass : "x-grid-cell",
55990 tdClass : "x-grid-td",
55991 hdClass : "x-grid-hd",
55992 splitClass : "x-grid-hd-split",
55994 init: function(grid){
55996 var cid = this.grid.getGridEl().id;
55997 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
55998 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
55999 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
56000 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
56003 getColumnRenderers : function(){
56004 var renderers = [];
56005 var cm = this.grid.colModel;
56006 var colCount = cm.getColumnCount();
56007 for(var i = 0; i < colCount; i++){
56008 renderers[i] = cm.getRenderer(i);
56013 getColumnIds : function(){
56015 var cm = this.grid.colModel;
56016 var colCount = cm.getColumnCount();
56017 for(var i = 0; i < colCount; i++){
56018 ids[i] = cm.getColumnId(i);
56023 getDataIndexes : function(){
56024 if(!this.indexMap){
56025 this.indexMap = this.buildIndexMap();
56027 return this.indexMap.colToData;
56030 getColumnIndexByDataIndex : function(dataIndex){
56031 if(!this.indexMap){
56032 this.indexMap = this.buildIndexMap();
56034 return this.indexMap.dataToCol[dataIndex];
56038 * Set a css style for a column dynamically.
56039 * @param {Number} colIndex The index of the column
56040 * @param {String} name The css property name
56041 * @param {String} value The css value
56043 setCSSStyle : function(colIndex, name, value){
56044 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
56045 Roo.util.CSS.updateRule(selector, name, value);
56048 generateRules : function(cm){
56049 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
56050 Roo.util.CSS.removeStyleSheet(rulesId);
56051 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56052 var cid = cm.getColumnId(i);
56053 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
56054 this.tdSelector, cid, " {\n}\n",
56055 this.hdSelector, cid, " {\n}\n",
56056 this.splitSelector, cid, " {\n}\n");
56058 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56062 * Ext JS Library 1.1.1
56063 * Copyright(c) 2006-2007, Ext JS, LLC.
56065 * Originally Released Under LGPL - original licence link has changed is not relivant.
56068 * <script type="text/javascript">
56072 // This is a support class used internally by the Grid components
56073 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
56075 this.view = grid.getView();
56076 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56077 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
56079 this.setHandleElId(Roo.id(hd));
56080 this.setOuterHandleElId(Roo.id(hd2));
56082 this.scroll = false;
56084 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
56086 getDragData : function(e){
56087 var t = Roo.lib.Event.getTarget(e);
56088 var h = this.view.findHeaderCell(t);
56090 return {ddel: h.firstChild, header:h};
56095 onInitDrag : function(e){
56096 this.view.headersDisabled = true;
56097 var clone = this.dragData.ddel.cloneNode(true);
56098 clone.id = Roo.id();
56099 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
56100 this.proxy.update(clone);
56104 afterValidDrop : function(){
56106 setTimeout(function(){
56107 v.headersDisabled = false;
56111 afterInvalidDrop : function(){
56113 setTimeout(function(){
56114 v.headersDisabled = false;
56120 * Ext JS Library 1.1.1
56121 * Copyright(c) 2006-2007, Ext JS, LLC.
56123 * Originally Released Under LGPL - original licence link has changed is not relivant.
56126 * <script type="text/javascript">
56129 // This is a support class used internally by the Grid components
56130 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56132 this.view = grid.getView();
56133 // split the proxies so they don't interfere with mouse events
56134 this.proxyTop = Roo.DomHelper.append(document.body, {
56135 cls:"col-move-top", html:" "
56137 this.proxyBottom = Roo.DomHelper.append(document.body, {
56138 cls:"col-move-bottom", html:" "
56140 this.proxyTop.hide = this.proxyBottom.hide = function(){
56141 this.setLeftTop(-100,-100);
56142 this.setStyle("visibility", "hidden");
56144 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56145 // temporarily disabled
56146 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56147 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56149 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56150 proxyOffsets : [-4, -9],
56151 fly: Roo.Element.fly,
56153 getTargetFromEvent : function(e){
56154 var t = Roo.lib.Event.getTarget(e);
56155 var cindex = this.view.findCellIndex(t);
56156 if(cindex !== false){
56157 return this.view.getHeaderCell(cindex);
56162 nextVisible : function(h){
56163 var v = this.view, cm = this.grid.colModel;
56166 if(!cm.isHidden(v.getCellIndex(h))){
56174 prevVisible : function(h){
56175 var v = this.view, cm = this.grid.colModel;
56178 if(!cm.isHidden(v.getCellIndex(h))){
56186 positionIndicator : function(h, n, e){
56187 var x = Roo.lib.Event.getPageX(e);
56188 var r = Roo.lib.Dom.getRegion(n.firstChild);
56189 var px, pt, py = r.top + this.proxyOffsets[1];
56190 if((r.right - x) <= (r.right-r.left)/2){
56191 px = r.right+this.view.borderWidth;
56197 var oldIndex = this.view.getCellIndex(h);
56198 var newIndex = this.view.getCellIndex(n);
56200 if(this.grid.colModel.isFixed(newIndex)){
56204 var locked = this.grid.colModel.isLocked(newIndex);
56209 if(oldIndex < newIndex){
56212 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56215 px += this.proxyOffsets[0];
56216 this.proxyTop.setLeftTop(px, py);
56217 this.proxyTop.show();
56218 if(!this.bottomOffset){
56219 this.bottomOffset = this.view.mainHd.getHeight();
56221 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56222 this.proxyBottom.show();
56226 onNodeEnter : function(n, dd, e, data){
56227 if(data.header != n){
56228 this.positionIndicator(data.header, n, e);
56232 onNodeOver : function(n, dd, e, data){
56233 var result = false;
56234 if(data.header != n){
56235 result = this.positionIndicator(data.header, n, e);
56238 this.proxyTop.hide();
56239 this.proxyBottom.hide();
56241 return result ? this.dropAllowed : this.dropNotAllowed;
56244 onNodeOut : function(n, dd, e, data){
56245 this.proxyTop.hide();
56246 this.proxyBottom.hide();
56249 onNodeDrop : function(n, dd, e, data){
56250 var h = data.header;
56252 var cm = this.grid.colModel;
56253 var x = Roo.lib.Event.getPageX(e);
56254 var r = Roo.lib.Dom.getRegion(n.firstChild);
56255 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56256 var oldIndex = this.view.getCellIndex(h);
56257 var newIndex = this.view.getCellIndex(n);
56258 var locked = cm.isLocked(newIndex);
56262 if(oldIndex < newIndex){
56265 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56268 cm.setLocked(oldIndex, locked, true);
56269 cm.moveColumn(oldIndex, newIndex);
56270 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56278 * Ext JS Library 1.1.1
56279 * Copyright(c) 2006-2007, Ext JS, LLC.
56281 * Originally Released Under LGPL - original licence link has changed is not relivant.
56284 * <script type="text/javascript">
56288 * @class Roo.grid.GridView
56289 * @extends Roo.util.Observable
56292 * @param {Object} config
56294 Roo.grid.GridView = function(config){
56295 Roo.grid.GridView.superclass.constructor.call(this);
56298 Roo.apply(this, config);
56301 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56303 unselectable : 'unselectable="on"',
56304 unselectableCls : 'x-unselectable',
56307 rowClass : "x-grid-row",
56309 cellClass : "x-grid-col",
56311 tdClass : "x-grid-td",
56313 hdClass : "x-grid-hd",
56315 splitClass : "x-grid-split",
56317 sortClasses : ["sort-asc", "sort-desc"],
56319 enableMoveAnim : false,
56323 dh : Roo.DomHelper,
56325 fly : Roo.Element.fly,
56327 css : Roo.util.CSS,
56333 scrollIncrement : 22,
56335 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56337 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56339 bind : function(ds, cm){
56341 this.ds.un("load", this.onLoad, this);
56342 this.ds.un("datachanged", this.onDataChange, this);
56343 this.ds.un("add", this.onAdd, this);
56344 this.ds.un("remove", this.onRemove, this);
56345 this.ds.un("update", this.onUpdate, this);
56346 this.ds.un("clear", this.onClear, this);
56349 ds.on("load", this.onLoad, this);
56350 ds.on("datachanged", this.onDataChange, this);
56351 ds.on("add", this.onAdd, this);
56352 ds.on("remove", this.onRemove, this);
56353 ds.on("update", this.onUpdate, this);
56354 ds.on("clear", this.onClear, this);
56359 this.cm.un("widthchange", this.onColWidthChange, this);
56360 this.cm.un("headerchange", this.onHeaderChange, this);
56361 this.cm.un("hiddenchange", this.onHiddenChange, this);
56362 this.cm.un("columnmoved", this.onColumnMove, this);
56363 this.cm.un("columnlockchange", this.onColumnLock, this);
56366 this.generateRules(cm);
56367 cm.on("widthchange", this.onColWidthChange, this);
56368 cm.on("headerchange", this.onHeaderChange, this);
56369 cm.on("hiddenchange", this.onHiddenChange, this);
56370 cm.on("columnmoved", this.onColumnMove, this);
56371 cm.on("columnlockchange", this.onColumnLock, this);
56376 init: function(grid){
56377 Roo.grid.GridView.superclass.init.call(this, grid);
56379 this.bind(grid.dataSource, grid.colModel);
56381 grid.on("headerclick", this.handleHeaderClick, this);
56383 if(grid.trackMouseOver){
56384 grid.on("mouseover", this.onRowOver, this);
56385 grid.on("mouseout", this.onRowOut, this);
56387 grid.cancelTextSelection = function(){};
56388 this.gridId = grid.id;
56390 var tpls = this.templates || {};
56393 tpls.master = new Roo.Template(
56394 '<div class="x-grid" hidefocus="true">',
56395 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56396 '<div class="x-grid-topbar"></div>',
56397 '<div class="x-grid-scroller"><div></div></div>',
56398 '<div class="x-grid-locked">',
56399 '<div class="x-grid-header">{lockedHeader}</div>',
56400 '<div class="x-grid-body">{lockedBody}</div>',
56402 '<div class="x-grid-viewport">',
56403 '<div class="x-grid-header">{header}</div>',
56404 '<div class="x-grid-body">{body}</div>',
56406 '<div class="x-grid-bottombar"></div>',
56408 '<div class="x-grid-resize-proxy"> </div>',
56411 tpls.master.disableformats = true;
56415 tpls.header = new Roo.Template(
56416 '<table border="0" cellspacing="0" cellpadding="0">',
56417 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56420 tpls.header.disableformats = true;
56422 tpls.header.compile();
56425 tpls.hcell = new Roo.Template(
56426 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56427 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56430 tpls.hcell.disableFormats = true;
56432 tpls.hcell.compile();
56435 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56436 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56437 tpls.hsplit.disableFormats = true;
56439 tpls.hsplit.compile();
56442 tpls.body = new Roo.Template(
56443 '<table border="0" cellspacing="0" cellpadding="0">',
56444 "<tbody>{rows}</tbody>",
56447 tpls.body.disableFormats = true;
56449 tpls.body.compile();
56452 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56453 tpls.row.disableFormats = true;
56455 tpls.row.compile();
56458 tpls.cell = new Roo.Template(
56459 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56460 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56461 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56464 tpls.cell.disableFormats = true;
56466 tpls.cell.compile();
56468 this.templates = tpls;
56471 // remap these for backwards compat
56472 onColWidthChange : function(){
56473 this.updateColumns.apply(this, arguments);
56475 onHeaderChange : function(){
56476 this.updateHeaders.apply(this, arguments);
56478 onHiddenChange : function(){
56479 this.handleHiddenChange.apply(this, arguments);
56481 onColumnMove : function(){
56482 this.handleColumnMove.apply(this, arguments);
56484 onColumnLock : function(){
56485 this.handleLockChange.apply(this, arguments);
56488 onDataChange : function(){
56490 this.updateHeaderSortState();
56493 onClear : function(){
56497 onUpdate : function(ds, record){
56498 this.refreshRow(record);
56501 refreshRow : function(record){
56502 var ds = this.ds, index;
56503 if(typeof record == 'number'){
56505 record = ds.getAt(index);
56507 index = ds.indexOf(record);
56509 this.insertRows(ds, index, index, true);
56510 this.onRemove(ds, record, index+1, true);
56511 this.syncRowHeights(index, index);
56513 this.fireEvent("rowupdated", this, index, record);
56516 onAdd : function(ds, records, index){
56517 this.insertRows(ds, index, index + (records.length-1));
56520 onRemove : function(ds, record, index, isUpdate){
56521 if(isUpdate !== true){
56522 this.fireEvent("beforerowremoved", this, index, record);
56524 var bt = this.getBodyTable(), lt = this.getLockedTable();
56525 if(bt.rows[index]){
56526 bt.firstChild.removeChild(bt.rows[index]);
56528 if(lt.rows[index]){
56529 lt.firstChild.removeChild(lt.rows[index]);
56531 if(isUpdate !== true){
56532 this.stripeRows(index);
56533 this.syncRowHeights(index, index);
56535 this.fireEvent("rowremoved", this, index, record);
56539 onLoad : function(){
56540 this.scrollToTop();
56544 * Scrolls the grid to the top
56546 scrollToTop : function(){
56548 this.scroller.dom.scrollTop = 0;
56554 * Gets a panel in the header of the grid that can be used for toolbars etc.
56555 * After modifying the contents of this panel a call to grid.autoSize() may be
56556 * required to register any changes in size.
56557 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56558 * @return Roo.Element
56560 getHeaderPanel : function(doShow){
56562 this.headerPanel.show();
56564 return this.headerPanel;
56568 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56569 * After modifying the contents of this panel a call to grid.autoSize() may be
56570 * required to register any changes in size.
56571 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56572 * @return Roo.Element
56574 getFooterPanel : function(doShow){
56576 this.footerPanel.show();
56578 return this.footerPanel;
56581 initElements : function(){
56582 var E = Roo.Element;
56583 var el = this.grid.getGridEl().dom.firstChild;
56584 var cs = el.childNodes;
56586 this.el = new E(el);
56588 this.focusEl = new E(el.firstChild);
56589 this.focusEl.swallowEvent("click", true);
56591 this.headerPanel = new E(cs[1]);
56592 this.headerPanel.enableDisplayMode("block");
56594 this.scroller = new E(cs[2]);
56595 this.scrollSizer = new E(this.scroller.dom.firstChild);
56597 this.lockedWrap = new E(cs[3]);
56598 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56599 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56601 this.mainWrap = new E(cs[4]);
56602 this.mainHd = new E(this.mainWrap.dom.firstChild);
56603 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56605 this.footerPanel = new E(cs[5]);
56606 this.footerPanel.enableDisplayMode("block");
56608 this.resizeProxy = new E(cs[6]);
56610 this.headerSelector = String.format(
56611 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56612 this.lockedHd.id, this.mainHd.id
56615 this.splitterSelector = String.format(
56616 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56617 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56620 idToCssName : function(s)
56622 return s.replace(/[^a-z0-9]+/ig, '-');
56625 getHeaderCell : function(index){
56626 return Roo.DomQuery.select(this.headerSelector)[index];
56629 getHeaderCellMeasure : function(index){
56630 return this.getHeaderCell(index).firstChild;
56633 getHeaderCellText : function(index){
56634 return this.getHeaderCell(index).firstChild.firstChild;
56637 getLockedTable : function(){
56638 return this.lockedBody.dom.firstChild;
56641 getBodyTable : function(){
56642 return this.mainBody.dom.firstChild;
56645 getLockedRow : function(index){
56646 return this.getLockedTable().rows[index];
56649 getRow : function(index){
56650 return this.getBodyTable().rows[index];
56653 getRowComposite : function(index){
56655 this.rowEl = new Roo.CompositeElementLite();
56657 var els = [], lrow, mrow;
56658 if(lrow = this.getLockedRow(index)){
56661 if(mrow = this.getRow(index)){
56664 this.rowEl.elements = els;
56668 * Gets the 'td' of the cell
56670 * @param {Integer} rowIndex row to select
56671 * @param {Integer} colIndex column to select
56675 getCell : function(rowIndex, colIndex){
56676 var locked = this.cm.getLockedCount();
56678 if(colIndex < locked){
56679 source = this.lockedBody.dom.firstChild;
56681 source = this.mainBody.dom.firstChild;
56682 colIndex -= locked;
56684 return source.rows[rowIndex].childNodes[colIndex];
56687 getCellText : function(rowIndex, colIndex){
56688 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56691 getCellBox : function(cell){
56692 var b = this.fly(cell).getBox();
56693 if(Roo.isOpera){ // opera fails to report the Y
56694 b.y = cell.offsetTop + this.mainBody.getY();
56699 getCellIndex : function(cell){
56700 var id = String(cell.className).match(this.cellRE);
56702 return parseInt(id[1], 10);
56707 findHeaderIndex : function(n){
56708 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56709 return r ? this.getCellIndex(r) : false;
56712 findHeaderCell : function(n){
56713 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56714 return r ? r : false;
56717 findRowIndex : function(n){
56721 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56722 return r ? r.rowIndex : false;
56725 findCellIndex : function(node){
56726 var stop = this.el.dom;
56727 while(node && node != stop){
56728 if(this.findRE.test(node.className)){
56729 return this.getCellIndex(node);
56731 node = node.parentNode;
56736 getColumnId : function(index){
56737 return this.cm.getColumnId(index);
56740 getSplitters : function()
56742 if(this.splitterSelector){
56743 return Roo.DomQuery.select(this.splitterSelector);
56749 getSplitter : function(index){
56750 return this.getSplitters()[index];
56753 onRowOver : function(e, t){
56755 if((row = this.findRowIndex(t)) !== false){
56756 this.getRowComposite(row).addClass("x-grid-row-over");
56760 onRowOut : function(e, t){
56762 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56763 this.getRowComposite(row).removeClass("x-grid-row-over");
56767 renderHeaders : function(){
56769 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56770 var cb = [], lb = [], sb = [], lsb = [], p = {};
56771 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56772 p.cellId = "x-grid-hd-0-" + i;
56773 p.splitId = "x-grid-csplit-0-" + i;
56774 p.id = cm.getColumnId(i);
56775 p.value = cm.getColumnHeader(i) || "";
56776 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56777 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56778 if(!cm.isLocked(i)){
56779 cb[cb.length] = ct.apply(p);
56780 sb[sb.length] = st.apply(p);
56782 lb[lb.length] = ct.apply(p);
56783 lsb[lsb.length] = st.apply(p);
56786 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56787 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56790 updateHeaders : function(){
56791 var html = this.renderHeaders();
56792 this.lockedHd.update(html[0]);
56793 this.mainHd.update(html[1]);
56797 * Focuses the specified row.
56798 * @param {Number} row The row index
56800 focusRow : function(row)
56802 //Roo.log('GridView.focusRow');
56803 var x = this.scroller.dom.scrollLeft;
56804 this.focusCell(row, 0, false);
56805 this.scroller.dom.scrollLeft = x;
56809 * Focuses the specified cell.
56810 * @param {Number} row The row index
56811 * @param {Number} col The column index
56812 * @param {Boolean} hscroll false to disable horizontal scrolling
56814 focusCell : function(row, col, hscroll)
56816 //Roo.log('GridView.focusCell');
56817 var el = this.ensureVisible(row, col, hscroll);
56818 this.focusEl.alignTo(el, "tl-tl");
56820 this.focusEl.focus();
56822 this.focusEl.focus.defer(1, this.focusEl);
56827 * Scrolls the specified cell into view
56828 * @param {Number} row The row index
56829 * @param {Number} col The column index
56830 * @param {Boolean} hscroll false to disable horizontal scrolling
56832 ensureVisible : function(row, col, hscroll)
56834 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56835 //return null; //disable for testing.
56836 if(typeof row != "number"){
56837 row = row.rowIndex;
56839 if(row < 0 && row >= this.ds.getCount()){
56842 col = (col !== undefined ? col : 0);
56843 var cm = this.grid.colModel;
56844 while(cm.isHidden(col)){
56848 var el = this.getCell(row, col);
56852 var c = this.scroller.dom;
56854 var ctop = parseInt(el.offsetTop, 10);
56855 var cleft = parseInt(el.offsetLeft, 10);
56856 var cbot = ctop + el.offsetHeight;
56857 var cright = cleft + el.offsetWidth;
56859 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
56860 var stop = parseInt(c.scrollTop, 10);
56861 var sleft = parseInt(c.scrollLeft, 10);
56862 var sbot = stop + ch;
56863 var sright = sleft + c.clientWidth;
56865 Roo.log('GridView.ensureVisible:' +
56867 ' c.clientHeight:' + c.clientHeight +
56868 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
56876 c.scrollTop = ctop;
56877 //Roo.log("set scrolltop to ctop DISABLE?");
56878 }else if(cbot > sbot){
56879 //Roo.log("set scrolltop to cbot-ch");
56880 c.scrollTop = cbot-ch;
56883 if(hscroll !== false){
56885 c.scrollLeft = cleft;
56886 }else if(cright > sright){
56887 c.scrollLeft = cright-c.clientWidth;
56894 updateColumns : function(){
56895 this.grid.stopEditing();
56896 var cm = this.grid.colModel, colIds = this.getColumnIds();
56897 //var totalWidth = cm.getTotalWidth();
56899 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56900 //if(cm.isHidden(i)) continue;
56901 var w = cm.getColumnWidth(i);
56902 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56903 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56905 this.updateSplitters();
56908 generateRules : function(cm){
56909 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
56910 Roo.util.CSS.removeStyleSheet(rulesId);
56911 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56912 var cid = cm.getColumnId(i);
56914 if(cm.config[i].align){
56915 align = 'text-align:'+cm.config[i].align+';';
56918 if(cm.isHidden(i)){
56919 hidden = 'display:none;';
56921 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
56923 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
56924 this.hdSelector, cid, " {\n", align, width, "}\n",
56925 this.tdSelector, cid, " {\n",hidden,"\n}\n",
56926 this.splitSelector, cid, " {\n", hidden , "\n}\n");
56928 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56931 updateSplitters : function(){
56932 var cm = this.cm, s = this.getSplitters();
56933 if(s){ // splitters not created yet
56934 var pos = 0, locked = true;
56935 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56936 if(cm.isHidden(i)) {
56939 var w = cm.getColumnWidth(i); // make sure it's a number
56940 if(!cm.isLocked(i) && locked){
56945 s[i].style.left = (pos-this.splitOffset) + "px";
56950 handleHiddenChange : function(colModel, colIndex, hidden){
56952 this.hideColumn(colIndex);
56954 this.unhideColumn(colIndex);
56958 hideColumn : function(colIndex){
56959 var cid = this.getColumnId(colIndex);
56960 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
56961 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
56963 this.updateHeaders();
56965 this.updateSplitters();
56969 unhideColumn : function(colIndex){
56970 var cid = this.getColumnId(colIndex);
56971 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
56972 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
56975 this.updateHeaders();
56977 this.updateSplitters();
56981 insertRows : function(dm, firstRow, lastRow, isUpdate){
56982 if(firstRow == 0 && lastRow == dm.getCount()-1){
56986 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
56988 var s = this.getScrollState();
56989 var markup = this.renderRows(firstRow, lastRow);
56990 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
56991 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
56992 this.restoreScroll(s);
56994 this.fireEvent("rowsinserted", this, firstRow, lastRow);
56995 this.syncRowHeights(firstRow, lastRow);
56996 this.stripeRows(firstRow);
57002 bufferRows : function(markup, target, index){
57003 var before = null, trows = target.rows, tbody = target.tBodies[0];
57004 if(index < trows.length){
57005 before = trows[index];
57007 var b = document.createElement("div");
57008 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
57009 var rows = b.firstChild.rows;
57010 for(var i = 0, len = rows.length; i < len; i++){
57012 tbody.insertBefore(rows[0], before);
57014 tbody.appendChild(rows[0]);
57021 deleteRows : function(dm, firstRow, lastRow){
57022 if(dm.getRowCount()<1){
57023 this.fireEvent("beforerefresh", this);
57024 this.mainBody.update("");
57025 this.lockedBody.update("");
57026 this.fireEvent("refresh", this);
57028 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
57029 var bt = this.getBodyTable();
57030 var tbody = bt.firstChild;
57031 var rows = bt.rows;
57032 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
57033 tbody.removeChild(rows[firstRow]);
57035 this.stripeRows(firstRow);
57036 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
57040 updateRows : function(dataSource, firstRow, lastRow){
57041 var s = this.getScrollState();
57043 this.restoreScroll(s);
57046 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
57050 this.updateHeaderSortState();
57053 getScrollState : function(){
57055 var sb = this.scroller.dom;
57056 return {left: sb.scrollLeft, top: sb.scrollTop};
57059 stripeRows : function(startRow){
57060 if(!this.grid.stripeRows || this.ds.getCount() < 1){
57063 startRow = startRow || 0;
57064 var rows = this.getBodyTable().rows;
57065 var lrows = this.getLockedTable().rows;
57066 var cls = ' x-grid-row-alt ';
57067 for(var i = startRow, len = rows.length; i < len; i++){
57068 var row = rows[i], lrow = lrows[i];
57069 var isAlt = ((i+1) % 2 == 0);
57070 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
57071 if(isAlt == hasAlt){
57075 row.className += " x-grid-row-alt";
57077 row.className = row.className.replace("x-grid-row-alt", "");
57080 lrow.className = row.className;
57085 restoreScroll : function(state){
57086 //Roo.log('GridView.restoreScroll');
57087 var sb = this.scroller.dom;
57088 sb.scrollLeft = state.left;
57089 sb.scrollTop = state.top;
57093 syncScroll : function(){
57094 //Roo.log('GridView.syncScroll');
57095 var sb = this.scroller.dom;
57096 var sh = this.mainHd.dom;
57097 var bs = this.mainBody.dom;
57098 var lv = this.lockedBody.dom;
57099 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
57100 lv.scrollTop = bs.scrollTop = sb.scrollTop;
57103 handleScroll : function(e){
57105 var sb = this.scroller.dom;
57106 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
57110 handleWheel : function(e){
57111 var d = e.getWheelDelta();
57112 this.scroller.dom.scrollTop -= d*22;
57113 // set this here to prevent jumpy scrolling on large tables
57114 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
57118 renderRows : function(startRow, endRow){
57119 // pull in all the crap needed to render rows
57120 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
57121 var colCount = cm.getColumnCount();
57123 if(ds.getCount() < 1){
57127 // build a map for all the columns
57129 for(var i = 0; i < colCount; i++){
57130 var name = cm.getDataIndex(i);
57132 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57133 renderer : cm.getRenderer(i),
57134 id : cm.getColumnId(i),
57135 locked : cm.isLocked(i),
57136 has_editor : cm.isCellEditable(i)
57140 startRow = startRow || 0;
57141 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57143 // records to render
57144 var rs = ds.getRange(startRow, endRow);
57146 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57149 // As much as I hate to duplicate code, this was branched because FireFox really hates
57150 // [].join("") on strings. The performance difference was substantial enough to
57151 // branch this function
57152 doRender : Roo.isGecko ?
57153 function(cs, rs, ds, startRow, colCount, stripe){
57154 var ts = this.templates, ct = ts.cell, rt = ts.row;
57156 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57158 var hasListener = this.grid.hasListener('rowclass');
57160 for(var j = 0, len = rs.length; j < len; j++){
57161 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57162 for(var i = 0; i < colCount; i++){
57164 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57166 p.css = p.attr = "";
57167 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57168 if(p.value == undefined || p.value === "") {
57169 p.value = " ";
57172 p.css += ' x-grid-editable-cell';
57174 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57175 p.css += ' x-grid-dirty-cell';
57177 var markup = ct.apply(p);
57185 if(stripe && ((rowIndex+1) % 2 == 0)){
57186 alt.push("x-grid-row-alt")
57189 alt.push( " x-grid-dirty-row");
57192 if(this.getRowClass){
57193 alt.push(this.getRowClass(r, rowIndex));
57199 rowIndex : rowIndex,
57202 this.grid.fireEvent('rowclass', this, rowcfg);
57203 alt.push(rowcfg.rowClass);
57205 rp.alt = alt.join(" ");
57206 lbuf+= rt.apply(rp);
57208 buf+= rt.apply(rp);
57210 return [lbuf, buf];
57212 function(cs, rs, ds, startRow, colCount, stripe){
57213 var ts = this.templates, ct = ts.cell, rt = ts.row;
57215 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57216 var hasListener = this.grid.hasListener('rowclass');
57219 for(var j = 0, len = rs.length; j < len; j++){
57220 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57221 for(var i = 0; i < colCount; i++){
57223 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57225 p.css = p.attr = "";
57226 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57227 if(p.value == undefined || p.value === "") {
57228 p.value = " ";
57232 p.css += ' x-grid-editable-cell';
57234 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57235 p.css += ' x-grid-dirty-cell'
57238 var markup = ct.apply(p);
57240 cb[cb.length] = markup;
57242 lcb[lcb.length] = markup;
57246 if(stripe && ((rowIndex+1) % 2 == 0)){
57247 alt.push( "x-grid-row-alt");
57250 alt.push(" x-grid-dirty-row");
57253 if(this.getRowClass){
57254 alt.push( this.getRowClass(r, rowIndex));
57260 rowIndex : rowIndex,
57263 this.grid.fireEvent('rowclass', this, rowcfg);
57264 alt.push(rowcfg.rowClass);
57267 rp.alt = alt.join(" ");
57268 rp.cells = lcb.join("");
57269 lbuf[lbuf.length] = rt.apply(rp);
57270 rp.cells = cb.join("");
57271 buf[buf.length] = rt.apply(rp);
57273 return [lbuf.join(""), buf.join("")];
57276 renderBody : function(){
57277 var markup = this.renderRows();
57278 var bt = this.templates.body;
57279 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57283 * Refreshes the grid
57284 * @param {Boolean} headersToo
57286 refresh : function(headersToo){
57287 this.fireEvent("beforerefresh", this);
57288 this.grid.stopEditing();
57289 var result = this.renderBody();
57290 this.lockedBody.update(result[0]);
57291 this.mainBody.update(result[1]);
57292 if(headersToo === true){
57293 this.updateHeaders();
57294 this.updateColumns();
57295 this.updateSplitters();
57296 this.updateHeaderSortState();
57298 this.syncRowHeights();
57300 this.fireEvent("refresh", this);
57303 handleColumnMove : function(cm, oldIndex, newIndex){
57304 this.indexMap = null;
57305 var s = this.getScrollState();
57306 this.refresh(true);
57307 this.restoreScroll(s);
57308 this.afterMove(newIndex);
57311 afterMove : function(colIndex){
57312 if(this.enableMoveAnim && Roo.enableFx){
57313 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57315 // if multisort - fix sortOrder, and reload..
57316 if (this.grid.dataSource.multiSort) {
57317 // the we can call sort again..
57318 var dm = this.grid.dataSource;
57319 var cm = this.grid.colModel;
57321 for(var i = 0; i < cm.config.length; i++ ) {
57323 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57324 continue; // dont' bother, it's not in sort list or being set.
57327 so.push(cm.config[i].dataIndex);
57330 dm.load(dm.lastOptions);
57337 updateCell : function(dm, rowIndex, dataIndex){
57338 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57339 if(typeof colIndex == "undefined"){ // not present in grid
57342 var cm = this.grid.colModel;
57343 var cell = this.getCell(rowIndex, colIndex);
57344 var cellText = this.getCellText(rowIndex, colIndex);
57347 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57348 id : cm.getColumnId(colIndex),
57349 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57351 var renderer = cm.getRenderer(colIndex);
57352 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57353 if(typeof val == "undefined" || val === "") {
57356 cellText.innerHTML = val;
57357 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57358 this.syncRowHeights(rowIndex, rowIndex);
57361 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57363 if(this.grid.autoSizeHeaders){
57364 var h = this.getHeaderCellMeasure(colIndex);
57365 maxWidth = Math.max(maxWidth, h.scrollWidth);
57368 if(this.cm.isLocked(colIndex)){
57369 tb = this.getLockedTable();
57372 tb = this.getBodyTable();
57373 index = colIndex - this.cm.getLockedCount();
57376 var rows = tb.rows;
57377 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57378 for(var i = 0; i < stopIndex; i++){
57379 var cell = rows[i].childNodes[index].firstChild;
57380 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57383 return maxWidth + /*margin for error in IE*/ 5;
57386 * Autofit a column to its content.
57387 * @param {Number} colIndex
57388 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57390 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57391 if(this.cm.isHidden(colIndex)){
57392 return; // can't calc a hidden column
57395 var cid = this.cm.getColumnId(colIndex);
57396 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57397 if(this.grid.autoSizeHeaders){
57398 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57401 var newWidth = this.calcColumnWidth(colIndex);
57402 this.cm.setColumnWidth(colIndex,
57403 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57404 if(!suppressEvent){
57405 this.grid.fireEvent("columnresize", colIndex, newWidth);
57410 * Autofits all columns to their content and then expands to fit any extra space in the grid
57412 autoSizeColumns : function(){
57413 var cm = this.grid.colModel;
57414 var colCount = cm.getColumnCount();
57415 for(var i = 0; i < colCount; i++){
57416 this.autoSizeColumn(i, true, true);
57418 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57421 this.updateColumns();
57427 * Autofits all columns to the grid's width proportionate with their current size
57428 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57430 fitColumns : function(reserveScrollSpace){
57431 var cm = this.grid.colModel;
57432 var colCount = cm.getColumnCount();
57436 for (i = 0; i < colCount; i++){
57437 if(!cm.isHidden(i) && !cm.isFixed(i)){
57438 w = cm.getColumnWidth(i);
57444 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57445 if(reserveScrollSpace){
57448 var frac = (avail - cm.getTotalWidth())/width;
57449 while (cols.length){
57452 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57454 this.updateColumns();
57458 onRowSelect : function(rowIndex){
57459 var row = this.getRowComposite(rowIndex);
57460 row.addClass("x-grid-row-selected");
57463 onRowDeselect : function(rowIndex){
57464 var row = this.getRowComposite(rowIndex);
57465 row.removeClass("x-grid-row-selected");
57468 onCellSelect : function(row, col){
57469 var cell = this.getCell(row, col);
57471 Roo.fly(cell).addClass("x-grid-cell-selected");
57475 onCellDeselect : function(row, col){
57476 var cell = this.getCell(row, col);
57478 Roo.fly(cell).removeClass("x-grid-cell-selected");
57482 updateHeaderSortState : function(){
57484 // sort state can be single { field: xxx, direction : yyy}
57485 // or { xxx=>ASC , yyy : DESC ..... }
57488 if (!this.ds.multiSort) {
57489 var state = this.ds.getSortState();
57493 mstate[state.field] = state.direction;
57494 // FIXME... - this is not used here.. but might be elsewhere..
57495 this.sortState = state;
57498 mstate = this.ds.sortToggle;
57500 //remove existing sort classes..
57502 var sc = this.sortClasses;
57503 var hds = this.el.select(this.headerSelector).removeClass(sc);
57505 for(var f in mstate) {
57507 var sortColumn = this.cm.findColumnIndex(f);
57509 if(sortColumn != -1){
57510 var sortDir = mstate[f];
57511 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57520 handleHeaderClick : function(g, index,e){
57522 Roo.log("header click");
57525 // touch events on header are handled by context
57526 this.handleHdCtx(g,index,e);
57531 if(this.headersDisabled){
57534 var dm = g.dataSource, cm = g.colModel;
57535 if(!cm.isSortable(index)){
57540 if (dm.multiSort) {
57541 // update the sortOrder
57543 for(var i = 0; i < cm.config.length; i++ ) {
57545 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57546 continue; // dont' bother, it's not in sort list or being set.
57549 so.push(cm.config[i].dataIndex);
57555 dm.sort(cm.getDataIndex(index));
57559 destroy : function(){
57561 this.colMenu.removeAll();
57562 Roo.menu.MenuMgr.unregister(this.colMenu);
57563 this.colMenu.getEl().remove();
57564 delete this.colMenu;
57567 this.hmenu.removeAll();
57568 Roo.menu.MenuMgr.unregister(this.hmenu);
57569 this.hmenu.getEl().remove();
57572 if(this.grid.enableColumnMove){
57573 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57575 for(var dd in dds){
57576 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57577 var elid = dds[dd].dragElId;
57579 Roo.get(elid).remove();
57580 } else if(dds[dd].config.isTarget){
57581 dds[dd].proxyTop.remove();
57582 dds[dd].proxyBottom.remove();
57585 if(Roo.dd.DDM.locationCache[dd]){
57586 delete Roo.dd.DDM.locationCache[dd];
57589 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57592 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57593 this.bind(null, null);
57594 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57597 handleLockChange : function(){
57598 this.refresh(true);
57601 onDenyColumnLock : function(){
57605 onDenyColumnHide : function(){
57609 handleHdMenuClick : function(item){
57610 var index = this.hdCtxIndex;
57611 var cm = this.cm, ds = this.ds;
57614 ds.sort(cm.getDataIndex(index), "ASC");
57617 ds.sort(cm.getDataIndex(index), "DESC");
57620 var lc = cm.getLockedCount();
57621 if(cm.getColumnCount(true) <= lc+1){
57622 this.onDenyColumnLock();
57626 cm.setLocked(index, true, true);
57627 cm.moveColumn(index, lc);
57628 this.grid.fireEvent("columnmove", index, lc);
57630 cm.setLocked(index, true);
57634 var lc = cm.getLockedCount();
57635 if((lc-1) != index){
57636 cm.setLocked(index, false, true);
57637 cm.moveColumn(index, lc-1);
57638 this.grid.fireEvent("columnmove", index, lc-1);
57640 cm.setLocked(index, false);
57643 case 'wider': // used to expand cols on touch..
57645 var cw = cm.getColumnWidth(index);
57646 cw += (item.id == 'wider' ? 1 : -1) * 50;
57647 cw = Math.max(0, cw);
57648 cw = Math.min(cw,4000);
57649 cm.setColumnWidth(index, cw);
57653 index = cm.getIndexById(item.id.substr(4));
57655 if(item.checked && cm.getColumnCount(true) <= 1){
57656 this.onDenyColumnHide();
57659 cm.setHidden(index, item.checked);
57665 beforeColMenuShow : function(){
57666 var cm = this.cm, colCount = cm.getColumnCount();
57667 this.colMenu.removeAll();
57668 for(var i = 0; i < colCount; i++){
57669 this.colMenu.add(new Roo.menu.CheckItem({
57670 id: "col-"+cm.getColumnId(i),
57671 text: cm.getColumnHeader(i),
57672 checked: !cm.isHidden(i),
57678 handleHdCtx : function(g, index, e){
57680 var hd = this.getHeaderCell(index);
57681 this.hdCtxIndex = index;
57682 var ms = this.hmenu.items, cm = this.cm;
57683 ms.get("asc").setDisabled(!cm.isSortable(index));
57684 ms.get("desc").setDisabled(!cm.isSortable(index));
57685 if(this.grid.enableColLock !== false){
57686 ms.get("lock").setDisabled(cm.isLocked(index));
57687 ms.get("unlock").setDisabled(!cm.isLocked(index));
57689 this.hmenu.show(hd, "tl-bl");
57692 handleHdOver : function(e){
57693 var hd = this.findHeaderCell(e.getTarget());
57694 if(hd && !this.headersDisabled){
57695 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57696 this.fly(hd).addClass("x-grid-hd-over");
57701 handleHdOut : function(e){
57702 var hd = this.findHeaderCell(e.getTarget());
57704 this.fly(hd).removeClass("x-grid-hd-over");
57708 handleSplitDblClick : function(e, t){
57709 var i = this.getCellIndex(t);
57710 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57711 this.autoSizeColumn(i, true);
57716 render : function(){
57719 var colCount = cm.getColumnCount();
57721 if(this.grid.monitorWindowResize === true){
57722 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57724 var header = this.renderHeaders();
57725 var body = this.templates.body.apply({rows:""});
57726 var html = this.templates.master.apply({
57729 lockedHeader: header[0],
57733 //this.updateColumns();
57735 this.grid.getGridEl().dom.innerHTML = html;
57737 this.initElements();
57739 // a kludge to fix the random scolling effect in webkit
57740 this.el.on("scroll", function() {
57741 this.el.dom.scrollTop=0; // hopefully not recursive..
57744 this.scroller.on("scroll", this.handleScroll, this);
57745 this.lockedBody.on("mousewheel", this.handleWheel, this);
57746 this.mainBody.on("mousewheel", this.handleWheel, this);
57748 this.mainHd.on("mouseover", this.handleHdOver, this);
57749 this.mainHd.on("mouseout", this.handleHdOut, this);
57750 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57751 {delegate: "."+this.splitClass});
57753 this.lockedHd.on("mouseover", this.handleHdOver, this);
57754 this.lockedHd.on("mouseout", this.handleHdOut, this);
57755 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57756 {delegate: "."+this.splitClass});
57758 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57759 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57762 this.updateSplitters();
57764 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57765 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57766 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57769 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57770 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57772 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57773 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57775 if(this.grid.enableColLock !== false){
57776 this.hmenu.add('-',
57777 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57778 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57782 this.hmenu.add('-',
57783 {id:"wider", text: this.columnsWiderText},
57784 {id:"narrow", text: this.columnsNarrowText }
57790 if(this.grid.enableColumnHide !== false){
57792 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57793 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57794 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57796 this.hmenu.add('-',
57797 {id:"columns", text: this.columnsText, menu: this.colMenu}
57800 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57802 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57805 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57806 this.dd = new Roo.grid.GridDragZone(this.grid, {
57807 ddGroup : this.grid.ddGroup || 'GridDD'
57813 for(var i = 0; i < colCount; i++){
57814 if(cm.isHidden(i)){
57815 this.hideColumn(i);
57817 if(cm.config[i].align){
57818 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57819 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57823 this.updateHeaderSortState();
57825 this.beforeInitialResize();
57828 // two part rendering gives faster view to the user
57829 this.renderPhase2.defer(1, this);
57832 renderPhase2 : function(){
57833 // render the rows now
57835 if(this.grid.autoSizeColumns){
57836 this.autoSizeColumns();
57840 beforeInitialResize : function(){
57844 onColumnSplitterMoved : function(i, w){
57845 this.userResized = true;
57846 var cm = this.grid.colModel;
57847 cm.setColumnWidth(i, w, true);
57848 var cid = cm.getColumnId(i);
57849 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57850 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57851 this.updateSplitters();
57853 this.grid.fireEvent("columnresize", i, w);
57856 syncRowHeights : function(startIndex, endIndex){
57857 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
57858 startIndex = startIndex || 0;
57859 var mrows = this.getBodyTable().rows;
57860 var lrows = this.getLockedTable().rows;
57861 var len = mrows.length-1;
57862 endIndex = Math.min(endIndex || len, len);
57863 for(var i = startIndex; i <= endIndex; i++){
57864 var m = mrows[i], l = lrows[i];
57865 var h = Math.max(m.offsetHeight, l.offsetHeight);
57866 m.style.height = l.style.height = h + "px";
57871 layout : function(initialRender, is2ndPass)
57874 var auto = g.autoHeight;
57875 var scrollOffset = 16;
57876 var c = g.getGridEl(), cm = this.cm,
57877 expandCol = g.autoExpandColumn,
57879 //c.beginMeasure();
57881 if(!c.dom.offsetWidth){ // display:none?
57883 this.lockedWrap.show();
57884 this.mainWrap.show();
57889 var hasLock = this.cm.isLocked(0);
57891 var tbh = this.headerPanel.getHeight();
57892 var bbh = this.footerPanel.getHeight();
57895 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
57896 var newHeight = ch + c.getBorderWidth("tb");
57898 newHeight = Math.min(g.maxHeight, newHeight);
57900 c.setHeight(newHeight);
57904 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
57907 var s = this.scroller;
57909 var csize = c.getSize(true);
57911 this.el.setSize(csize.width, csize.height);
57913 this.headerPanel.setWidth(csize.width);
57914 this.footerPanel.setWidth(csize.width);
57916 var hdHeight = this.mainHd.getHeight();
57917 var vw = csize.width;
57918 var vh = csize.height - (tbh + bbh);
57922 var bt = this.getBodyTable();
57924 if(cm.getLockedCount() == cm.config.length){
57925 bt = this.getLockedTable();
57928 var ltWidth = hasLock ?
57929 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
57931 var scrollHeight = bt.offsetHeight;
57932 var scrollWidth = ltWidth + bt.offsetWidth;
57933 var vscroll = false, hscroll = false;
57935 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
57937 var lw = this.lockedWrap, mw = this.mainWrap;
57938 var lb = this.lockedBody, mb = this.mainBody;
57940 setTimeout(function(){
57941 var t = s.dom.offsetTop;
57942 var w = s.dom.clientWidth,
57943 h = s.dom.clientHeight;
57946 lw.setSize(ltWidth, h);
57948 mw.setLeftTop(ltWidth, t);
57949 mw.setSize(w-ltWidth, h);
57951 lb.setHeight(h-hdHeight);
57952 mb.setHeight(h-hdHeight);
57954 if(is2ndPass !== true && !gv.userResized && expandCol){
57955 // high speed resize without full column calculation
57957 var ci = cm.getIndexById(expandCol);
57959 ci = cm.findColumnIndex(expandCol);
57961 ci = Math.max(0, ci); // make sure it's got at least the first col.
57962 var expandId = cm.getColumnId(ci);
57963 var tw = cm.getTotalWidth(false);
57964 var currentWidth = cm.getColumnWidth(ci);
57965 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
57966 if(currentWidth != cw){
57967 cm.setColumnWidth(ci, cw, true);
57968 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57969 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
57970 gv.updateSplitters();
57971 gv.layout(false, true);
57983 onWindowResize : function(){
57984 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
57990 appendFooter : function(parentEl){
57994 sortAscText : "Sort Ascending",
57995 sortDescText : "Sort Descending",
57996 lockText : "Lock Column",
57997 unlockText : "Unlock Column",
57998 columnsText : "Columns",
58000 columnsWiderText : "Wider",
58001 columnsNarrowText : "Thinner"
58005 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
58006 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
58007 this.proxy.el.addClass('x-grid3-col-dd');
58010 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
58011 handleMouseDown : function(e){
58015 callHandleMouseDown : function(e){
58016 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
58021 * Ext JS Library 1.1.1
58022 * Copyright(c) 2006-2007, Ext JS, LLC.
58024 * Originally Released Under LGPL - original licence link has changed is not relivant.
58027 * <script type="text/javascript">
58031 // This is a support class used internally by the Grid components
58032 Roo.grid.SplitDragZone = function(grid, hd, hd2){
58034 this.view = grid.getView();
58035 this.proxy = this.view.resizeProxy;
58036 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
58037 "gridSplitters" + this.grid.getGridEl().id, {
58038 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
58040 this.setHandleElId(Roo.id(hd));
58041 this.setOuterHandleElId(Roo.id(hd2));
58042 this.scroll = false;
58044 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
58045 fly: Roo.Element.fly,
58047 b4StartDrag : function(x, y){
58048 this.view.headersDisabled = true;
58049 this.proxy.setHeight(this.view.mainWrap.getHeight());
58050 var w = this.cm.getColumnWidth(this.cellIndex);
58051 var minw = Math.max(w-this.grid.minColumnWidth, 0);
58052 this.resetConstraints();
58053 this.setXConstraint(minw, 1000);
58054 this.setYConstraint(0, 0);
58055 this.minX = x - minw;
58056 this.maxX = x + 1000;
58058 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
58062 handleMouseDown : function(e){
58063 ev = Roo.EventObject.setEvent(e);
58064 var t = this.fly(ev.getTarget());
58065 if(t.hasClass("x-grid-split")){
58066 this.cellIndex = this.view.getCellIndex(t.dom);
58067 this.split = t.dom;
58068 this.cm = this.grid.colModel;
58069 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
58070 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
58075 endDrag : function(e){
58076 this.view.headersDisabled = false;
58077 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
58078 var diff = endX - this.startPos;
58079 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
58082 autoOffset : function(){
58083 this.setDelta(0,0);
58087 * Ext JS Library 1.1.1
58088 * Copyright(c) 2006-2007, Ext JS, LLC.
58090 * Originally Released Under LGPL - original licence link has changed is not relivant.
58093 * <script type="text/javascript">
58097 // This is a support class used internally by the Grid components
58098 Roo.grid.GridDragZone = function(grid, config){
58099 this.view = grid.getView();
58100 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
58101 if(this.view.lockedBody){
58102 this.setHandleElId(Roo.id(this.view.mainBody.dom));
58103 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
58105 this.scroll = false;
58107 this.ddel = document.createElement('div');
58108 this.ddel.className = 'x-grid-dd-wrap';
58111 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
58112 ddGroup : "GridDD",
58114 getDragData : function(e){
58115 var t = Roo.lib.Event.getTarget(e);
58116 var rowIndex = this.view.findRowIndex(t);
58117 var sm = this.grid.selModel;
58119 //Roo.log(rowIndex);
58121 if (sm.getSelectedCell) {
58122 // cell selection..
58123 if (!sm.getSelectedCell()) {
58126 if (rowIndex != sm.getSelectedCell()[0]) {
58131 if (sm.getSelections && sm.getSelections().length < 1) {
58136 // before it used to all dragging of unseleted... - now we dont do that.
58137 if(rowIndex !== false){
58142 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58144 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58147 if (e.hasModifier()){
58148 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58151 Roo.log("getDragData");
58156 rowIndex: rowIndex,
58157 selections: sm.getSelections ? sm.getSelections() : (
58158 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
58165 onInitDrag : function(e){
58166 var data = this.dragData;
58167 this.ddel.innerHTML = this.grid.getDragDropText();
58168 this.proxy.update(this.ddel);
58169 // fire start drag?
58172 afterRepair : function(){
58173 this.dragging = false;
58176 getRepairXY : function(e, data){
58180 onEndDrag : function(data, e){
58184 onValidDrop : function(dd, e, id){
58189 beforeInvalidDrop : function(e, id){
58194 * Ext JS Library 1.1.1
58195 * Copyright(c) 2006-2007, Ext JS, LLC.
58197 * Originally Released Under LGPL - original licence link has changed is not relivant.
58200 * <script type="text/javascript">
58205 * @class Roo.grid.ColumnModel
58206 * @extends Roo.util.Observable
58207 * This is the default implementation of a ColumnModel used by the Grid. It defines
58208 * the columns in the grid.
58211 var colModel = new Roo.grid.ColumnModel([
58212 {header: "Ticker", width: 60, sortable: true, locked: true},
58213 {header: "Company Name", width: 150, sortable: true},
58214 {header: "Market Cap.", width: 100, sortable: true},
58215 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58216 {header: "Employees", width: 100, sortable: true, resizable: false}
58221 * The config options listed for this class are options which may appear in each
58222 * individual column definition.
58223 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58225 * @param {Object} config An Array of column config objects. See this class's
58226 * config objects for details.
58228 Roo.grid.ColumnModel = function(config){
58230 * The config passed into the constructor
58232 this.config = config;
58235 // if no id, create one
58236 // if the column does not have a dataIndex mapping,
58237 // map it to the order it is in the config
58238 for(var i = 0, len = config.length; i < len; i++){
58240 if(typeof c.dataIndex == "undefined"){
58243 if(typeof c.renderer == "string"){
58244 c.renderer = Roo.util.Format[c.renderer];
58246 if(typeof c.id == "undefined"){
58249 if(c.editor && c.editor.xtype){
58250 c.editor = Roo.factory(c.editor, Roo.grid);
58252 if(c.editor && c.editor.isFormField){
58253 c.editor = new Roo.grid.GridEditor(c.editor);
58255 this.lookup[c.id] = c;
58259 * The width of columns which have no width specified (defaults to 100)
58262 this.defaultWidth = 100;
58265 * Default sortable of columns which have no sortable specified (defaults to false)
58268 this.defaultSortable = false;
58272 * @event widthchange
58273 * Fires when the width of a column changes.
58274 * @param {ColumnModel} this
58275 * @param {Number} columnIndex The column index
58276 * @param {Number} newWidth The new width
58278 "widthchange": true,
58280 * @event headerchange
58281 * Fires when the text of a header changes.
58282 * @param {ColumnModel} this
58283 * @param {Number} columnIndex The column index
58284 * @param {Number} newText The new header text
58286 "headerchange": true,
58288 * @event hiddenchange
58289 * Fires when a column is hidden or "unhidden".
58290 * @param {ColumnModel} this
58291 * @param {Number} columnIndex The column index
58292 * @param {Boolean} hidden true if hidden, false otherwise
58294 "hiddenchange": true,
58296 * @event columnmoved
58297 * Fires when a column is moved.
58298 * @param {ColumnModel} this
58299 * @param {Number} oldIndex
58300 * @param {Number} newIndex
58302 "columnmoved" : true,
58304 * @event columlockchange
58305 * Fires when a column's locked state is changed
58306 * @param {ColumnModel} this
58307 * @param {Number} colIndex
58308 * @param {Boolean} locked true if locked
58310 "columnlockchange" : true
58312 Roo.grid.ColumnModel.superclass.constructor.call(this);
58314 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58316 * @cfg {String} header The header text to display in the Grid view.
58319 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58320 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58321 * specified, the column's index is used as an index into the Record's data Array.
58324 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58325 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58328 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58329 * Defaults to the value of the {@link #defaultSortable} property.
58330 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58333 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58336 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58339 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58342 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58345 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58346 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58347 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58348 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58351 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58354 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58357 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58360 * @cfg {String} cursor (Optional)
58363 * @cfg {String} tooltip (Optional)
58366 * @cfg {Number} xs (Optional)
58369 * @cfg {Number} sm (Optional)
58372 * @cfg {Number} md (Optional)
58375 * @cfg {Number} lg (Optional)
58378 * Returns the id of the column at the specified index.
58379 * @param {Number} index The column index
58380 * @return {String} the id
58382 getColumnId : function(index){
58383 return this.config[index].id;
58387 * Returns the column for a specified id.
58388 * @param {String} id The column id
58389 * @return {Object} the column
58391 getColumnById : function(id){
58392 return this.lookup[id];
58397 * Returns the column for a specified dataIndex.
58398 * @param {String} dataIndex The column dataIndex
58399 * @return {Object|Boolean} the column or false if not found
58401 getColumnByDataIndex: function(dataIndex){
58402 var index = this.findColumnIndex(dataIndex);
58403 return index > -1 ? this.config[index] : false;
58407 * Returns the index for a specified column id.
58408 * @param {String} id The column id
58409 * @return {Number} the index, or -1 if not found
58411 getIndexById : function(id){
58412 for(var i = 0, len = this.config.length; i < len; i++){
58413 if(this.config[i].id == id){
58421 * Returns the index for a specified column dataIndex.
58422 * @param {String} dataIndex The column dataIndex
58423 * @return {Number} the index, or -1 if not found
58426 findColumnIndex : function(dataIndex){
58427 for(var i = 0, len = this.config.length; i < len; i++){
58428 if(this.config[i].dataIndex == dataIndex){
58436 moveColumn : function(oldIndex, newIndex){
58437 var c = this.config[oldIndex];
58438 this.config.splice(oldIndex, 1);
58439 this.config.splice(newIndex, 0, c);
58440 this.dataMap = null;
58441 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58444 isLocked : function(colIndex){
58445 return this.config[colIndex].locked === true;
58448 setLocked : function(colIndex, value, suppressEvent){
58449 if(this.isLocked(colIndex) == value){
58452 this.config[colIndex].locked = value;
58453 if(!suppressEvent){
58454 this.fireEvent("columnlockchange", this, colIndex, value);
58458 getTotalLockedWidth : function(){
58459 var totalWidth = 0;
58460 for(var i = 0; i < this.config.length; i++){
58461 if(this.isLocked(i) && !this.isHidden(i)){
58462 this.totalWidth += this.getColumnWidth(i);
58468 getLockedCount : function(){
58469 for(var i = 0, len = this.config.length; i < len; i++){
58470 if(!this.isLocked(i)){
58475 return this.config.length;
58479 * Returns the number of columns.
58482 getColumnCount : function(visibleOnly){
58483 if(visibleOnly === true){
58485 for(var i = 0, len = this.config.length; i < len; i++){
58486 if(!this.isHidden(i)){
58492 return this.config.length;
58496 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58497 * @param {Function} fn
58498 * @param {Object} scope (optional)
58499 * @return {Array} result
58501 getColumnsBy : function(fn, scope){
58503 for(var i = 0, len = this.config.length; i < len; i++){
58504 var c = this.config[i];
58505 if(fn.call(scope||this, c, i) === true){
58513 * Returns true if the specified column is sortable.
58514 * @param {Number} col The column index
58515 * @return {Boolean}
58517 isSortable : function(col){
58518 if(typeof this.config[col].sortable == "undefined"){
58519 return this.defaultSortable;
58521 return this.config[col].sortable;
58525 * Returns the rendering (formatting) function defined for the column.
58526 * @param {Number} col The column index.
58527 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58529 getRenderer : function(col){
58530 if(!this.config[col].renderer){
58531 return Roo.grid.ColumnModel.defaultRenderer;
58533 return this.config[col].renderer;
58537 * Sets the rendering (formatting) function for a column.
58538 * @param {Number} col The column index
58539 * @param {Function} fn The function to use to process the cell's raw data
58540 * to return HTML markup for the grid view. The render function is called with
58541 * the following parameters:<ul>
58542 * <li>Data value.</li>
58543 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58544 * <li>css A CSS style string to apply to the table cell.</li>
58545 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58546 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58547 * <li>Row index</li>
58548 * <li>Column index</li>
58549 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58551 setRenderer : function(col, fn){
58552 this.config[col].renderer = fn;
58556 * Returns the width for the specified column.
58557 * @param {Number} col The column index
58560 getColumnWidth : function(col){
58561 return this.config[col].width * 1 || this.defaultWidth;
58565 * Sets the width for a column.
58566 * @param {Number} col The column index
58567 * @param {Number} width The new width
58569 setColumnWidth : function(col, width, suppressEvent){
58570 this.config[col].width = width;
58571 this.totalWidth = null;
58572 if(!suppressEvent){
58573 this.fireEvent("widthchange", this, col, width);
58578 * Returns the total width of all columns.
58579 * @param {Boolean} includeHidden True to include hidden column widths
58582 getTotalWidth : function(includeHidden){
58583 if(!this.totalWidth){
58584 this.totalWidth = 0;
58585 for(var i = 0, len = this.config.length; i < len; i++){
58586 if(includeHidden || !this.isHidden(i)){
58587 this.totalWidth += this.getColumnWidth(i);
58591 return this.totalWidth;
58595 * Returns the header for the specified column.
58596 * @param {Number} col The column index
58599 getColumnHeader : function(col){
58600 return this.config[col].header;
58604 * Sets the header for a column.
58605 * @param {Number} col The column index
58606 * @param {String} header The new header
58608 setColumnHeader : function(col, header){
58609 this.config[col].header = header;
58610 this.fireEvent("headerchange", this, col, header);
58614 * Returns the tooltip for the specified column.
58615 * @param {Number} col The column index
58618 getColumnTooltip : function(col){
58619 return this.config[col].tooltip;
58622 * Sets the tooltip for a column.
58623 * @param {Number} col The column index
58624 * @param {String} tooltip The new tooltip
58626 setColumnTooltip : function(col, tooltip){
58627 this.config[col].tooltip = tooltip;
58631 * Returns the dataIndex for the specified column.
58632 * @param {Number} col The column index
58635 getDataIndex : function(col){
58636 return this.config[col].dataIndex;
58640 * Sets the dataIndex for a column.
58641 * @param {Number} col The column index
58642 * @param {Number} dataIndex The new dataIndex
58644 setDataIndex : function(col, dataIndex){
58645 this.config[col].dataIndex = dataIndex;
58651 * Returns true if the cell is editable.
58652 * @param {Number} colIndex The column index
58653 * @param {Number} rowIndex The row index - this is nto actually used..?
58654 * @return {Boolean}
58656 isCellEditable : function(colIndex, rowIndex){
58657 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58661 * Returns the editor defined for the cell/column.
58662 * return false or null to disable editing.
58663 * @param {Number} colIndex The column index
58664 * @param {Number} rowIndex The row index
58667 getCellEditor : function(colIndex, rowIndex){
58668 return this.config[colIndex].editor;
58672 * Sets if a column is editable.
58673 * @param {Number} col The column index
58674 * @param {Boolean} editable True if the column is editable
58676 setEditable : function(col, editable){
58677 this.config[col].editable = editable;
58682 * Returns true if the column is hidden.
58683 * @param {Number} colIndex The column index
58684 * @return {Boolean}
58686 isHidden : function(colIndex){
58687 return this.config[colIndex].hidden;
58692 * Returns true if the column width cannot be changed
58694 isFixed : function(colIndex){
58695 return this.config[colIndex].fixed;
58699 * Returns true if the column can be resized
58700 * @return {Boolean}
58702 isResizable : function(colIndex){
58703 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58706 * Sets if a column is hidden.
58707 * @param {Number} colIndex The column index
58708 * @param {Boolean} hidden True if the column is hidden
58710 setHidden : function(colIndex, hidden){
58711 this.config[colIndex].hidden = hidden;
58712 this.totalWidth = null;
58713 this.fireEvent("hiddenchange", this, colIndex, hidden);
58717 * Sets the editor for a column.
58718 * @param {Number} col The column index
58719 * @param {Object} editor The editor object
58721 setEditor : function(col, editor){
58722 this.config[col].editor = editor;
58726 Roo.grid.ColumnModel.defaultRenderer = function(value)
58728 if(typeof value == "object") {
58731 if(typeof value == "string" && value.length < 1){
58735 return String.format("{0}", value);
58738 // Alias for backwards compatibility
58739 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
58742 * Ext JS Library 1.1.1
58743 * Copyright(c) 2006-2007, Ext JS, LLC.
58745 * Originally Released Under LGPL - original licence link has changed is not relivant.
58748 * <script type="text/javascript">
58752 * @class Roo.grid.AbstractSelectionModel
58753 * @extends Roo.util.Observable
58754 * Abstract base class for grid SelectionModels. It provides the interface that should be
58755 * implemented by descendant classes. This class should not be directly instantiated.
58758 Roo.grid.AbstractSelectionModel = function(){
58759 this.locked = false;
58760 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
58763 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
58764 /** @ignore Called by the grid automatically. Do not call directly. */
58765 init : function(grid){
58771 * Locks the selections.
58774 this.locked = true;
58778 * Unlocks the selections.
58780 unlock : function(){
58781 this.locked = false;
58785 * Returns true if the selections are locked.
58786 * @return {Boolean}
58788 isLocked : function(){
58789 return this.locked;
58793 * Ext JS Library 1.1.1
58794 * Copyright(c) 2006-2007, Ext JS, LLC.
58796 * Originally Released Under LGPL - original licence link has changed is not relivant.
58799 * <script type="text/javascript">
58802 * @extends Roo.grid.AbstractSelectionModel
58803 * @class Roo.grid.RowSelectionModel
58804 * The default SelectionModel used by {@link Roo.grid.Grid}.
58805 * It supports multiple selections and keyboard selection/navigation.
58807 * @param {Object} config
58809 Roo.grid.RowSelectionModel = function(config){
58810 Roo.apply(this, config);
58811 this.selections = new Roo.util.MixedCollection(false, function(o){
58816 this.lastActive = false;
58820 * @event selectionchange
58821 * Fires when the selection changes
58822 * @param {SelectionModel} this
58824 "selectionchange" : true,
58826 * @event afterselectionchange
58827 * Fires after the selection changes (eg. by key press or clicking)
58828 * @param {SelectionModel} this
58830 "afterselectionchange" : true,
58832 * @event beforerowselect
58833 * Fires when a row is selected being selected, return false to cancel.
58834 * @param {SelectionModel} this
58835 * @param {Number} rowIndex The selected index
58836 * @param {Boolean} keepExisting False if other selections will be cleared
58838 "beforerowselect" : true,
58841 * Fires when a row is selected.
58842 * @param {SelectionModel} this
58843 * @param {Number} rowIndex The selected index
58844 * @param {Roo.data.Record} r The record
58846 "rowselect" : true,
58848 * @event rowdeselect
58849 * Fires when a row is deselected.
58850 * @param {SelectionModel} this
58851 * @param {Number} rowIndex The selected index
58853 "rowdeselect" : true
58855 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
58856 this.locked = false;
58859 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
58861 * @cfg {Boolean} singleSelect
58862 * True to allow selection of only one row at a time (defaults to false)
58864 singleSelect : false,
58867 initEvents : function(){
58869 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
58870 this.grid.on("mousedown", this.handleMouseDown, this);
58871 }else{ // allow click to work like normal
58872 this.grid.on("rowclick", this.handleDragableRowClick, this);
58875 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
58876 "up" : function(e){
58878 this.selectPrevious(e.shiftKey);
58879 }else if(this.last !== false && this.lastActive !== false){
58880 var last = this.last;
58881 this.selectRange(this.last, this.lastActive-1);
58882 this.grid.getView().focusRow(this.lastActive);
58883 if(last !== false){
58887 this.selectFirstRow();
58889 this.fireEvent("afterselectionchange", this);
58891 "down" : function(e){
58893 this.selectNext(e.shiftKey);
58894 }else if(this.last !== false && this.lastActive !== false){
58895 var last = this.last;
58896 this.selectRange(this.last, this.lastActive+1);
58897 this.grid.getView().focusRow(this.lastActive);
58898 if(last !== false){
58902 this.selectFirstRow();
58904 this.fireEvent("afterselectionchange", this);
58909 var view = this.grid.view;
58910 view.on("refresh", this.onRefresh, this);
58911 view.on("rowupdated", this.onRowUpdated, this);
58912 view.on("rowremoved", this.onRemove, this);
58916 onRefresh : function(){
58917 var ds = this.grid.dataSource, i, v = this.grid.view;
58918 var s = this.selections;
58919 s.each(function(r){
58920 if((i = ds.indexOfId(r.id)) != -1){
58922 s.add(ds.getAt(i)); // updating the selection relate data
58930 onRemove : function(v, index, r){
58931 this.selections.remove(r);
58935 onRowUpdated : function(v, index, r){
58936 if(this.isSelected(r)){
58937 v.onRowSelect(index);
58943 * @param {Array} records The records to select
58944 * @param {Boolean} keepExisting (optional) True to keep existing selections
58946 selectRecords : function(records, keepExisting){
58948 this.clearSelections();
58950 var ds = this.grid.dataSource;
58951 for(var i = 0, len = records.length; i < len; i++){
58952 this.selectRow(ds.indexOf(records[i]), true);
58957 * Gets the number of selected rows.
58960 getCount : function(){
58961 return this.selections.length;
58965 * Selects the first row in the grid.
58967 selectFirstRow : function(){
58972 * Select the last row.
58973 * @param {Boolean} keepExisting (optional) True to keep existing selections
58975 selectLastRow : function(keepExisting){
58976 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
58980 * Selects the row immediately following the last selected row.
58981 * @param {Boolean} keepExisting (optional) True to keep existing selections
58983 selectNext : function(keepExisting){
58984 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
58985 this.selectRow(this.last+1, keepExisting);
58986 this.grid.getView().focusRow(this.last);
58991 * Selects the row that precedes the last selected row.
58992 * @param {Boolean} keepExisting (optional) True to keep existing selections
58994 selectPrevious : function(keepExisting){
58996 this.selectRow(this.last-1, keepExisting);
58997 this.grid.getView().focusRow(this.last);
59002 * Returns the selected records
59003 * @return {Array} Array of selected records
59005 getSelections : function(){
59006 return [].concat(this.selections.items);
59010 * Returns the first selected record.
59013 getSelected : function(){
59014 return this.selections.itemAt(0);
59019 * Clears all selections.
59021 clearSelections : function(fast){
59026 var ds = this.grid.dataSource;
59027 var s = this.selections;
59028 s.each(function(r){
59029 this.deselectRow(ds.indexOfId(r.id));
59033 this.selections.clear();
59040 * Selects all rows.
59042 selectAll : function(){
59046 this.selections.clear();
59047 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
59048 this.selectRow(i, true);
59053 * Returns True if there is a selection.
59054 * @return {Boolean}
59056 hasSelection : function(){
59057 return this.selections.length > 0;
59061 * Returns True if the specified row is selected.
59062 * @param {Number/Record} record The record or index of the record to check
59063 * @return {Boolean}
59065 isSelected : function(index){
59066 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
59067 return (r && this.selections.key(r.id) ? true : false);
59071 * Returns True if the specified record id is selected.
59072 * @param {String} id The id of record to check
59073 * @return {Boolean}
59075 isIdSelected : function(id){
59076 return (this.selections.key(id) ? true : false);
59080 handleMouseDown : function(e, t){
59081 var view = this.grid.getView(), rowIndex;
59082 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
59085 if(e.shiftKey && this.last !== false){
59086 var last = this.last;
59087 this.selectRange(last, rowIndex, e.ctrlKey);
59088 this.last = last; // reset the last
59089 view.focusRow(rowIndex);
59091 var isSelected = this.isSelected(rowIndex);
59092 if(e.button !== 0 && isSelected){
59093 view.focusRow(rowIndex);
59094 }else if(e.ctrlKey && isSelected){
59095 this.deselectRow(rowIndex);
59096 }else if(!isSelected){
59097 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
59098 view.focusRow(rowIndex);
59101 this.fireEvent("afterselectionchange", this);
59104 handleDragableRowClick : function(grid, rowIndex, e)
59106 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
59107 this.selectRow(rowIndex, false);
59108 grid.view.focusRow(rowIndex);
59109 this.fireEvent("afterselectionchange", this);
59114 * Selects multiple rows.
59115 * @param {Array} rows Array of the indexes of the row to select
59116 * @param {Boolean} keepExisting (optional) True to keep existing selections
59118 selectRows : function(rows, keepExisting){
59120 this.clearSelections();
59122 for(var i = 0, len = rows.length; i < len; i++){
59123 this.selectRow(rows[i], true);
59128 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59129 * @param {Number} startRow The index of the first row in the range
59130 * @param {Number} endRow The index of the last row in the range
59131 * @param {Boolean} keepExisting (optional) True to retain existing selections
59133 selectRange : function(startRow, endRow, keepExisting){
59138 this.clearSelections();
59140 if(startRow <= endRow){
59141 for(var i = startRow; i <= endRow; i++){
59142 this.selectRow(i, true);
59145 for(var i = startRow; i >= endRow; i--){
59146 this.selectRow(i, true);
59152 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59153 * @param {Number} startRow The index of the first row in the range
59154 * @param {Number} endRow The index of the last row in the range
59156 deselectRange : function(startRow, endRow, preventViewNotify){
59160 for(var i = startRow; i <= endRow; i++){
59161 this.deselectRow(i, preventViewNotify);
59167 * @param {Number} row The index of the row to select
59168 * @param {Boolean} keepExisting (optional) True to keep existing selections
59170 selectRow : function(index, keepExisting, preventViewNotify){
59171 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
59174 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59175 if(!keepExisting || this.singleSelect){
59176 this.clearSelections();
59178 var r = this.grid.dataSource.getAt(index);
59179 this.selections.add(r);
59180 this.last = this.lastActive = index;
59181 if(!preventViewNotify){
59182 this.grid.getView().onRowSelect(index);
59184 this.fireEvent("rowselect", this, index, r);
59185 this.fireEvent("selectionchange", this);
59191 * @param {Number} row The index of the row to deselect
59193 deselectRow : function(index, preventViewNotify){
59197 if(this.last == index){
59200 if(this.lastActive == index){
59201 this.lastActive = false;
59203 var r = this.grid.dataSource.getAt(index);
59204 this.selections.remove(r);
59205 if(!preventViewNotify){
59206 this.grid.getView().onRowDeselect(index);
59208 this.fireEvent("rowdeselect", this, index);
59209 this.fireEvent("selectionchange", this);
59213 restoreLast : function(){
59215 this.last = this._last;
59220 acceptsNav : function(row, col, cm){
59221 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59225 onEditorKey : function(field, e){
59226 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59231 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59233 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59235 }else if(k == e.ENTER && !e.ctrlKey){
59239 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59241 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59243 }else if(k == e.ESC){
59247 g.startEditing(newCell[0], newCell[1]);
59252 * Ext JS Library 1.1.1
59253 * Copyright(c) 2006-2007, Ext JS, LLC.
59255 * Originally Released Under LGPL - original licence link has changed is not relivant.
59258 * <script type="text/javascript">
59261 * @class Roo.grid.CellSelectionModel
59262 * @extends Roo.grid.AbstractSelectionModel
59263 * This class provides the basic implementation for cell selection in a grid.
59265 * @param {Object} config The object containing the configuration of this model.
59266 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59268 Roo.grid.CellSelectionModel = function(config){
59269 Roo.apply(this, config);
59271 this.selection = null;
59275 * @event beforerowselect
59276 * Fires before a cell is selected.
59277 * @param {SelectionModel} this
59278 * @param {Number} rowIndex The selected row index
59279 * @param {Number} colIndex The selected cell index
59281 "beforecellselect" : true,
59283 * @event cellselect
59284 * Fires when a cell is selected.
59285 * @param {SelectionModel} this
59286 * @param {Number} rowIndex The selected row index
59287 * @param {Number} colIndex The selected cell index
59289 "cellselect" : true,
59291 * @event selectionchange
59292 * Fires when the active selection changes.
59293 * @param {SelectionModel} this
59294 * @param {Object} selection null for no selection or an object (o) with two properties
59296 <li>o.record: the record object for the row the selection is in</li>
59297 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59300 "selectionchange" : true,
59303 * Fires when the tab (or enter) was pressed on the last editable cell
59304 * You can use this to trigger add new row.
59305 * @param {SelectionModel} this
59309 * @event beforeeditnext
59310 * Fires before the next editable sell is made active
59311 * You can use this to skip to another cell or fire the tabend
59312 * if you set cell to false
59313 * @param {Object} eventdata object : { cell : [ row, col ] }
59315 "beforeeditnext" : true
59317 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59320 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59322 enter_is_tab: false,
59325 initEvents : function(){
59326 this.grid.on("mousedown", this.handleMouseDown, this);
59327 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59328 var view = this.grid.view;
59329 view.on("refresh", this.onViewChange, this);
59330 view.on("rowupdated", this.onRowUpdated, this);
59331 view.on("beforerowremoved", this.clearSelections, this);
59332 view.on("beforerowsinserted", this.clearSelections, this);
59333 if(this.grid.isEditor){
59334 this.grid.on("beforeedit", this.beforeEdit, this);
59339 beforeEdit : function(e){
59340 this.select(e.row, e.column, false, true, e.record);
59344 onRowUpdated : function(v, index, r){
59345 if(this.selection && this.selection.record == r){
59346 v.onCellSelect(index, this.selection.cell[1]);
59351 onViewChange : function(){
59352 this.clearSelections(true);
59356 * Returns the currently selected cell,.
59357 * @return {Array} The selected cell (row, column) or null if none selected.
59359 getSelectedCell : function(){
59360 return this.selection ? this.selection.cell : null;
59364 * Clears all selections.
59365 * @param {Boolean} true to prevent the gridview from being notified about the change.
59367 clearSelections : function(preventNotify){
59368 var s = this.selection;
59370 if(preventNotify !== true){
59371 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59373 this.selection = null;
59374 this.fireEvent("selectionchange", this, null);
59379 * Returns true if there is a selection.
59380 * @return {Boolean}
59382 hasSelection : function(){
59383 return this.selection ? true : false;
59387 handleMouseDown : function(e, t){
59388 var v = this.grid.getView();
59389 if(this.isLocked()){
59392 var row = v.findRowIndex(t);
59393 var cell = v.findCellIndex(t);
59394 if(row !== false && cell !== false){
59395 this.select(row, cell);
59401 * @param {Number} rowIndex
59402 * @param {Number} collIndex
59404 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59405 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59406 this.clearSelections();
59407 r = r || this.grid.dataSource.getAt(rowIndex);
59410 cell : [rowIndex, colIndex]
59412 if(!preventViewNotify){
59413 var v = this.grid.getView();
59414 v.onCellSelect(rowIndex, colIndex);
59415 if(preventFocus !== true){
59416 v.focusCell(rowIndex, colIndex);
59419 this.fireEvent("cellselect", this, rowIndex, colIndex);
59420 this.fireEvent("selectionchange", this, this.selection);
59425 isSelectable : function(rowIndex, colIndex, cm){
59426 return !cm.isHidden(colIndex);
59430 handleKeyDown : function(e){
59431 //Roo.log('Cell Sel Model handleKeyDown');
59432 if(!e.isNavKeyPress()){
59435 var g = this.grid, s = this.selection;
59438 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59440 this.select(cell[0], cell[1]);
59445 var walk = function(row, col, step){
59446 return g.walkCells(row, col, step, sm.isSelectable, sm);
59448 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59455 // handled by onEditorKey
59456 if (g.isEditor && g.editing) {
59460 newCell = walk(r, c-1, -1);
59462 newCell = walk(r, c+1, 1);
59467 newCell = walk(r+1, c, 1);
59471 newCell = walk(r-1, c, -1);
59475 newCell = walk(r, c+1, 1);
59479 newCell = walk(r, c-1, -1);
59484 if(g.isEditor && !g.editing){
59485 g.startEditing(r, c);
59494 this.select(newCell[0], newCell[1]);
59500 acceptsNav : function(row, col, cm){
59501 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59505 * @param {Number} field (not used) - as it's normally used as a listener
59506 * @param {Number} e - event - fake it by using
59508 * var e = Roo.EventObjectImpl.prototype;
59509 * e.keyCode = e.TAB
59513 onEditorKey : function(field, e){
59515 var k = e.getKey(),
59518 ed = g.activeEditor,
59520 ///Roo.log('onEditorKey' + k);
59523 if (this.enter_is_tab && k == e.ENTER) {
59529 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59531 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59537 } else if(k == e.ENTER && !e.ctrlKey){
59540 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59542 } else if(k == e.ESC){
59547 var ecall = { cell : newCell, forward : forward };
59548 this.fireEvent('beforeeditnext', ecall );
59549 newCell = ecall.cell;
59550 forward = ecall.forward;
59554 //Roo.log('next cell after edit');
59555 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59556 } else if (forward) {
59557 // tabbed past last
59558 this.fireEvent.defer(100, this, ['tabend',this]);
59563 * Ext JS Library 1.1.1
59564 * Copyright(c) 2006-2007, Ext JS, LLC.
59566 * Originally Released Under LGPL - original licence link has changed is not relivant.
59569 * <script type="text/javascript">
59573 * @class Roo.grid.EditorGrid
59574 * @extends Roo.grid.Grid
59575 * Class for creating and editable grid.
59576 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59577 * The container MUST have some type of size defined for the grid to fill. The container will be
59578 * automatically set to position relative if it isn't already.
59579 * @param {Object} dataSource The data model to bind to
59580 * @param {Object} colModel The column model with info about this grid's columns
59582 Roo.grid.EditorGrid = function(container, config){
59583 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59584 this.getGridEl().addClass("xedit-grid");
59586 if(!this.selModel){
59587 this.selModel = new Roo.grid.CellSelectionModel();
59590 this.activeEditor = null;
59594 * @event beforeedit
59595 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59596 * <ul style="padding:5px;padding-left:16px;">
59597 * <li>grid - This grid</li>
59598 * <li>record - The record being edited</li>
59599 * <li>field - The field name being edited</li>
59600 * <li>value - The value for the field being edited.</li>
59601 * <li>row - The grid row index</li>
59602 * <li>column - The grid column index</li>
59603 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59605 * @param {Object} e An edit event (see above for description)
59607 "beforeedit" : true,
59610 * Fires after a cell is edited. <br />
59611 * <ul style="padding:5px;padding-left:16px;">
59612 * <li>grid - This grid</li>
59613 * <li>record - The record being edited</li>
59614 * <li>field - The field name being edited</li>
59615 * <li>value - The value being set</li>
59616 * <li>originalValue - The original value for the field, before the edit.</li>
59617 * <li>row - The grid row index</li>
59618 * <li>column - The grid column index</li>
59620 * @param {Object} e An edit event (see above for description)
59622 "afteredit" : true,
59624 * @event validateedit
59625 * Fires after a cell is edited, but before the value is set in the record.
59626 * You can use this to modify the value being set in the field, Return false
59627 * to cancel the change. The edit event object has the following properties <br />
59628 * <ul style="padding:5px;padding-left:16px;">
59629 * <li>editor - This editor</li>
59630 * <li>grid - This grid</li>
59631 * <li>record - The record being edited</li>
59632 * <li>field - The field name being edited</li>
59633 * <li>value - The value being set</li>
59634 * <li>originalValue - The original value for the field, before the edit.</li>
59635 * <li>row - The grid row index</li>
59636 * <li>column - The grid column index</li>
59637 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59639 * @param {Object} e An edit event (see above for description)
59641 "validateedit" : true
59643 this.on("bodyscroll", this.stopEditing, this);
59644 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59647 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59649 * @cfg {Number} clicksToEdit
59650 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59657 trackMouseOver: false, // causes very odd FF errors
59659 onCellDblClick : function(g, row, col){
59660 this.startEditing(row, col);
59663 onEditComplete : function(ed, value, startValue){
59664 this.editing = false;
59665 this.activeEditor = null;
59666 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59668 var field = this.colModel.getDataIndex(ed.col);
59673 originalValue: startValue,
59680 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59683 if(String(value) !== String(startValue)){
59685 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59686 r.set(field, e.value);
59687 // if we are dealing with a combo box..
59688 // then we also set the 'name' colum to be the displayField
59689 if (ed.field.displayField && ed.field.name) {
59690 r.set(ed.field.name, ed.field.el.dom.value);
59693 delete e.cancel; //?? why!!!
59694 this.fireEvent("afteredit", e);
59697 this.fireEvent("afteredit", e); // always fire it!
59699 this.view.focusCell(ed.row, ed.col);
59703 * Starts editing the specified for the specified row/column
59704 * @param {Number} rowIndex
59705 * @param {Number} colIndex
59707 startEditing : function(row, col){
59708 this.stopEditing();
59709 if(this.colModel.isCellEditable(col, row)){
59710 this.view.ensureVisible(row, col, true);
59712 var r = this.dataSource.getAt(row);
59713 var field = this.colModel.getDataIndex(col);
59714 var cell = Roo.get(this.view.getCell(row,col));
59719 value: r.data[field],
59724 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59725 this.editing = true;
59726 var ed = this.colModel.getCellEditor(col, row);
59732 ed.render(ed.parentEl || document.body);
59738 (function(){ // complex but required for focus issues in safari, ie and opera
59742 ed.on("complete", this.onEditComplete, this, {single: true});
59743 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
59744 this.activeEditor = ed;
59745 var v = r.data[field];
59746 ed.startEdit(this.view.getCell(row, col), v);
59747 // combo's with 'displayField and name set
59748 if (ed.field.displayField && ed.field.name) {
59749 ed.field.el.dom.value = r.data[ed.field.name];
59753 }).defer(50, this);
59759 * Stops any active editing
59761 stopEditing : function(){
59762 if(this.activeEditor){
59763 this.activeEditor.completeEdit();
59765 this.activeEditor = null;
59769 * Called to get grid's drag proxy text, by default returns this.ddText.
59772 getDragDropText : function(){
59773 var count = this.selModel.getSelectedCell() ? 1 : 0;
59774 return String.format(this.ddText, count, count == 1 ? '' : 's');
59779 * Ext JS Library 1.1.1
59780 * Copyright(c) 2006-2007, Ext JS, LLC.
59782 * Originally Released Under LGPL - original licence link has changed is not relivant.
59785 * <script type="text/javascript">
59788 // private - not really -- you end up using it !
59789 // This is a support class used internally by the Grid components
59792 * @class Roo.grid.GridEditor
59793 * @extends Roo.Editor
59794 * Class for creating and editable grid elements.
59795 * @param {Object} config any settings (must include field)
59797 Roo.grid.GridEditor = function(field, config){
59798 if (!config && field.field) {
59800 field = Roo.factory(config.field, Roo.form);
59802 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
59803 field.monitorTab = false;
59806 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
59809 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
59812 alignment: "tl-tl",
59815 cls: "x-small-editor x-grid-editor",
59820 * Ext JS Library 1.1.1
59821 * Copyright(c) 2006-2007, Ext JS, LLC.
59823 * Originally Released Under LGPL - original licence link has changed is not relivant.
59826 * <script type="text/javascript">
59831 Roo.grid.PropertyRecord = Roo.data.Record.create([
59832 {name:'name',type:'string'}, 'value'
59836 Roo.grid.PropertyStore = function(grid, source){
59838 this.store = new Roo.data.Store({
59839 recordType : Roo.grid.PropertyRecord
59841 this.store.on('update', this.onUpdate, this);
59843 this.setSource(source);
59845 Roo.grid.PropertyStore.superclass.constructor.call(this);
59850 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
59851 setSource : function(o){
59853 this.store.removeAll();
59856 if(this.isEditableValue(o[k])){
59857 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
59860 this.store.loadRecords({records: data}, {}, true);
59863 onUpdate : function(ds, record, type){
59864 if(type == Roo.data.Record.EDIT){
59865 var v = record.data['value'];
59866 var oldValue = record.modified['value'];
59867 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
59868 this.source[record.id] = v;
59870 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
59877 getProperty : function(row){
59878 return this.store.getAt(row);
59881 isEditableValue: function(val){
59882 if(val && val instanceof Date){
59884 }else if(typeof val == 'object' || typeof val == 'function'){
59890 setValue : function(prop, value){
59891 this.source[prop] = value;
59892 this.store.getById(prop).set('value', value);
59895 getSource : function(){
59896 return this.source;
59900 Roo.grid.PropertyColumnModel = function(grid, store){
59903 g.PropertyColumnModel.superclass.constructor.call(this, [
59904 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
59905 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
59907 this.store = store;
59908 this.bselect = Roo.DomHelper.append(document.body, {
59909 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
59910 {tag: 'option', value: 'true', html: 'true'},
59911 {tag: 'option', value: 'false', html: 'false'}
59914 Roo.id(this.bselect);
59917 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
59918 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
59919 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
59920 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
59921 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
59923 this.renderCellDelegate = this.renderCell.createDelegate(this);
59924 this.renderPropDelegate = this.renderProp.createDelegate(this);
59927 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
59931 valueText : 'Value',
59933 dateFormat : 'm/j/Y',
59936 renderDate : function(dateVal){
59937 return dateVal.dateFormat(this.dateFormat);
59940 renderBool : function(bVal){
59941 return bVal ? 'true' : 'false';
59944 isCellEditable : function(colIndex, rowIndex){
59945 return colIndex == 1;
59948 getRenderer : function(col){
59950 this.renderCellDelegate : this.renderPropDelegate;
59953 renderProp : function(v){
59954 return this.getPropertyName(v);
59957 renderCell : function(val){
59959 if(val instanceof Date){
59960 rv = this.renderDate(val);
59961 }else if(typeof val == 'boolean'){
59962 rv = this.renderBool(val);
59964 return Roo.util.Format.htmlEncode(rv);
59967 getPropertyName : function(name){
59968 var pn = this.grid.propertyNames;
59969 return pn && pn[name] ? pn[name] : name;
59972 getCellEditor : function(colIndex, rowIndex){
59973 var p = this.store.getProperty(rowIndex);
59974 var n = p.data['name'], val = p.data['value'];
59976 if(typeof(this.grid.customEditors[n]) == 'string'){
59977 return this.editors[this.grid.customEditors[n]];
59979 if(typeof(this.grid.customEditors[n]) != 'undefined'){
59980 return this.grid.customEditors[n];
59982 if(val instanceof Date){
59983 return this.editors['date'];
59984 }else if(typeof val == 'number'){
59985 return this.editors['number'];
59986 }else if(typeof val == 'boolean'){
59987 return this.editors['boolean'];
59989 return this.editors['string'];
59995 * @class Roo.grid.PropertyGrid
59996 * @extends Roo.grid.EditorGrid
59997 * This class represents the interface of a component based property grid control.
59998 * <br><br>Usage:<pre><code>
59999 var grid = new Roo.grid.PropertyGrid("my-container-id", {
60007 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60008 * The container MUST have some type of size defined for the grid to fill. The container will be
60009 * automatically set to position relative if it isn't already.
60010 * @param {Object} config A config object that sets properties on this grid.
60012 Roo.grid.PropertyGrid = function(container, config){
60013 config = config || {};
60014 var store = new Roo.grid.PropertyStore(this);
60015 this.store = store;
60016 var cm = new Roo.grid.PropertyColumnModel(this, store);
60017 store.store.sort('name', 'ASC');
60018 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
60021 enableColLock:false,
60022 enableColumnMove:false,
60024 trackMouseOver: false,
60027 this.getGridEl().addClass('x-props-grid');
60028 this.lastEditRow = null;
60029 this.on('columnresize', this.onColumnResize, this);
60032 * @event beforepropertychange
60033 * Fires before a property changes (return false to stop?)
60034 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60035 * @param {String} id Record Id
60036 * @param {String} newval New Value
60037 * @param {String} oldval Old Value
60039 "beforepropertychange": true,
60041 * @event propertychange
60042 * Fires after a property changes
60043 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60044 * @param {String} id Record Id
60045 * @param {String} newval New Value
60046 * @param {String} oldval Old Value
60048 "propertychange": true
60050 this.customEditors = this.customEditors || {};
60052 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
60055 * @cfg {Object} customEditors map of colnames=> custom editors.
60056 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
60057 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
60058 * false disables editing of the field.
60062 * @cfg {Object} propertyNames map of property Names to their displayed value
60065 render : function(){
60066 Roo.grid.PropertyGrid.superclass.render.call(this);
60067 this.autoSize.defer(100, this);
60070 autoSize : function(){
60071 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
60073 this.view.fitColumns();
60077 onColumnResize : function(){
60078 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
60082 * Sets the data for the Grid
60083 * accepts a Key => Value object of all the elements avaiable.
60084 * @param {Object} data to appear in grid.
60086 setSource : function(source){
60087 this.store.setSource(source);
60091 * Gets all the data from the grid.
60092 * @return {Object} data data stored in grid
60094 getSource : function(){
60095 return this.store.getSource();
60104 * @class Roo.grid.Calendar
60105 * @extends Roo.util.Grid
60106 * This class extends the Grid to provide a calendar widget
60107 * <br><br>Usage:<pre><code>
60108 var grid = new Roo.grid.Calendar("my-container-id", {
60111 selModel: mySelectionModel,
60112 autoSizeColumns: true,
60113 monitorWindowResize: false,
60114 trackMouseOver: true
60115 eventstore : real data store..
60121 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60122 * The container MUST have some type of size defined for the grid to fill. The container will be
60123 * automatically set to position relative if it isn't already.
60124 * @param {Object} config A config object that sets properties on this grid.
60126 Roo.grid.Calendar = function(container, config){
60127 // initialize the container
60128 this.container = Roo.get(container);
60129 this.container.update("");
60130 this.container.setStyle("overflow", "hidden");
60131 this.container.addClass('x-grid-container');
60133 this.id = this.container.id;
60135 Roo.apply(this, config);
60136 // check and correct shorthanded configs
60140 for (var r = 0;r < 6;r++) {
60143 for (var c =0;c < 7;c++) {
60147 if (this.eventStore) {
60148 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60149 this.eventStore.on('load',this.onLoad, this);
60150 this.eventStore.on('beforeload',this.clearEvents, this);
60154 this.dataSource = new Roo.data.Store({
60155 proxy: new Roo.data.MemoryProxy(rows),
60156 reader: new Roo.data.ArrayReader({}, [
60157 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60160 this.dataSource.load();
60161 this.ds = this.dataSource;
60162 this.ds.xmodule = this.xmodule || false;
60165 var cellRender = function(v,x,r)
60167 return String.format(
60168 '<div class="fc-day fc-widget-content"><div>' +
60169 '<div class="fc-event-container"></div>' +
60170 '<div class="fc-day-number">{0}</div>'+
60172 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60173 '</div></div>', v);
60178 this.colModel = new Roo.grid.ColumnModel( [
60180 xtype: 'ColumnModel',
60182 dataIndex : 'weekday0',
60184 renderer : cellRender
60187 xtype: 'ColumnModel',
60189 dataIndex : 'weekday1',
60191 renderer : cellRender
60194 xtype: 'ColumnModel',
60196 dataIndex : 'weekday2',
60197 header : 'Tuesday',
60198 renderer : cellRender
60201 xtype: 'ColumnModel',
60203 dataIndex : 'weekday3',
60204 header : 'Wednesday',
60205 renderer : cellRender
60208 xtype: 'ColumnModel',
60210 dataIndex : 'weekday4',
60211 header : 'Thursday',
60212 renderer : cellRender
60215 xtype: 'ColumnModel',
60217 dataIndex : 'weekday5',
60219 renderer : cellRender
60222 xtype: 'ColumnModel',
60224 dataIndex : 'weekday6',
60225 header : 'Saturday',
60226 renderer : cellRender
60229 this.cm = this.colModel;
60230 this.cm.xmodule = this.xmodule || false;
60234 //this.selModel = new Roo.grid.CellSelectionModel();
60235 //this.sm = this.selModel;
60236 //this.selModel.init(this);
60240 this.container.setWidth(this.width);
60244 this.container.setHeight(this.height);
60251 * The raw click event for the entire grid.
60252 * @param {Roo.EventObject} e
60257 * The raw dblclick event for the entire grid.
60258 * @param {Roo.EventObject} e
60262 * @event contextmenu
60263 * The raw contextmenu event for the entire grid.
60264 * @param {Roo.EventObject} e
60266 "contextmenu" : true,
60269 * The raw mousedown event for the entire grid.
60270 * @param {Roo.EventObject} e
60272 "mousedown" : true,
60275 * The raw mouseup event for the entire grid.
60276 * @param {Roo.EventObject} e
60281 * The raw mouseover event for the entire grid.
60282 * @param {Roo.EventObject} e
60284 "mouseover" : true,
60287 * The raw mouseout event for the entire grid.
60288 * @param {Roo.EventObject} e
60293 * The raw keypress event for the entire grid.
60294 * @param {Roo.EventObject} e
60299 * The raw keydown event for the entire grid.
60300 * @param {Roo.EventObject} e
60308 * Fires when a cell is clicked
60309 * @param {Grid} this
60310 * @param {Number} rowIndex
60311 * @param {Number} columnIndex
60312 * @param {Roo.EventObject} e
60314 "cellclick" : true,
60316 * @event celldblclick
60317 * Fires when a cell is double clicked
60318 * @param {Grid} this
60319 * @param {Number} rowIndex
60320 * @param {Number} columnIndex
60321 * @param {Roo.EventObject} e
60323 "celldblclick" : true,
60326 * Fires when a row is clicked
60327 * @param {Grid} this
60328 * @param {Number} rowIndex
60329 * @param {Roo.EventObject} e
60333 * @event rowdblclick
60334 * Fires when a row is double clicked
60335 * @param {Grid} this
60336 * @param {Number} rowIndex
60337 * @param {Roo.EventObject} e
60339 "rowdblclick" : true,
60341 * @event headerclick
60342 * Fires when a header is clicked
60343 * @param {Grid} this
60344 * @param {Number} columnIndex
60345 * @param {Roo.EventObject} e
60347 "headerclick" : true,
60349 * @event headerdblclick
60350 * Fires when a header cell is double clicked
60351 * @param {Grid} this
60352 * @param {Number} columnIndex
60353 * @param {Roo.EventObject} e
60355 "headerdblclick" : true,
60357 * @event rowcontextmenu
60358 * Fires when a row is right clicked
60359 * @param {Grid} this
60360 * @param {Number} rowIndex
60361 * @param {Roo.EventObject} e
60363 "rowcontextmenu" : true,
60365 * @event cellcontextmenu
60366 * Fires when a cell is right clicked
60367 * @param {Grid} this
60368 * @param {Number} rowIndex
60369 * @param {Number} cellIndex
60370 * @param {Roo.EventObject} e
60372 "cellcontextmenu" : true,
60374 * @event headercontextmenu
60375 * Fires when a header is right clicked
60376 * @param {Grid} this
60377 * @param {Number} columnIndex
60378 * @param {Roo.EventObject} e
60380 "headercontextmenu" : true,
60382 * @event bodyscroll
60383 * Fires when the body element is scrolled
60384 * @param {Number} scrollLeft
60385 * @param {Number} scrollTop
60387 "bodyscroll" : true,
60389 * @event columnresize
60390 * Fires when the user resizes a column
60391 * @param {Number} columnIndex
60392 * @param {Number} newSize
60394 "columnresize" : true,
60396 * @event columnmove
60397 * Fires when the user moves a column
60398 * @param {Number} oldIndex
60399 * @param {Number} newIndex
60401 "columnmove" : true,
60404 * Fires when row(s) start being dragged
60405 * @param {Grid} this
60406 * @param {Roo.GridDD} dd The drag drop object
60407 * @param {event} e The raw browser event
60409 "startdrag" : true,
60412 * Fires when a drag operation is complete
60413 * @param {Grid} this
60414 * @param {Roo.GridDD} dd The drag drop object
60415 * @param {event} e The raw browser event
60420 * Fires when dragged row(s) are dropped on a valid DD target
60421 * @param {Grid} this
60422 * @param {Roo.GridDD} dd The drag drop object
60423 * @param {String} targetId The target drag drop object
60424 * @param {event} e The raw browser event
60429 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60430 * @param {Grid} this
60431 * @param {Roo.GridDD} dd The drag drop object
60432 * @param {String} targetId The target drag drop object
60433 * @param {event} e The raw browser event
60438 * Fires when the dragged row(s) first cross another DD target while being dragged
60439 * @param {Grid} this
60440 * @param {Roo.GridDD} dd The drag drop object
60441 * @param {String} targetId The target drag drop object
60442 * @param {event} e The raw browser event
60444 "dragenter" : true,
60447 * Fires when the dragged row(s) leave another DD target while being dragged
60448 * @param {Grid} this
60449 * @param {Roo.GridDD} dd The drag drop object
60450 * @param {String} targetId The target drag drop object
60451 * @param {event} e The raw browser event
60456 * Fires when a row is rendered, so you can change add a style to it.
60457 * @param {GridView} gridview The grid view
60458 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60464 * Fires when the grid is rendered
60465 * @param {Grid} grid
60470 * Fires when a date is selected
60471 * @param {DatePicker} this
60472 * @param {Date} date The selected date
60476 * @event monthchange
60477 * Fires when the displayed month changes
60478 * @param {DatePicker} this
60479 * @param {Date} date The selected month
60481 'monthchange': true,
60483 * @event evententer
60484 * Fires when mouse over an event
60485 * @param {Calendar} this
60486 * @param {event} Event
60488 'evententer': true,
60490 * @event eventleave
60491 * Fires when the mouse leaves an
60492 * @param {Calendar} this
60495 'eventleave': true,
60497 * @event eventclick
60498 * Fires when the mouse click an
60499 * @param {Calendar} this
60502 'eventclick': true,
60504 * @event eventrender
60505 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60506 * @param {Calendar} this
60507 * @param {data} data to be modified
60509 'eventrender': true
60513 Roo.grid.Grid.superclass.constructor.call(this);
60514 this.on('render', function() {
60515 this.view.el.addClass('x-grid-cal');
60517 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60521 if (!Roo.grid.Calendar.style) {
60522 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60525 '.x-grid-cal .x-grid-col' : {
60526 height: 'auto !important',
60527 'vertical-align': 'top'
60529 '.x-grid-cal .fc-event-hori' : {
60540 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60542 * @cfg {Store} eventStore The store that loads events.
60547 activeDate : false,
60550 monitorWindowResize : false,
60553 resizeColumns : function() {
60554 var col = (this.view.el.getWidth() / 7) - 3;
60555 // loop through cols, and setWidth
60556 for(var i =0 ; i < 7 ; i++){
60557 this.cm.setColumnWidth(i, col);
60560 setDate :function(date) {
60562 Roo.log('setDate?');
60564 this.resizeColumns();
60565 var vd = this.activeDate;
60566 this.activeDate = date;
60567 // if(vd && this.el){
60568 // var t = date.getTime();
60569 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60570 // Roo.log('using add remove');
60572 // this.fireEvent('monthchange', this, date);
60574 // this.cells.removeClass("fc-state-highlight");
60575 // this.cells.each(function(c){
60576 // if(c.dateValue == t){
60577 // c.addClass("fc-state-highlight");
60578 // setTimeout(function(){
60579 // try{c.dom.firstChild.focus();}catch(e){}
60589 var days = date.getDaysInMonth();
60591 var firstOfMonth = date.getFirstDateOfMonth();
60592 var startingPos = firstOfMonth.getDay()-this.startDay;
60594 if(startingPos < this.startDay){
60598 var pm = date.add(Date.MONTH, -1);
60599 var prevStart = pm.getDaysInMonth()-startingPos;
60603 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60605 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60606 //this.cells.addClassOnOver('fc-state-hover');
60608 var cells = this.cells.elements;
60609 var textEls = this.textNodes;
60611 //Roo.each(cells, function(cell){
60612 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60615 days += startingPos;
60617 // convert everything to numbers so it's fast
60618 var day = 86400000;
60619 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60622 //Roo.log(prevStart);
60624 var today = new Date().clearTime().getTime();
60625 var sel = date.clearTime().getTime();
60626 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60627 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60628 var ddMatch = this.disabledDatesRE;
60629 var ddText = this.disabledDatesText;
60630 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60631 var ddaysText = this.disabledDaysText;
60632 var format = this.format;
60634 var setCellClass = function(cal, cell){
60636 //Roo.log('set Cell Class');
60638 var t = d.getTime();
60643 cell.dateValue = t;
60645 cell.className += " fc-today";
60646 cell.className += " fc-state-highlight";
60647 cell.title = cal.todayText;
60650 // disable highlight in other month..
60651 cell.className += " fc-state-highlight";
60656 //cell.className = " fc-state-disabled";
60657 cell.title = cal.minText;
60661 //cell.className = " fc-state-disabled";
60662 cell.title = cal.maxText;
60666 if(ddays.indexOf(d.getDay()) != -1){
60667 // cell.title = ddaysText;
60668 // cell.className = " fc-state-disabled";
60671 if(ddMatch && format){
60672 var fvalue = d.dateFormat(format);
60673 if(ddMatch.test(fvalue)){
60674 cell.title = ddText.replace("%0", fvalue);
60675 cell.className = " fc-state-disabled";
60679 if (!cell.initialClassName) {
60680 cell.initialClassName = cell.dom.className;
60683 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60688 for(; i < startingPos; i++) {
60689 cells[i].dayName = (++prevStart);
60690 Roo.log(textEls[i]);
60691 d.setDate(d.getDate()+1);
60693 //cells[i].className = "fc-past fc-other-month";
60694 setCellClass(this, cells[i]);
60699 for(; i < days; i++){
60700 intDay = i - startingPos + 1;
60701 cells[i].dayName = (intDay);
60702 d.setDate(d.getDate()+1);
60704 cells[i].className = ''; // "x-date-active";
60705 setCellClass(this, cells[i]);
60709 for(; i < 42; i++) {
60710 //textEls[i].innerHTML = (++extraDays);
60712 d.setDate(d.getDate()+1);
60713 cells[i].dayName = (++extraDays);
60714 cells[i].className = "fc-future fc-other-month";
60715 setCellClass(this, cells[i]);
60718 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60720 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60722 // this will cause all the cells to mis
60725 for (var r = 0;r < 6;r++) {
60726 for (var c =0;c < 7;c++) {
60727 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60731 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60732 for(i=0;i<cells.length;i++) {
60734 this.cells.elements[i].dayName = cells[i].dayName ;
60735 this.cells.elements[i].className = cells[i].className;
60736 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
60737 this.cells.elements[i].title = cells[i].title ;
60738 this.cells.elements[i].dateValue = cells[i].dateValue ;
60744 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
60745 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
60747 ////if(totalRows != 6){
60748 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
60749 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
60752 this.fireEvent('monthchange', this, date);
60757 * Returns the grid's SelectionModel.
60758 * @return {SelectionModel}
60760 getSelectionModel : function(){
60761 if(!this.selModel){
60762 this.selModel = new Roo.grid.CellSelectionModel();
60764 return this.selModel;
60768 this.eventStore.load()
60774 findCell : function(dt) {
60775 dt = dt.clearTime().getTime();
60777 this.cells.each(function(c){
60778 //Roo.log("check " +c.dateValue + '?=' + dt);
60779 if(c.dateValue == dt){
60789 findCells : function(rec) {
60790 var s = rec.data.start_dt.clone().clearTime().getTime();
60792 var e= rec.data.end_dt.clone().clearTime().getTime();
60795 this.cells.each(function(c){
60796 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
60798 if(c.dateValue > e){
60801 if(c.dateValue < s){
60810 findBestRow: function(cells)
60814 for (var i =0 ; i < cells.length;i++) {
60815 ret = Math.max(cells[i].rows || 0,ret);
60822 addItem : function(rec)
60824 // look for vertical location slot in
60825 var cells = this.findCells(rec);
60827 rec.row = this.findBestRow(cells);
60829 // work out the location.
60833 for(var i =0; i < cells.length; i++) {
60841 if (crow.start.getY() == cells[i].getY()) {
60843 crow.end = cells[i];
60859 for (var i = 0; i < cells.length;i++) {
60860 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
60867 clearEvents: function() {
60869 if (!this.eventStore.getCount()) {
60872 // reset number of rows in cells.
60873 Roo.each(this.cells.elements, function(c){
60877 this.eventStore.each(function(e) {
60878 this.clearEvent(e);
60883 clearEvent : function(ev)
60886 Roo.each(ev.els, function(el) {
60887 el.un('mouseenter' ,this.onEventEnter, this);
60888 el.un('mouseleave' ,this.onEventLeave, this);
60896 renderEvent : function(ev,ctr) {
60898 ctr = this.view.el.select('.fc-event-container',true).first();
60902 this.clearEvent(ev);
60908 var cells = ev.cells;
60909 var rows = ev.rows;
60910 this.fireEvent('eventrender', this, ev);
60912 for(var i =0; i < rows.length; i++) {
60916 cls += ' fc-event-start';
60918 if ((i+1) == rows.length) {
60919 cls += ' fc-event-end';
60922 //Roo.log(ev.data);
60923 // how many rows should it span..
60924 var cg = this.eventTmpl.append(ctr,Roo.apply({
60927 }, ev.data) , true);
60930 cg.on('mouseenter' ,this.onEventEnter, this, ev);
60931 cg.on('mouseleave' ,this.onEventLeave, this, ev);
60932 cg.on('click', this.onEventClick, this, ev);
60936 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
60937 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
60940 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
60941 cg.setWidth(ebox.right - sbox.x -2);
60945 renderEvents: function()
60947 // first make sure there is enough space..
60949 if (!this.eventTmpl) {
60950 this.eventTmpl = new Roo.Template(
60951 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
60952 '<div class="fc-event-inner">' +
60953 '<span class="fc-event-time">{time}</span>' +
60954 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
60956 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
60964 this.cells.each(function(c) {
60965 //Roo.log(c.select('.fc-day-content div',true).first());
60966 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
60969 var ctr = this.view.el.select('.fc-event-container',true).first();
60972 this.eventStore.each(function(ev){
60974 this.renderEvent(ev);
60978 this.view.layout();
60982 onEventEnter: function (e, el,event,d) {
60983 this.fireEvent('evententer', this, el, event);
60986 onEventLeave: function (e, el,event,d) {
60987 this.fireEvent('eventleave', this, el, event);
60990 onEventClick: function (e, el,event,d) {
60991 this.fireEvent('eventclick', this, el, event);
60994 onMonthChange: function () {
60998 onLoad: function () {
61000 //Roo.log('calendar onload');
61002 if(this.eventStore.getCount() > 0){
61006 this.eventStore.each(function(d){
61011 if (typeof(add.end_dt) == 'undefined') {
61012 Roo.log("Missing End time in calendar data: ");
61016 if (typeof(add.start_dt) == 'undefined') {
61017 Roo.log("Missing Start time in calendar data: ");
61021 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
61022 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
61023 add.id = add.id || d.id;
61024 add.title = add.title || '??';
61032 this.renderEvents();
61042 render : function ()
61046 if (!this.view.el.hasClass('course-timesheet')) {
61047 this.view.el.addClass('course-timesheet');
61049 if (this.tsStyle) {
61054 Roo.log(_this.grid.view.el.getWidth());
61057 this.tsStyle = Roo.util.CSS.createStyleSheet({
61058 '.course-timesheet .x-grid-row' : {
61061 '.x-grid-row td' : {
61062 'vertical-align' : 0
61064 '.course-edit-link' : {
61066 'text-overflow' : 'ellipsis',
61067 'overflow' : 'hidden',
61068 'white-space' : 'nowrap',
61069 'cursor' : 'pointer'
61074 '.de-act-sup-link' : {
61075 'color' : 'purple',
61076 'text-decoration' : 'line-through'
61080 'text-decoration' : 'line-through'
61082 '.course-timesheet .course-highlight' : {
61083 'border-top-style': 'dashed !important',
61084 'border-bottom-bottom': 'dashed !important'
61086 '.course-timesheet .course-item' : {
61087 'font-family' : 'tahoma, arial, helvetica',
61088 'font-size' : '11px',
61089 'overflow' : 'hidden',
61090 'padding-left' : '10px',
61091 'padding-right' : '10px',
61092 'padding-top' : '10px'
61100 monitorWindowResize : false,
61101 cellrenderer : function(v,x,r)
61106 xtype: 'CellSelectionModel',
61113 beforeload : function (_self, options)
61115 options.params = options.params || {};
61116 options.params._month = _this.monthField.getValue();
61117 options.params.limit = 9999;
61118 options.params['sort'] = 'when_dt';
61119 options.params['dir'] = 'ASC';
61120 this.proxy.loadResponse = this.loadResponse;
61122 //this.addColumns();
61124 load : function (_self, records, options)
61126 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
61127 // if you click on the translation.. you can edit it...
61128 var el = Roo.get(this);
61129 var id = el.dom.getAttribute('data-id');
61130 var d = el.dom.getAttribute('data-date');
61131 var t = el.dom.getAttribute('data-time');
61132 //var id = this.child('span').dom.textContent;
61135 Pman.Dialog.CourseCalendar.show({
61139 productitem_active : id ? 1 : 0
61141 _this.grid.ds.load({});
61146 _this.panel.fireEvent('resize', [ '', '' ]);
61149 loadResponse : function(o, success, response){
61150 // this is overridden on before load..
61152 Roo.log("our code?");
61153 //Roo.log(success);
61154 //Roo.log(response)
61155 delete this.activeRequest;
61157 this.fireEvent("loadexception", this, o, response);
61158 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61163 result = o.reader.read(response);
61165 Roo.log("load exception?");
61166 this.fireEvent("loadexception", this, o, response, e);
61167 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61170 Roo.log("ready...");
61171 // loop through result.records;
61172 // and set this.tdate[date] = [] << array of records..
61174 Roo.each(result.records, function(r){
61176 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61177 _this.tdata[r.data.when_dt.format('j')] = [];
61179 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61182 //Roo.log(_this.tdata);
61184 result.records = [];
61185 result.totalRecords = 6;
61187 // let's generate some duumy records for the rows.
61188 //var st = _this.dateField.getValue();
61190 // work out monday..
61191 //st = st.add(Date.DAY, -1 * st.format('w'));
61193 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61195 var firstOfMonth = date.getFirstDayOfMonth();
61196 var days = date.getDaysInMonth();
61198 var firstAdded = false;
61199 for (var i = 0; i < result.totalRecords ; i++) {
61200 //var d= st.add(Date.DAY, i);
61203 for(var w = 0 ; w < 7 ; w++){
61204 if(!firstAdded && firstOfMonth != w){
61211 var dd = (d > 0 && d < 10) ? "0"+d : d;
61212 row['weekday'+w] = String.format(
61213 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61214 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61216 date.format('Y-m-')+dd
61219 if(typeof(_this.tdata[d]) != 'undefined'){
61220 Roo.each(_this.tdata[d], function(r){
61224 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61225 if(r.parent_id*1>0){
61226 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61229 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61230 deactive = 'de-act-link';
61233 row['weekday'+w] += String.format(
61234 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61236 r.product_id_name, //1
61237 r.when_dt.format('h:ia'), //2
61247 // only do this if something added..
61249 result.records.push(_this.grid.dataSource.reader.newRow(row));
61253 // push it twice. (second one with an hour..
61257 this.fireEvent("load", this, o, o.request.arg);
61258 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61260 sortInfo : {field: 'when_dt', direction : 'ASC' },
61262 xtype: 'HttpProxy',
61265 url : baseURL + '/Roo/Shop_course.php'
61268 xtype: 'JsonReader',
61285 'name': 'parent_id',
61289 'name': 'product_id',
61293 'name': 'productitem_id',
61311 click : function (_self, e)
61313 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61314 sd.setMonth(sd.getMonth()-1);
61315 _this.monthField.setValue(sd.format('Y-m-d'));
61316 _this.grid.ds.load({});
61322 xtype: 'Separator',
61326 xtype: 'MonthField',
61329 render : function (_self)
61331 _this.monthField = _self;
61332 // _this.monthField.set today
61334 select : function (combo, date)
61336 _this.grid.ds.load({});
61339 value : (function() { return new Date(); })()
61342 xtype: 'Separator',
61348 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61358 click : function (_self, e)
61360 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61361 sd.setMonth(sd.getMonth()+1);
61362 _this.monthField.setValue(sd.format('Y-m-d'));
61363 _this.grid.ds.load({});
61376 * Ext JS Library 1.1.1
61377 * Copyright(c) 2006-2007, Ext JS, LLC.
61379 * Originally Released Under LGPL - original licence link has changed is not relivant.
61382 * <script type="text/javascript">
61386 * @class Roo.LoadMask
61387 * A simple utility class for generically masking elements while loading data. If the element being masked has
61388 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61389 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61390 * element's UpdateManager load indicator and will be destroyed after the initial load.
61392 * Create a new LoadMask
61393 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61394 * @param {Object} config The config object
61396 Roo.LoadMask = function(el, config){
61397 this.el = Roo.get(el);
61398 Roo.apply(this, config);
61400 this.store.on('beforeload', this.onBeforeLoad, this);
61401 this.store.on('load', this.onLoad, this);
61402 this.store.on('loadexception', this.onLoadException, this);
61403 this.removeMask = false;
61405 var um = this.el.getUpdateManager();
61406 um.showLoadIndicator = false; // disable the default indicator
61407 um.on('beforeupdate', this.onBeforeLoad, this);
61408 um.on('update', this.onLoad, this);
61409 um.on('failure', this.onLoad, this);
61410 this.removeMask = true;
61414 Roo.LoadMask.prototype = {
61416 * @cfg {Boolean} removeMask
61417 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61418 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61421 * @cfg {String} msg
61422 * The text to display in a centered loading message box (defaults to 'Loading...')
61424 msg : 'Loading...',
61426 * @cfg {String} msgCls
61427 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61429 msgCls : 'x-mask-loading',
61432 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61438 * Disables the mask to prevent it from being displayed
61440 disable : function(){
61441 this.disabled = true;
61445 * Enables the mask so that it can be displayed
61447 enable : function(){
61448 this.disabled = false;
61451 onLoadException : function()
61453 Roo.log(arguments);
61455 if (typeof(arguments[3]) != 'undefined') {
61456 Roo.MessageBox.alert("Error loading",arguments[3]);
61460 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61461 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61468 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61471 onLoad : function()
61473 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61477 onBeforeLoad : function(){
61478 if(!this.disabled){
61479 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61484 destroy : function(){
61486 this.store.un('beforeload', this.onBeforeLoad, this);
61487 this.store.un('load', this.onLoad, this);
61488 this.store.un('loadexception', this.onLoadException, this);
61490 var um = this.el.getUpdateManager();
61491 um.un('beforeupdate', this.onBeforeLoad, this);
61492 um.un('update', this.onLoad, this);
61493 um.un('failure', this.onLoad, this);
61498 * Ext JS Library 1.1.1
61499 * Copyright(c) 2006-2007, Ext JS, LLC.
61501 * Originally Released Under LGPL - original licence link has changed is not relivant.
61504 * <script type="text/javascript">
61509 * @class Roo.XTemplate
61510 * @extends Roo.Template
61511 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61513 var t = new Roo.XTemplate(
61514 '<select name="{name}">',
61515 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61519 // then append, applying the master template values
61522 * Supported features:
61527 {a_variable} - output encoded.
61528 {a_variable.format:("Y-m-d")} - call a method on the variable
61529 {a_variable:raw} - unencoded output
61530 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61531 {a_variable:this.method_on_template(...)} - call a method on the template object.
61536 <tpl for="a_variable or condition.."></tpl>
61537 <tpl if="a_variable or condition"></tpl>
61538 <tpl exec="some javascript"></tpl>
61539 <tpl name="named_template"></tpl> (experimental)
61541 <tpl for="."></tpl> - just iterate the property..
61542 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61546 Roo.XTemplate = function()
61548 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61555 Roo.extend(Roo.XTemplate, Roo.Template, {
61558 * The various sub templates
61563 * basic tag replacing syntax
61566 * // you can fake an object call by doing this
61570 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61573 * compile the template
61575 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61578 compile: function()
61582 s = ['<tpl>', s, '</tpl>'].join('');
61584 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61585 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61586 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61587 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61588 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61593 while(true == !!(m = s.match(re))){
61594 var forMatch = m[0].match(nameRe),
61595 ifMatch = m[0].match(ifRe),
61596 execMatch = m[0].match(execRe),
61597 namedMatch = m[0].match(namedRe),
61602 name = forMatch && forMatch[1] ? forMatch[1] : '';
61605 // if - puts fn into test..
61606 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61608 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61613 // exec - calls a function... returns empty if true is returned.
61614 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61616 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61624 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61625 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61626 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61629 var uid = namedMatch ? namedMatch[1] : id;
61633 id: namedMatch ? namedMatch[1] : id,
61640 s = s.replace(m[0], '');
61642 s = s.replace(m[0], '{xtpl'+ id + '}');
61647 for(var i = tpls.length-1; i >= 0; --i){
61648 this.compileTpl(tpls[i]);
61649 this.tpls[tpls[i].id] = tpls[i];
61651 this.master = tpls[tpls.length-1];
61655 * same as applyTemplate, except it's done to one of the subTemplates
61656 * when using named templates, you can do:
61658 * var str = pl.applySubTemplate('your-name', values);
61661 * @param {Number} id of the template
61662 * @param {Object} values to apply to template
61663 * @param {Object} parent (normaly the instance of this object)
61665 applySubTemplate : function(id, values, parent)
61669 var t = this.tpls[id];
61673 if(t.test && !t.test.call(this, values, parent)){
61677 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61678 Roo.log(e.toString());
61684 if(t.exec && t.exec.call(this, values, parent)){
61688 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61689 Roo.log(e.toString());
61694 var vs = t.target ? t.target.call(this, values, parent) : values;
61695 parent = t.target ? values : parent;
61696 if(t.target && vs instanceof Array){
61698 for(var i = 0, len = vs.length; i < len; i++){
61699 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61701 return buf.join('');
61703 return t.compiled.call(this, vs, parent);
61705 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61706 Roo.log(e.toString());
61707 Roo.log(t.compiled);
61712 compileTpl : function(tpl)
61714 var fm = Roo.util.Format;
61715 var useF = this.disableFormats !== true;
61716 var sep = Roo.isGecko ? "+" : ",";
61717 var undef = function(str) {
61718 Roo.log("Property not found :" + str);
61722 var fn = function(m, name, format, args)
61724 //Roo.log(arguments);
61725 args = args ? args.replace(/\\'/g,"'") : args;
61726 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61727 if (typeof(format) == 'undefined') {
61728 format= 'htmlEncode';
61730 if (format == 'raw' ) {
61734 if(name.substr(0, 4) == 'xtpl'){
61735 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
61738 // build an array of options to determine if value is undefined..
61740 // basically get 'xxxx.yyyy' then do
61741 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
61742 // (function () { Roo.log("Property not found"); return ''; })() :
61747 Roo.each(name.split('.'), function(st) {
61748 lookfor += (lookfor.length ? '.': '') + st;
61749 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
61752 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
61755 if(format && useF){
61757 args = args ? ',' + args : "";
61759 if(format.substr(0, 5) != "this."){
61760 format = "fm." + format + '(';
61762 format = 'this.call("'+ format.substr(5) + '", ';
61766 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
61770 // called with xxyx.yuu:(test,test)
61772 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
61774 // raw.. - :raw modifier..
61775 return "'"+ sep + udef_st + name + ")"+sep+"'";
61779 // branched to use + in gecko and [].join() in others
61781 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
61782 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
61785 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
61786 body.push(tpl.body.replace(/(\r\n|\n)/g,
61787 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
61788 body.push("'].join('');};};");
61789 body = body.join('');
61792 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
61794 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
61800 applyTemplate : function(values){
61801 return this.master.compiled.call(this, values, {});
61802 //var s = this.subs;
61805 apply : function(){
61806 return this.applyTemplate.apply(this, arguments);
61811 Roo.XTemplate.from = function(el){
61812 el = Roo.getDom(el);
61813 return new Roo.XTemplate(el.value || el.innerHTML);