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]);
891 * Utility function that allows you to easily switch a string between two alternating values. The passed value
892 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
893 * they are already different, the first value passed in is returned. Note that this method returns the new value
894 * but does not change the current string.
896 // alternate sort directions
897 sort = sort.toggle('ASC', 'DESC');
899 // instead of conditional logic:
900 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
902 * @param {String} value The value to compare to the current string
903 * @param {String} other The new value to use if the string already equals the first value passed in
904 * @return {String} The new value
907 String.prototype.toggle = function(value, other){
908 return this == value ? other : value;
911 * Ext JS Library 1.1.1
912 * Copyright(c) 2006-2007, Ext JS, LLC.
914 * Originally Released Under LGPL - original licence link has changed is not relivant.
917 * <script type="text/javascript">
923 Roo.applyIf(Number.prototype, {
925 * Checks whether or not the current number is within a desired range. If the number is already within the
926 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
927 * exceeded. Note that this method returns the constrained value but does not change the current number.
928 * @param {Number} min The minimum number in the range
929 * @param {Number} max The maximum number in the range
930 * @return {Number} The constrained value if outside the range, otherwise the current value
932 constrain : function(min, max){
933 return Math.min(Math.max(this, min), max);
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">
948 Roo.applyIf(Array.prototype, {
951 * Checks whether or not the specified object exists in the array.
952 * @param {Object} o The object to check for
953 * @return {Number} The index of o in the array (or -1 if it is not found)
955 indexOf : function(o){
956 for (var i = 0, len = this.length; i < len; i++){
957 if(this[i] == o) { return i; }
963 * Removes the specified object from the array. If the object is not found nothing happens.
964 * @param {Object} o The object to remove
966 remove : function(o){
967 var index = this.indexOf(o);
969 this.splice(index, 1);
973 * Map (JS 1.6 compatibility)
974 * @param {Function} function to call
978 var len = this.length >>> 0;
979 if (typeof fun != "function") {
980 throw new TypeError();
982 var res = new Array(len);
983 var thisp = arguments[1];
984 for (var i = 0; i < len; i++)
987 res[i] = fun.call(thisp, this[i], i, this);
1000 * Ext JS Library 1.1.1
1001 * Copyright(c) 2006-2007, Ext JS, LLC.
1003 * Originally Released Under LGPL - original licence link has changed is not relivant.
1006 * <script type="text/javascript">
1012 * The date parsing and format syntax is a subset of
1013 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1014 * supported will provide results equivalent to their PHP versions.
1016 * Following is the list of all currently supported formats:
1019 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1021 Format Output Description
1022 ------ ---------- --------------------------------------------------------------
1023 d 10 Day of the month, 2 digits with leading zeros
1024 D Wed A textual representation of a day, three letters
1025 j 10 Day of the month without leading zeros
1026 l Wednesday A full textual representation of the day of the week
1027 S th English ordinal day of month suffix, 2 chars (use with j)
1028 w 3 Numeric representation of the day of the week
1029 z 9 The julian date, or day of the year (0-365)
1030 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1031 F January A full textual representation of the month
1032 m 01 Numeric representation of a month, with leading zeros
1033 M Jan Month name abbreviation, three letters
1034 n 1 Numeric representation of a month, without leading zeros
1035 t 31 Number of days in the given month
1036 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1037 Y 2007 A full numeric representation of a year, 4 digits
1038 y 07 A two digit representation of a year
1039 a pm Lowercase Ante meridiem and Post meridiem
1040 A PM Uppercase Ante meridiem and Post meridiem
1041 g 3 12-hour format of an hour without leading zeros
1042 G 15 24-hour format of an hour without leading zeros
1043 h 03 12-hour format of an hour with leading zeros
1044 H 15 24-hour format of an hour with leading zeros
1045 i 05 Minutes with leading zeros
1046 s 01 Seconds, with leading zeros
1047 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1048 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1049 T CST Timezone setting of the machine running the code
1050 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1053 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1055 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1056 document.write(dt.format('Y-m-d')); //2007-01-10
1057 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1058 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
1061 * Here are some standard date/time patterns that you might find helpful. They
1062 * are not part of the source of Date.js, but to use them you can simply copy this
1063 * block of code into any script that is included after Date.js and they will also become
1064 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1067 ISO8601Long:"Y-m-d H:i:s",
1068 ISO8601Short:"Y-m-d",
1070 LongDate: "l, F d, Y",
1071 FullDateTime: "l, F d, Y g:i:s A",
1074 LongTime: "g:i:s A",
1075 SortableDateTime: "Y-m-d\\TH:i:s",
1076 UniversalSortableDateTime: "Y-m-d H:i:sO",
1083 var dt = new Date();
1084 document.write(dt.format(Date.patterns.ShortDate));
1089 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1090 * They generate precompiled functions from date formats instead of parsing and
1091 * processing the pattern every time you format a date. These functions are available
1092 * on every Date object (any javascript function).
1094 * The original article and download are here:
1095 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1102 Returns the number of milliseconds between this date and date
1103 @param {Date} date (optional) Defaults to now
1104 @return {Number} The diff in milliseconds
1105 @member Date getElapsed
1107 Date.prototype.getElapsed = function(date) {
1108 return Math.abs((date || new Date()).getTime()-this.getTime());
1110 // was in date file..
1114 Date.parseFunctions = {count:0};
1116 Date.parseRegexes = [];
1118 Date.formatFunctions = {count:0};
1121 Date.prototype.dateFormat = function(format) {
1122 if (Date.formatFunctions[format] == null) {
1123 Date.createNewFormat(format);
1125 var func = Date.formatFunctions[format];
1126 return this[func]();
1131 * Formats a date given the supplied format string
1132 * @param {String} format The format string
1133 * @return {String} The formatted date
1136 Date.prototype.format = Date.prototype.dateFormat;
1139 Date.createNewFormat = function(format) {
1140 var funcName = "format" + Date.formatFunctions.count++;
1141 Date.formatFunctions[format] = funcName;
1142 var code = "Date.prototype." + funcName + " = function(){return ";
1143 var special = false;
1145 for (var i = 0; i < format.length; ++i) {
1146 ch = format.charAt(i);
1147 if (!special && ch == "\\") {
1152 code += "'" + String.escape(ch) + "' + ";
1155 code += Date.getFormatCode(ch);
1158 /** eval:var:zzzzzzzzzzzzz */
1159 eval(code.substring(0, code.length - 3) + ";}");
1163 Date.getFormatCode = function(character) {
1164 switch (character) {
1166 return "String.leftPad(this.getDate(), 2, '0') + ";
1168 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1170 return "this.getDate() + ";
1172 return "Date.dayNames[this.getDay()] + ";
1174 return "this.getSuffix() + ";
1176 return "this.getDay() + ";
1178 return "this.getDayOfYear() + ";
1180 return "this.getWeekOfYear() + ";
1182 return "Date.monthNames[this.getMonth()] + ";
1184 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1186 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1188 return "(this.getMonth() + 1) + ";
1190 return "this.getDaysInMonth() + ";
1192 return "(this.isLeapYear() ? 1 : 0) + ";
1194 return "this.getFullYear() + ";
1196 return "('' + this.getFullYear()).substring(2, 4) + ";
1198 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1200 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1202 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1204 return "this.getHours() + ";
1206 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1208 return "String.leftPad(this.getHours(), 2, '0') + ";
1210 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1212 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1214 return "this.getGMTOffset() + ";
1216 return "this.getGMTColonOffset() + ";
1218 return "this.getTimezone() + ";
1220 return "(this.getTimezoneOffset() * -60) + ";
1222 return "'" + String.escape(character) + "' + ";
1227 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1228 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1229 * the date format that is not specified will default to the current date value for that part. Time parts can also
1230 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1231 * string or the parse operation will fail.
1234 //dt = Fri May 25 2007 (current date)
1235 var dt = new Date();
1237 //dt = Thu May 25 2006 (today's month/day in 2006)
1238 dt = Date.parseDate("2006", "Y");
1240 //dt = Sun Jan 15 2006 (all date parts specified)
1241 dt = Date.parseDate("2006-1-15", "Y-m-d");
1243 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1244 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1246 * @param {String} input The unparsed date as a string
1247 * @param {String} format The format the date is in
1248 * @return {Date} The parsed date
1251 Date.parseDate = function(input, format) {
1252 if (Date.parseFunctions[format] == null) {
1253 Date.createParser(format);
1255 var func = Date.parseFunctions[format];
1256 return Date[func](input);
1262 Date.createParser = function(format) {
1263 var funcName = "parse" + Date.parseFunctions.count++;
1264 var regexNum = Date.parseRegexes.length;
1265 var currentGroup = 1;
1266 Date.parseFunctions[format] = funcName;
1268 var code = "Date." + funcName + " = function(input){\n"
1269 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1270 + "var d = new Date();\n"
1271 + "y = d.getFullYear();\n"
1272 + "m = d.getMonth();\n"
1273 + "d = d.getDate();\n"
1274 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1275 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1276 + "if (results && results.length > 0) {";
1279 var special = false;
1281 for (var i = 0; i < format.length; ++i) {
1282 ch = format.charAt(i);
1283 if (!special && ch == "\\") {
1288 regex += String.escape(ch);
1291 var obj = Date.formatCodeToRegex(ch, currentGroup);
1292 currentGroup += obj.g;
1294 if (obj.g && obj.c) {
1300 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1301 + "{v = new Date(y, m, d, h, i, s);}\n"
1302 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1303 + "{v = new Date(y, m, d, h, i);}\n"
1304 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1305 + "{v = new Date(y, m, d, h);}\n"
1306 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1307 + "{v = new Date(y, m, d);}\n"
1308 + "else if (y >= 0 && m >= 0)\n"
1309 + "{v = new Date(y, m);}\n"
1310 + "else if (y >= 0)\n"
1311 + "{v = new Date(y);}\n"
1312 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1313 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1314 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1317 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1318 /** eval:var:zzzzzzzzzzzzz */
1323 Date.formatCodeToRegex = function(character, currentGroup) {
1324 switch (character) {
1328 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1331 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1332 s:"(\\d{1,2})"}; // day of month without leading zeroes
1335 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1336 s:"(\\d{2})"}; // day of month with leading zeroes
1340 s:"(?:" + Date.dayNames.join("|") + ")"};
1344 s:"(?:st|nd|rd|th)"};
1359 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1360 s:"(" + Date.monthNames.join("|") + ")"};
1363 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1364 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1367 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1368 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1371 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1372 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1383 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1387 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1388 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1392 c:"if (results[" + currentGroup + "] == 'am') {\n"
1393 + "if (h == 12) { h = 0; }\n"
1394 + "} else { if (h < 12) { h += 12; }}",
1398 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1399 + "if (h == 12) { h = 0; }\n"
1400 + "} else { if (h < 12) { h += 12; }}",
1405 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1406 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1410 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1411 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1414 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1418 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1423 "o = results[", currentGroup, "];\n",
1424 "var sn = o.substring(0,1);\n", // get + / - sign
1425 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1426 "var mn = o.substring(3,5) % 60;\n", // get minutes
1427 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1428 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1430 s:"([+\-]\\d{2,4})"};
1436 "o = results[", currentGroup, "];\n",
1437 "var sn = o.substring(0,1);\n",
1438 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1439 "var mn = o.substring(4,6) % 60;\n",
1440 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1441 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1447 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1450 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1451 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1452 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1456 s:String.escape(character)};
1461 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1462 * @return {String} The abbreviated timezone name (e.g. 'CST')
1464 Date.prototype.getTimezone = function() {
1465 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1469 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1470 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1472 Date.prototype.getGMTOffset = function() {
1473 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1474 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1475 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1479 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1480 * @return {String} 2-characters representing hours and 2-characters representing minutes
1481 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1483 Date.prototype.getGMTColonOffset = function() {
1484 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1485 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1487 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1491 * Get the numeric day number of the year, adjusted for leap year.
1492 * @return {Number} 0 through 364 (365 in leap years)
1494 Date.prototype.getDayOfYear = function() {
1496 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1497 for (var i = 0; i < this.getMonth(); ++i) {
1498 num += Date.daysInMonth[i];
1500 return num + this.getDate() - 1;
1504 * Get the string representation of the numeric week number of the year
1505 * (equivalent to the format specifier 'W').
1506 * @return {String} '00' through '52'
1508 Date.prototype.getWeekOfYear = function() {
1509 // Skip to Thursday of this week
1510 var now = this.getDayOfYear() + (4 - this.getDay());
1511 // Find the first Thursday of the year
1512 var jan1 = new Date(this.getFullYear(), 0, 1);
1513 var then = (7 - jan1.getDay() + 4);
1514 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1518 * Whether or not the current date is in a leap year.
1519 * @return {Boolean} True if the current date is in a leap year, else false
1521 Date.prototype.isLeapYear = function() {
1522 var year = this.getFullYear();
1523 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1527 * Get the first day of the current month, adjusted for leap year. The returned value
1528 * is the numeric day index within the week (0-6) which can be used in conjunction with
1529 * the {@link #monthNames} array to retrieve the textual day name.
1532 var dt = new Date('1/10/2007');
1533 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1535 * @return {Number} The day number (0-6)
1537 Date.prototype.getFirstDayOfMonth = function() {
1538 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1539 return (day < 0) ? (day + 7) : day;
1543 * Get the last day of the current month, adjusted for leap year. The returned value
1544 * is the numeric day index within the week (0-6) which can be used in conjunction with
1545 * the {@link #monthNames} array to retrieve the textual day name.
1548 var dt = new Date('1/10/2007');
1549 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1551 * @return {Number} The day number (0-6)
1553 Date.prototype.getLastDayOfMonth = function() {
1554 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1555 return (day < 0) ? (day + 7) : day;
1560 * Get the first date of this date's month
1563 Date.prototype.getFirstDateOfMonth = function() {
1564 return new Date(this.getFullYear(), this.getMonth(), 1);
1568 * Get the last date of this date's month
1571 Date.prototype.getLastDateOfMonth = function() {
1572 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1575 * Get the number of days in the current month, adjusted for leap year.
1576 * @return {Number} The number of days in the month
1578 Date.prototype.getDaysInMonth = function() {
1579 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1580 return Date.daysInMonth[this.getMonth()];
1584 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1585 * @return {String} 'st, 'nd', 'rd' or 'th'
1587 Date.prototype.getSuffix = function() {
1588 switch (this.getDate()) {
1605 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1608 * An array of textual month names.
1609 * Override these values for international dates, for example...
1610 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1629 * An array of textual day names.
1630 * Override these values for international dates, for example...
1631 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1647 Date.monthNumbers = {
1662 * Creates and returns a new Date instance with the exact same date value as the called instance.
1663 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1664 * variable will also be changed. When the intention is to create a new variable that will not
1665 * modify the original instance, you should create a clone.
1667 * Example of correctly cloning a date:
1670 var orig = new Date('10/1/2006');
1673 document.write(orig); //returns 'Thu Oct 05 2006'!
1676 var orig = new Date('10/1/2006');
1677 var copy = orig.clone();
1679 document.write(orig); //returns 'Thu Oct 01 2006'
1681 * @return {Date} The new Date instance
1683 Date.prototype.clone = function() {
1684 return new Date(this.getTime());
1688 * Clears any time information from this date
1689 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1690 @return {Date} this or the clone
1692 Date.prototype.clearTime = function(clone){
1694 return this.clone().clearTime();
1699 this.setMilliseconds(0);
1704 // safari setMonth is broken -- check that this is only donw once...
1705 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1706 Date.brokenSetMonth = Date.prototype.setMonth;
1707 Date.prototype.setMonth = function(num){
1709 var n = Math.ceil(-num);
1710 var back_year = Math.ceil(n/12);
1711 var month = (n % 12) ? 12 - n % 12 : 0 ;
1712 this.setFullYear(this.getFullYear() - back_year);
1713 return Date.brokenSetMonth.call(this, month);
1715 return Date.brokenSetMonth.apply(this, arguments);
1720 /** Date interval constant
1724 /** Date interval constant
1728 /** Date interval constant
1732 /** Date interval constant
1736 /** Date interval constant
1740 /** Date interval constant
1744 /** Date interval constant
1750 * Provides a convenient method of performing basic date arithmetic. This method
1751 * does not modify the Date instance being called - it creates and returns
1752 * a new Date instance containing the resulting date value.
1757 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1758 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1760 //Negative values will subtract correctly:
1761 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1762 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1764 //You can even chain several calls together in one line!
1765 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1766 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1769 * @param {String} interval A valid date interval enum value
1770 * @param {Number} value The amount to add to the current date
1771 * @return {Date} The new Date instance
1773 Date.prototype.add = function(interval, value){
1774 var d = this.clone();
1775 if (!interval || value === 0) { return d; }
1776 switch(interval.toLowerCase()){
1778 d.setMilliseconds(this.getMilliseconds() + value);
1781 d.setSeconds(this.getSeconds() + value);
1784 d.setMinutes(this.getMinutes() + value);
1787 d.setHours(this.getHours() + value);
1790 d.setDate(this.getDate() + value);
1793 var day = this.getDate();
1795 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1798 d.setMonth(this.getMonth() + value);
1801 d.setFullYear(this.getFullYear() + value);
1808 * Ext JS Library 1.1.1
1809 * Copyright(c) 2006-2007, Ext JS, LLC.
1811 * Originally Released Under LGPL - original licence link has changed is not relivant.
1814 * <script type="text/javascript">
1818 * @class Roo.lib.Dom
1821 * Dom utils (from YIU afaik)
1826 * Get the view width
1827 * @param {Boolean} full True will get the full document, otherwise it's the view width
1828 * @return {Number} The width
1831 getViewWidth : function(full) {
1832 return full ? this.getDocumentWidth() : this.getViewportWidth();
1835 * Get the view height
1836 * @param {Boolean} full True will get the full document, otherwise it's the view height
1837 * @return {Number} The height
1839 getViewHeight : function(full) {
1840 return full ? this.getDocumentHeight() : this.getViewportHeight();
1843 getDocumentHeight: function() {
1844 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1845 return Math.max(scrollHeight, this.getViewportHeight());
1848 getDocumentWidth: function() {
1849 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1850 return Math.max(scrollWidth, this.getViewportWidth());
1853 getViewportHeight: function() {
1854 var height = self.innerHeight;
1855 var mode = document.compatMode;
1857 if ((mode || Roo.isIE) && !Roo.isOpera) {
1858 height = (mode == "CSS1Compat") ?
1859 document.documentElement.clientHeight :
1860 document.body.clientHeight;
1866 getViewportWidth: function() {
1867 var width = self.innerWidth;
1868 var mode = document.compatMode;
1870 if (mode || Roo.isIE) {
1871 width = (mode == "CSS1Compat") ?
1872 document.documentElement.clientWidth :
1873 document.body.clientWidth;
1878 isAncestor : function(p, c) {
1885 if (p.contains && !Roo.isSafari) {
1886 return p.contains(c);
1887 } else if (p.compareDocumentPosition) {
1888 return !!(p.compareDocumentPosition(c) & 16);
1890 var parent = c.parentNode;
1895 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1898 parent = parent.parentNode;
1904 getRegion : function(el) {
1905 return Roo.lib.Region.getRegion(el);
1908 getY : function(el) {
1909 return this.getXY(el)[1];
1912 getX : function(el) {
1913 return this.getXY(el)[0];
1916 getXY : function(el) {
1917 var p, pe, b, scroll, bd = document.body;
1918 el = Roo.getDom(el);
1919 var fly = Roo.lib.AnimBase.fly;
1920 if (el.getBoundingClientRect) {
1921 b = el.getBoundingClientRect();
1922 scroll = fly(document).getScroll();
1923 return [b.left + scroll.left, b.top + scroll.top];
1929 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1936 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1943 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1944 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1951 if (p != el && pe.getStyle('overflow') != 'visible') {
1959 if (Roo.isSafari && hasAbsolute) {
1964 if (Roo.isGecko && !hasAbsolute) {
1966 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1967 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1971 while (p && p != bd) {
1972 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1984 setXY : function(el, xy) {
1985 el = Roo.fly(el, '_setXY');
1987 var pts = el.translatePoints(xy);
1988 if (xy[0] !== false) {
1989 el.dom.style.left = pts.left + "px";
1991 if (xy[1] !== false) {
1992 el.dom.style.top = pts.top + "px";
1996 setX : function(el, x) {
1997 this.setXY(el, [x, false]);
2000 setY : function(el, y) {
2001 this.setXY(el, [false, y]);
2005 * Portions of this file are based on pieces of Yahoo User Interface Library
2006 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2007 * YUI licensed under the BSD License:
2008 * http://developer.yahoo.net/yui/license.txt
2009 * <script type="text/javascript">
2013 Roo.lib.Event = function() {
2014 var loadComplete = false;
2016 var unloadListeners = [];
2018 var onAvailStack = [];
2020 var lastError = null;
2033 startInterval: function() {
2034 if (!this._interval) {
2036 var callback = function() {
2037 self._tryPreloadAttach();
2039 this._interval = setInterval(callback, this.POLL_INTERVAL);
2044 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2045 onAvailStack.push({ id: p_id,
2048 override: p_override,
2049 checkReady: false });
2051 retryCount = this.POLL_RETRYS;
2052 this.startInterval();
2056 addListener: function(el, eventName, fn) {
2057 el = Roo.getDom(el);
2062 if ("unload" == eventName) {
2063 unloadListeners[unloadListeners.length] =
2064 [el, eventName, fn];
2068 var wrappedFn = function(e) {
2069 return fn(Roo.lib.Event.getEvent(e));
2072 var li = [el, eventName, fn, wrappedFn];
2074 var index = listeners.length;
2075 listeners[index] = li;
2077 this.doAdd(el, eventName, wrappedFn, false);
2083 removeListener: function(el, eventName, fn) {
2086 el = Roo.getDom(el);
2089 return this.purgeElement(el, false, eventName);
2093 if ("unload" == eventName) {
2095 for (i = 0,len = unloadListeners.length; i < len; i++) {
2096 var li = unloadListeners[i];
2099 li[1] == eventName &&
2101 unloadListeners.splice(i, 1);
2109 var cacheItem = null;
2112 var index = arguments[3];
2114 if ("undefined" == typeof index) {
2115 index = this._getCacheIndex(el, eventName, fn);
2119 cacheItem = listeners[index];
2122 if (!el || !cacheItem) {
2126 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2128 delete listeners[index][this.WFN];
2129 delete listeners[index][this.FN];
2130 listeners.splice(index, 1);
2137 getTarget: function(ev, resolveTextNode) {
2138 ev = ev.browserEvent || ev;
2139 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2140 var t = ev.target || ev.srcElement;
2141 return this.resolveTextNode(t);
2145 resolveTextNode: function(node) {
2146 if (Roo.isSafari && node && 3 == node.nodeType) {
2147 return node.parentNode;
2154 getPageX: function(ev) {
2155 ev = ev.browserEvent || ev;
2156 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2158 if (!x && 0 !== x) {
2159 x = ev.clientX || 0;
2162 x += this.getScroll()[1];
2170 getPageY: function(ev) {
2171 ev = ev.browserEvent || ev;
2172 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2174 if (!y && 0 !== y) {
2175 y = ev.clientY || 0;
2178 y += this.getScroll()[0];
2187 getXY: function(ev) {
2188 ev = ev.browserEvent || ev;
2189 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2190 return [this.getPageX(ev), this.getPageY(ev)];
2194 getRelatedTarget: function(ev) {
2195 ev = ev.browserEvent || ev;
2196 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2197 var t = ev.relatedTarget;
2199 if (ev.type == "mouseout") {
2201 } else if (ev.type == "mouseover") {
2206 return this.resolveTextNode(t);
2210 getTime: function(ev) {
2211 ev = ev.browserEvent || ev;
2212 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2214 var t = new Date().getTime();
2218 this.lastError = ex;
2227 stopEvent: function(ev) {
2228 this.stopPropagation(ev);
2229 this.preventDefault(ev);
2233 stopPropagation: function(ev) {
2234 ev = ev.browserEvent || ev;
2235 if (ev.stopPropagation) {
2236 ev.stopPropagation();
2238 ev.cancelBubble = true;
2243 preventDefault: function(ev) {
2244 ev = ev.browserEvent || ev;
2245 if(ev.preventDefault) {
2246 ev.preventDefault();
2248 ev.returnValue = false;
2253 getEvent: function(e) {
2254 var ev = e || window.event;
2256 var c = this.getEvent.caller;
2258 ev = c.arguments[0];
2259 if (ev && Event == ev.constructor) {
2269 getCharCode: function(ev) {
2270 ev = ev.browserEvent || ev;
2271 return ev.charCode || ev.keyCode || 0;
2275 _getCacheIndex: function(el, eventName, fn) {
2276 for (var i = 0,len = listeners.length; i < len; ++i) {
2277 var li = listeners[i];
2279 li[this.FN] == fn &&
2280 li[this.EL] == el &&
2281 li[this.TYPE] == eventName) {
2293 getEl: function(id) {
2294 return document.getElementById(id);
2298 clearCache: function() {
2302 _load: function(e) {
2303 loadComplete = true;
2304 var EU = Roo.lib.Event;
2308 EU.doRemove(window, "load", EU._load);
2313 _tryPreloadAttach: function() {
2322 var tryAgain = !loadComplete;
2324 tryAgain = (retryCount > 0);
2329 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2330 var item = onAvailStack[i];
2332 var el = this.getEl(item.id);
2335 if (!item.checkReady ||
2338 (document && document.body)) {
2341 if (item.override) {
2342 if (item.override === true) {
2345 scope = item.override;
2348 item.fn.call(scope, item.obj);
2349 onAvailStack[i] = null;
2352 notAvail.push(item);
2357 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2361 this.startInterval();
2363 clearInterval(this._interval);
2364 this._interval = null;
2367 this.locked = false;
2374 purgeElement: function(el, recurse, eventName) {
2375 var elListeners = this.getListeners(el, eventName);
2377 for (var i = 0,len = elListeners.length; i < len; ++i) {
2378 var l = elListeners[i];
2379 this.removeListener(el, l.type, l.fn);
2383 if (recurse && el && el.childNodes) {
2384 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2385 this.purgeElement(el.childNodes[i], recurse, eventName);
2391 getListeners: function(el, eventName) {
2392 var results = [], searchLists;
2394 searchLists = [listeners, unloadListeners];
2395 } else if (eventName == "unload") {
2396 searchLists = [unloadListeners];
2398 searchLists = [listeners];
2401 for (var j = 0; j < searchLists.length; ++j) {
2402 var searchList = searchLists[j];
2403 if (searchList && searchList.length > 0) {
2404 for (var i = 0,len = searchList.length; i < len; ++i) {
2405 var l = searchList[i];
2406 if (l && l[this.EL] === el &&
2407 (!eventName || eventName === l[this.TYPE])) {
2412 adjust: l[this.ADJ_SCOPE],
2420 return (results.length) ? results : null;
2424 _unload: function(e) {
2426 var EU = Roo.lib.Event, i, j, l, len, index;
2428 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2429 l = unloadListeners[i];
2432 if (l[EU.ADJ_SCOPE]) {
2433 if (l[EU.ADJ_SCOPE] === true) {
2436 scope = l[EU.ADJ_SCOPE];
2439 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2440 unloadListeners[i] = null;
2446 unloadListeners = null;
2448 if (listeners && listeners.length > 0) {
2449 j = listeners.length;
2452 l = listeners[index];
2454 EU.removeListener(l[EU.EL], l[EU.TYPE],
2464 EU.doRemove(window, "unload", EU._unload);
2469 getScroll: function() {
2470 var dd = document.documentElement, db = document.body;
2471 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2472 return [dd.scrollTop, dd.scrollLeft];
2474 return [db.scrollTop, db.scrollLeft];
2481 doAdd: function () {
2482 if (window.addEventListener) {
2483 return function(el, eventName, fn, capture) {
2484 el.addEventListener(eventName, fn, (capture));
2486 } else if (window.attachEvent) {
2487 return function(el, eventName, fn, capture) {
2488 el.attachEvent("on" + eventName, fn);
2497 doRemove: function() {
2498 if (window.removeEventListener) {
2499 return function (el, eventName, fn, capture) {
2500 el.removeEventListener(eventName, fn, (capture));
2502 } else if (window.detachEvent) {
2503 return function (el, eventName, fn) {
2504 el.detachEvent("on" + eventName, fn);
2516 var E = Roo.lib.Event;
2517 E.on = E.addListener;
2518 E.un = E.removeListener;
2520 if (document && document.body) {
2523 E.doAdd(window, "load", E._load);
2525 E.doAdd(window, "unload", E._unload);
2526 E._tryPreloadAttach();
2530 * Portions of this file are based on pieces of Yahoo User Interface Library
2531 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2532 * YUI licensed under the BSD License:
2533 * http://developer.yahoo.net/yui/license.txt
2534 * <script type="text/javascript">
2540 * @class Roo.lib.Ajax
2547 request : function(method, uri, cb, data, options) {
2549 var hs = options.headers;
2552 if(hs.hasOwnProperty(h)){
2553 this.initHeader(h, hs[h], false);
2557 if(options.xmlData){
2558 this.initHeader('Content-Type', 'text/xml', false);
2560 data = options.xmlData;
2564 return this.asyncRequest(method, uri, cb, data);
2567 serializeForm : function(form) {
2568 if(typeof form == 'string') {
2569 form = (document.getElementById(form) || document.forms[form]);
2572 var el, name, val, disabled, data = '', hasSubmit = false;
2573 for (var i = 0; i < form.elements.length; i++) {
2574 el = form.elements[i];
2575 disabled = form.elements[i].disabled;
2576 name = form.elements[i].name;
2577 val = form.elements[i].value;
2579 if (!disabled && name){
2583 case 'select-multiple':
2584 for (var j = 0; j < el.options.length; j++) {
2585 if (el.options[j].selected) {
2587 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2590 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2598 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2611 if(hasSubmit == false) {
2612 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2617 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2622 data = data.substr(0, data.length - 1);
2630 useDefaultHeader:true,
2632 defaultPostHeader:'application/x-www-form-urlencoded',
2634 useDefaultXhrHeader:true,
2636 defaultXhrHeader:'XMLHttpRequest',
2638 hasDefaultHeaders:true,
2650 setProgId:function(id)
2652 this.activeX.unshift(id);
2655 setDefaultPostHeader:function(b)
2657 this.useDefaultHeader = b;
2660 setDefaultXhrHeader:function(b)
2662 this.useDefaultXhrHeader = b;
2665 setPollingInterval:function(i)
2667 if (typeof i == 'number' && isFinite(i)) {
2668 this.pollInterval = i;
2672 createXhrObject:function(transactionId)
2678 http = new XMLHttpRequest();
2680 obj = { conn:http, tId:transactionId };
2684 for (var i = 0; i < this.activeX.length; ++i) {
2688 http = new ActiveXObject(this.activeX[i]);
2690 obj = { conn:http, tId:transactionId };
2703 getConnectionObject:function()
2706 var tId = this.transactionId;
2710 o = this.createXhrObject(tId);
2712 this.transactionId++;
2723 asyncRequest:function(method, uri, callback, postData)
2725 var o = this.getConnectionObject();
2731 o.conn.open(method, uri, true);
2733 if (this.useDefaultXhrHeader) {
2734 if (!this.defaultHeaders['X-Requested-With']) {
2735 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2739 if(postData && this.useDefaultHeader){
2740 this.initHeader('Content-Type', this.defaultPostHeader);
2743 if (this.hasDefaultHeaders || this.hasHeaders) {
2747 this.handleReadyState(o, callback);
2748 o.conn.send(postData || null);
2754 handleReadyState:function(o, callback)
2758 if (callback && callback.timeout) {
2760 this.timeout[o.tId] = window.setTimeout(function() {
2761 oConn.abort(o, callback, true);
2762 }, callback.timeout);
2765 this.poll[o.tId] = window.setInterval(
2767 if (o.conn && o.conn.readyState == 4) {
2768 window.clearInterval(oConn.poll[o.tId]);
2769 delete oConn.poll[o.tId];
2771 if(callback && callback.timeout) {
2772 window.clearTimeout(oConn.timeout[o.tId]);
2773 delete oConn.timeout[o.tId];
2776 oConn.handleTransactionResponse(o, callback);
2779 , this.pollInterval);
2782 handleTransactionResponse:function(o, callback, isAbort)
2786 this.releaseObject(o);
2790 var httpStatus, responseObject;
2794 if (o.conn.status !== undefined && o.conn.status != 0) {
2795 httpStatus = o.conn.status;
2807 if (httpStatus >= 200 && httpStatus < 300) {
2808 responseObject = this.createResponseObject(o, callback.argument);
2809 if (callback.success) {
2810 if (!callback.scope) {
2811 callback.success(responseObject);
2816 callback.success.apply(callback.scope, [responseObject]);
2821 switch (httpStatus) {
2829 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2830 if (callback.failure) {
2831 if (!callback.scope) {
2832 callback.failure(responseObject);
2835 callback.failure.apply(callback.scope, [responseObject]);
2840 responseObject = this.createResponseObject(o, callback.argument);
2841 if (callback.failure) {
2842 if (!callback.scope) {
2843 callback.failure(responseObject);
2846 callback.failure.apply(callback.scope, [responseObject]);
2852 this.releaseObject(o);
2853 responseObject = null;
2856 createResponseObject:function(o, callbackArg)
2863 var headerStr = o.conn.getAllResponseHeaders();
2864 var header = headerStr.split('\n');
2865 for (var i = 0; i < header.length; i++) {
2866 var delimitPos = header[i].indexOf(':');
2867 if (delimitPos != -1) {
2868 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2876 obj.status = o.conn.status;
2877 obj.statusText = o.conn.statusText;
2878 obj.getResponseHeader = headerObj;
2879 obj.getAllResponseHeaders = headerStr;
2880 obj.responseText = o.conn.responseText;
2881 obj.responseXML = o.conn.responseXML;
2883 if (typeof callbackArg !== undefined) {
2884 obj.argument = callbackArg;
2890 createExceptionObject:function(tId, callbackArg, isAbort)
2893 var COMM_ERROR = 'communication failure';
2894 var ABORT_CODE = -1;
2895 var ABORT_ERROR = 'transaction aborted';
2901 obj.status = ABORT_CODE;
2902 obj.statusText = ABORT_ERROR;
2905 obj.status = COMM_CODE;
2906 obj.statusText = COMM_ERROR;
2910 obj.argument = callbackArg;
2916 initHeader:function(label, value, isDefault)
2918 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2920 if (headerObj[label] === undefined) {
2921 headerObj[label] = value;
2926 headerObj[label] = value + "," + headerObj[label];
2930 this.hasDefaultHeaders = true;
2933 this.hasHeaders = true;
2938 setHeader:function(o)
2940 if (this.hasDefaultHeaders) {
2941 for (var prop in this.defaultHeaders) {
2942 if (this.defaultHeaders.hasOwnProperty(prop)) {
2943 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2948 if (this.hasHeaders) {
2949 for (var prop in this.headers) {
2950 if (this.headers.hasOwnProperty(prop)) {
2951 o.conn.setRequestHeader(prop, this.headers[prop]);
2955 this.hasHeaders = false;
2959 resetDefaultHeaders:function() {
2960 delete this.defaultHeaders;
2961 this.defaultHeaders = {};
2962 this.hasDefaultHeaders = false;
2965 abort:function(o, callback, isTimeout)
2967 if(this.isCallInProgress(o)) {
2969 window.clearInterval(this.poll[o.tId]);
2970 delete this.poll[o.tId];
2972 delete this.timeout[o.tId];
2975 this.handleTransactionResponse(o, callback, true);
2985 isCallInProgress:function(o)
2988 return o.conn.readyState != 4 && o.conn.readyState != 0;
2997 releaseObject:function(o)
3006 'MSXML2.XMLHTTP.3.0',
3014 * Portions of this file are based on pieces of Yahoo User Interface Library
3015 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3016 * YUI licensed under the BSD License:
3017 * http://developer.yahoo.net/yui/license.txt
3018 * <script type="text/javascript">
3022 Roo.lib.Region = function(t, r, b, l) {
3032 Roo.lib.Region.prototype = {
3033 contains : function(region) {
3034 return ( region.left >= this.left &&
3035 region.right <= this.right &&
3036 region.top >= this.top &&
3037 region.bottom <= this.bottom );
3041 getArea : function() {
3042 return ( (this.bottom - this.top) * (this.right - this.left) );
3045 intersect : function(region) {
3046 var t = Math.max(this.top, region.top);
3047 var r = Math.min(this.right, region.right);
3048 var b = Math.min(this.bottom, region.bottom);
3049 var l = Math.max(this.left, region.left);
3051 if (b >= t && r >= l) {
3052 return new Roo.lib.Region(t, r, b, l);
3057 union : function(region) {
3058 var t = Math.min(this.top, region.top);
3059 var r = Math.max(this.right, region.right);
3060 var b = Math.max(this.bottom, region.bottom);
3061 var l = Math.min(this.left, region.left);
3063 return new Roo.lib.Region(t, r, b, l);
3066 adjust : function(t, l, b, r) {
3075 Roo.lib.Region.getRegion = function(el) {
3076 var p = Roo.lib.Dom.getXY(el);
3079 var r = p[0] + el.offsetWidth;
3080 var b = p[1] + el.offsetHeight;
3083 return new Roo.lib.Region(t, r, b, l);
3086 * Portions of this file are based on pieces of Yahoo User Interface Library
3087 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3088 * YUI licensed under the BSD License:
3089 * http://developer.yahoo.net/yui/license.txt
3090 * <script type="text/javascript">
3093 //@@dep Roo.lib.Region
3096 Roo.lib.Point = function(x, y) {
3097 if (x instanceof Array) {
3101 this.x = this.right = this.left = this[0] = x;
3102 this.y = this.top = this.bottom = this[1] = y;
3105 Roo.lib.Point.prototype = new Roo.lib.Region();
3107 * Portions of this file are based on pieces of Yahoo User Interface Library
3108 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3109 * YUI licensed under the BSD License:
3110 * http://developer.yahoo.net/yui/license.txt
3111 * <script type="text/javascript">
3118 scroll : function(el, args, duration, easing, cb, scope) {
3119 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3122 motion : function(el, args, duration, easing, cb, scope) {
3123 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3126 color : function(el, args, duration, easing, cb, scope) {
3127 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3130 run : function(el, args, duration, easing, cb, scope, type) {
3131 type = type || Roo.lib.AnimBase;
3132 if (typeof easing == "string") {
3133 easing = Roo.lib.Easing[easing];
3135 var anim = new type(el, args, duration, easing);
3136 anim.animateX(function() {
3137 Roo.callback(cb, scope);
3143 * Portions of this file are based on pieces of Yahoo User Interface Library
3144 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3145 * YUI licensed under the BSD License:
3146 * http://developer.yahoo.net/yui/license.txt
3147 * <script type="text/javascript">
3155 if (!libFlyweight) {
3156 libFlyweight = new Roo.Element.Flyweight();
3158 libFlyweight.dom = el;
3159 return libFlyweight;
3162 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3166 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3168 this.init(el, attributes, duration, method);
3172 Roo.lib.AnimBase.fly = fly;
3176 Roo.lib.AnimBase.prototype = {
3178 toString: function() {
3179 var el = this.getEl();
3180 var id = el.id || el.tagName;
3181 return ("Anim " + id);
3185 noNegatives: /width|height|opacity|padding/i,
3186 offsetAttribute: /^((width|height)|(top|left))$/,
3187 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3188 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3192 doMethod: function(attr, start, end) {
3193 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3197 setAttribute: function(attr, val, unit) {
3198 if (this.patterns.noNegatives.test(attr)) {
3199 val = (val > 0) ? val : 0;
3202 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3206 getAttribute: function(attr) {
3207 var el = this.getEl();
3208 var val = fly(el).getStyle(attr);
3210 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3211 return parseFloat(val);
3214 var a = this.patterns.offsetAttribute.exec(attr) || [];
3215 var pos = !!( a[3] );
3216 var box = !!( a[2] );
3219 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3220 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3229 getDefaultUnit: function(attr) {
3230 if (this.patterns.defaultUnit.test(attr)) {
3237 animateX : function(callback, scope) {
3238 var f = function() {
3239 this.onComplete.removeListener(f);
3240 if (typeof callback == "function") {
3241 callback.call(scope || this, this);
3244 this.onComplete.addListener(f, this);
3249 setRuntimeAttribute: function(attr) {
3252 var attributes = this.attributes;
3254 this.runtimeAttributes[attr] = {};
3256 var isset = function(prop) {
3257 return (typeof prop !== 'undefined');
3260 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3264 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3267 if (isset(attributes[attr]['to'])) {
3268 end = attributes[attr]['to'];
3269 } else if (isset(attributes[attr]['by'])) {
3270 if (start.constructor == Array) {
3272 for (var i = 0, len = start.length; i < len; ++i) {
3273 end[i] = start[i] + attributes[attr]['by'][i];
3276 end = start + attributes[attr]['by'];
3280 this.runtimeAttributes[attr].start = start;
3281 this.runtimeAttributes[attr].end = end;
3284 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3288 init: function(el, attributes, duration, method) {
3290 var isAnimated = false;
3293 var startTime = null;
3296 var actualFrames = 0;
3299 el = Roo.getDom(el);
3302 this.attributes = attributes || {};
3305 this.duration = duration || 1;
3308 this.method = method || Roo.lib.Easing.easeNone;
3311 this.useSeconds = true;
3314 this.currentFrame = 0;
3317 this.totalFrames = Roo.lib.AnimMgr.fps;
3320 this.getEl = function() {
3325 this.isAnimated = function() {
3330 this.getStartTime = function() {
3334 this.runtimeAttributes = {};
3337 this.animate = function() {
3338 if (this.isAnimated()) {
3342 this.currentFrame = 0;
3344 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3346 Roo.lib.AnimMgr.registerElement(this);
3350 this.stop = function(finish) {
3352 this.currentFrame = this.totalFrames;
3353 this._onTween.fire();
3355 Roo.lib.AnimMgr.stop(this);
3358 var onStart = function() {
3359 this.onStart.fire();
3361 this.runtimeAttributes = {};
3362 for (var attr in this.attributes) {
3363 this.setRuntimeAttribute(attr);
3368 startTime = new Date();
3372 var onTween = function() {
3374 duration: new Date() - this.getStartTime(),
3375 currentFrame: this.currentFrame
3378 data.toString = function() {
3380 'duration: ' + data.duration +
3381 ', currentFrame: ' + data.currentFrame
3385 this.onTween.fire(data);
3387 var runtimeAttributes = this.runtimeAttributes;
3389 for (var attr in runtimeAttributes) {
3390 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3396 var onComplete = function() {
3397 var actual_duration = (new Date() - startTime) / 1000 ;
3400 duration: actual_duration,
3401 frames: actualFrames,
3402 fps: actualFrames / actual_duration
3405 data.toString = function() {
3407 'duration: ' + data.duration +
3408 ', frames: ' + data.frames +
3409 ', fps: ' + data.fps
3415 this.onComplete.fire(data);
3419 this._onStart = new Roo.util.Event(this);
3420 this.onStart = new Roo.util.Event(this);
3421 this.onTween = new Roo.util.Event(this);
3422 this._onTween = new Roo.util.Event(this);
3423 this.onComplete = new Roo.util.Event(this);
3424 this._onComplete = new Roo.util.Event(this);
3425 this._onStart.addListener(onStart);
3426 this._onTween.addListener(onTween);
3427 this._onComplete.addListener(onComplete);
3432 * Portions of this file are based on pieces of Yahoo User Interface Library
3433 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3434 * YUI licensed under the BSD License:
3435 * http://developer.yahoo.net/yui/license.txt
3436 * <script type="text/javascript">
3440 Roo.lib.AnimMgr = new function() {
3457 this.registerElement = function(tween) {
3458 queue[queue.length] = tween;
3460 tween._onStart.fire();
3465 this.unRegister = function(tween, index) {
3466 tween._onComplete.fire();
3467 index = index || getIndex(tween);
3469 queue.splice(index, 1);
3473 if (tweenCount <= 0) {
3479 this.start = function() {
3480 if (thread === null) {
3481 thread = setInterval(this.run, this.delay);
3486 this.stop = function(tween) {
3488 clearInterval(thread);
3490 for (var i = 0, len = queue.length; i < len; ++i) {
3491 if (queue[0].isAnimated()) {
3492 this.unRegister(queue[0], 0);
3501 this.unRegister(tween);
3506 this.run = function() {
3507 for (var i = 0, len = queue.length; i < len; ++i) {
3508 var tween = queue[i];
3509 if (!tween || !tween.isAnimated()) {
3513 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3515 tween.currentFrame += 1;
3517 if (tween.useSeconds) {
3518 correctFrame(tween);
3520 tween._onTween.fire();
3523 Roo.lib.AnimMgr.stop(tween, i);
3528 var getIndex = function(anim) {
3529 for (var i = 0, len = queue.length; i < len; ++i) {
3530 if (queue[i] == anim) {
3538 var correctFrame = function(tween) {
3539 var frames = tween.totalFrames;
3540 var frame = tween.currentFrame;
3541 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3542 var elapsed = (new Date() - tween.getStartTime());
3545 if (elapsed < tween.duration * 1000) {
3546 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3548 tweak = frames - (frame + 1);
3550 if (tweak > 0 && isFinite(tweak)) {
3551 if (tween.currentFrame + tweak >= frames) {
3552 tweak = frames - (frame + 1);
3555 tween.currentFrame += tweak;
3561 * Portions of this file are based on pieces of Yahoo User Interface Library
3562 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3563 * YUI licensed under the BSD License:
3564 * http://developer.yahoo.net/yui/license.txt
3565 * <script type="text/javascript">
3568 Roo.lib.Bezier = new function() {
3570 this.getPosition = function(points, t) {
3571 var n = points.length;
3574 for (var i = 0; i < n; ++i) {
3575 tmp[i] = [points[i][0], points[i][1]];
3578 for (var j = 1; j < n; ++j) {
3579 for (i = 0; i < n - j; ++i) {
3580 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3581 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3585 return [ tmp[0][0], tmp[0][1] ];
3589 * Portions of this file are based on pieces of Yahoo User Interface Library
3590 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3591 * YUI licensed under the BSD License:
3592 * http://developer.yahoo.net/yui/license.txt
3593 * <script type="text/javascript">
3598 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3599 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3602 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3604 var fly = Roo.lib.AnimBase.fly;
3606 var superclass = Y.ColorAnim.superclass;
3607 var proto = Y.ColorAnim.prototype;
3609 proto.toString = function() {
3610 var el = this.getEl();
3611 var id = el.id || el.tagName;
3612 return ("ColorAnim " + id);
3615 proto.patterns.color = /color$/i;
3616 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3617 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3618 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3619 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3622 proto.parseColor = function(s) {
3623 if (s.length == 3) {
3627 var c = this.patterns.hex.exec(s);
3628 if (c && c.length == 4) {
3629 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3632 c = this.patterns.rgb.exec(s);
3633 if (c && c.length == 4) {
3634 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3637 c = this.patterns.hex3.exec(s);
3638 if (c && c.length == 4) {
3639 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3644 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3645 proto.getAttribute = function(attr) {
3646 var el = this.getEl();
3647 if (this.patterns.color.test(attr)) {
3648 var val = fly(el).getStyle(attr);
3650 if (this.patterns.transparent.test(val)) {
3651 var parent = el.parentNode;
3652 val = fly(parent).getStyle(attr);
3654 while (parent && this.patterns.transparent.test(val)) {
3655 parent = parent.parentNode;
3656 val = fly(parent).getStyle(attr);
3657 if (parent.tagName.toUpperCase() == 'HTML') {
3663 val = superclass.getAttribute.call(this, attr);
3668 proto.getAttribute = function(attr) {
3669 var el = this.getEl();
3670 if (this.patterns.color.test(attr)) {
3671 var val = fly(el).getStyle(attr);
3673 if (this.patterns.transparent.test(val)) {
3674 var parent = el.parentNode;
3675 val = fly(parent).getStyle(attr);
3677 while (parent && this.patterns.transparent.test(val)) {
3678 parent = parent.parentNode;
3679 val = fly(parent).getStyle(attr);
3680 if (parent.tagName.toUpperCase() == 'HTML') {
3686 val = superclass.getAttribute.call(this, attr);
3692 proto.doMethod = function(attr, start, end) {
3695 if (this.patterns.color.test(attr)) {
3697 for (var i = 0, len = start.length; i < len; ++i) {
3698 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3701 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3704 val = superclass.doMethod.call(this, attr, start, end);
3710 proto.setRuntimeAttribute = function(attr) {
3711 superclass.setRuntimeAttribute.call(this, attr);
3713 if (this.patterns.color.test(attr)) {
3714 var attributes = this.attributes;
3715 var start = this.parseColor(this.runtimeAttributes[attr].start);
3716 var end = this.parseColor(this.runtimeAttributes[attr].end);
3718 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3719 end = this.parseColor(attributes[attr].by);
3721 for (var i = 0, len = start.length; i < len; ++i) {
3722 end[i] = start[i] + end[i];
3726 this.runtimeAttributes[attr].start = start;
3727 this.runtimeAttributes[attr].end = end;
3733 * Portions of this file are based on pieces of Yahoo User Interface Library
3734 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3735 * YUI licensed under the BSD License:
3736 * http://developer.yahoo.net/yui/license.txt
3737 * <script type="text/javascript">
3743 easeNone: function (t, b, c, d) {
3744 return c * t / d + b;
3748 easeIn: function (t, b, c, d) {
3749 return c * (t /= d) * t + b;
3753 easeOut: function (t, b, c, d) {
3754 return -c * (t /= d) * (t - 2) + b;
3758 easeBoth: function (t, b, c, d) {
3759 if ((t /= d / 2) < 1) {
3760 return c / 2 * t * t + b;
3763 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3767 easeInStrong: function (t, b, c, d) {
3768 return c * (t /= d) * t * t * t + b;
3772 easeOutStrong: function (t, b, c, d) {
3773 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3777 easeBothStrong: function (t, b, c, d) {
3778 if ((t /= d / 2) < 1) {
3779 return c / 2 * t * t * t * t + b;
3782 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3787 elasticIn: function (t, b, c, d, a, p) {
3791 if ((t /= d) == 1) {
3798 if (!a || a < Math.abs(c)) {
3803 var s = p / (2 * Math.PI) * Math.asin(c / a);
3806 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3810 elasticOut: function (t, b, c, d, a, p) {
3814 if ((t /= d) == 1) {
3821 if (!a || a < Math.abs(c)) {
3826 var s = p / (2 * Math.PI) * Math.asin(c / a);
3829 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3833 elasticBoth: function (t, b, c, d, a, p) {
3838 if ((t /= d / 2) == 2) {
3846 if (!a || a < Math.abs(c)) {
3851 var s = p / (2 * Math.PI) * Math.asin(c / a);
3855 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3856 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3858 return a * Math.pow(2, -10 * (t -= 1)) *
3859 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3864 backIn: function (t, b, c, d, s) {
3865 if (typeof s == 'undefined') {
3868 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3872 backOut: function (t, b, c, d, s) {
3873 if (typeof s == 'undefined') {
3876 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3880 backBoth: function (t, b, c, d, s) {
3881 if (typeof s == 'undefined') {
3885 if ((t /= d / 2 ) < 1) {
3886 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3888 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3892 bounceIn: function (t, b, c, d) {
3893 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3897 bounceOut: function (t, b, c, d) {
3898 if ((t /= d) < (1 / 2.75)) {
3899 return c * (7.5625 * t * t) + b;
3900 } else if (t < (2 / 2.75)) {
3901 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3902 } else if (t < (2.5 / 2.75)) {
3903 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3905 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3909 bounceBoth: function (t, b, c, d) {
3911 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3913 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3916 * Portions of this file are based on pieces of Yahoo User Interface Library
3917 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3918 * YUI licensed under the BSD License:
3919 * http://developer.yahoo.net/yui/license.txt
3920 * <script type="text/javascript">
3924 Roo.lib.Motion = function(el, attributes, duration, method) {
3926 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3930 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3934 var superclass = Y.Motion.superclass;
3935 var proto = Y.Motion.prototype;
3937 proto.toString = function() {
3938 var el = this.getEl();
3939 var id = el.id || el.tagName;
3940 return ("Motion " + id);
3943 proto.patterns.points = /^points$/i;
3945 proto.setAttribute = function(attr, val, unit) {
3946 if (this.patterns.points.test(attr)) {
3947 unit = unit || 'px';
3948 superclass.setAttribute.call(this, 'left', val[0], unit);
3949 superclass.setAttribute.call(this, 'top', val[1], unit);
3951 superclass.setAttribute.call(this, attr, val, unit);
3955 proto.getAttribute = function(attr) {
3956 if (this.patterns.points.test(attr)) {
3958 superclass.getAttribute.call(this, 'left'),
3959 superclass.getAttribute.call(this, 'top')
3962 val = superclass.getAttribute.call(this, attr);
3968 proto.doMethod = function(attr, start, end) {
3971 if (this.patterns.points.test(attr)) {
3972 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3973 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3975 val = superclass.doMethod.call(this, attr, start, end);
3980 proto.setRuntimeAttribute = function(attr) {
3981 if (this.patterns.points.test(attr)) {
3982 var el = this.getEl();
3983 var attributes = this.attributes;
3985 var control = attributes['points']['control'] || [];
3989 if (control.length > 0 && !(control[0] instanceof Array)) {
3990 control = [control];
3993 for (i = 0,len = control.length; i < len; ++i) {
3994 tmp[i] = control[i];
3999 Roo.fly(el).position();
4001 if (isset(attributes['points']['from'])) {
4002 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4005 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4008 start = this.getAttribute('points');
4011 if (isset(attributes['points']['to'])) {
4012 end = translateValues.call(this, attributes['points']['to'], start);
4014 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4015 for (i = 0,len = control.length; i < len; ++i) {
4016 control[i] = translateValues.call(this, control[i], start);
4020 } else if (isset(attributes['points']['by'])) {
4021 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4023 for (i = 0,len = control.length; i < len; ++i) {
4024 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4028 this.runtimeAttributes[attr] = [start];
4030 if (control.length > 0) {
4031 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4034 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4037 superclass.setRuntimeAttribute.call(this, attr);
4041 var translateValues = function(val, start) {
4042 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4043 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4048 var isset = function(prop) {
4049 return (typeof prop !== 'undefined');
4053 * Portions of this file are based on pieces of Yahoo User Interface Library
4054 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4055 * YUI licensed under the BSD License:
4056 * http://developer.yahoo.net/yui/license.txt
4057 * <script type="text/javascript">
4061 Roo.lib.Scroll = function(el, attributes, duration, method) {
4063 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4067 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4071 var superclass = Y.Scroll.superclass;
4072 var proto = Y.Scroll.prototype;
4074 proto.toString = function() {
4075 var el = this.getEl();
4076 var id = el.id || el.tagName;
4077 return ("Scroll " + id);
4080 proto.doMethod = function(attr, start, end) {
4083 if (attr == 'scroll') {
4085 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4086 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4090 val = superclass.doMethod.call(this, attr, start, end);
4095 proto.getAttribute = function(attr) {
4097 var el = this.getEl();
4099 if (attr == 'scroll') {
4100 val = [ el.scrollLeft, el.scrollTop ];
4102 val = superclass.getAttribute.call(this, attr);
4108 proto.setAttribute = function(attr, val, unit) {
4109 var el = this.getEl();
4111 if (attr == 'scroll') {
4112 el.scrollLeft = val[0];
4113 el.scrollTop = val[1];
4115 superclass.setAttribute.call(this, attr, val, unit);
4121 * Ext JS Library 1.1.1
4122 * Copyright(c) 2006-2007, Ext JS, LLC.
4124 * Originally Released Under LGPL - original licence link has changed is not relivant.
4127 * <script type="text/javascript">
4131 // nasty IE9 hack - what a pile of crap that is..
4133 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4134 Range.prototype.createContextualFragment = function (html) {
4135 var doc = window.document;
4136 var container = doc.createElement("div");
4137 container.innerHTML = html;
4138 var frag = doc.createDocumentFragment(), n;
4139 while ((n = container.firstChild)) {
4140 frag.appendChild(n);
4147 * @class Roo.DomHelper
4148 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4149 * 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>.
4152 Roo.DomHelper = function(){
4153 var tempTableEl = null;
4154 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4155 var tableRe = /^table|tbody|tr|td$/i;
4157 // build as innerHTML where available
4159 var createHtml = function(o){
4160 if(typeof o == 'string'){
4169 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4170 if(attr == "style"){
4172 if(typeof s == "function"){
4175 if(typeof s == "string"){
4176 b += ' style="' + s + '"';
4177 }else if(typeof s == "object"){
4180 if(typeof s[key] != "function"){
4181 b += key + ":" + s[key] + ";";
4188 b += ' class="' + o["cls"] + '"';
4189 }else if(attr == "htmlFor"){
4190 b += ' for="' + o["htmlFor"] + '"';
4192 b += " " + attr + '="' + o[attr] + '"';
4196 if(emptyTags.test(o.tag)){
4200 var cn = o.children || o.cn;
4202 //http://bugs.kde.org/show_bug.cgi?id=71506
4203 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4204 for(var i = 0, len = cn.length; i < len; i++) {
4205 b += createHtml(cn[i], b);
4208 b += createHtml(cn, b);
4214 b += "</" + o.tag + ">";
4221 var createDom = function(o, parentNode){
4223 // defininition craeted..
4225 if (o.ns && o.ns != 'html') {
4227 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4228 xmlns[o.ns] = o.xmlns;
4231 if (typeof(xmlns[o.ns]) == 'undefined') {
4232 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4238 if (typeof(o) == 'string') {
4239 return parentNode.appendChild(document.createTextNode(o));
4241 o.tag = o.tag || div;
4242 if (o.ns && Roo.isIE) {
4244 o.tag = o.ns + ':' + o.tag;
4247 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4248 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4251 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4252 attr == "style" || typeof o[attr] == "function") { continue; }
4254 if(attr=="cls" && Roo.isIE){
4255 el.className = o["cls"];
4257 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4263 Roo.DomHelper.applyStyles(el, o.style);
4264 var cn = o.children || o.cn;
4266 //http://bugs.kde.org/show_bug.cgi?id=71506
4267 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4268 for(var i = 0, len = cn.length; i < len; i++) {
4269 createDom(cn[i], el);
4276 el.innerHTML = o.html;
4279 parentNode.appendChild(el);
4284 var ieTable = function(depth, s, h, e){
4285 tempTableEl.innerHTML = [s, h, e].join('');
4286 var i = -1, el = tempTableEl;
4293 // kill repeat to save bytes
4297 tbe = '</tbody>'+te,
4303 * Nasty code for IE's broken table implementation
4305 var insertIntoTable = function(tag, where, el, html){
4307 tempTableEl = document.createElement('div');
4312 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4315 if(where == 'beforebegin'){
4319 before = el.nextSibling;
4322 node = ieTable(4, trs, html, tre);
4324 else if(tag == 'tr'){
4325 if(where == 'beforebegin'){
4328 node = ieTable(3, tbs, html, tbe);
4329 } else if(where == 'afterend'){
4330 before = el.nextSibling;
4332 node = ieTable(3, tbs, html, tbe);
4333 } else{ // INTO a TR
4334 if(where == 'afterbegin'){
4335 before = el.firstChild;
4337 node = ieTable(4, trs, html, tre);
4339 } else if(tag == 'tbody'){
4340 if(where == 'beforebegin'){
4343 node = ieTable(2, ts, html, te);
4344 } else if(where == 'afterend'){
4345 before = el.nextSibling;
4347 node = ieTable(2, ts, html, te);
4349 if(where == 'afterbegin'){
4350 before = el.firstChild;
4352 node = ieTable(3, tbs, html, tbe);
4355 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4358 if(where == 'afterbegin'){
4359 before = el.firstChild;
4361 node = ieTable(2, ts, html, te);
4363 el.insertBefore(node, before);
4368 /** True to force the use of DOM instead of html fragments @type Boolean */
4372 * Returns the markup for the passed Element(s) config
4373 * @param {Object} o The Dom object spec (and children)
4376 markup : function(o){
4377 return createHtml(o);
4381 * Applies a style specification to an element
4382 * @param {String/HTMLElement} el The element to apply styles to
4383 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4384 * a function which returns such a specification.
4386 applyStyles : function(el, styles){
4389 if(typeof styles == "string"){
4390 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4392 while ((matches = re.exec(styles)) != null){
4393 el.setStyle(matches[1], matches[2]);
4395 }else if (typeof styles == "object"){
4396 for (var style in styles){
4397 el.setStyle(style, styles[style]);
4399 }else if (typeof styles == "function"){
4400 Roo.DomHelper.applyStyles(el, styles.call());
4406 * Inserts an HTML fragment into the Dom
4407 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4408 * @param {HTMLElement} el The context element
4409 * @param {String} html The HTML fragmenet
4410 * @return {HTMLElement} The new node
4412 insertHtml : function(where, el, html){
4413 where = where.toLowerCase();
4414 if(el.insertAdjacentHTML){
4415 if(tableRe.test(el.tagName)){
4417 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4423 el.insertAdjacentHTML('BeforeBegin', html);
4424 return el.previousSibling;
4426 el.insertAdjacentHTML('AfterBegin', html);
4427 return el.firstChild;
4429 el.insertAdjacentHTML('BeforeEnd', html);
4430 return el.lastChild;
4432 el.insertAdjacentHTML('AfterEnd', html);
4433 return el.nextSibling;
4435 throw 'Illegal insertion point -> "' + where + '"';
4437 var range = el.ownerDocument.createRange();
4441 range.setStartBefore(el);
4442 frag = range.createContextualFragment(html);
4443 el.parentNode.insertBefore(frag, el);
4444 return el.previousSibling;
4447 range.setStartBefore(el.firstChild);
4448 frag = range.createContextualFragment(html);
4449 el.insertBefore(frag, el.firstChild);
4450 return el.firstChild;
4452 el.innerHTML = html;
4453 return el.firstChild;
4457 range.setStartAfter(el.lastChild);
4458 frag = range.createContextualFragment(html);
4459 el.appendChild(frag);
4460 return el.lastChild;
4462 el.innerHTML = html;
4463 return el.lastChild;
4466 range.setStartAfter(el);
4467 frag = range.createContextualFragment(html);
4468 el.parentNode.insertBefore(frag, el.nextSibling);
4469 return el.nextSibling;
4471 throw 'Illegal insertion point -> "' + where + '"';
4475 * Creates new Dom element(s) and inserts them before el
4476 * @param {String/HTMLElement/Element} el The context element
4477 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4478 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4479 * @return {HTMLElement/Roo.Element} The new node
4481 insertBefore : function(el, o, returnElement){
4482 return this.doInsert(el, o, returnElement, "beforeBegin");
4486 * Creates new Dom element(s) and inserts them after el
4487 * @param {String/HTMLElement/Element} el The context element
4488 * @param {Object} o The Dom object spec (and children)
4489 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4490 * @return {HTMLElement/Roo.Element} The new node
4492 insertAfter : function(el, o, returnElement){
4493 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4497 * Creates new Dom element(s) and inserts them as the first child of el
4498 * @param {String/HTMLElement/Element} el The context element
4499 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4500 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4501 * @return {HTMLElement/Roo.Element} The new node
4503 insertFirst : function(el, o, returnElement){
4504 return this.doInsert(el, o, returnElement, "afterBegin");
4508 doInsert : function(el, o, returnElement, pos, sibling){
4509 el = Roo.getDom(el);
4511 if(this.useDom || o.ns){
4512 newNode = createDom(o, null);
4513 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4515 var html = createHtml(o);
4516 newNode = this.insertHtml(pos, el, html);
4518 return returnElement ? Roo.get(newNode, true) : newNode;
4522 * Creates new Dom element(s) and appends them to el
4523 * @param {String/HTMLElement/Element} el The context element
4524 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4525 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4526 * @return {HTMLElement/Roo.Element} The new node
4528 append : function(el, o, returnElement){
4529 el = Roo.getDom(el);
4531 if(this.useDom || o.ns){
4532 newNode = createDom(o, null);
4533 el.appendChild(newNode);
4535 var html = createHtml(o);
4536 newNode = this.insertHtml("beforeEnd", el, html);
4538 return returnElement ? Roo.get(newNode, true) : newNode;
4542 * Creates new Dom element(s) and overwrites the contents of el with them
4543 * @param {String/HTMLElement/Element} el The context element
4544 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4545 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4546 * @return {HTMLElement/Roo.Element} The new node
4548 overwrite : function(el, o, returnElement){
4549 el = Roo.getDom(el);
4552 while (el.childNodes.length) {
4553 el.removeChild(el.firstChild);
4557 el.innerHTML = createHtml(o);
4560 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4564 * Creates a new Roo.DomHelper.Template from the Dom object spec
4565 * @param {Object} o The Dom object spec (and children)
4566 * @return {Roo.DomHelper.Template} The new template
4568 createTemplate : function(o){
4569 var html = createHtml(o);
4570 return new Roo.Template(html);
4576 * Ext JS Library 1.1.1
4577 * Copyright(c) 2006-2007, Ext JS, LLC.
4579 * Originally Released Under LGPL - original licence link has changed is not relivant.
4582 * <script type="text/javascript">
4586 * @class Roo.Template
4587 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4588 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4591 var t = new Roo.Template({
4592 html : '<div name="{id}">' +
4593 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4595 myformat: function (value, allValues) {
4596 return 'XX' + value;
4599 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4601 * For more information see this blog post with examples:
4602 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4603 - Create Elements using DOM, HTML fragments and Templates</a>.
4605 * @param {Object} cfg - Configuration object.
4607 Roo.Template = function(cfg){
4609 if(cfg instanceof Array){
4611 }else if(arguments.length > 1){
4612 cfg = Array.prototype.join.call(arguments, "");
4616 if (typeof(cfg) == 'object') {
4627 Roo.Template.prototype = {
4630 * @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..
4631 * it should be fixed so that template is observable...
4635 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4639 * Returns an HTML fragment of this template with the specified values applied.
4640 * @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'})
4641 * @return {String} The HTML fragment
4643 applyTemplate : function(values){
4647 return this.compiled(values);
4649 var useF = this.disableFormats !== true;
4650 var fm = Roo.util.Format, tpl = this;
4651 var fn = function(m, name, format, args){
4653 if(format.substr(0, 5) == "this."){
4654 return tpl.call(format.substr(5), values[name], values);
4657 // quoted values are required for strings in compiled templates,
4658 // but for non compiled we need to strip them
4659 // quoted reversed for jsmin
4660 var re = /^\s*['"](.*)["']\s*$/;
4661 args = args.split(',');
4662 for(var i = 0, len = args.length; i < len; i++){
4663 args[i] = args[i].replace(re, "$1");
4665 args = [values[name]].concat(args);
4667 args = [values[name]];
4669 return fm[format].apply(fm, args);
4672 return values[name] !== undefined ? values[name] : "";
4675 return this.html.replace(this.re, fn);
4693 this.loading = true;
4694 this.compiled = false;
4696 var cx = new Roo.data.Connection();
4700 success : function (response) {
4702 _t.html = response.responseText;
4706 failure : function(response) {
4707 Roo.log("Template failed to load from " + _t.url);
4714 * Sets the HTML used as the template and optionally compiles it.
4715 * @param {String} html
4716 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4717 * @return {Roo.Template} this
4719 set : function(html, compile){
4721 this.compiled = null;
4729 * True to disable format functions (defaults to false)
4732 disableFormats : false,
4735 * The regular expression used to match template variables
4739 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4742 * Compiles the template into an internal function, eliminating the RegEx overhead.
4743 * @return {Roo.Template} this
4745 compile : function(){
4746 var fm = Roo.util.Format;
4747 var useF = this.disableFormats !== true;
4748 var sep = Roo.isGecko ? "+" : ",";
4749 var fn = function(m, name, format, args){
4751 args = args ? ',' + args : "";
4752 if(format.substr(0, 5) != "this."){
4753 format = "fm." + format + '(';
4755 format = 'this.call("'+ format.substr(5) + '", ';
4759 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4761 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4764 // branched to use + in gecko and [].join() in others
4766 body = "this.compiled = function(values){ return '" +
4767 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4770 body = ["this.compiled = function(values){ return ['"];
4771 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4772 body.push("'].join('');};");
4773 body = body.join('');
4783 // private function used to call members
4784 call : function(fnName, value, allValues){
4785 return this[fnName](value, allValues);
4789 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4790 * @param {String/HTMLElement/Roo.Element} el The context element
4791 * @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'})
4792 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4793 * @return {HTMLElement/Roo.Element} The new node or Element
4795 insertFirst: function(el, values, returnElement){
4796 return this.doInsert('afterBegin', el, values, returnElement);
4800 * Applies the supplied values to the template and inserts the new node(s) before el.
4801 * @param {String/HTMLElement/Roo.Element} el The context element
4802 * @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'})
4803 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4804 * @return {HTMLElement/Roo.Element} The new node or Element
4806 insertBefore: function(el, values, returnElement){
4807 return this.doInsert('beforeBegin', el, values, returnElement);
4811 * Applies the supplied values to the template and inserts the new node(s) after el.
4812 * @param {String/HTMLElement/Roo.Element} el The context element
4813 * @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'})
4814 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4815 * @return {HTMLElement/Roo.Element} The new node or Element
4817 insertAfter : function(el, values, returnElement){
4818 return this.doInsert('afterEnd', el, values, returnElement);
4822 * Applies the supplied values to the template and appends the new node(s) to el.
4823 * @param {String/HTMLElement/Roo.Element} el The context element
4824 * @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'})
4825 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4826 * @return {HTMLElement/Roo.Element} The new node or Element
4828 append : function(el, values, returnElement){
4829 return this.doInsert('beforeEnd', el, values, returnElement);
4832 doInsert : function(where, el, values, returnEl){
4833 el = Roo.getDom(el);
4834 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4835 return returnEl ? Roo.get(newNode, true) : newNode;
4839 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4840 * @param {String/HTMLElement/Roo.Element} el The context element
4841 * @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'})
4842 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4843 * @return {HTMLElement/Roo.Element} The new node or Element
4845 overwrite : function(el, values, returnElement){
4846 el = Roo.getDom(el);
4847 el.innerHTML = this.applyTemplate(values);
4848 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4852 * Alias for {@link #applyTemplate}
4855 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4858 Roo.DomHelper.Template = Roo.Template;
4861 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4862 * @param {String/HTMLElement} el A DOM element or its id
4863 * @returns {Roo.Template} The created template
4866 Roo.Template.from = function(el){
4867 el = Roo.getDom(el);
4868 return new Roo.Template(el.value || el.innerHTML);
4871 * Ext JS Library 1.1.1
4872 * Copyright(c) 2006-2007, Ext JS, LLC.
4874 * Originally Released Under LGPL - original licence link has changed is not relivant.
4877 * <script type="text/javascript">
4882 * This is code is also distributed under MIT license for use
4883 * with jQuery and prototype JavaScript libraries.
4886 * @class Roo.DomQuery
4887 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).
4889 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>
4892 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.
4894 <h4>Element Selectors:</h4>
4896 <li> <b>*</b> any element</li>
4897 <li> <b>E</b> an element with the tag E</li>
4898 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4899 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4900 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4901 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4903 <h4>Attribute Selectors:</h4>
4904 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4906 <li> <b>E[foo]</b> has an attribute "foo"</li>
4907 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4908 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4909 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4910 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4911 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4912 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4914 <h4>Pseudo Classes:</h4>
4916 <li> <b>E:first-child</b> E is the first child of its parent</li>
4917 <li> <b>E:last-child</b> E is the last child of its parent</li>
4918 <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>
4919 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4920 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4921 <li> <b>E:only-child</b> E is the only child of its parent</li>
4922 <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>
4923 <li> <b>E:first</b> the first E in the resultset</li>
4924 <li> <b>E:last</b> the last E in the resultset</li>
4925 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4926 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4927 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4928 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4929 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4930 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4931 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4932 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4933 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4935 <h4>CSS Value Selectors:</h4>
4937 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4938 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4939 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4940 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4941 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4942 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4946 Roo.DomQuery = function(){
4947 var cache = {}, simpleCache = {}, valueCache = {};
4948 var nonSpace = /\S/;
4949 var trimRe = /^\s+|\s+$/g;
4950 var tplRe = /\{(\d+)\}/g;
4951 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4952 var tagTokenRe = /^(#)?([\w-\*]+)/;
4953 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4955 function child(p, index){
4957 var n = p.firstChild;
4959 if(n.nodeType == 1){
4970 while((n = n.nextSibling) && n.nodeType != 1);
4975 while((n = n.previousSibling) && n.nodeType != 1);
4979 function children(d){
4980 var n = d.firstChild, ni = -1;
4982 var nx = n.nextSibling;
4983 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4993 function byClassName(c, a, v){
4997 var r = [], ri = -1, cn;
4998 for(var i = 0, ci; ci = c[i]; i++){
4999 if((' '+ci.className+' ').indexOf(v) != -1){
5006 function attrValue(n, attr){
5007 if(!n.tagName && typeof n.length != "undefined"){
5016 if(attr == "class" || attr == "className"){
5019 return n.getAttribute(attr) || n[attr];
5023 function getNodes(ns, mode, tagName){
5024 var result = [], ri = -1, cs;
5028 tagName = tagName || "*";
5029 if(typeof ns.getElementsByTagName != "undefined"){
5033 for(var i = 0, ni; ni = ns[i]; i++){
5034 cs = ni.getElementsByTagName(tagName);
5035 for(var j = 0, ci; ci = cs[j]; j++){
5039 }else if(mode == "/" || mode == ">"){
5040 var utag = tagName.toUpperCase();
5041 for(var i = 0, ni, cn; ni = ns[i]; i++){
5042 cn = ni.children || ni.childNodes;
5043 for(var j = 0, cj; cj = cn[j]; j++){
5044 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5049 }else if(mode == "+"){
5050 var utag = tagName.toUpperCase();
5051 for(var i = 0, n; n = ns[i]; i++){
5052 while((n = n.nextSibling) && n.nodeType != 1);
5053 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5057 }else if(mode == "~"){
5058 for(var i = 0, n; n = ns[i]; i++){
5059 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5068 function concat(a, b){
5072 for(var i = 0, l = b.length; i < l; i++){
5078 function byTag(cs, tagName){
5079 if(cs.tagName || cs == document){
5085 var r = [], ri = -1;
5086 tagName = tagName.toLowerCase();
5087 for(var i = 0, ci; ci = cs[i]; i++){
5088 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5095 function byId(cs, attr, id){
5096 if(cs.tagName || cs == document){
5102 var r = [], ri = -1;
5103 for(var i = 0,ci; ci = cs[i]; i++){
5104 if(ci && ci.id == id){
5112 function byAttribute(cs, attr, value, op, custom){
5113 var r = [], ri = -1, st = custom=="{";
5114 var f = Roo.DomQuery.operators[op];
5115 for(var i = 0, ci; ci = cs[i]; i++){
5118 a = Roo.DomQuery.getStyle(ci, attr);
5120 else if(attr == "class" || attr == "className"){
5122 }else if(attr == "for"){
5124 }else if(attr == "href"){
5125 a = ci.getAttribute("href", 2);
5127 a = ci.getAttribute(attr);
5129 if((f && f(a, value)) || (!f && a)){
5136 function byPseudo(cs, name, value){
5137 return Roo.DomQuery.pseudos[name](cs, value);
5140 // This is for IE MSXML which does not support expandos.
5141 // IE runs the same speed using setAttribute, however FF slows way down
5142 // and Safari completely fails so they need to continue to use expandos.
5143 var isIE = window.ActiveXObject ? true : false;
5145 // this eval is stop the compressor from
5146 // renaming the variable to something shorter
5148 /** eval:var:batch */
5153 function nodupIEXml(cs){
5155 cs[0].setAttribute("_nodup", d);
5157 for(var i = 1, len = cs.length; i < len; i++){
5159 if(!c.getAttribute("_nodup") != d){
5160 c.setAttribute("_nodup", d);
5164 for(var i = 0, len = cs.length; i < len; i++){
5165 cs[i].removeAttribute("_nodup");
5174 var len = cs.length, c, i, r = cs, cj, ri = -1;
5175 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5178 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5179 return nodupIEXml(cs);
5183 for(i = 1; c = cs[i]; i++){
5188 for(var j = 0; j < i; j++){
5191 for(j = i+1; cj = cs[j]; j++){
5203 function quickDiffIEXml(c1, c2){
5205 for(var i = 0, len = c1.length; i < len; i++){
5206 c1[i].setAttribute("_qdiff", d);
5209 for(var i = 0, len = c2.length; i < len; i++){
5210 if(c2[i].getAttribute("_qdiff") != d){
5211 r[r.length] = c2[i];
5214 for(var i = 0, len = c1.length; i < len; i++){
5215 c1[i].removeAttribute("_qdiff");
5220 function quickDiff(c1, c2){
5221 var len1 = c1.length;
5225 if(isIE && c1[0].selectSingleNode){
5226 return quickDiffIEXml(c1, c2);
5229 for(var i = 0; i < len1; i++){
5233 for(var i = 0, len = c2.length; i < len; i++){
5234 if(c2[i]._qdiff != d){
5235 r[r.length] = c2[i];
5241 function quickId(ns, mode, root, id){
5243 var d = root.ownerDocument || root;
5244 return d.getElementById(id);
5246 ns = getNodes(ns, mode, "*");
5247 return byId(ns, null, id);
5251 getStyle : function(el, name){
5252 return Roo.fly(el).getStyle(name);
5255 * Compiles a selector/xpath query into a reusable function. The returned function
5256 * takes one parameter "root" (optional), which is the context node from where the query should start.
5257 * @param {String} selector The selector/xpath query
5258 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5259 * @return {Function}
5261 compile : function(path, type){
5262 type = type || "select";
5264 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5265 var q = path, mode, lq;
5266 var tk = Roo.DomQuery.matchers;
5267 var tklen = tk.length;
5270 // accept leading mode switch
5271 var lmode = q.match(modeRe);
5272 if(lmode && lmode[1]){
5273 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5274 q = q.replace(lmode[1], "");
5276 // strip leading slashes
5277 while(path.substr(0, 1)=="/"){
5278 path = path.substr(1);
5281 while(q && lq != q){
5283 var tm = q.match(tagTokenRe);
5284 if(type == "select"){
5287 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5289 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5291 q = q.replace(tm[0], "");
5292 }else if(q.substr(0, 1) != '@'){
5293 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5298 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5300 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5302 q = q.replace(tm[0], "");
5305 while(!(mm = q.match(modeRe))){
5306 var matched = false;
5307 for(var j = 0; j < tklen; j++){
5309 var m = q.match(t.re);
5311 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5314 q = q.replace(m[0], "");
5319 // prevent infinite loop on bad selector
5321 throw 'Error parsing selector, parsing failed at "' + q + '"';
5325 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5326 q = q.replace(mm[1], "");
5329 fn[fn.length] = "return nodup(n);\n}";
5332 * list of variables that need from compression as they are used by eval.
5342 * eval:var:byClassName
5344 * eval:var:byAttribute
5345 * eval:var:attrValue
5353 * Selects a group of elements.
5354 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5355 * @param {Node} root (optional) The start of the query (defaults to document).
5358 select : function(path, root, type){
5359 if(!root || root == document){
5362 if(typeof root == "string"){
5363 root = document.getElementById(root);
5365 var paths = path.split(",");
5367 for(var i = 0, len = paths.length; i < len; i++){
5368 var p = paths[i].replace(trimRe, "");
5370 cache[p] = Roo.DomQuery.compile(p);
5372 throw p + " is not a valid selector";
5375 var result = cache[p](root);
5376 if(result && result != document){
5377 results = results.concat(result);
5380 if(paths.length > 1){
5381 return nodup(results);
5387 * Selects a single element.
5388 * @param {String} selector The selector/xpath query
5389 * @param {Node} root (optional) The start of the query (defaults to document).
5392 selectNode : function(path, root){
5393 return Roo.DomQuery.select(path, root)[0];
5397 * Selects the value of a node, optionally replacing null with the defaultValue.
5398 * @param {String} selector The selector/xpath query
5399 * @param {Node} root (optional) The start of the query (defaults to document).
5400 * @param {String} defaultValue
5402 selectValue : function(path, root, defaultValue){
5403 path = path.replace(trimRe, "");
5404 if(!valueCache[path]){
5405 valueCache[path] = Roo.DomQuery.compile(path, "select");
5407 var n = valueCache[path](root);
5408 n = n[0] ? n[0] : n;
5409 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5410 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5414 * Selects the value of a node, parsing integers and floats.
5415 * @param {String} selector The selector/xpath query
5416 * @param {Node} root (optional) The start of the query (defaults to document).
5417 * @param {Number} defaultValue
5420 selectNumber : function(path, root, defaultValue){
5421 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5422 return parseFloat(v);
5426 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5427 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5428 * @param {String} selector The simple selector to test
5431 is : function(el, ss){
5432 if(typeof el == "string"){
5433 el = document.getElementById(el);
5435 var isArray = (el instanceof Array);
5436 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5437 return isArray ? (result.length == el.length) : (result.length > 0);
5441 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5442 * @param {Array} el An array of elements to filter
5443 * @param {String} selector The simple selector to test
5444 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5445 * the selector instead of the ones that match
5448 filter : function(els, ss, nonMatches){
5449 ss = ss.replace(trimRe, "");
5450 if(!simpleCache[ss]){
5451 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5453 var result = simpleCache[ss](els);
5454 return nonMatches ? quickDiff(result, els) : result;
5458 * Collection of matching regular expressions and code snippets.
5462 select: 'n = byClassName(n, null, " {1} ");'
5464 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5465 select: 'n = byPseudo(n, "{1}", "{2}");'
5467 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5468 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5471 select: 'n = byId(n, null, "{1}");'
5474 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5479 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5480 * 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, > <.
5483 "=" : function(a, v){
5486 "!=" : function(a, v){
5489 "^=" : function(a, v){
5490 return a && a.substr(0, v.length) == v;
5492 "$=" : function(a, v){
5493 return a && a.substr(a.length-v.length) == v;
5495 "*=" : function(a, v){
5496 return a && a.indexOf(v) !== -1;
5498 "%=" : function(a, v){
5499 return (a % v) == 0;
5501 "|=" : function(a, v){
5502 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5504 "~=" : function(a, v){
5505 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5510 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5511 * and the argument (if any) supplied in the selector.
5514 "first-child" : function(c){
5515 var r = [], ri = -1, n;
5516 for(var i = 0, ci; ci = n = c[i]; i++){
5517 while((n = n.previousSibling) && n.nodeType != 1);
5525 "last-child" : function(c){
5526 var r = [], ri = -1, n;
5527 for(var i = 0, ci; ci = n = c[i]; i++){
5528 while((n = n.nextSibling) && n.nodeType != 1);
5536 "nth-child" : function(c, a) {
5537 var r = [], ri = -1;
5538 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5539 var f = (m[1] || 1) - 0, l = m[2] - 0;
5540 for(var i = 0, n; n = c[i]; i++){
5541 var pn = n.parentNode;
5542 if (batch != pn._batch) {
5544 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5545 if(cn.nodeType == 1){
5552 if (l == 0 || n.nodeIndex == l){
5555 } else if ((n.nodeIndex + l) % f == 0){
5563 "only-child" : function(c){
5564 var r = [], ri = -1;;
5565 for(var i = 0, ci; ci = c[i]; i++){
5566 if(!prev(ci) && !next(ci)){
5573 "empty" : function(c){
5574 var r = [], ri = -1;
5575 for(var i = 0, ci; ci = c[i]; i++){
5576 var cns = ci.childNodes, j = 0, cn, empty = true;
5579 if(cn.nodeType == 1 || cn.nodeType == 3){
5591 "contains" : function(c, v){
5592 var r = [], ri = -1;
5593 for(var i = 0, ci; ci = c[i]; i++){
5594 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5601 "nodeValue" : function(c, v){
5602 var r = [], ri = -1;
5603 for(var i = 0, ci; ci = c[i]; i++){
5604 if(ci.firstChild && ci.firstChild.nodeValue == v){
5611 "checked" : function(c){
5612 var r = [], ri = -1;
5613 for(var i = 0, ci; ci = c[i]; i++){
5614 if(ci.checked == true){
5621 "not" : function(c, ss){
5622 return Roo.DomQuery.filter(c, ss, true);
5625 "odd" : function(c){
5626 return this["nth-child"](c, "odd");
5629 "even" : function(c){
5630 return this["nth-child"](c, "even");
5633 "nth" : function(c, a){
5634 return c[a-1] || [];
5637 "first" : function(c){
5641 "last" : function(c){
5642 return c[c.length-1] || [];
5645 "has" : function(c, ss){
5646 var s = Roo.DomQuery.select;
5647 var r = [], ri = -1;
5648 for(var i = 0, ci; ci = c[i]; i++){
5649 if(s(ss, ci).length > 0){
5656 "next" : function(c, ss){
5657 var is = Roo.DomQuery.is;
5658 var r = [], ri = -1;
5659 for(var i = 0, ci; ci = c[i]; i++){
5668 "prev" : function(c, ss){
5669 var is = Roo.DomQuery.is;
5670 var r = [], ri = -1;
5671 for(var i = 0, ci; ci = c[i]; i++){
5684 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5685 * @param {String} path The selector/xpath query
5686 * @param {Node} root (optional) The start of the query (defaults to document).
5691 Roo.query = Roo.DomQuery.select;
5694 * Ext JS Library 1.1.1
5695 * Copyright(c) 2006-2007, Ext JS, LLC.
5697 * Originally Released Under LGPL - original licence link has changed is not relivant.
5700 * <script type="text/javascript">
5704 * @class Roo.util.Observable
5705 * Base class that provides a common interface for publishing events. Subclasses are expected to
5706 * to have a property "events" with all the events defined.<br>
5709 Employee = function(name){
5716 Roo.extend(Employee, Roo.util.Observable);
5718 * @param {Object} config properties to use (incuding events / listeners)
5721 Roo.util.Observable = function(cfg){
5724 this.addEvents(cfg.events || {});
5726 delete cfg.events; // make sure
5729 Roo.apply(this, cfg);
5732 this.on(this.listeners);
5733 delete this.listeners;
5736 Roo.util.Observable.prototype = {
5738 * @cfg {Object} listeners list of events and functions to call for this object,
5742 'click' : function(e) {
5752 * Fires the specified event with the passed parameters (minus the event name).
5753 * @param {String} eventName
5754 * @param {Object...} args Variable number of parameters are passed to handlers
5755 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5757 fireEvent : function(){
5758 var ce = this.events[arguments[0].toLowerCase()];
5759 if(typeof ce == "object"){
5760 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5767 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5770 * Appends an event handler to this component
5771 * @param {String} eventName The type of event to listen for
5772 * @param {Function} handler The method the event invokes
5773 * @param {Object} scope (optional) The scope in which to execute the handler
5774 * function. The handler function's "this" context.
5775 * @param {Object} options (optional) An object containing handler configuration
5776 * properties. This may contain any of the following properties:<ul>
5777 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5778 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5779 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5780 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5781 * by the specified number of milliseconds. If the event fires again within that time, the original
5782 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5785 * <b>Combining Options</b><br>
5786 * Using the options argument, it is possible to combine different types of listeners:<br>
5788 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5790 el.on('click', this.onClick, this, {
5797 * <b>Attaching multiple handlers in 1 call</b><br>
5798 * The method also allows for a single argument to be passed which is a config object containing properties
5799 * which specify multiple handlers.
5808 fn: this.onMouseOver,
5812 fn: this.onMouseOut,
5818 * Or a shorthand syntax which passes the same scope object to all handlers:
5821 'click': this.onClick,
5822 'mouseover': this.onMouseOver,
5823 'mouseout': this.onMouseOut,
5828 addListener : function(eventName, fn, scope, o){
5829 if(typeof eventName == "object"){
5832 if(this.filterOptRe.test(e)){
5835 if(typeof o[e] == "function"){
5837 this.addListener(e, o[e], o.scope, o);
5839 // individual options
5840 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5845 o = (!o || typeof o == "boolean") ? {} : o;
5846 eventName = eventName.toLowerCase();
5847 var ce = this.events[eventName] || true;
5848 if(typeof ce == "boolean"){
5849 ce = new Roo.util.Event(this, eventName);
5850 this.events[eventName] = ce;
5852 ce.addListener(fn, scope, o);
5856 * Removes a listener
5857 * @param {String} eventName The type of event to listen for
5858 * @param {Function} handler The handler to remove
5859 * @param {Object} scope (optional) The scope (this object) for the handler
5861 removeListener : function(eventName, fn, scope){
5862 var ce = this.events[eventName.toLowerCase()];
5863 if(typeof ce == "object"){
5864 ce.removeListener(fn, scope);
5869 * Removes all listeners for this object
5871 purgeListeners : function(){
5872 for(var evt in this.events){
5873 if(typeof this.events[evt] == "object"){
5874 this.events[evt].clearListeners();
5879 relayEvents : function(o, events){
5880 var createHandler = function(ename){
5882 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5885 for(var i = 0, len = events.length; i < len; i++){
5886 var ename = events[i];
5887 if(!this.events[ename]){ this.events[ename] = true; };
5888 o.on(ename, createHandler(ename), this);
5893 * Used to define events on this Observable
5894 * @param {Object} object The object with the events defined
5896 addEvents : function(o){
5900 Roo.applyIf(this.events, o);
5904 * Checks to see if this object has any listeners for a specified event
5905 * @param {String} eventName The name of the event to check for
5906 * @return {Boolean} True if the event is being listened for, else false
5908 hasListener : function(eventName){
5909 var e = this.events[eventName];
5910 return typeof e == "object" && e.listeners.length > 0;
5914 * Appends an event handler to this element (shorthand for addListener)
5915 * @param {String} eventName The type of event to listen for
5916 * @param {Function} handler The method the event invokes
5917 * @param {Object} scope (optional) The scope in which to execute the handler
5918 * function. The handler function's "this" context.
5919 * @param {Object} options (optional)
5922 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5924 * Removes a listener (shorthand for removeListener)
5925 * @param {String} eventName The type of event to listen for
5926 * @param {Function} handler The handler to remove
5927 * @param {Object} scope (optional) The scope (this object) for the handler
5930 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5933 * Starts capture on the specified Observable. All events will be passed
5934 * to the supplied function with the event name + standard signature of the event
5935 * <b>before</b> the event is fired. If the supplied function returns false,
5936 * the event will not fire.
5937 * @param {Observable} o The Observable to capture
5938 * @param {Function} fn The function to call
5939 * @param {Object} scope (optional) The scope (this object) for the fn
5942 Roo.util.Observable.capture = function(o, fn, scope){
5943 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5947 * Removes <b>all</b> added captures from the Observable.
5948 * @param {Observable} o The Observable to release
5951 Roo.util.Observable.releaseCapture = function(o){
5952 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5957 var createBuffered = function(h, o, scope){
5958 var task = new Roo.util.DelayedTask();
5960 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5964 var createSingle = function(h, e, fn, scope){
5966 e.removeListener(fn, scope);
5967 return h.apply(scope, arguments);
5971 var createDelayed = function(h, o, scope){
5973 var args = Array.prototype.slice.call(arguments, 0);
5974 setTimeout(function(){
5975 h.apply(scope, args);
5980 Roo.util.Event = function(obj, name){
5983 this.listeners = [];
5986 Roo.util.Event.prototype = {
5987 addListener : function(fn, scope, options){
5988 var o = options || {};
5989 scope = scope || this.obj;
5990 if(!this.isListening(fn, scope)){
5991 var l = {fn: fn, scope: scope, options: o};
5994 h = createDelayed(h, o, scope);
5997 h = createSingle(h, this, fn, scope);
6000 h = createBuffered(h, o, scope);
6003 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6004 this.listeners.push(l);
6006 this.listeners = this.listeners.slice(0);
6007 this.listeners.push(l);
6012 findListener : function(fn, scope){
6013 scope = scope || this.obj;
6014 var ls = this.listeners;
6015 for(var i = 0, len = ls.length; i < len; i++){
6017 if(l.fn == fn && l.scope == scope){
6024 isListening : function(fn, scope){
6025 return this.findListener(fn, scope) != -1;
6028 removeListener : function(fn, scope){
6030 if((index = this.findListener(fn, scope)) != -1){
6032 this.listeners.splice(index, 1);
6034 this.listeners = this.listeners.slice(0);
6035 this.listeners.splice(index, 1);
6042 clearListeners : function(){
6043 this.listeners = [];
6047 var ls = this.listeners, scope, len = ls.length;
6050 var args = Array.prototype.slice.call(arguments, 0);
6051 for(var i = 0; i < len; i++){
6053 if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6054 this.firing = false;
6058 this.firing = false;
6065 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6072 * @class Roo.Document
6073 * @extends Roo.util.Observable
6074 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6076 * @param {Object} config the methods and properties of the 'base' class for the application.
6078 * Generic Page handler - implement this to start your app..
6081 * MyProject = new Roo.Document({
6083 'load' : true // your events..
6086 'ready' : function() {
6087 // fired on Roo.onReady()
6092 Roo.Document = function(cfg) {
6097 Roo.util.Observable.call(this,cfg);
6101 Roo.onReady(function() {
6102 _this.fireEvent('ready');
6108 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6110 * Ext JS Library 1.1.1
6111 * Copyright(c) 2006-2007, Ext JS, LLC.
6113 * Originally Released Under LGPL - original licence link has changed is not relivant.
6116 * <script type="text/javascript">
6120 * @class Roo.EventManager
6121 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6122 * several useful events directly.
6123 * See {@link Roo.EventObject} for more details on normalized event objects.
6126 Roo.EventManager = function(){
6127 var docReadyEvent, docReadyProcId, docReadyState = false;
6128 var resizeEvent, resizeTask, textEvent, textSize;
6129 var E = Roo.lib.Event;
6130 var D = Roo.lib.Dom;
6135 var fireDocReady = function(){
6137 docReadyState = true;
6140 clearInterval(docReadyProcId);
6142 if(Roo.isGecko || Roo.isOpera) {
6143 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6146 var defer = document.getElementById("ie-deferred-loader");
6148 defer.onreadystatechange = null;
6149 defer.parentNode.removeChild(defer);
6153 docReadyEvent.fire();
6154 docReadyEvent.clearListeners();
6159 var initDocReady = function(){
6160 docReadyEvent = new Roo.util.Event();
6161 if(Roo.isGecko || Roo.isOpera) {
6162 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6164 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6165 var defer = document.getElementById("ie-deferred-loader");
6166 defer.onreadystatechange = function(){
6167 if(this.readyState == "complete"){
6171 }else if(Roo.isSafari){
6172 docReadyProcId = setInterval(function(){
6173 var rs = document.readyState;
6174 if(rs == "complete") {
6179 // no matter what, make sure it fires on load
6180 E.on(window, "load", fireDocReady);
6183 var createBuffered = function(h, o){
6184 var task = new Roo.util.DelayedTask(h);
6186 // create new event object impl so new events don't wipe out properties
6187 e = new Roo.EventObjectImpl(e);
6188 task.delay(o.buffer, h, null, [e]);
6192 var createSingle = function(h, el, ename, fn){
6194 Roo.EventManager.removeListener(el, ename, fn);
6199 var createDelayed = function(h, o){
6201 // create new event object impl so new events don't wipe out properties
6202 e = new Roo.EventObjectImpl(e);
6203 setTimeout(function(){
6208 var transitionEndVal = false;
6210 var transitionEnd = function()
6212 if (transitionEndVal) {
6213 return transitionEndVal;
6215 var el = document.createElement('div');
6217 var transEndEventNames = {
6218 WebkitTransition : 'webkitTransitionEnd',
6219 MozTransition : 'transitionend',
6220 OTransition : 'oTransitionEnd otransitionend',
6221 transition : 'transitionend'
6224 for (var name in transEndEventNames) {
6225 if (el.style[name] !== undefined) {
6226 transitionEndVal = transEndEventNames[name];
6227 return transitionEndVal ;
6233 var listen = function(element, ename, opt, fn, scope){
6234 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6235 fn = fn || o.fn; scope = scope || o.scope;
6236 var el = Roo.getDom(element);
6240 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6243 if (ename == 'transitionend') {
6244 ename = transitionEnd();
6246 var h = function(e){
6247 e = Roo.EventObject.setEvent(e);
6250 t = e.getTarget(o.delegate, el);
6257 if(o.stopEvent === true){
6260 if(o.preventDefault === true){
6263 if(o.stopPropagation === true){
6264 e.stopPropagation();
6267 if(o.normalized === false){
6271 fn.call(scope || el, e, t, o);
6274 h = createDelayed(h, o);
6277 h = createSingle(h, el, ename, fn);
6280 h = createBuffered(h, o);
6282 fn._handlers = fn._handlers || [];
6285 fn._handlers.push([Roo.id(el), ename, h]);
6290 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6291 el.addEventListener("DOMMouseScroll", h, false);
6292 E.on(window, 'unload', function(){
6293 el.removeEventListener("DOMMouseScroll", h, false);
6296 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6297 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6302 var stopListening = function(el, ename, fn){
6303 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6305 for(var i = 0, len = hds.length; i < len; i++){
6307 if(h[0] == id && h[1] == ename){
6314 E.un(el, ename, hd);
6315 el = Roo.getDom(el);
6316 if(ename == "mousewheel" && el.addEventListener){
6317 el.removeEventListener("DOMMouseScroll", hd, false);
6319 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6320 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6324 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6331 * @scope Roo.EventManager
6336 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6337 * object with a Roo.EventObject
6338 * @param {Function} fn The method the event invokes
6339 * @param {Object} scope An object that becomes the scope of the handler
6340 * @param {boolean} override If true, the obj passed in becomes
6341 * the execution scope of the listener
6342 * @return {Function} The wrapped function
6345 wrap : function(fn, scope, override){
6347 Roo.EventObject.setEvent(e);
6348 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6353 * Appends an event handler to an element (shorthand for addListener)
6354 * @param {String/HTMLElement} element The html element or id to assign the
6355 * @param {String} eventName The type of event to listen for
6356 * @param {Function} handler The method the event invokes
6357 * @param {Object} scope (optional) The scope in which to execute the handler
6358 * function. The handler function's "this" context.
6359 * @param {Object} options (optional) An object containing handler configuration
6360 * properties. This may contain any of the following properties:<ul>
6361 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6362 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6363 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6364 * <li>preventDefault {Boolean} True to prevent the default action</li>
6365 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6366 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6367 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6368 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6369 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6370 * by the specified number of milliseconds. If the event fires again within that time, the original
6371 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6374 * <b>Combining Options</b><br>
6375 * Using the options argument, it is possible to combine different types of listeners:<br>
6377 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6379 el.on('click', this.onClick, this, {
6386 * <b>Attaching multiple handlers in 1 call</b><br>
6387 * The method also allows for a single argument to be passed which is a config object containing properties
6388 * which specify multiple handlers.
6398 fn: this.onMouseOver
6407 * Or a shorthand syntax:<br>
6410 'click' : this.onClick,
6411 'mouseover' : this.onMouseOver,
6412 'mouseout' : this.onMouseOut
6416 addListener : function(element, eventName, fn, scope, options){
6417 if(typeof eventName == "object"){
6423 if(typeof o[e] == "function"){
6425 listen(element, e, o, o[e], o.scope);
6427 // individual options
6428 listen(element, e, o[e]);
6433 return listen(element, eventName, options, fn, scope);
6437 * Removes an event handler
6439 * @param {String/HTMLElement} element The id or html element to remove the
6441 * @param {String} eventName The type of event
6442 * @param {Function} fn
6443 * @return {Boolean} True if a listener was actually removed
6445 removeListener : function(element, eventName, fn){
6446 return stopListening(element, eventName, fn);
6450 * Fires when the document is ready (before onload and before images are loaded). Can be
6451 * accessed shorthanded Roo.onReady().
6452 * @param {Function} fn The method the event invokes
6453 * @param {Object} scope An object that becomes the scope of the handler
6454 * @param {boolean} options
6456 onDocumentReady : function(fn, scope, options){
6457 if(docReadyState){ // if it already fired
6458 docReadyEvent.addListener(fn, scope, options);
6459 docReadyEvent.fire();
6460 docReadyEvent.clearListeners();
6466 docReadyEvent.addListener(fn, scope, options);
6470 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6471 * @param {Function} fn The method the event invokes
6472 * @param {Object} scope An object that becomes the scope of the handler
6473 * @param {boolean} options
6475 onWindowResize : function(fn, scope, options){
6477 resizeEvent = new Roo.util.Event();
6478 resizeTask = new Roo.util.DelayedTask(function(){
6479 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6481 E.on(window, "resize", function(){
6483 resizeTask.delay(50);
6485 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6489 resizeEvent.addListener(fn, scope, options);
6493 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6494 * @param {Function} fn The method the event invokes
6495 * @param {Object} scope An object that becomes the scope of the handler
6496 * @param {boolean} options
6498 onTextResize : function(fn, scope, options){
6500 textEvent = new Roo.util.Event();
6501 var textEl = new Roo.Element(document.createElement('div'));
6502 textEl.dom.className = 'x-text-resize';
6503 textEl.dom.innerHTML = 'X';
6504 textEl.appendTo(document.body);
6505 textSize = textEl.dom.offsetHeight;
6506 setInterval(function(){
6507 if(textEl.dom.offsetHeight != textSize){
6508 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6510 }, this.textResizeInterval);
6512 textEvent.addListener(fn, scope, options);
6516 * Removes the passed window resize listener.
6517 * @param {Function} fn The method the event invokes
6518 * @param {Object} scope The scope of handler
6520 removeResizeListener : function(fn, scope){
6522 resizeEvent.removeListener(fn, scope);
6527 fireResize : function(){
6529 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6533 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6537 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6539 textResizeInterval : 50
6544 * @scopeAlias pub=Roo.EventManager
6548 * Appends an event handler to an element (shorthand for addListener)
6549 * @param {String/HTMLElement} element The html element or id to assign the
6550 * @param {String} eventName The type of event to listen for
6551 * @param {Function} handler The method the event invokes
6552 * @param {Object} scope (optional) The scope in which to execute the handler
6553 * function. The handler function's "this" context.
6554 * @param {Object} options (optional) An object containing handler configuration
6555 * properties. This may contain any of the following properties:<ul>
6556 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6557 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6558 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6559 * <li>preventDefault {Boolean} True to prevent the default action</li>
6560 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6561 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6562 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6563 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6564 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6565 * by the specified number of milliseconds. If the event fires again within that time, the original
6566 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6569 * <b>Combining Options</b><br>
6570 * Using the options argument, it is possible to combine different types of listeners:<br>
6572 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6574 el.on('click', this.onClick, this, {
6581 * <b>Attaching multiple handlers in 1 call</b><br>
6582 * The method also allows for a single argument to be passed which is a config object containing properties
6583 * which specify multiple handlers.
6593 fn: this.onMouseOver
6602 * Or a shorthand syntax:<br>
6605 'click' : this.onClick,
6606 'mouseover' : this.onMouseOver,
6607 'mouseout' : this.onMouseOut
6611 pub.on = pub.addListener;
6612 pub.un = pub.removeListener;
6614 pub.stoppedMouseDownEvent = new Roo.util.Event();
6618 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6619 * @param {Function} fn The method the event invokes
6620 * @param {Object} scope An object that becomes the scope of the handler
6621 * @param {boolean} override If true, the obj passed in becomes
6622 * the execution scope of the listener
6626 Roo.onReady = Roo.EventManager.onDocumentReady;
6628 Roo.onReady(function(){
6629 var bd = Roo.get(document.body);
6634 : Roo.isIE11 ? "roo-ie11"
6635 : Roo.isEdge ? "roo-edge"
6636 : Roo.isGecko ? "roo-gecko"
6637 : Roo.isOpera ? "roo-opera"
6638 : Roo.isSafari ? "roo-safari" : ""];
6641 cls.push("roo-mac");
6644 cls.push("roo-linux");
6647 cls.push("roo-ios");
6650 cls.push("roo-touch");
6652 if(Roo.isBorderBox){
6653 cls.push('roo-border-box');
6655 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6656 var p = bd.dom.parentNode;
6658 p.className += ' roo-strict';
6661 bd.addClass(cls.join(' '));
6665 * @class Roo.EventObject
6666 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6667 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6670 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6672 var target = e.getTarget();
6675 var myDiv = Roo.get("myDiv");
6676 myDiv.on("click", handleClick);
6678 Roo.EventManager.on("myDiv", 'click', handleClick);
6679 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6683 Roo.EventObject = function(){
6685 var E = Roo.lib.Event;
6687 // safari keypress events for special keys return bad keycodes
6690 63235 : 39, // right
6693 63276 : 33, // page up
6694 63277 : 34, // page down
6695 63272 : 46, // delete
6700 // normalize button clicks
6701 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6702 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6704 Roo.EventObjectImpl = function(e){
6706 this.setEvent(e.browserEvent || e);
6709 Roo.EventObjectImpl.prototype = {
6711 * Used to fix doc tools.
6712 * @scope Roo.EventObject.prototype
6718 /** The normal browser event */
6719 browserEvent : null,
6720 /** The button pressed in a mouse event */
6722 /** True if the shift key was down during the event */
6724 /** True if the control key was down during the event */
6726 /** True if the alt key was down during the event */
6785 setEvent : function(e){
6786 if(e == this || (e && e.browserEvent)){ // already wrapped
6789 this.browserEvent = e;
6791 // normalize buttons
6792 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6793 if(e.type == 'click' && this.button == -1){
6797 this.shiftKey = e.shiftKey;
6798 // mac metaKey behaves like ctrlKey
6799 this.ctrlKey = e.ctrlKey || e.metaKey;
6800 this.altKey = e.altKey;
6801 // in getKey these will be normalized for the mac
6802 this.keyCode = e.keyCode;
6803 // keyup warnings on firefox.
6804 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6805 // cache the target for the delayed and or buffered events
6806 this.target = E.getTarget(e);
6808 this.xy = E.getXY(e);
6811 this.shiftKey = false;
6812 this.ctrlKey = false;
6813 this.altKey = false;
6823 * Stop the event (preventDefault and stopPropagation)
6825 stopEvent : function(){
6826 if(this.browserEvent){
6827 if(this.browserEvent.type == 'mousedown'){
6828 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6830 E.stopEvent(this.browserEvent);
6835 * Prevents the browsers default handling of the event.
6837 preventDefault : function(){
6838 if(this.browserEvent){
6839 E.preventDefault(this.browserEvent);
6844 isNavKeyPress : function(){
6845 var k = this.keyCode;
6846 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6847 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6850 isSpecialKey : function(){
6851 var k = this.keyCode;
6852 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6853 (k == 16) || (k == 17) ||
6854 (k >= 18 && k <= 20) ||
6855 (k >= 33 && k <= 35) ||
6856 (k >= 36 && k <= 39) ||
6857 (k >= 44 && k <= 45);
6860 * Cancels bubbling of the event.
6862 stopPropagation : function(){
6863 if(this.browserEvent){
6864 if(this.type == 'mousedown'){
6865 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6867 E.stopPropagation(this.browserEvent);
6872 * Gets the key code for the event.
6875 getCharCode : function(){
6876 return this.charCode || this.keyCode;
6880 * Returns a normalized keyCode for the event.
6881 * @return {Number} The key code
6883 getKey : function(){
6884 var k = this.keyCode || this.charCode;
6885 return Roo.isSafari ? (safariKeys[k] || k) : k;
6889 * Gets the x coordinate of the event.
6892 getPageX : function(){
6897 * Gets the y coordinate of the event.
6900 getPageY : function(){
6905 * Gets the time of the event.
6908 getTime : function(){
6909 if(this.browserEvent){
6910 return E.getTime(this.browserEvent);
6916 * Gets the page coordinates of the event.
6917 * @return {Array} The xy values like [x, y]
6924 * Gets the target for the event.
6925 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6926 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6927 search as a number or element (defaults to 10 || document.body)
6928 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6929 * @return {HTMLelement}
6931 getTarget : function(selector, maxDepth, returnEl){
6932 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6935 * Gets the related target.
6936 * @return {HTMLElement}
6938 getRelatedTarget : function(){
6939 if(this.browserEvent){
6940 return E.getRelatedTarget(this.browserEvent);
6946 * Normalizes mouse wheel delta across browsers
6947 * @return {Number} The delta
6949 getWheelDelta : function(){
6950 var e = this.browserEvent;
6952 if(e.wheelDelta){ /* IE/Opera. */
6953 delta = e.wheelDelta/120;
6954 }else if(e.detail){ /* Mozilla case. */
6955 delta = -e.detail/3;
6961 * Returns true if the control, meta, shift or alt key was pressed during this event.
6964 hasModifier : function(){
6965 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6969 * Returns true if the target of this event equals el or is a child of el
6970 * @param {String/HTMLElement/Element} el
6971 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6974 within : function(el, related){
6975 var t = this[related ? "getRelatedTarget" : "getTarget"]();
6976 return t && Roo.fly(el).contains(t);
6979 getPoint : function(){
6980 return new Roo.lib.Point(this.xy[0], this.xy[1]);
6984 return new Roo.EventObjectImpl();
6989 * Ext JS Library 1.1.1
6990 * Copyright(c) 2006-2007, Ext JS, LLC.
6992 * Originally Released Under LGPL - original licence link has changed is not relivant.
6995 * <script type="text/javascript">
6999 // was in Composite Element!??!?!
7002 var D = Roo.lib.Dom;
7003 var E = Roo.lib.Event;
7004 var A = Roo.lib.Anim;
7006 // local style camelizing for speed
7008 var camelRe = /(-[a-z])/gi;
7009 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7010 var view = document.defaultView;
7013 * @class Roo.Element
7014 * Represents an Element in the DOM.<br><br>
7017 var el = Roo.get("my-div");
7020 var el = getEl("my-div");
7022 // or with a DOM element
7023 var el = Roo.get(myDivElement);
7025 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7026 * each call instead of constructing a new one.<br><br>
7027 * <b>Animations</b><br />
7028 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7029 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7031 Option Default Description
7032 --------- -------- ---------------------------------------------
7033 duration .35 The duration of the animation in seconds
7034 easing easeOut The YUI easing method
7035 callback none A function to execute when the anim completes
7036 scope this The scope (this) of the callback function
7038 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7039 * manipulate the animation. Here's an example:
7041 var el = Roo.get("my-div");
7046 // default animation
7047 el.setWidth(100, true);
7049 // animation with some options set
7056 // using the "anim" property to get the Anim object
7062 el.setWidth(100, opt);
7064 if(opt.anim.isAnimated()){
7068 * <b> Composite (Collections of) Elements</b><br />
7069 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7070 * @constructor Create a new Element directly.
7071 * @param {String/HTMLElement} element
7072 * @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).
7074 Roo.Element = function(element, forceNew){
7075 var dom = typeof element == "string" ?
7076 document.getElementById(element) : element;
7077 if(!dom){ // invalid id/element
7081 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7082 return Roo.Element.cache[id];
7092 * The DOM element ID
7095 this.id = id || Roo.id(dom);
7098 var El = Roo.Element;
7102 * The element's default display mode (defaults to "")
7105 originalDisplay : "",
7109 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7115 * Sets the element's visibility mode. When setVisible() is called it
7116 * will use this to determine whether to set the visibility or the display property.
7117 * @param visMode Element.VISIBILITY or Element.DISPLAY
7118 * @return {Roo.Element} this
7120 setVisibilityMode : function(visMode){
7121 this.visibilityMode = visMode;
7125 * Convenience method for setVisibilityMode(Element.DISPLAY)
7126 * @param {String} display (optional) What to set display to when visible
7127 * @return {Roo.Element} this
7129 enableDisplayMode : function(display){
7130 this.setVisibilityMode(El.DISPLAY);
7131 if(typeof display != "undefined") { this.originalDisplay = display; }
7136 * 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)
7137 * @param {String} selector The simple selector to test
7138 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7139 search as a number or element (defaults to 10 || document.body)
7140 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7141 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7143 findParent : function(simpleSelector, maxDepth, returnEl){
7144 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7145 maxDepth = maxDepth || 50;
7146 if(typeof maxDepth != "number"){
7147 stopEl = Roo.getDom(maxDepth);
7150 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7151 if(dq.is(p, simpleSelector)){
7152 return returnEl ? Roo.get(p) : p;
7162 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7163 * @param {String} selector The simple selector to test
7164 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7165 search as a number or element (defaults to 10 || document.body)
7166 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7167 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7169 findParentNode : function(simpleSelector, maxDepth, returnEl){
7170 var p = Roo.fly(this.dom.parentNode, '_internal');
7171 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7175 * Looks at the scrollable parent element
7177 findScrollableParent : function()
7179 var overflowRegex = /(auto|scroll)/;
7181 if(this.getStyle('position') === 'fixed'){
7182 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7185 var excludeStaticParent = this.getStyle('position') === "absolute";
7187 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7189 if (excludeStaticParent && parent.getStyle('position') === "static") {
7193 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7197 if(parent.dom.nodeName.toLowerCase() == 'body'){
7198 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7202 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7206 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7207 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7208 * @param {String} selector The simple selector to test
7209 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7210 search as a number or element (defaults to 10 || document.body)
7211 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7213 up : function(simpleSelector, maxDepth){
7214 return this.findParentNode(simpleSelector, maxDepth, true);
7220 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7221 * @param {String} selector The simple selector to test
7222 * @return {Boolean} True if this element matches the selector, else false
7224 is : function(simpleSelector){
7225 return Roo.DomQuery.is(this.dom, simpleSelector);
7229 * Perform animation on this element.
7230 * @param {Object} args The YUI animation control args
7231 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7232 * @param {Function} onComplete (optional) Function to call when animation completes
7233 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7234 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7235 * @return {Roo.Element} this
7237 animate : function(args, duration, onComplete, easing, animType){
7238 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7243 * @private Internal animation call
7245 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7246 animType = animType || 'run';
7248 var anim = Roo.lib.Anim[animType](
7250 (opt.duration || defaultDur) || .35,
7251 (opt.easing || defaultEase) || 'easeOut',
7253 Roo.callback(cb, this);
7254 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7262 // private legacy anim prep
7263 preanim : function(a, i){
7264 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7268 * Removes worthless text nodes
7269 * @param {Boolean} forceReclean (optional) By default the element
7270 * keeps track if it has been cleaned already so
7271 * you can call this over and over. However, if you update the element and
7272 * need to force a reclean, you can pass true.
7274 clean : function(forceReclean){
7275 if(this.isCleaned && forceReclean !== true){
7279 var d = this.dom, n = d.firstChild, ni = -1;
7281 var nx = n.nextSibling;
7282 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7289 this.isCleaned = true;
7294 calcOffsetsTo : function(el){
7297 var restorePos = false;
7298 if(el.getStyle('position') == 'static'){
7299 el.position('relative');
7304 while(op && op != d && op.tagName != 'HTML'){
7307 op = op.offsetParent;
7310 el.position('static');
7316 * Scrolls this element into view within the passed container.
7317 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7318 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7319 * @return {Roo.Element} this
7321 scrollIntoView : function(container, hscroll){
7322 var c = Roo.getDom(container) || document.body;
7325 var o = this.calcOffsetsTo(c),
7328 b = t+el.offsetHeight,
7329 r = l+el.offsetWidth;
7331 var ch = c.clientHeight;
7332 var ct = parseInt(c.scrollTop, 10);
7333 var cl = parseInt(c.scrollLeft, 10);
7335 var cr = cl + c.clientWidth;
7343 if(hscroll !== false){
7347 c.scrollLeft = r-c.clientWidth;
7354 scrollChildIntoView : function(child, hscroll){
7355 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7359 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7360 * the new height may not be available immediately.
7361 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7362 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7363 * @param {Function} onComplete (optional) Function to call when animation completes
7364 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7365 * @return {Roo.Element} this
7367 autoHeight : function(animate, duration, onComplete, easing){
7368 var oldHeight = this.getHeight();
7370 this.setHeight(1); // force clipping
7371 setTimeout(function(){
7372 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7374 this.setHeight(height);
7376 if(typeof onComplete == "function"){
7380 this.setHeight(oldHeight); // restore original height
7381 this.setHeight(height, animate, duration, function(){
7383 if(typeof onComplete == "function") { onComplete(); }
7384 }.createDelegate(this), easing);
7386 }.createDelegate(this), 0);
7391 * Returns true if this element is an ancestor of the passed element
7392 * @param {HTMLElement/String} el The element to check
7393 * @return {Boolean} True if this element is an ancestor of el, else false
7395 contains : function(el){
7396 if(!el){return false;}
7397 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7401 * Checks whether the element is currently visible using both visibility and display properties.
7402 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7403 * @return {Boolean} True if the element is currently visible, else false
7405 isVisible : function(deep) {
7406 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7407 if(deep !== true || !vis){
7410 var p = this.dom.parentNode;
7411 while(p && p.tagName.toLowerCase() != "body"){
7412 if(!Roo.fly(p, '_isVisible').isVisible()){
7421 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7422 * @param {String} selector The CSS selector
7423 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7424 * @return {CompositeElement/CompositeElementLite} The composite element
7426 select : function(selector, unique){
7427 return El.select(selector, unique, this.dom);
7431 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7432 * @param {String} selector The CSS selector
7433 * @return {Array} An array of the matched nodes
7435 query : function(selector, unique){
7436 return Roo.DomQuery.select(selector, this.dom);
7440 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7441 * @param {String} selector The CSS selector
7442 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7443 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7445 child : function(selector, returnDom){
7446 var n = Roo.DomQuery.selectNode(selector, this.dom);
7447 return returnDom ? n : Roo.get(n);
7451 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7452 * @param {String} selector The CSS selector
7453 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7454 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7456 down : function(selector, returnDom){
7457 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7458 return returnDom ? n : Roo.get(n);
7462 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7463 * @param {String} group The group the DD object is member of
7464 * @param {Object} config The DD config object
7465 * @param {Object} overrides An object containing methods to override/implement on the DD object
7466 * @return {Roo.dd.DD} The DD object
7468 initDD : function(group, config, overrides){
7469 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7470 return Roo.apply(dd, overrides);
7474 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7475 * @param {String} group The group the DDProxy object is member of
7476 * @param {Object} config The DDProxy config object
7477 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7478 * @return {Roo.dd.DDProxy} The DDProxy object
7480 initDDProxy : function(group, config, overrides){
7481 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7482 return Roo.apply(dd, overrides);
7486 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7487 * @param {String} group The group the DDTarget object is member of
7488 * @param {Object} config The DDTarget config object
7489 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7490 * @return {Roo.dd.DDTarget} The DDTarget object
7492 initDDTarget : function(group, config, overrides){
7493 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7494 return Roo.apply(dd, overrides);
7498 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7499 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7500 * @param {Boolean} visible Whether the element is visible
7501 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7502 * @return {Roo.Element} this
7504 setVisible : function(visible, animate){
7506 if(this.visibilityMode == El.DISPLAY){
7507 this.setDisplayed(visible);
7510 this.dom.style.visibility = visible ? "visible" : "hidden";
7513 // closure for composites
7515 var visMode = this.visibilityMode;
7517 this.setOpacity(.01);
7518 this.setVisible(true);
7520 this.anim({opacity: { to: (visible?1:0) }},
7521 this.preanim(arguments, 1),
7522 null, .35, 'easeIn', function(){
7524 if(visMode == El.DISPLAY){
7525 dom.style.display = "none";
7527 dom.style.visibility = "hidden";
7529 Roo.get(dom).setOpacity(1);
7537 * Returns true if display is not "none"
7540 isDisplayed : function() {
7541 return this.getStyle("display") != "none";
7545 * Toggles the element's visibility or display, depending on visibility mode.
7546 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7547 * @return {Roo.Element} this
7549 toggle : function(animate){
7550 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7555 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7556 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7557 * @return {Roo.Element} this
7559 setDisplayed : function(value) {
7560 if(typeof value == "boolean"){
7561 value = value ? this.originalDisplay : "none";
7563 this.setStyle("display", value);
7568 * Tries to focus the element. Any exceptions are caught and ignored.
7569 * @return {Roo.Element} this
7571 focus : function() {
7579 * Tries to blur the element. Any exceptions are caught and ignored.
7580 * @return {Roo.Element} this
7590 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7591 * @param {String/Array} className The CSS class to add, or an array of classes
7592 * @return {Roo.Element} this
7594 addClass : function(className){
7595 if(className instanceof Array){
7596 for(var i = 0, len = className.length; i < len; i++) {
7597 this.addClass(className[i]);
7600 if(className && !this.hasClass(className)){
7601 this.dom.className = this.dom.className + " " + className;
7608 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7609 * @param {String/Array} className The CSS class to add, or an array of classes
7610 * @return {Roo.Element} this
7612 radioClass : function(className){
7613 var siblings = this.dom.parentNode.childNodes;
7614 for(var i = 0; i < siblings.length; i++) {
7615 var s = siblings[i];
7616 if(s.nodeType == 1){
7617 Roo.get(s).removeClass(className);
7620 this.addClass(className);
7625 * Removes one or more CSS classes from the element.
7626 * @param {String/Array} className The CSS class to remove, or an array of classes
7627 * @return {Roo.Element} this
7629 removeClass : function(className){
7630 if(!className || !this.dom.className){
7633 if(className instanceof Array){
7634 for(var i = 0, len = className.length; i < len; i++) {
7635 this.removeClass(className[i]);
7638 if(this.hasClass(className)){
7639 var re = this.classReCache[className];
7641 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7642 this.classReCache[className] = re;
7644 this.dom.className =
7645 this.dom.className.replace(re, " ");
7655 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7656 * @param {String} className The CSS class to toggle
7657 * @return {Roo.Element} this
7659 toggleClass : function(className){
7660 if(this.hasClass(className)){
7661 this.removeClass(className);
7663 this.addClass(className);
7669 * Checks if the specified CSS class exists on this element's DOM node.
7670 * @param {String} className The CSS class to check for
7671 * @return {Boolean} True if the class exists, else false
7673 hasClass : function(className){
7674 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7678 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7679 * @param {String} oldClassName The CSS class to replace
7680 * @param {String} newClassName The replacement CSS class
7681 * @return {Roo.Element} this
7683 replaceClass : function(oldClassName, newClassName){
7684 this.removeClass(oldClassName);
7685 this.addClass(newClassName);
7690 * Returns an object with properties matching the styles requested.
7691 * For example, el.getStyles('color', 'font-size', 'width') might return
7692 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7693 * @param {String} style1 A style name
7694 * @param {String} style2 A style name
7695 * @param {String} etc.
7696 * @return {Object} The style object
7698 getStyles : function(){
7699 var a = arguments, len = a.length, r = {};
7700 for(var i = 0; i < len; i++){
7701 r[a[i]] = this.getStyle(a[i]);
7707 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7708 * @param {String} property The style property whose value is returned.
7709 * @return {String} The current value of the style property for this element.
7711 getStyle : function(){
7712 return view && view.getComputedStyle ?
7714 var el = this.dom, v, cs, camel;
7715 if(prop == 'float'){
7718 if(el.style && (v = el.style[prop])){
7721 if(cs = view.getComputedStyle(el, "")){
7722 if(!(camel = propCache[prop])){
7723 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7730 var el = this.dom, v, cs, camel;
7731 if(prop == 'opacity'){
7732 if(typeof el.style.filter == 'string'){
7733 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7735 var fv = parseFloat(m[1]);
7737 return fv ? fv / 100 : 0;
7742 }else if(prop == 'float'){
7743 prop = "styleFloat";
7745 if(!(camel = propCache[prop])){
7746 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7748 if(v = el.style[camel]){
7751 if(cs = el.currentStyle){
7759 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7760 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7761 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7762 * @return {Roo.Element} this
7764 setStyle : function(prop, value){
7765 if(typeof prop == "string"){
7767 if (prop == 'float') {
7768 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7773 if(!(camel = propCache[prop])){
7774 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7777 if(camel == 'opacity') {
7778 this.setOpacity(value);
7780 this.dom.style[camel] = value;
7783 for(var style in prop){
7784 if(typeof prop[style] != "function"){
7785 this.setStyle(style, prop[style]);
7793 * More flexible version of {@link #setStyle} for setting style properties.
7794 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7795 * a function which returns such a specification.
7796 * @return {Roo.Element} this
7798 applyStyles : function(style){
7799 Roo.DomHelper.applyStyles(this.dom, style);
7804 * 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).
7805 * @return {Number} The X position of the element
7808 return D.getX(this.dom);
7812 * 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).
7813 * @return {Number} The Y position of the element
7816 return D.getY(this.dom);
7820 * 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).
7821 * @return {Array} The XY position of the element
7824 return D.getXY(this.dom);
7828 * 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).
7829 * @param {Number} The X position of the element
7830 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7831 * @return {Roo.Element} this
7833 setX : function(x, animate){
7835 D.setX(this.dom, x);
7837 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7843 * 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).
7844 * @param {Number} The Y position of the element
7845 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7846 * @return {Roo.Element} this
7848 setY : function(y, animate){
7850 D.setY(this.dom, y);
7852 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7858 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7859 * @param {String} left The left CSS property value
7860 * @return {Roo.Element} this
7862 setLeft : function(left){
7863 this.setStyle("left", this.addUnits(left));
7868 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7869 * @param {String} top The top CSS property value
7870 * @return {Roo.Element} this
7872 setTop : function(top){
7873 this.setStyle("top", this.addUnits(top));
7878 * Sets the element's CSS right style.
7879 * @param {String} right The right CSS property value
7880 * @return {Roo.Element} this
7882 setRight : function(right){
7883 this.setStyle("right", this.addUnits(right));
7888 * Sets the element's CSS bottom style.
7889 * @param {String} bottom The bottom CSS property value
7890 * @return {Roo.Element} this
7892 setBottom : function(bottom){
7893 this.setStyle("bottom", this.addUnits(bottom));
7898 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7899 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7900 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7901 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7902 * @return {Roo.Element} this
7904 setXY : function(pos, animate){
7906 D.setXY(this.dom, pos);
7908 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7914 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7915 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7916 * @param {Number} x X value for new position (coordinates are page-based)
7917 * @param {Number} y Y value for new position (coordinates are page-based)
7918 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7919 * @return {Roo.Element} this
7921 setLocation : function(x, y, animate){
7922 this.setXY([x, y], this.preanim(arguments, 2));
7927 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7928 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7929 * @param {Number} x X value for new position (coordinates are page-based)
7930 * @param {Number} y Y value for new position (coordinates are page-based)
7931 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7932 * @return {Roo.Element} this
7934 moveTo : function(x, y, animate){
7935 this.setXY([x, y], this.preanim(arguments, 2));
7940 * Returns the region of the given element.
7941 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7942 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7944 getRegion : function(){
7945 return D.getRegion(this.dom);
7949 * Returns the offset height of the element
7950 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7951 * @return {Number} The element's height
7953 getHeight : function(contentHeight){
7954 var h = this.dom.offsetHeight || 0;
7955 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7959 * Returns the offset width of the element
7960 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7961 * @return {Number} The element's width
7963 getWidth : function(contentWidth){
7964 var w = this.dom.offsetWidth || 0;
7965 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7969 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7970 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7971 * if a height has not been set using CSS.
7974 getComputedHeight : function(){
7975 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7977 h = parseInt(this.getStyle('height'), 10) || 0;
7978 if(!this.isBorderBox()){
7979 h += this.getFrameWidth('tb');
7986 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7987 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7988 * if a width has not been set using CSS.
7991 getComputedWidth : function(){
7992 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7994 w = parseInt(this.getStyle('width'), 10) || 0;
7995 if(!this.isBorderBox()){
7996 w += this.getFrameWidth('lr');
8003 * Returns the size of the element.
8004 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8005 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8007 getSize : function(contentSize){
8008 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8012 * Returns the width and height of the viewport.
8013 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8015 getViewSize : function(){
8016 var d = this.dom, doc = document, aw = 0, ah = 0;
8017 if(d == doc || d == doc.body){
8018 return {width : D.getViewWidth(), height: D.getViewHeight()};
8021 width : d.clientWidth,
8022 height: d.clientHeight
8028 * Returns the value of the "value" attribute
8029 * @param {Boolean} asNumber true to parse the value as a number
8030 * @return {String/Number}
8032 getValue : function(asNumber){
8033 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8037 adjustWidth : function(width){
8038 if(typeof width == "number"){
8039 if(this.autoBoxAdjust && !this.isBorderBox()){
8040 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8050 adjustHeight : function(height){
8051 if(typeof height == "number"){
8052 if(this.autoBoxAdjust && !this.isBorderBox()){
8053 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8063 * Set the width of the element
8064 * @param {Number} width The new width
8065 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8066 * @return {Roo.Element} this
8068 setWidth : function(width, animate){
8069 width = this.adjustWidth(width);
8071 this.dom.style.width = this.addUnits(width);
8073 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8079 * Set the height of the element
8080 * @param {Number} height The new height
8081 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8082 * @return {Roo.Element} this
8084 setHeight : function(height, animate){
8085 height = this.adjustHeight(height);
8087 this.dom.style.height = this.addUnits(height);
8089 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8095 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8096 * @param {Number} width The new width
8097 * @param {Number} height The new height
8098 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8099 * @return {Roo.Element} this
8101 setSize : function(width, height, animate){
8102 if(typeof width == "object"){ // in case of object from getSize()
8103 height = width.height; width = width.width;
8105 width = this.adjustWidth(width); height = this.adjustHeight(height);
8107 this.dom.style.width = this.addUnits(width);
8108 this.dom.style.height = this.addUnits(height);
8110 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8116 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8117 * @param {Number} x X value for new position (coordinates are page-based)
8118 * @param {Number} y Y value for new position (coordinates are page-based)
8119 * @param {Number} width The new width
8120 * @param {Number} height The new height
8121 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8122 * @return {Roo.Element} this
8124 setBounds : function(x, y, width, height, animate){
8126 this.setSize(width, height);
8127 this.setLocation(x, y);
8129 width = this.adjustWidth(width); height = this.adjustHeight(height);
8130 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8131 this.preanim(arguments, 4), 'motion');
8137 * 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.
8138 * @param {Roo.lib.Region} region The region to fill
8139 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8140 * @return {Roo.Element} this
8142 setRegion : function(region, animate){
8143 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8148 * Appends an event handler
8150 * @param {String} eventName The type of event to append
8151 * @param {Function} fn The method the event invokes
8152 * @param {Object} scope (optional) The scope (this object) of the fn
8153 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8155 addListener : function(eventName, fn, scope, options){
8157 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8162 * Removes an event handler from this element
8163 * @param {String} eventName the type of event to remove
8164 * @param {Function} fn the method the event invokes
8165 * @return {Roo.Element} this
8167 removeListener : function(eventName, fn){
8168 Roo.EventManager.removeListener(this.dom, eventName, fn);
8173 * Removes all previous added listeners from this element
8174 * @return {Roo.Element} this
8176 removeAllListeners : function(){
8177 E.purgeElement(this.dom);
8181 relayEvent : function(eventName, observable){
8182 this.on(eventName, function(e){
8183 observable.fireEvent(eventName, e);
8188 * Set the opacity of the element
8189 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8190 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8191 * @return {Roo.Element} this
8193 setOpacity : function(opacity, animate){
8195 var s = this.dom.style;
8198 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8199 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8201 s.opacity = opacity;
8204 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8210 * Gets the left X coordinate
8211 * @param {Boolean} local True to get the local css position instead of page coordinate
8214 getLeft : function(local){
8218 return parseInt(this.getStyle("left"), 10) || 0;
8223 * Gets the right X coordinate of the element (element X position + element width)
8224 * @param {Boolean} local True to get the local css position instead of page coordinate
8227 getRight : function(local){
8229 return this.getX() + this.getWidth();
8231 return (this.getLeft(true) + this.getWidth()) || 0;
8236 * Gets the top Y coordinate
8237 * @param {Boolean} local True to get the local css position instead of page coordinate
8240 getTop : function(local) {
8244 return parseInt(this.getStyle("top"), 10) || 0;
8249 * Gets the bottom Y coordinate of the element (element Y position + element height)
8250 * @param {Boolean} local True to get the local css position instead of page coordinate
8253 getBottom : function(local){
8255 return this.getY() + this.getHeight();
8257 return (this.getTop(true) + this.getHeight()) || 0;
8262 * Initializes positioning on this element. If a desired position is not passed, it will make the
8263 * the element positioned relative IF it is not already positioned.
8264 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8265 * @param {Number} zIndex (optional) The zIndex to apply
8266 * @param {Number} x (optional) Set the page X position
8267 * @param {Number} y (optional) Set the page Y position
8269 position : function(pos, zIndex, x, y){
8271 if(this.getStyle('position') == 'static'){
8272 this.setStyle('position', 'relative');
8275 this.setStyle("position", pos);
8278 this.setStyle("z-index", zIndex);
8280 if(x !== undefined && y !== undefined){
8282 }else if(x !== undefined){
8284 }else if(y !== undefined){
8290 * Clear positioning back to the default when the document was loaded
8291 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8292 * @return {Roo.Element} this
8294 clearPositioning : function(value){
8302 "position" : "static"
8308 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8309 * snapshot before performing an update and then restoring the element.
8312 getPositioning : function(){
8313 var l = this.getStyle("left");
8314 var t = this.getStyle("top");
8316 "position" : this.getStyle("position"),
8318 "right" : l ? "" : this.getStyle("right"),
8320 "bottom" : t ? "" : this.getStyle("bottom"),
8321 "z-index" : this.getStyle("z-index")
8326 * Gets the width of the border(s) for the specified side(s)
8327 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8328 * passing lr would get the border (l)eft width + the border (r)ight width.
8329 * @return {Number} The width of the sides passed added together
8331 getBorderWidth : function(side){
8332 return this.addStyles(side, El.borders);
8336 * Gets the width of the padding(s) for the specified side(s)
8337 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8338 * passing lr would get the padding (l)eft + the padding (r)ight.
8339 * @return {Number} The padding of the sides passed added together
8341 getPadding : function(side){
8342 return this.addStyles(side, El.paddings);
8346 * Set positioning with an object returned by getPositioning().
8347 * @param {Object} posCfg
8348 * @return {Roo.Element} this
8350 setPositioning : function(pc){
8351 this.applyStyles(pc);
8352 if(pc.right == "auto"){
8353 this.dom.style.right = "";
8355 if(pc.bottom == "auto"){
8356 this.dom.style.bottom = "";
8362 fixDisplay : function(){
8363 if(this.getStyle("display") == "none"){
8364 this.setStyle("visibility", "hidden");
8365 this.setStyle("display", this.originalDisplay); // first try reverting to default
8366 if(this.getStyle("display") == "none"){ // if that fails, default to block
8367 this.setStyle("display", "block");
8373 * Quick set left and top adding default units
8374 * @param {String} left The left CSS property value
8375 * @param {String} top The top CSS property value
8376 * @return {Roo.Element} this
8378 setLeftTop : function(left, top){
8379 this.dom.style.left = this.addUnits(left);
8380 this.dom.style.top = this.addUnits(top);
8385 * Move this element relative to its current position.
8386 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8387 * @param {Number} distance How far to move the element in pixels
8388 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8389 * @return {Roo.Element} this
8391 move : function(direction, distance, animate){
8392 var xy = this.getXY();
8393 direction = direction.toLowerCase();
8397 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8401 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8406 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8411 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8418 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8419 * @return {Roo.Element} this
8422 if(!this.isClipped){
8423 this.isClipped = true;
8424 this.originalClip = {
8425 "o": this.getStyle("overflow"),
8426 "x": this.getStyle("overflow-x"),
8427 "y": this.getStyle("overflow-y")
8429 this.setStyle("overflow", "hidden");
8430 this.setStyle("overflow-x", "hidden");
8431 this.setStyle("overflow-y", "hidden");
8437 * Return clipping (overflow) to original clipping before clip() was called
8438 * @return {Roo.Element} this
8440 unclip : function(){
8442 this.isClipped = false;
8443 var o = this.originalClip;
8444 if(o.o){this.setStyle("overflow", o.o);}
8445 if(o.x){this.setStyle("overflow-x", o.x);}
8446 if(o.y){this.setStyle("overflow-y", o.y);}
8453 * Gets the x,y coordinates specified by the anchor position on the element.
8454 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8455 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8456 * {width: (target width), height: (target height)} (defaults to the element's current size)
8457 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8458 * @return {Array} [x, y] An array containing the element's x and y coordinates
8460 getAnchorXY : function(anchor, local, s){
8461 //Passing a different size is useful for pre-calculating anchors,
8462 //especially for anchored animations that change the el size.
8464 var w, h, vp = false;
8467 if(d == document.body || d == document){
8469 w = D.getViewWidth(); h = D.getViewHeight();
8471 w = this.getWidth(); h = this.getHeight();
8474 w = s.width; h = s.height;
8476 var x = 0, y = 0, r = Math.round;
8477 switch((anchor || "tl").toLowerCase()){
8519 var sc = this.getScroll();
8520 return [x + sc.left, y + sc.top];
8522 //Add the element's offset xy
8523 var o = this.getXY();
8524 return [x+o[0], y+o[1]];
8528 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8529 * supported position values.
8530 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8531 * @param {String} position The position to align to.
8532 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8533 * @return {Array} [x, y]
8535 getAlignToXY : function(el, p, o){
8539 throw "Element.alignTo with an element that doesn't exist";
8541 var c = false; //constrain to viewport
8542 var p1 = "", p2 = "";
8549 }else if(p.indexOf("-") == -1){
8552 p = p.toLowerCase();
8553 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8555 throw "Element.alignTo with an invalid alignment " + p;
8557 p1 = m[1]; p2 = m[2]; c = !!m[3];
8559 //Subtract the aligned el's internal xy from the target's offset xy
8560 //plus custom offset to get the aligned el's new offset xy
8561 var a1 = this.getAnchorXY(p1, true);
8562 var a2 = el.getAnchorXY(p2, false);
8563 var x = a2[0] - a1[0] + o[0];
8564 var y = a2[1] - a1[1] + o[1];
8566 //constrain the aligned el to viewport if necessary
8567 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8568 // 5px of margin for ie
8569 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8571 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8572 //perpendicular to the vp border, allow the aligned el to slide on that border,
8573 //otherwise swap the aligned el to the opposite border of the target.
8574 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8575 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8576 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8577 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8580 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8581 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8583 if((x+w) > dw + scrollX){
8584 x = swapX ? r.left-w : dw+scrollX-w;
8587 x = swapX ? r.right : scrollX;
8589 if((y+h) > dh + scrollY){
8590 y = swapY ? r.top-h : dh+scrollY-h;
8593 y = swapY ? r.bottom : scrollY;
8600 getConstrainToXY : function(){
8601 var os = {top:0, left:0, bottom:0, right: 0};
8603 return function(el, local, offsets, proposedXY){
8605 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8607 var vw, vh, vx = 0, vy = 0;
8608 if(el.dom == document.body || el.dom == document){
8609 vw = Roo.lib.Dom.getViewWidth();
8610 vh = Roo.lib.Dom.getViewHeight();
8612 vw = el.dom.clientWidth;
8613 vh = el.dom.clientHeight;
8615 var vxy = el.getXY();
8621 var s = el.getScroll();
8623 vx += offsets.left + s.left;
8624 vy += offsets.top + s.top;
8626 vw -= offsets.right;
8627 vh -= offsets.bottom;
8632 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8633 var x = xy[0], y = xy[1];
8634 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8636 // only move it if it needs it
8639 // first validate right/bottom
8648 // then make sure top/left isn't negative
8657 return moved ? [x, y] : false;
8662 adjustForConstraints : function(xy, parent, offsets){
8663 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8667 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8668 * document it aligns it to the viewport.
8669 * The position parameter is optional, and can be specified in any one of the following formats:
8671 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8672 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8673 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8674 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8675 * <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
8676 * element's anchor point, and the second value is used as the target's anchor point.</li>
8678 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8679 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8680 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8681 * that specified in order to enforce the viewport constraints.
8682 * Following are all of the supported anchor positions:
8685 ----- -----------------------------
8686 tl The top left corner (default)
8687 t The center of the top edge
8688 tr The top right corner
8689 l The center of the left edge
8690 c In the center of the element
8691 r The center of the right edge
8692 bl The bottom left corner
8693 b The center of the bottom edge
8694 br The bottom right corner
8698 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8699 el.alignTo("other-el");
8701 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8702 el.alignTo("other-el", "tr?");
8704 // align the bottom right corner of el with the center left edge of other-el
8705 el.alignTo("other-el", "br-l?");
8707 // align the center of el with the bottom left corner of other-el and
8708 // adjust the x position by -6 pixels (and the y position by 0)
8709 el.alignTo("other-el", "c-bl", [-6, 0]);
8711 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8712 * @param {String} position The position to align to.
8713 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8714 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8715 * @return {Roo.Element} this
8717 alignTo : function(element, position, offsets, animate){
8718 var xy = this.getAlignToXY(element, position, offsets);
8719 this.setXY(xy, this.preanim(arguments, 3));
8724 * Anchors an element to another element and realigns it when the window is resized.
8725 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8726 * @param {String} position The position to align to.
8727 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8728 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8729 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8730 * is a number, it is used as the buffer delay (defaults to 50ms).
8731 * @param {Function} callback The function to call after the animation finishes
8732 * @return {Roo.Element} this
8734 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8735 var action = function(){
8736 this.alignTo(el, alignment, offsets, animate);
8737 Roo.callback(callback, this);
8739 Roo.EventManager.onWindowResize(action, this);
8740 var tm = typeof monitorScroll;
8741 if(tm != 'undefined'){
8742 Roo.EventManager.on(window, 'scroll', action, this,
8743 {buffer: tm == 'number' ? monitorScroll : 50});
8745 action.call(this); // align immediately
8749 * Clears any opacity settings from this element. Required in some cases for IE.
8750 * @return {Roo.Element} this
8752 clearOpacity : function(){
8753 if (window.ActiveXObject) {
8754 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8755 this.dom.style.filter = "";
8758 this.dom.style.opacity = "";
8759 this.dom.style["-moz-opacity"] = "";
8760 this.dom.style["-khtml-opacity"] = "";
8766 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8767 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8768 * @return {Roo.Element} this
8770 hide : function(animate){
8771 this.setVisible(false, this.preanim(arguments, 0));
8776 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8777 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8778 * @return {Roo.Element} this
8780 show : function(animate){
8781 this.setVisible(true, this.preanim(arguments, 0));
8786 * @private Test if size has a unit, otherwise appends the default
8788 addUnits : function(size){
8789 return Roo.Element.addUnits(size, this.defaultUnit);
8793 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8794 * @return {Roo.Element} this
8796 beginMeasure : function(){
8798 if(el.offsetWidth || el.offsetHeight){
8799 return this; // offsets work already
8802 var p = this.dom, b = document.body; // start with this element
8803 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8804 var pe = Roo.get(p);
8805 if(pe.getStyle('display') == 'none'){
8806 changed.push({el: p, visibility: pe.getStyle("visibility")});
8807 p.style.visibility = "hidden";
8808 p.style.display = "block";
8812 this._measureChanged = changed;
8818 * Restores displays to before beginMeasure was called
8819 * @return {Roo.Element} this
8821 endMeasure : function(){
8822 var changed = this._measureChanged;
8824 for(var i = 0, len = changed.length; i < len; i++) {
8826 r.el.style.visibility = r.visibility;
8827 r.el.style.display = "none";
8829 this._measureChanged = null;
8835 * Update the innerHTML of this element, optionally searching for and processing scripts
8836 * @param {String} html The new HTML
8837 * @param {Boolean} loadScripts (optional) true to look for and process scripts
8838 * @param {Function} callback For async script loading you can be noticed when the update completes
8839 * @return {Roo.Element} this
8841 update : function(html, loadScripts, callback){
8842 if(typeof html == "undefined"){
8845 if(loadScripts !== true){
8846 this.dom.innerHTML = html;
8847 if(typeof callback == "function"){
8855 html += '<span id="' + id + '"></span>';
8857 E.onAvailable(id, function(){
8858 var hd = document.getElementsByTagName("head")[0];
8859 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8860 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8861 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8864 while(match = re.exec(html)){
8865 var attrs = match[1];
8866 var srcMatch = attrs ? attrs.match(srcRe) : false;
8867 if(srcMatch && srcMatch[2]){
8868 var s = document.createElement("script");
8869 s.src = srcMatch[2];
8870 var typeMatch = attrs.match(typeRe);
8871 if(typeMatch && typeMatch[2]){
8872 s.type = typeMatch[2];
8875 }else if(match[2] && match[2].length > 0){
8876 if(window.execScript) {
8877 window.execScript(match[2]);
8885 window.eval(match[2]);
8889 var el = document.getElementById(id);
8890 if(el){el.parentNode.removeChild(el);}
8891 if(typeof callback == "function"){
8895 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8900 * Direct access to the UpdateManager update() method (takes the same parameters).
8901 * @param {String/Function} url The url for this request or a function to call to get the url
8902 * @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}
8903 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8904 * @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.
8905 * @return {Roo.Element} this
8908 var um = this.getUpdateManager();
8909 um.update.apply(um, arguments);
8914 * Gets this element's UpdateManager
8915 * @return {Roo.UpdateManager} The UpdateManager
8917 getUpdateManager : function(){
8918 if(!this.updateManager){
8919 this.updateManager = new Roo.UpdateManager(this);
8921 return this.updateManager;
8925 * Disables text selection for this element (normalized across browsers)
8926 * @return {Roo.Element} this
8928 unselectable : function(){
8929 this.dom.unselectable = "on";
8930 this.swallowEvent("selectstart", true);
8931 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8932 this.addClass("x-unselectable");
8937 * Calculates the x, y to center this element on the screen
8938 * @return {Array} The x, y values [x, y]
8940 getCenterXY : function(){
8941 return this.getAlignToXY(document, 'c-c');
8945 * Centers the Element in either the viewport, or another Element.
8946 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8948 center : function(centerIn){
8949 this.alignTo(centerIn || document, 'c-c');
8954 * Tests various css rules/browsers to determine if this element uses a border box
8957 isBorderBox : function(){
8958 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8962 * Return a box {x, y, width, height} that can be used to set another elements
8963 * size/location to match this element.
8964 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8965 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8966 * @return {Object} box An object in the format {x, y, width, height}
8968 getBox : function(contentBox, local){
8973 var left = parseInt(this.getStyle("left"), 10) || 0;
8974 var top = parseInt(this.getStyle("top"), 10) || 0;
8977 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8979 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8981 var l = this.getBorderWidth("l")+this.getPadding("l");
8982 var r = this.getBorderWidth("r")+this.getPadding("r");
8983 var t = this.getBorderWidth("t")+this.getPadding("t");
8984 var b = this.getBorderWidth("b")+this.getPadding("b");
8985 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)};
8987 bx.right = bx.x + bx.width;
8988 bx.bottom = bx.y + bx.height;
8993 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8994 for more information about the sides.
8995 * @param {String} sides
8998 getFrameWidth : function(sides, onlyContentBox){
8999 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9003 * 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.
9004 * @param {Object} box The box to fill {x, y, width, height}
9005 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9006 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9007 * @return {Roo.Element} this
9009 setBox : function(box, adjust, animate){
9010 var w = box.width, h = box.height;
9011 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9012 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9013 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9015 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9020 * Forces the browser to repaint this element
9021 * @return {Roo.Element} this
9023 repaint : function(){
9025 this.addClass("x-repaint");
9026 setTimeout(function(){
9027 Roo.get(dom).removeClass("x-repaint");
9033 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9034 * then it returns the calculated width of the sides (see getPadding)
9035 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9036 * @return {Object/Number}
9038 getMargins : function(side){
9041 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9042 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9043 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9044 right: parseInt(this.getStyle("margin-right"), 10) || 0
9047 return this.addStyles(side, El.margins);
9052 addStyles : function(sides, styles){
9054 for(var i = 0, len = sides.length; i < len; i++){
9055 v = this.getStyle(styles[sides.charAt(i)]);
9057 w = parseInt(v, 10);
9065 * Creates a proxy element of this element
9066 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9067 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9068 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9069 * @return {Roo.Element} The new proxy element
9071 createProxy : function(config, renderTo, matchBox){
9073 renderTo = Roo.getDom(renderTo);
9075 renderTo = document.body;
9077 config = typeof config == "object" ?
9078 config : {tag : "div", cls: config};
9079 var proxy = Roo.DomHelper.append(renderTo, config, true);
9081 proxy.setBox(this.getBox());
9087 * Puts a mask over this element to disable user interaction. Requires core.css.
9088 * This method can only be applied to elements which accept child nodes.
9089 * @param {String} msg (optional) A message to display in the mask
9090 * @param {String} msgCls (optional) A css class to apply to the msg element
9091 * @return {Element} The mask element
9093 mask : function(msg, msgCls)
9095 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9096 this.setStyle("position", "relative");
9099 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9101 this.addClass("x-masked");
9102 this._mask.setDisplayed(true);
9107 while (dom && dom.style) {
9108 if (!isNaN(parseInt(dom.style.zIndex))) {
9109 z = Math.max(z, parseInt(dom.style.zIndex));
9111 dom = dom.parentNode;
9113 // if we are masking the body - then it hides everything..
9114 if (this.dom == document.body) {
9116 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9117 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9120 if(typeof msg == 'string'){
9122 this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9124 var mm = this._maskMsg;
9125 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9126 if (mm.dom.firstChild) { // weird IE issue?
9127 mm.dom.firstChild.innerHTML = msg;
9129 mm.setDisplayed(true);
9131 mm.setStyle('z-index', z + 102);
9133 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9134 this._mask.setHeight(this.getHeight());
9136 this._mask.setStyle('z-index', z + 100);
9142 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9143 * it is cached for reuse.
9145 unmask : function(removeEl){
9147 if(removeEl === true){
9148 this._mask.remove();
9151 this._maskMsg.remove();
9152 delete this._maskMsg;
9155 this._mask.setDisplayed(false);
9157 this._maskMsg.setDisplayed(false);
9161 this.removeClass("x-masked");
9165 * Returns true if this element is masked
9168 isMasked : function(){
9169 return this._mask && this._mask.isVisible();
9173 * Creates an iframe shim for this element to keep selects and other windowed objects from
9175 * @return {Roo.Element} The new shim element
9177 createShim : function(){
9178 var el = document.createElement('iframe');
9179 el.frameBorder = 'no';
9180 el.className = 'roo-shim';
9181 if(Roo.isIE && Roo.isSecure){
9182 el.src = Roo.SSL_SECURE_URL;
9184 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9185 shim.autoBoxAdjust = false;
9190 * Removes this element from the DOM and deletes it from the cache
9192 remove : function(){
9193 if(this.dom.parentNode){
9194 this.dom.parentNode.removeChild(this.dom);
9196 delete El.cache[this.dom.id];
9200 * Sets up event handlers to add and remove a css class when the mouse is over this element
9201 * @param {String} className
9202 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9203 * mouseout events for children elements
9204 * @return {Roo.Element} this
9206 addClassOnOver : function(className, preventFlicker){
9207 this.on("mouseover", function(){
9208 Roo.fly(this, '_internal').addClass(className);
9210 var removeFn = function(e){
9211 if(preventFlicker !== true || !e.within(this, true)){
9212 Roo.fly(this, '_internal').removeClass(className);
9215 this.on("mouseout", removeFn, this.dom);
9220 * Sets up event handlers to add and remove a css class when this element has the focus
9221 * @param {String} className
9222 * @return {Roo.Element} this
9224 addClassOnFocus : function(className){
9225 this.on("focus", function(){
9226 Roo.fly(this, '_internal').addClass(className);
9228 this.on("blur", function(){
9229 Roo.fly(this, '_internal').removeClass(className);
9234 * 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)
9235 * @param {String} className
9236 * @return {Roo.Element} this
9238 addClassOnClick : function(className){
9240 this.on("mousedown", function(){
9241 Roo.fly(dom, '_internal').addClass(className);
9242 var d = Roo.get(document);
9243 var fn = function(){
9244 Roo.fly(dom, '_internal').removeClass(className);
9245 d.removeListener("mouseup", fn);
9247 d.on("mouseup", fn);
9253 * Stops the specified event from bubbling and optionally prevents the default action
9254 * @param {String} eventName
9255 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9256 * @return {Roo.Element} this
9258 swallowEvent : function(eventName, preventDefault){
9259 var fn = function(e){
9260 e.stopPropagation();
9265 if(eventName instanceof Array){
9266 for(var i = 0, len = eventName.length; i < len; i++){
9267 this.on(eventName[i], fn);
9271 this.on(eventName, fn);
9278 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9281 * Sizes this element to its parent element's dimensions performing
9282 * neccessary box adjustments.
9283 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9284 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9285 * @return {Roo.Element} this
9287 fitToParent : function(monitorResize, targetParent) {
9288 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9289 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9290 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9293 var p = Roo.get(targetParent || this.dom.parentNode);
9294 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9295 if (monitorResize === true) {
9296 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9297 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9303 * Gets the next sibling, skipping text nodes
9304 * @return {HTMLElement} The next sibling or null
9306 getNextSibling : function(){
9307 var n = this.dom.nextSibling;
9308 while(n && n.nodeType != 1){
9315 * Gets the previous sibling, skipping text nodes
9316 * @return {HTMLElement} The previous sibling or null
9318 getPrevSibling : function(){
9319 var n = this.dom.previousSibling;
9320 while(n && n.nodeType != 1){
9321 n = n.previousSibling;
9328 * Appends the passed element(s) to this element
9329 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9330 * @return {Roo.Element} this
9332 appendChild: function(el){
9339 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9340 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9341 * automatically generated with the specified attributes.
9342 * @param {HTMLElement} insertBefore (optional) a child element of this element
9343 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9344 * @return {Roo.Element} The new child element
9346 createChild: function(config, insertBefore, returnDom){
9347 config = config || {tag:'div'};
9349 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9351 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9355 * Appends this element to the passed element
9356 * @param {String/HTMLElement/Element} el The new parent element
9357 * @return {Roo.Element} this
9359 appendTo: function(el){
9360 el = Roo.getDom(el);
9361 el.appendChild(this.dom);
9366 * Inserts this element before the passed element in the DOM
9367 * @param {String/HTMLElement/Element} el The element to insert before
9368 * @return {Roo.Element} this
9370 insertBefore: function(el){
9371 el = Roo.getDom(el);
9372 el.parentNode.insertBefore(this.dom, el);
9377 * Inserts this element after the passed element in the DOM
9378 * @param {String/HTMLElement/Element} el The element to insert after
9379 * @return {Roo.Element} this
9381 insertAfter: function(el){
9382 el = Roo.getDom(el);
9383 el.parentNode.insertBefore(this.dom, el.nextSibling);
9388 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9389 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9390 * @return {Roo.Element} The new child
9392 insertFirst: function(el, returnDom){
9394 if(typeof el == 'object' && !el.nodeType){ // dh config
9395 return this.createChild(el, this.dom.firstChild, returnDom);
9397 el = Roo.getDom(el);
9398 this.dom.insertBefore(el, this.dom.firstChild);
9399 return !returnDom ? Roo.get(el) : el;
9404 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9405 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9406 * @param {String} where (optional) 'before' or 'after' defaults to before
9407 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9408 * @return {Roo.Element} the inserted Element
9410 insertSibling: function(el, where, returnDom){
9411 where = where ? where.toLowerCase() : 'before';
9413 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9415 if(typeof el == 'object' && !el.nodeType){ // dh config
9416 if(where == 'after' && !this.dom.nextSibling){
9417 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9419 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9423 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9424 where == 'before' ? this.dom : this.dom.nextSibling);
9433 * Creates and wraps this element with another element
9434 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9435 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9436 * @return {HTMLElement/Element} The newly created wrapper element
9438 wrap: function(config, returnDom){
9440 config = {tag: "div"};
9442 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9443 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9448 * Replaces the passed element with this element
9449 * @param {String/HTMLElement/Element} el The element to replace
9450 * @return {Roo.Element} this
9452 replace: function(el){
9454 this.insertBefore(el);
9460 * Inserts an html fragment into this element
9461 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9462 * @param {String} html The HTML fragment
9463 * @param {Boolean} returnEl True to return an Roo.Element
9464 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9466 insertHtml : function(where, html, returnEl){
9467 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9468 return returnEl ? Roo.get(el) : el;
9472 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9473 * @param {Object} o The object with the attributes
9474 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9475 * @return {Roo.Element} this
9477 set : function(o, useSet){
9479 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9481 if(attr == "style" || typeof o[attr] == "function") { continue; }
9483 el.className = o["cls"];
9486 el.setAttribute(attr, o[attr]);
9493 Roo.DomHelper.applyStyles(el, o.style);
9499 * Convenience method for constructing a KeyMap
9500 * @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:
9501 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9502 * @param {Function} fn The function to call
9503 * @param {Object} scope (optional) The scope of the function
9504 * @return {Roo.KeyMap} The KeyMap created
9506 addKeyListener : function(key, fn, scope){
9508 if(typeof key != "object" || key instanceof Array){
9524 return new Roo.KeyMap(this, config);
9528 * Creates a KeyMap for this element
9529 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9530 * @return {Roo.KeyMap} The KeyMap created
9532 addKeyMap : function(config){
9533 return new Roo.KeyMap(this, config);
9537 * Returns true if this element is scrollable.
9540 isScrollable : function(){
9542 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9546 * 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().
9547 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9548 * @param {Number} value The new scroll value
9549 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9550 * @return {Element} this
9553 scrollTo : function(side, value, animate){
9554 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9556 this.dom[prop] = value;
9558 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9559 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9565 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9566 * within this element's scrollable range.
9567 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9568 * @param {Number} distance How far to scroll the element in pixels
9569 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9570 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9571 * was scrolled as far as it could go.
9573 scroll : function(direction, distance, animate){
9574 if(!this.isScrollable()){
9578 var l = el.scrollLeft, t = el.scrollTop;
9579 var w = el.scrollWidth, h = el.scrollHeight;
9580 var cw = el.clientWidth, ch = el.clientHeight;
9581 direction = direction.toLowerCase();
9582 var scrolled = false;
9583 var a = this.preanim(arguments, 2);
9588 var v = Math.min(l + distance, w-cw);
9589 this.scrollTo("left", v, a);
9596 var v = Math.max(l - distance, 0);
9597 this.scrollTo("left", v, a);
9605 var v = Math.max(t - distance, 0);
9606 this.scrollTo("top", v, a);
9614 var v = Math.min(t + distance, h-ch);
9615 this.scrollTo("top", v, a);
9624 * Translates the passed page coordinates into left/top css values for this element
9625 * @param {Number/Array} x The page x or an array containing [x, y]
9626 * @param {Number} y The page y
9627 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9629 translatePoints : function(x, y){
9630 if(typeof x == 'object' || x instanceof Array){
9633 var p = this.getStyle('position');
9634 var o = this.getXY();
9636 var l = parseInt(this.getStyle('left'), 10);
9637 var t = parseInt(this.getStyle('top'), 10);
9640 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9643 t = (p == "relative") ? 0 : this.dom.offsetTop;
9646 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9650 * Returns the current scroll position of the element.
9651 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9653 getScroll : function(){
9654 var d = this.dom, doc = document;
9655 if(d == doc || d == doc.body){
9656 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9657 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9658 return {left: l, top: t};
9660 return {left: d.scrollLeft, top: d.scrollTop};
9665 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9666 * are convert to standard 6 digit hex color.
9667 * @param {String} attr The css attribute
9668 * @param {String} defaultValue The default value to use when a valid color isn't found
9669 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9672 getColor : function(attr, defaultValue, prefix){
9673 var v = this.getStyle(attr);
9674 if(!v || v == "transparent" || v == "inherit") {
9675 return defaultValue;
9677 var color = typeof prefix == "undefined" ? "#" : prefix;
9678 if(v.substr(0, 4) == "rgb("){
9679 var rvs = v.slice(4, v.length -1).split(",");
9680 for(var i = 0; i < 3; i++){
9681 var h = parseInt(rvs[i]).toString(16);
9688 if(v.substr(0, 1) == "#"){
9690 for(var i = 1; i < 4; i++){
9691 var c = v.charAt(i);
9694 }else if(v.length == 7){
9695 color += v.substr(1);
9699 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9703 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9704 * gradient background, rounded corners and a 4-way shadow.
9705 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9706 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9707 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9708 * @return {Roo.Element} this
9710 boxWrap : function(cls){
9711 cls = cls || 'x-box';
9712 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9713 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9718 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9719 * @param {String} namespace The namespace in which to look for the attribute
9720 * @param {String} name The attribute name
9721 * @return {String} The attribute value
9723 getAttributeNS : Roo.isIE ? function(ns, name){
9725 var type = typeof d[ns+":"+name];
9726 if(type != 'undefined' && type != 'unknown'){
9727 return d[ns+":"+name];
9730 } : function(ns, name){
9732 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9737 * Sets or Returns the value the dom attribute value
9738 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9739 * @param {String} value (optional) The value to set the attribute to
9740 * @return {String} The attribute value
9742 attr : function(name){
9743 if (arguments.length > 1) {
9744 this.dom.setAttribute(name, arguments[1]);
9745 return arguments[1];
9747 if (typeof(name) == 'object') {
9748 for(var i in name) {
9749 this.attr(i, name[i]);
9755 if (!this.dom.hasAttribute(name)) {
9758 return this.dom.getAttribute(name);
9765 var ep = El.prototype;
9768 * Appends an event handler (Shorthand for addListener)
9769 * @param {String} eventName The type of event to append
9770 * @param {Function} fn The method the event invokes
9771 * @param {Object} scope (optional) The scope (this object) of the fn
9772 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9775 ep.on = ep.addListener;
9777 ep.mon = ep.addListener;
9780 * Removes an event handler from this element (shorthand for removeListener)
9781 * @param {String} eventName the type of event to remove
9782 * @param {Function} fn the method the event invokes
9783 * @return {Roo.Element} this
9786 ep.un = ep.removeListener;
9789 * true to automatically adjust width and height settings for box-model issues (default to true)
9791 ep.autoBoxAdjust = true;
9794 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9797 El.addUnits = function(v, defaultUnit){
9798 if(v === "" || v == "auto"){
9801 if(v === undefined){
9804 if(typeof v == "number" || !El.unitPattern.test(v)){
9805 return v + (defaultUnit || 'px');
9810 // special markup used throughout Roo when box wrapping elements
9811 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>';
9813 * Visibility mode constant - Use visibility to hide element
9819 * Visibility mode constant - Use display to hide element
9825 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9826 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9827 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9839 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9840 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9841 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9842 * @return {Element} The Element object
9845 El.get = function(el){
9847 if(!el){ return null; }
9848 if(typeof el == "string"){ // element id
9849 if(!(elm = document.getElementById(el))){
9852 if(ex = El.cache[el]){
9855 ex = El.cache[el] = new El(elm);
9858 }else if(el.tagName){ // dom element
9862 if(ex = El.cache[id]){
9865 ex = El.cache[id] = new El(el);
9868 }else if(el instanceof El){
9870 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9871 // catch case where it hasn't been appended
9872 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9875 }else if(el.isComposite){
9877 }else if(el instanceof Array){
9878 return El.select(el);
9879 }else if(el == document){
9880 // create a bogus element object representing the document object
9882 var f = function(){};
9883 f.prototype = El.prototype;
9885 docEl.dom = document;
9893 El.uncache = function(el){
9894 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9896 delete El.cache[a[i].id || a[i]];
9902 // Garbage collection - uncache elements/purge listeners on orphaned elements
9903 // so we don't hold a reference and cause the browser to retain them
9904 El.garbageCollect = function(){
9905 if(!Roo.enableGarbageCollector){
9906 clearInterval(El.collectorThread);
9909 for(var eid in El.cache){
9910 var el = El.cache[eid], d = el.dom;
9911 // -------------------------------------------------------
9912 // Determining what is garbage:
9913 // -------------------------------------------------------
9915 // dom node is null, definitely garbage
9916 // -------------------------------------------------------
9918 // no parentNode == direct orphan, definitely garbage
9919 // -------------------------------------------------------
9920 // !d.offsetParent && !document.getElementById(eid)
9921 // display none elements have no offsetParent so we will
9922 // also try to look it up by it's id. However, check
9923 // offsetParent first so we don't do unneeded lookups.
9924 // This enables collection of elements that are not orphans
9925 // directly, but somewhere up the line they have an orphan
9927 // -------------------------------------------------------
9928 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9929 delete El.cache[eid];
9930 if(d && Roo.enableListenerCollection){
9936 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9940 El.Flyweight = function(dom){
9943 El.Flyweight.prototype = El.prototype;
9945 El._flyweights = {};
9947 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9948 * the dom node can be overwritten by other code.
9949 * @param {String/HTMLElement} el The dom node or id
9950 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9951 * prevent conflicts (e.g. internally Roo uses "_internal")
9953 * @return {Element} The shared Element object
9955 El.fly = function(el, named){
9956 named = named || '_global';
9957 el = Roo.getDom(el);
9961 if(!El._flyweights[named]){
9962 El._flyweights[named] = new El.Flyweight();
9964 El._flyweights[named].dom = el;
9965 return El._flyweights[named];
9969 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9970 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9971 * Shorthand of {@link Roo.Element#get}
9972 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9973 * @return {Element} The Element object
9979 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9980 * the dom node can be overwritten by other code.
9981 * Shorthand of {@link Roo.Element#fly}
9982 * @param {String/HTMLElement} el The dom node or id
9983 * @param {String} named (optional) Allows for creation of named reusable flyweights to
9984 * prevent conflicts (e.g. internally Roo uses "_internal")
9986 * @return {Element} The shared Element object
9992 // speedy lookup for elements never to box adjust
9993 var noBoxAdjust = Roo.isStrict ? {
9996 input:1, select:1, textarea:1
9998 if(Roo.isIE || Roo.isGecko){
9999 noBoxAdjust['button'] = 1;
10003 Roo.EventManager.on(window, 'unload', function(){
10005 delete El._flyweights;
10013 Roo.Element.selectorFunction = Roo.DomQuery.select;
10016 Roo.Element.select = function(selector, unique, root){
10018 if(typeof selector == "string"){
10019 els = Roo.Element.selectorFunction(selector, root);
10020 }else if(selector.length !== undefined){
10023 throw "Invalid selector";
10025 if(unique === true){
10026 return new Roo.CompositeElement(els);
10028 return new Roo.CompositeElementLite(els);
10032 * Selects elements based on the passed CSS selector to enable working on them as 1.
10033 * @param {String/Array} selector The CSS selector or an array of elements
10034 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10035 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10036 * @return {CompositeElementLite/CompositeElement}
10040 Roo.select = Roo.Element.select;
10057 * Ext JS Library 1.1.1
10058 * Copyright(c) 2006-2007, Ext JS, LLC.
10060 * Originally Released Under LGPL - original licence link has changed is not relivant.
10063 * <script type="text/javascript">
10068 //Notifies Element that fx methods are available
10069 Roo.enableFx = true;
10073 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10074 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10075 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10076 * Element effects to work.</p><br/>
10078 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10079 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10080 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10081 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10082 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10083 * expected results and should be done with care.</p><br/>
10085 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10086 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10089 ----- -----------------------------
10090 tl The top left corner
10091 t The center of the top edge
10092 tr The top right corner
10093 l The center of the left edge
10094 r The center of the right edge
10095 bl The bottom left corner
10096 b The center of the bottom edge
10097 br The bottom right corner
10099 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10100 * below are common options that can be passed to any Fx method.</b>
10101 * @cfg {Function} callback A function called when the effect is finished
10102 * @cfg {Object} scope The scope of the effect function
10103 * @cfg {String} easing A valid Easing value for the effect
10104 * @cfg {String} afterCls A css class to apply after the effect
10105 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10106 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10107 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10108 * effects that end with the element being visually hidden, ignored otherwise)
10109 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10110 * a function which returns such a specification that will be applied to the Element after the effect finishes
10111 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10112 * @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
10113 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10117 * Slides the element into view. An anchor point can be optionally passed to set the point of
10118 * origin for the slide effect. This function automatically handles wrapping the element with
10119 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10122 // default: slide the element in from the top
10125 // custom: slide the element in from the right with a 2-second duration
10126 el.slideIn('r', { duration: 2 });
10128 // common config options shown with default values
10134 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10135 * @param {Object} options (optional) Object literal with any of the Fx config options
10136 * @return {Roo.Element} The Element
10138 slideIn : function(anchor, o){
10139 var el = this.getFxEl();
10142 el.queueFx(o, function(){
10144 anchor = anchor || "t";
10146 // fix display to visibility
10149 // restore values after effect
10150 var r = this.getFxRestore();
10151 var b = this.getBox();
10152 // fixed size for slide
10156 var wrap = this.fxWrap(r.pos, o, "hidden");
10158 var st = this.dom.style;
10159 st.visibility = "visible";
10160 st.position = "absolute";
10162 // clear out temp styles after slide and unwrap
10163 var after = function(){
10164 el.fxUnwrap(wrap, r.pos, o);
10165 st.width = r.width;
10166 st.height = r.height;
10169 // time to calc the positions
10170 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10172 switch(anchor.toLowerCase()){
10174 wrap.setSize(b.width, 0);
10175 st.left = st.bottom = "0";
10179 wrap.setSize(0, b.height);
10180 st.right = st.top = "0";
10184 wrap.setSize(0, b.height);
10185 wrap.setX(b.right);
10186 st.left = st.top = "0";
10187 a = {width: bw, points: pt};
10190 wrap.setSize(b.width, 0);
10191 wrap.setY(b.bottom);
10192 st.left = st.top = "0";
10193 a = {height: bh, points: pt};
10196 wrap.setSize(0, 0);
10197 st.right = st.bottom = "0";
10198 a = {width: bw, height: bh};
10201 wrap.setSize(0, 0);
10202 wrap.setY(b.y+b.height);
10203 st.right = st.top = "0";
10204 a = {width: bw, height: bh, points: pt};
10207 wrap.setSize(0, 0);
10208 wrap.setXY([b.right, b.bottom]);
10209 st.left = st.top = "0";
10210 a = {width: bw, height: bh, points: pt};
10213 wrap.setSize(0, 0);
10214 wrap.setX(b.x+b.width);
10215 st.left = st.bottom = "0";
10216 a = {width: bw, height: bh, points: pt};
10219 this.dom.style.visibility = "visible";
10222 arguments.callee.anim = wrap.fxanim(a,
10232 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10233 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10234 * 'hidden') but block elements will still take up space in the document. The element must be removed
10235 * from the DOM using the 'remove' config option if desired. This function automatically handles
10236 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10239 // default: slide the element out to the top
10242 // custom: slide the element out to the right with a 2-second duration
10243 el.slideOut('r', { duration: 2 });
10245 // common config options shown with default values
10253 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10254 * @param {Object} options (optional) Object literal with any of the Fx config options
10255 * @return {Roo.Element} The Element
10257 slideOut : function(anchor, o){
10258 var el = this.getFxEl();
10261 el.queueFx(o, function(){
10263 anchor = anchor || "t";
10265 // restore values after effect
10266 var r = this.getFxRestore();
10268 var b = this.getBox();
10269 // fixed size for slide
10273 var wrap = this.fxWrap(r.pos, o, "visible");
10275 var st = this.dom.style;
10276 st.visibility = "visible";
10277 st.position = "absolute";
10281 var after = function(){
10283 el.setDisplayed(false);
10288 el.fxUnwrap(wrap, r.pos, o);
10290 st.width = r.width;
10291 st.height = r.height;
10296 var a, zero = {to: 0};
10297 switch(anchor.toLowerCase()){
10299 st.left = st.bottom = "0";
10300 a = {height: zero};
10303 st.right = st.top = "0";
10307 st.left = st.top = "0";
10308 a = {width: zero, points: {to:[b.right, b.y]}};
10311 st.left = st.top = "0";
10312 a = {height: zero, points: {to:[b.x, b.bottom]}};
10315 st.right = st.bottom = "0";
10316 a = {width: zero, height: zero};
10319 st.right = st.top = "0";
10320 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10323 st.left = st.top = "0";
10324 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10327 st.left = st.bottom = "0";
10328 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10332 arguments.callee.anim = wrap.fxanim(a,
10342 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10343 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10344 * The element must be removed from the DOM using the 'remove' config option if desired.
10350 // common config options shown with default values
10358 * @param {Object} options (optional) Object literal with any of the Fx config options
10359 * @return {Roo.Element} The Element
10361 puff : function(o){
10362 var el = this.getFxEl();
10365 el.queueFx(o, function(){
10366 this.clearOpacity();
10369 // restore values after effect
10370 var r = this.getFxRestore();
10371 var st = this.dom.style;
10373 var after = function(){
10375 el.setDisplayed(false);
10382 el.setPositioning(r.pos);
10383 st.width = r.width;
10384 st.height = r.height;
10389 var width = this.getWidth();
10390 var height = this.getHeight();
10392 arguments.callee.anim = this.fxanim({
10393 width : {to: this.adjustWidth(width * 2)},
10394 height : {to: this.adjustHeight(height * 2)},
10395 points : {by: [-(width * .5), -(height * .5)]},
10397 fontSize: {to:200, unit: "%"}
10408 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10409 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10410 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10416 // all config options shown with default values
10424 * @param {Object} options (optional) Object literal with any of the Fx config options
10425 * @return {Roo.Element} The Element
10427 switchOff : function(o){
10428 var el = this.getFxEl();
10431 el.queueFx(o, function(){
10432 this.clearOpacity();
10435 // restore values after effect
10436 var r = this.getFxRestore();
10437 var st = this.dom.style;
10439 var after = function(){
10441 el.setDisplayed(false);
10447 el.setPositioning(r.pos);
10448 st.width = r.width;
10449 st.height = r.height;
10454 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10455 this.clearOpacity();
10459 points:{by:[0, this.getHeight() * .5]}
10460 }, o, 'motion', 0.3, 'easeIn', after);
10461 }).defer(100, this);
10468 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10469 * changed using the "attr" config option) and then fading back to the original color. If no original
10470 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10473 // default: highlight background to yellow
10476 // custom: highlight foreground text to blue for 2 seconds
10477 el.highlight("0000ff", { attr: 'color', duration: 2 });
10479 // common config options shown with default values
10480 el.highlight("ffff9c", {
10481 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10482 endColor: (current color) or "ffffff",
10487 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10488 * @param {Object} options (optional) Object literal with any of the Fx config options
10489 * @return {Roo.Element} The Element
10491 highlight : function(color, o){
10492 var el = this.getFxEl();
10495 el.queueFx(o, function(){
10496 color = color || "ffff9c";
10497 attr = o.attr || "backgroundColor";
10499 this.clearOpacity();
10502 var origColor = this.getColor(attr);
10503 var restoreColor = this.dom.style[attr];
10504 endColor = (o.endColor || origColor) || "ffffff";
10506 var after = function(){
10507 el.dom.style[attr] = restoreColor;
10512 a[attr] = {from: color, to: endColor};
10513 arguments.callee.anim = this.fxanim(a,
10523 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10526 // default: a single light blue ripple
10529 // custom: 3 red ripples lasting 3 seconds total
10530 el.frame("ff0000", 3, { duration: 3 });
10532 // common config options shown with default values
10533 el.frame("C3DAF9", 1, {
10534 duration: 1 //duration of entire animation (not each individual ripple)
10535 // Note: Easing is not configurable and will be ignored if included
10538 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10539 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10540 * @param {Object} options (optional) Object literal with any of the Fx config options
10541 * @return {Roo.Element} The Element
10543 frame : function(color, count, o){
10544 var el = this.getFxEl();
10547 el.queueFx(o, function(){
10548 color = color || "#C3DAF9";
10549 if(color.length == 6){
10550 color = "#" + color;
10552 count = count || 1;
10553 duration = o.duration || 1;
10556 var b = this.getBox();
10557 var animFn = function(){
10558 var proxy = this.createProxy({
10561 visbility:"hidden",
10562 position:"absolute",
10563 "z-index":"35000", // yee haw
10564 border:"0px solid " + color
10567 var scale = Roo.isBorderBox ? 2 : 1;
10569 top:{from:b.y, to:b.y - 20},
10570 left:{from:b.x, to:b.x - 20},
10571 borderWidth:{from:0, to:10},
10572 opacity:{from:1, to:0},
10573 height:{from:b.height, to:(b.height + (20*scale))},
10574 width:{from:b.width, to:(b.width + (20*scale))}
10575 }, duration, function(){
10579 animFn.defer((duration/2)*1000, this);
10590 * Creates a pause before any subsequent queued effects begin. If there are
10591 * no effects queued after the pause it will have no effect.
10596 * @param {Number} seconds The length of time to pause (in seconds)
10597 * @return {Roo.Element} The Element
10599 pause : function(seconds){
10600 var el = this.getFxEl();
10603 el.queueFx(o, function(){
10604 setTimeout(function(){
10606 }, seconds * 1000);
10612 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10613 * using the "endOpacity" config option.
10616 // default: fade in from opacity 0 to 100%
10619 // custom: fade in from opacity 0 to 75% over 2 seconds
10620 el.fadeIn({ endOpacity: .75, duration: 2});
10622 // common config options shown with default values
10624 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10629 * @param {Object} options (optional) Object literal with any of the Fx config options
10630 * @return {Roo.Element} The Element
10632 fadeIn : function(o){
10633 var el = this.getFxEl();
10635 el.queueFx(o, function(){
10636 this.setOpacity(0);
10638 this.dom.style.visibility = 'visible';
10639 var to = o.endOpacity || 1;
10640 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10641 o, null, .5, "easeOut", function(){
10643 this.clearOpacity();
10652 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10653 * using the "endOpacity" config option.
10656 // default: fade out from the element's current opacity to 0
10659 // custom: fade out from the element's current opacity to 25% over 2 seconds
10660 el.fadeOut({ endOpacity: .25, duration: 2});
10662 // common config options shown with default values
10664 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10671 * @param {Object} options (optional) Object literal with any of the Fx config options
10672 * @return {Roo.Element} The Element
10674 fadeOut : function(o){
10675 var el = this.getFxEl();
10677 el.queueFx(o, function(){
10678 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10679 o, null, .5, "easeOut", function(){
10680 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10681 this.dom.style.display = "none";
10683 this.dom.style.visibility = "hidden";
10685 this.clearOpacity();
10693 * Animates the transition of an element's dimensions from a starting height/width
10694 * to an ending height/width.
10697 // change height and width to 100x100 pixels
10698 el.scale(100, 100);
10700 // common config options shown with default values. The height and width will default to
10701 // the element's existing values if passed as null.
10704 [element's height], {
10709 * @param {Number} width The new width (pass undefined to keep the original width)
10710 * @param {Number} height The new height (pass undefined to keep the original height)
10711 * @param {Object} options (optional) Object literal with any of the Fx config options
10712 * @return {Roo.Element} The Element
10714 scale : function(w, h, o){
10715 this.shift(Roo.apply({}, o, {
10723 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10724 * Any of these properties not specified in the config object will not be changed. This effect
10725 * requires that at least one new dimension, position or opacity setting must be passed in on
10726 * the config object in order for the function to have any effect.
10729 // slide the element horizontally to x position 200 while changing the height and opacity
10730 el.shift({ x: 200, height: 50, opacity: .8 });
10732 // common config options shown with default values.
10734 width: [element's width],
10735 height: [element's height],
10736 x: [element's x position],
10737 y: [element's y position],
10738 opacity: [element's opacity],
10743 * @param {Object} options Object literal with any of the Fx config options
10744 * @return {Roo.Element} The Element
10746 shift : function(o){
10747 var el = this.getFxEl();
10749 el.queueFx(o, function(){
10750 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10751 if(w !== undefined){
10752 a.width = {to: this.adjustWidth(w)};
10754 if(h !== undefined){
10755 a.height = {to: this.adjustHeight(h)};
10757 if(x !== undefined || y !== undefined){
10759 x !== undefined ? x : this.getX(),
10760 y !== undefined ? y : this.getY()
10763 if(op !== undefined){
10764 a.opacity = {to: op};
10766 if(o.xy !== undefined){
10767 a.points = {to: o.xy};
10769 arguments.callee.anim = this.fxanim(a,
10770 o, 'motion', .35, "easeOut", function(){
10778 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10779 * ending point of the effect.
10782 // default: slide the element downward while fading out
10785 // custom: slide the element out to the right with a 2-second duration
10786 el.ghost('r', { duration: 2 });
10788 // common config options shown with default values
10796 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10797 * @param {Object} options (optional) Object literal with any of the Fx config options
10798 * @return {Roo.Element} The Element
10800 ghost : function(anchor, o){
10801 var el = this.getFxEl();
10804 el.queueFx(o, function(){
10805 anchor = anchor || "b";
10807 // restore values after effect
10808 var r = this.getFxRestore();
10809 var w = this.getWidth(),
10810 h = this.getHeight();
10812 var st = this.dom.style;
10814 var after = function(){
10816 el.setDisplayed(false);
10822 el.setPositioning(r.pos);
10823 st.width = r.width;
10824 st.height = r.height;
10829 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10830 switch(anchor.toLowerCase()){
10857 arguments.callee.anim = this.fxanim(a,
10867 * Ensures that all effects queued after syncFx is called on the element are
10868 * run concurrently. This is the opposite of {@link #sequenceFx}.
10869 * @return {Roo.Element} The Element
10871 syncFx : function(){
10872 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10881 * Ensures that all effects queued after sequenceFx is called on the element are
10882 * run in sequence. This is the opposite of {@link #syncFx}.
10883 * @return {Roo.Element} The Element
10885 sequenceFx : function(){
10886 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10888 concurrent : false,
10895 nextFx : function(){
10896 var ef = this.fxQueue[0];
10903 * Returns true if the element has any effects actively running or queued, else returns false.
10904 * @return {Boolean} True if element has active effects, else false
10906 hasActiveFx : function(){
10907 return this.fxQueue && this.fxQueue[0];
10911 * Stops any running effects and clears the element's internal effects queue if it contains
10912 * any additional effects that haven't started yet.
10913 * @return {Roo.Element} The Element
10915 stopFx : function(){
10916 if(this.hasActiveFx()){
10917 var cur = this.fxQueue[0];
10918 if(cur && cur.anim && cur.anim.isAnimated()){
10919 this.fxQueue = [cur]; // clear out others
10920 cur.anim.stop(true);
10927 beforeFx : function(o){
10928 if(this.hasActiveFx() && !o.concurrent){
10939 * Returns true if the element is currently blocking so that no other effect can be queued
10940 * until this effect is finished, else returns false if blocking is not set. This is commonly
10941 * used to ensure that an effect initiated by a user action runs to completion prior to the
10942 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10943 * @return {Boolean} True if blocking, else false
10945 hasFxBlock : function(){
10946 var q = this.fxQueue;
10947 return q && q[0] && q[0].block;
10951 queueFx : function(o, fn){
10955 if(!this.hasFxBlock()){
10956 Roo.applyIf(o, this.fxDefaults);
10958 var run = this.beforeFx(o);
10959 fn.block = o.block;
10960 this.fxQueue.push(fn);
10972 fxWrap : function(pos, o, vis){
10974 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10977 wrapXY = this.getXY();
10979 var div = document.createElement("div");
10980 div.style.visibility = vis;
10981 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10982 wrap.setPositioning(pos);
10983 if(wrap.getStyle("position") == "static"){
10984 wrap.position("relative");
10986 this.clearPositioning('auto');
10988 wrap.dom.appendChild(this.dom);
10990 wrap.setXY(wrapXY);
10997 fxUnwrap : function(wrap, pos, o){
10998 this.clearPositioning();
10999 this.setPositioning(pos);
11001 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11007 getFxRestore : function(){
11008 var st = this.dom.style;
11009 return {pos: this.getPositioning(), width: st.width, height : st.height};
11013 afterFx : function(o){
11015 this.applyStyles(o.afterStyle);
11018 this.addClass(o.afterCls);
11020 if(o.remove === true){
11023 Roo.callback(o.callback, o.scope, [this]);
11025 this.fxQueue.shift();
11031 getFxEl : function(){ // support for composite element fx
11032 return Roo.get(this.dom);
11036 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11037 animType = animType || 'run';
11039 var anim = Roo.lib.Anim[animType](
11041 (opt.duration || defaultDur) || .35,
11042 (opt.easing || defaultEase) || 'easeOut',
11044 Roo.callback(cb, this);
11053 // backwords compat
11054 Roo.Fx.resize = Roo.Fx.scale;
11056 //When included, Roo.Fx is automatically applied to Element so that all basic
11057 //effects are available directly via the Element API
11058 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11060 * Ext JS Library 1.1.1
11061 * Copyright(c) 2006-2007, Ext JS, LLC.
11063 * Originally Released Under LGPL - original licence link has changed is not relivant.
11066 * <script type="text/javascript">
11071 * @class Roo.CompositeElement
11072 * Standard composite class. Creates a Roo.Element for every element in the collection.
11074 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11075 * actions will be performed on all the elements in this collection.</b>
11077 * All methods return <i>this</i> and can be chained.
11079 var els = Roo.select("#some-el div.some-class", true);
11080 // or select directly from an existing element
11081 var el = Roo.get('some-el');
11082 el.select('div.some-class', true);
11084 els.setWidth(100); // all elements become 100 width
11085 els.hide(true); // all elements fade out and hide
11087 els.setWidth(100).hide(true);
11090 Roo.CompositeElement = function(els){
11091 this.elements = [];
11092 this.addElements(els);
11094 Roo.CompositeElement.prototype = {
11096 addElements : function(els){
11100 if(typeof els == "string"){
11101 els = Roo.Element.selectorFunction(els);
11103 var yels = this.elements;
11104 var index = yels.length-1;
11105 for(var i = 0, len = els.length; i < len; i++) {
11106 yels[++index] = Roo.get(els[i]);
11112 * Clears this composite and adds the elements returned by the passed selector.
11113 * @param {String/Array} els A string CSS selector, an array of elements or an element
11114 * @return {CompositeElement} this
11116 fill : function(els){
11117 this.elements = [];
11123 * Filters this composite to only elements that match the passed selector.
11124 * @param {String} selector A string CSS selector
11125 * @param {Boolean} inverse return inverse filter (not matches)
11126 * @return {CompositeElement} this
11128 filter : function(selector, inverse){
11130 inverse = inverse || false;
11131 this.each(function(el){
11132 var match = inverse ? !el.is(selector) : el.is(selector);
11134 els[els.length] = el.dom;
11141 invoke : function(fn, args){
11142 var els = this.elements;
11143 for(var i = 0, len = els.length; i < len; i++) {
11144 Roo.Element.prototype[fn].apply(els[i], args);
11149 * Adds elements to this composite.
11150 * @param {String/Array} els A string CSS selector, an array of elements or an element
11151 * @return {CompositeElement} this
11153 add : function(els){
11154 if(typeof els == "string"){
11155 this.addElements(Roo.Element.selectorFunction(els));
11156 }else if(els.length !== undefined){
11157 this.addElements(els);
11159 this.addElements([els]);
11164 * Calls the passed function passing (el, this, index) for each element in this composite.
11165 * @param {Function} fn The function to call
11166 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11167 * @return {CompositeElement} this
11169 each : function(fn, scope){
11170 var els = this.elements;
11171 for(var i = 0, len = els.length; i < len; i++){
11172 if(fn.call(scope || els[i], els[i], this, i) === false) {
11180 * Returns the Element object at the specified index
11181 * @param {Number} index
11182 * @return {Roo.Element}
11184 item : function(index){
11185 return this.elements[index] || null;
11189 * Returns the first Element
11190 * @return {Roo.Element}
11192 first : function(){
11193 return this.item(0);
11197 * Returns the last Element
11198 * @return {Roo.Element}
11201 return this.item(this.elements.length-1);
11205 * Returns the number of elements in this composite
11208 getCount : function(){
11209 return this.elements.length;
11213 * Returns true if this composite contains the passed element
11216 contains : function(el){
11217 return this.indexOf(el) !== -1;
11221 * Returns true if this composite contains the passed element
11224 indexOf : function(el){
11225 return this.elements.indexOf(Roo.get(el));
11230 * Removes the specified element(s).
11231 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11232 * or an array of any of those.
11233 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11234 * @return {CompositeElement} this
11236 removeElement : function(el, removeDom){
11237 if(el instanceof Array){
11238 for(var i = 0, len = el.length; i < len; i++){
11239 this.removeElement(el[i]);
11243 var index = typeof el == 'number' ? el : this.indexOf(el);
11246 var d = this.elements[index];
11250 d.parentNode.removeChild(d);
11253 this.elements.splice(index, 1);
11259 * Replaces the specified element with the passed element.
11260 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11262 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11263 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11264 * @return {CompositeElement} this
11266 replaceElement : function(el, replacement, domReplace){
11267 var index = typeof el == 'number' ? el : this.indexOf(el);
11270 this.elements[index].replaceWith(replacement);
11272 this.elements.splice(index, 1, Roo.get(replacement))
11279 * Removes all elements.
11281 clear : function(){
11282 this.elements = [];
11286 Roo.CompositeElement.createCall = function(proto, fnName){
11287 if(!proto[fnName]){
11288 proto[fnName] = function(){
11289 return this.invoke(fnName, arguments);
11293 for(var fnName in Roo.Element.prototype){
11294 if(typeof Roo.Element.prototype[fnName] == "function"){
11295 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11301 * Ext JS Library 1.1.1
11302 * Copyright(c) 2006-2007, Ext JS, LLC.
11304 * Originally Released Under LGPL - original licence link has changed is not relivant.
11307 * <script type="text/javascript">
11311 * @class Roo.CompositeElementLite
11312 * @extends Roo.CompositeElement
11313 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11315 var els = Roo.select("#some-el div.some-class");
11316 // or select directly from an existing element
11317 var el = Roo.get('some-el');
11318 el.select('div.some-class');
11320 els.setWidth(100); // all elements become 100 width
11321 els.hide(true); // all elements fade out and hide
11323 els.setWidth(100).hide(true);
11324 </code></pre><br><br>
11325 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11326 * actions will be performed on all the elements in this collection.</b>
11328 Roo.CompositeElementLite = function(els){
11329 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11330 this.el = new Roo.Element.Flyweight();
11332 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11333 addElements : function(els){
11335 if(els instanceof Array){
11336 this.elements = this.elements.concat(els);
11338 var yels = this.elements;
11339 var index = yels.length-1;
11340 for(var i = 0, len = els.length; i < len; i++) {
11341 yels[++index] = els[i];
11347 invoke : function(fn, args){
11348 var els = this.elements;
11350 for(var i = 0, len = els.length; i < len; i++) {
11352 Roo.Element.prototype[fn].apply(el, args);
11357 * Returns a flyweight Element of the dom element object at the specified index
11358 * @param {Number} index
11359 * @return {Roo.Element}
11361 item : function(index){
11362 if(!this.elements[index]){
11365 this.el.dom = this.elements[index];
11369 // fixes scope with flyweight
11370 addListener : function(eventName, handler, scope, opt){
11371 var els = this.elements;
11372 for(var i = 0, len = els.length; i < len; i++) {
11373 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11379 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11380 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11381 * a reference to the dom node, use el.dom.</b>
11382 * @param {Function} fn The function to call
11383 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11384 * @return {CompositeElement} this
11386 each : function(fn, scope){
11387 var els = this.elements;
11389 for(var i = 0, len = els.length; i < len; i++){
11391 if(fn.call(scope || el, el, this, i) === false){
11398 indexOf : function(el){
11399 return this.elements.indexOf(Roo.getDom(el));
11402 replaceElement : function(el, replacement, domReplace){
11403 var index = typeof el == 'number' ? el : this.indexOf(el);
11405 replacement = Roo.getDom(replacement);
11407 var d = this.elements[index];
11408 d.parentNode.insertBefore(replacement, d);
11409 d.parentNode.removeChild(d);
11411 this.elements.splice(index, 1, replacement);
11416 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11420 * Ext JS Library 1.1.1
11421 * Copyright(c) 2006-2007, Ext JS, LLC.
11423 * Originally Released Under LGPL - original licence link has changed is not relivant.
11426 * <script type="text/javascript">
11432 * @class Roo.data.Connection
11433 * @extends Roo.util.Observable
11434 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11435 * either to a configured URL, or to a URL specified at request time.<br><br>
11437 * Requests made by this class are asynchronous, and will return immediately. No data from
11438 * the server will be available to the statement immediately following the {@link #request} call.
11439 * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11441 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11442 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11443 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11444 * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11445 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11446 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11447 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11448 * standard DOM methods.
11450 * @param {Object} config a configuration object.
11452 Roo.data.Connection = function(config){
11453 Roo.apply(this, config);
11456 * @event beforerequest
11457 * Fires before a network request is made to retrieve a data object.
11458 * @param {Connection} conn This Connection object.
11459 * @param {Object} options The options config object passed to the {@link #request} method.
11461 "beforerequest" : true,
11463 * @event requestcomplete
11464 * Fires if the request was successfully completed.
11465 * @param {Connection} conn This Connection object.
11466 * @param {Object} response The XHR object containing the response data.
11467 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11468 * @param {Object} options The options config object passed to the {@link #request} method.
11470 "requestcomplete" : true,
11472 * @event requestexception
11473 * Fires if an error HTTP status was returned from the server.
11474 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11475 * @param {Connection} conn This Connection object.
11476 * @param {Object} response The XHR object containing the response data.
11477 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11478 * @param {Object} options The options config object passed to the {@link #request} method.
11480 "requestexception" : true
11482 Roo.data.Connection.superclass.constructor.call(this);
11485 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11487 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11490 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11491 * extra parameters to each request made by this object. (defaults to undefined)
11494 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11495 * to each request made by this object. (defaults to undefined)
11498 * @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)
11501 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11505 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11511 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11514 disableCaching: true,
11517 * Sends an HTTP request to a remote server.
11518 * @param {Object} options An object which may contain the following properties:<ul>
11519 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11520 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11521 * request, a url encoded string or a function to call to get either.</li>
11522 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11523 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11524 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11525 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11526 * <li>options {Object} The parameter to the request call.</li>
11527 * <li>success {Boolean} True if the request succeeded.</li>
11528 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11530 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11531 * The callback is passed the following parameters:<ul>
11532 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11533 * <li>options {Object} The parameter to the request call.</li>
11535 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11536 * The callback is passed the following parameters:<ul>
11537 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11538 * <li>options {Object} The parameter to the request call.</li>
11540 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11541 * for the callback function. Defaults to the browser window.</li>
11542 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11543 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11544 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11545 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11546 * params for the post data. Any params will be appended to the URL.</li>
11547 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11549 * @return {Number} transactionId
11551 request : function(o){
11552 if(this.fireEvent("beforerequest", this, o) !== false){
11555 if(typeof p == "function"){
11556 p = p.call(o.scope||window, o);
11558 if(typeof p == "object"){
11559 p = Roo.urlEncode(o.params);
11561 if(this.extraParams){
11562 var extras = Roo.urlEncode(this.extraParams);
11563 p = p ? (p + '&' + extras) : extras;
11566 var url = o.url || this.url;
11567 if(typeof url == 'function'){
11568 url = url.call(o.scope||window, o);
11572 var form = Roo.getDom(o.form);
11573 url = url || form.action;
11575 var enctype = form.getAttribute("enctype");
11576 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11577 return this.doFormUpload(o, p, url);
11579 var f = Roo.lib.Ajax.serializeForm(form);
11580 p = p ? (p + '&' + f) : f;
11583 var hs = o.headers;
11584 if(this.defaultHeaders){
11585 hs = Roo.apply(hs || {}, this.defaultHeaders);
11592 success: this.handleResponse,
11593 failure: this.handleFailure,
11595 argument: {options: o},
11596 timeout : o.timeout || this.timeout
11599 var method = o.method||this.method||(p ? "POST" : "GET");
11601 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11602 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11605 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11609 }else if(this.autoAbort !== false){
11613 if((method == 'GET' && p) || o.xmlData){
11614 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11617 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11618 return this.transId;
11620 Roo.callback(o.callback, o.scope, [o, null, null]);
11626 * Determine whether this object has a request outstanding.
11627 * @param {Number} transactionId (Optional) defaults to the last transaction
11628 * @return {Boolean} True if there is an outstanding request.
11630 isLoading : function(transId){
11632 return Roo.lib.Ajax.isCallInProgress(transId);
11634 return this.transId ? true : false;
11639 * Aborts any outstanding request.
11640 * @param {Number} transactionId (Optional) defaults to the last transaction
11642 abort : function(transId){
11643 if(transId || this.isLoading()){
11644 Roo.lib.Ajax.abort(transId || this.transId);
11649 handleResponse : function(response){
11650 this.transId = false;
11651 var options = response.argument.options;
11652 response.argument = options ? options.argument : null;
11653 this.fireEvent("requestcomplete", this, response, options);
11654 Roo.callback(options.success, options.scope, [response, options]);
11655 Roo.callback(options.callback, options.scope, [options, true, response]);
11659 handleFailure : function(response, e){
11660 this.transId = false;
11661 var options = response.argument.options;
11662 response.argument = options ? options.argument : null;
11663 this.fireEvent("requestexception", this, response, options, e);
11664 Roo.callback(options.failure, options.scope, [response, options]);
11665 Roo.callback(options.callback, options.scope, [options, false, response]);
11669 doFormUpload : function(o, ps, url){
11671 var frame = document.createElement('iframe');
11674 frame.className = 'x-hidden';
11676 frame.src = Roo.SSL_SECURE_URL;
11678 document.body.appendChild(frame);
11681 document.frames[id].name = id;
11684 var form = Roo.getDom(o.form);
11686 form.method = 'POST';
11687 form.enctype = form.encoding = 'multipart/form-data';
11693 if(ps){ // add dynamic params
11695 ps = Roo.urlDecode(ps, false);
11697 if(ps.hasOwnProperty(k)){
11698 hd = document.createElement('input');
11699 hd.type = 'hidden';
11702 form.appendChild(hd);
11709 var r = { // bogus response object
11714 r.argument = o ? o.argument : null;
11719 doc = frame.contentWindow.document;
11721 doc = (frame.contentDocument || window.frames[id].document);
11723 if(doc && doc.body){
11724 r.responseText = doc.body.innerHTML;
11726 if(doc && doc.XMLDocument){
11727 r.responseXML = doc.XMLDocument;
11729 r.responseXML = doc;
11736 Roo.EventManager.removeListener(frame, 'load', cb, this);
11738 this.fireEvent("requestcomplete", this, r, o);
11739 Roo.callback(o.success, o.scope, [r, o]);
11740 Roo.callback(o.callback, o.scope, [o, true, r]);
11742 setTimeout(function(){document.body.removeChild(frame);}, 100);
11745 Roo.EventManager.on(frame, 'load', cb, this);
11748 if(hiddens){ // remove dynamic params
11749 for(var i = 0, len = hiddens.length; i < len; i++){
11750 form.removeChild(hiddens[i]);
11757 * Ext JS Library 1.1.1
11758 * Copyright(c) 2006-2007, Ext JS, LLC.
11760 * Originally Released Under LGPL - original licence link has changed is not relivant.
11763 * <script type="text/javascript">
11767 * Global Ajax request class.
11770 * @extends Roo.data.Connection
11773 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
11774 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11775 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
11776 * @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)
11777 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11778 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11779 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11781 Roo.Ajax = new Roo.data.Connection({
11790 * Serialize the passed form into a url encoded string
11792 * @param {String/HTMLElement} form
11795 serializeForm : function(form){
11796 return Roo.lib.Ajax.serializeForm(form);
11800 * Ext JS Library 1.1.1
11801 * Copyright(c) 2006-2007, Ext JS, LLC.
11803 * Originally Released Under LGPL - original licence link has changed is not relivant.
11806 * <script type="text/javascript">
11811 * @class Roo.UpdateManager
11812 * @extends Roo.util.Observable
11813 * Provides AJAX-style update for Element object.<br><br>
11816 * // Get it from a Roo.Element object
11817 * var el = Roo.get("foo");
11818 * var mgr = el.getUpdateManager();
11819 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
11821 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11823 * // or directly (returns the same UpdateManager instance)
11824 * var mgr = new Roo.UpdateManager("myElementId");
11825 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11826 * mgr.on("update", myFcnNeedsToKnow);
11828 // short handed call directly from the element object
11829 Roo.get("foo").load({
11833 text: "Loading Foo..."
11837 * Create new UpdateManager directly.
11838 * @param {String/HTMLElement/Roo.Element} el The element to update
11839 * @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).
11841 Roo.UpdateManager = function(el, forceNew){
11843 if(!forceNew && el.updateManager){
11844 return el.updateManager;
11847 * The Element object
11848 * @type Roo.Element
11852 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11855 this.defaultUrl = null;
11859 * @event beforeupdate
11860 * Fired before an update is made, return false from your handler and the update is cancelled.
11861 * @param {Roo.Element} el
11862 * @param {String/Object/Function} url
11863 * @param {String/Object} params
11865 "beforeupdate": true,
11868 * Fired after successful update is made.
11869 * @param {Roo.Element} el
11870 * @param {Object} oResponseObject The response Object
11875 * Fired on update failure.
11876 * @param {Roo.Element} el
11877 * @param {Object} oResponseObject The response Object
11881 var d = Roo.UpdateManager.defaults;
11883 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11886 this.sslBlankUrl = d.sslBlankUrl;
11888 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11891 this.disableCaching = d.disableCaching;
11893 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
11896 this.indicatorText = d.indicatorText;
11898 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11901 this.showLoadIndicator = d.showLoadIndicator;
11903 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11906 this.timeout = d.timeout;
11909 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11912 this.loadScripts = d.loadScripts;
11915 * Transaction object of current executing transaction
11917 this.transaction = null;
11922 this.autoRefreshProcId = null;
11924 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11927 this.refreshDelegate = this.refresh.createDelegate(this);
11929 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11932 this.updateDelegate = this.update.createDelegate(this);
11934 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11937 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11941 this.successDelegate = this.processSuccess.createDelegate(this);
11945 this.failureDelegate = this.processFailure.createDelegate(this);
11947 if(!this.renderer){
11949 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11951 this.renderer = new Roo.UpdateManager.BasicRenderer();
11954 Roo.UpdateManager.superclass.constructor.call(this);
11957 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11959 * Get the Element this UpdateManager is bound to
11960 * @return {Roo.Element} The element
11962 getEl : function(){
11966 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11967 * @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:
11970 url: "your-url.php",<br/>
11971 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11972 callback: yourFunction,<br/>
11973 scope: yourObject, //(optional scope) <br/>
11974 discardUrl: false, <br/>
11975 nocache: false,<br/>
11976 text: "Loading...",<br/>
11978 scripts: false<br/>
11981 * The only required property is url. The optional properties nocache, text and scripts
11982 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11983 * @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}
11984 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11985 * @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.
11987 update : function(url, params, callback, discardUrl){
11988 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11989 var method = this.method,
11991 if(typeof url == "object"){ // must be config object
11994 params = params || cfg.params;
11995 callback = callback || cfg.callback;
11996 discardUrl = discardUrl || cfg.discardUrl;
11997 if(callback && cfg.scope){
11998 callback = callback.createDelegate(cfg.scope);
12000 if(typeof cfg.method != "undefined"){method = cfg.method;};
12001 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12002 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12003 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12004 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12006 this.showLoading();
12008 this.defaultUrl = url;
12010 if(typeof url == "function"){
12011 url = url.call(this);
12014 method = method || (params ? "POST" : "GET");
12015 if(method == "GET"){
12016 url = this.prepareUrl(url);
12019 var o = Roo.apply(cfg ||{}, {
12022 success: this.successDelegate,
12023 failure: this.failureDelegate,
12024 callback: undefined,
12025 timeout: (this.timeout*1000),
12026 argument: {"url": url, "form": null, "callback": callback, "params": params}
12028 Roo.log("updated manager called with timeout of " + o.timeout);
12029 this.transaction = Roo.Ajax.request(o);
12034 * 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.
12035 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12036 * @param {String/HTMLElement} form The form Id or form element
12037 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12038 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12039 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12041 formUpdate : function(form, url, reset, callback){
12042 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12043 if(typeof url == "function"){
12044 url = url.call(this);
12046 form = Roo.getDom(form);
12047 this.transaction = Roo.Ajax.request({
12050 success: this.successDelegate,
12051 failure: this.failureDelegate,
12052 timeout: (this.timeout*1000),
12053 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12055 this.showLoading.defer(1, this);
12060 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12061 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12063 refresh : function(callback){
12064 if(this.defaultUrl == null){
12067 this.update(this.defaultUrl, null, callback, true);
12071 * Set this element to auto refresh.
12072 * @param {Number} interval How often to update (in seconds).
12073 * @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)
12074 * @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}
12075 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12076 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12078 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12080 this.update(url || this.defaultUrl, params, callback, true);
12082 if(this.autoRefreshProcId){
12083 clearInterval(this.autoRefreshProcId);
12085 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12089 * Stop auto refresh on this element.
12091 stopAutoRefresh : function(){
12092 if(this.autoRefreshProcId){
12093 clearInterval(this.autoRefreshProcId);
12094 delete this.autoRefreshProcId;
12098 isAutoRefreshing : function(){
12099 return this.autoRefreshProcId ? true : false;
12102 * Called to update the element to "Loading" state. Override to perform custom action.
12104 showLoading : function(){
12105 if(this.showLoadIndicator){
12106 this.el.update(this.indicatorText);
12111 * Adds unique parameter to query string if disableCaching = true
12114 prepareUrl : function(url){
12115 if(this.disableCaching){
12116 var append = "_dc=" + (new Date().getTime());
12117 if(url.indexOf("?") !== -1){
12118 url += "&" + append;
12120 url += "?" + append;
12129 processSuccess : function(response){
12130 this.transaction = null;
12131 if(response.argument.form && response.argument.reset){
12132 try{ // put in try/catch since some older FF releases had problems with this
12133 response.argument.form.reset();
12136 if(this.loadScripts){
12137 this.renderer.render(this.el, response, this,
12138 this.updateComplete.createDelegate(this, [response]));
12140 this.renderer.render(this.el, response, this);
12141 this.updateComplete(response);
12145 updateComplete : function(response){
12146 this.fireEvent("update", this.el, response);
12147 if(typeof response.argument.callback == "function"){
12148 response.argument.callback(this.el, true, response);
12155 processFailure : function(response){
12156 this.transaction = null;
12157 this.fireEvent("failure", this.el, response);
12158 if(typeof response.argument.callback == "function"){
12159 response.argument.callback(this.el, false, response);
12164 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12165 * @param {Object} renderer The object implementing the render() method
12167 setRenderer : function(renderer){
12168 this.renderer = renderer;
12171 getRenderer : function(){
12172 return this.renderer;
12176 * Set the defaultUrl used for updates
12177 * @param {String/Function} defaultUrl The url or a function to call to get the url
12179 setDefaultUrl : function(defaultUrl){
12180 this.defaultUrl = defaultUrl;
12184 * Aborts the executing transaction
12186 abort : function(){
12187 if(this.transaction){
12188 Roo.Ajax.abort(this.transaction);
12193 * Returns true if an update is in progress
12194 * @return {Boolean}
12196 isUpdating : function(){
12197 if(this.transaction){
12198 return Roo.Ajax.isLoading(this.transaction);
12205 * @class Roo.UpdateManager.defaults
12206 * @static (not really - but it helps the doc tool)
12207 * The defaults collection enables customizing the default properties of UpdateManager
12209 Roo.UpdateManager.defaults = {
12211 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12217 * True to process scripts by default (Defaults to false).
12220 loadScripts : false,
12223 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12226 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12228 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12231 disableCaching : false,
12233 * Whether to show indicatorText when loading (Defaults to true).
12236 showLoadIndicator : true,
12238 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12241 indicatorText : '<div class="loading-indicator">Loading...</div>'
12245 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12247 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12248 * @param {String/HTMLElement/Roo.Element} el The element to update
12249 * @param {String} url The url
12250 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12251 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12254 * @member Roo.UpdateManager
12256 Roo.UpdateManager.updateElement = function(el, url, params, options){
12257 var um = Roo.get(el, true).getUpdateManager();
12258 Roo.apply(um, options);
12259 um.update(url, params, options ? options.callback : null);
12261 // alias for backwards compat
12262 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12264 * @class Roo.UpdateManager.BasicRenderer
12265 * Default Content renderer. Updates the elements innerHTML with the responseText.
12267 Roo.UpdateManager.BasicRenderer = function(){};
12269 Roo.UpdateManager.BasicRenderer.prototype = {
12271 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12272 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12273 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12274 * @param {Roo.Element} el The element being rendered
12275 * @param {Object} response The YUI Connect response object
12276 * @param {UpdateManager} updateManager The calling update manager
12277 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12279 render : function(el, response, updateManager, callback){
12280 el.update(response.responseText, updateManager.loadScripts, callback);
12286 * (c)) Alan Knowles
12292 * @class Roo.DomTemplate
12293 * @extends Roo.Template
12294 * An effort at a dom based template engine..
12296 * Similar to XTemplate, except it uses dom parsing to create the template..
12298 * Supported features:
12303 {a_variable} - output encoded.
12304 {a_variable.format:("Y-m-d")} - call a method on the variable
12305 {a_variable:raw} - unencoded output
12306 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12307 {a_variable:this.method_on_template(...)} - call a method on the template object.
12312 <div roo-for="a_variable or condition.."></div>
12313 <div roo-if="a_variable or condition"></div>
12314 <div roo-exec="some javascript"></div>
12315 <div roo-name="named_template"></div>
12320 Roo.DomTemplate = function()
12322 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12329 Roo.extend(Roo.DomTemplate, Roo.Template, {
12331 * id counter for sub templates.
12335 * flag to indicate if dom parser is inside a pre,
12336 * it will strip whitespace if not.
12341 * The various sub templates
12349 * basic tag replacing syntax
12352 * // you can fake an object call by doing this
12356 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12357 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12359 iterChild : function (node, method) {
12361 var oldPre = this.inPre;
12362 if (node.tagName == 'PRE') {
12365 for( var i = 0; i < node.childNodes.length; i++) {
12366 method.call(this, node.childNodes[i]);
12368 this.inPre = oldPre;
12374 * compile the template
12376 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12379 compile: function()
12383 // covert the html into DOM...
12387 doc = document.implementation.createHTMLDocument("");
12388 doc.documentElement.innerHTML = this.html ;
12389 div = doc.documentElement;
12391 // old IE... - nasty -- it causes all sorts of issues.. with
12392 // images getting pulled from server..
12393 div = document.createElement('div');
12394 div.innerHTML = this.html;
12396 //doc.documentElement.innerHTML = htmlBody
12402 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12404 var tpls = this.tpls;
12406 // create a top level template from the snippet..
12408 //Roo.log(div.innerHTML);
12415 body : div.innerHTML,
12428 Roo.each(tpls, function(tp){
12429 this.compileTpl(tp);
12430 this.tpls[tp.id] = tp;
12433 this.master = tpls[0];
12439 compileNode : function(node, istop) {
12444 // skip anything not a tag..
12445 if (node.nodeType != 1) {
12446 if (node.nodeType == 3 && !this.inPre) {
12447 // reduce white space..
12448 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12471 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12472 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12473 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12474 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12480 // just itterate children..
12481 this.iterChild(node,this.compileNode);
12484 tpl.uid = this.id++;
12485 tpl.value = node.getAttribute('roo-' + tpl.attr);
12486 node.removeAttribute('roo-'+ tpl.attr);
12487 if (tpl.attr != 'name') {
12488 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12489 node.parentNode.replaceChild(placeholder, node);
12492 var placeholder = document.createElement('span');
12493 placeholder.className = 'roo-tpl-' + tpl.value;
12494 node.parentNode.replaceChild(placeholder, node);
12497 // parent now sees '{domtplXXXX}
12498 this.iterChild(node,this.compileNode);
12500 // we should now have node body...
12501 var div = document.createElement('div');
12502 div.appendChild(node);
12504 // this has the unfortunate side effect of converting tagged attributes
12505 // eg. href="{...}" into %7C...%7D
12506 // this has been fixed by searching for those combo's although it's a bit hacky..
12509 tpl.body = div.innerHTML;
12516 switch (tpl.value) {
12517 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12518 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12519 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12524 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12528 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12532 tpl.id = tpl.value; // replace non characters???
12538 this.tpls.push(tpl);
12548 * Compile a segment of the template into a 'sub-template'
12554 compileTpl : function(tpl)
12556 var fm = Roo.util.Format;
12557 var useF = this.disableFormats !== true;
12559 var sep = Roo.isGecko ? "+\n" : ",\n";
12561 var undef = function(str) {
12562 Roo.debug && Roo.log("Property not found :" + str);
12566 //Roo.log(tpl.body);
12570 var fn = function(m, lbrace, name, format, args)
12573 //Roo.log(arguments);
12574 args = args ? args.replace(/\\'/g,"'") : args;
12575 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12576 if (typeof(format) == 'undefined') {
12577 format = 'htmlEncode';
12579 if (format == 'raw' ) {
12583 if(name.substr(0, 6) == 'domtpl'){
12584 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12587 // build an array of options to determine if value is undefined..
12589 // basically get 'xxxx.yyyy' then do
12590 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12591 // (function () { Roo.log("Property not found"); return ''; })() :
12596 Roo.each(name.split('.'), function(st) {
12597 lookfor += (lookfor.length ? '.': '') + st;
12598 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12601 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12604 if(format && useF){
12606 args = args ? ',' + args : "";
12608 if(format.substr(0, 5) != "this."){
12609 format = "fm." + format + '(';
12611 format = 'this.call("'+ format.substr(5) + '", ';
12615 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12618 if (args && args.length) {
12619 // called with xxyx.yuu:(test,test)
12621 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12623 // raw.. - :raw modifier..
12624 return "'"+ sep + udef_st + name + ")"+sep+"'";
12628 // branched to use + in gecko and [].join() in others
12630 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12631 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12634 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12635 body.push(tpl.body.replace(/(\r\n|\n)/g,
12636 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12637 body.push("'].join('');};};");
12638 body = body.join('');
12641 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12643 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12650 * same as applyTemplate, except it's done to one of the subTemplates
12651 * when using named templates, you can do:
12653 * var str = pl.applySubTemplate('your-name', values);
12656 * @param {Number} id of the template
12657 * @param {Object} values to apply to template
12658 * @param {Object} parent (normaly the instance of this object)
12660 applySubTemplate : function(id, values, parent)
12664 var t = this.tpls[id];
12668 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12669 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12673 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12680 if(t.execCall && t.execCall.call(this, values, parent)){
12684 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12690 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12691 parent = t.target ? values : parent;
12692 if(t.forCall && vs instanceof Array){
12694 for(var i = 0, len = vs.length; i < len; i++){
12696 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12698 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12700 //Roo.log(t.compiled);
12704 return buf.join('');
12707 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12712 return t.compiled.call(this, vs, parent);
12714 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12716 //Roo.log(t.compiled);
12724 applyTemplate : function(values){
12725 return this.master.compiled.call(this, values, {});
12726 //var s = this.subs;
12729 apply : function(){
12730 return this.applyTemplate.apply(this, arguments);
12735 Roo.DomTemplate.from = function(el){
12736 el = Roo.getDom(el);
12737 return new Roo.Domtemplate(el.value || el.innerHTML);
12740 * Ext JS Library 1.1.1
12741 * Copyright(c) 2006-2007, Ext JS, LLC.
12743 * Originally Released Under LGPL - original licence link has changed is not relivant.
12746 * <script type="text/javascript">
12750 * @class Roo.util.DelayedTask
12751 * Provides a convenient method of performing setTimeout where a new
12752 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12753 * You can use this class to buffer
12754 * the keypress events for a certain number of milliseconds, and perform only if they stop
12755 * for that amount of time.
12756 * @constructor The parameters to this constructor serve as defaults and are not required.
12757 * @param {Function} fn (optional) The default function to timeout
12758 * @param {Object} scope (optional) The default scope of that timeout
12759 * @param {Array} args (optional) The default Array of arguments
12761 Roo.util.DelayedTask = function(fn, scope, args){
12762 var id = null, d, t;
12764 var call = function(){
12765 var now = new Date().getTime();
12769 fn.apply(scope, args || []);
12773 * Cancels any pending timeout and queues a new one
12774 * @param {Number} delay The milliseconds to delay
12775 * @param {Function} newFn (optional) Overrides function passed to constructor
12776 * @param {Object} newScope (optional) Overrides scope passed to constructor
12777 * @param {Array} newArgs (optional) Overrides args passed to constructor
12779 this.delay = function(delay, newFn, newScope, newArgs){
12780 if(id && delay != d){
12784 t = new Date().getTime();
12786 scope = newScope || scope;
12787 args = newArgs || args;
12789 id = setInterval(call, d);
12794 * Cancel the last queued timeout
12796 this.cancel = function(){
12804 * Ext JS Library 1.1.1
12805 * Copyright(c) 2006-2007, Ext JS, LLC.
12807 * Originally Released Under LGPL - original licence link has changed is not relivant.
12810 * <script type="text/javascript">
12814 Roo.util.TaskRunner = function(interval){
12815 interval = interval || 10;
12816 var tasks = [], removeQueue = [];
12818 var running = false;
12820 var stopThread = function(){
12826 var startThread = function(){
12829 id = setInterval(runTasks, interval);
12833 var removeTask = function(task){
12834 removeQueue.push(task);
12840 var runTasks = function(){
12841 if(removeQueue.length > 0){
12842 for(var i = 0, len = removeQueue.length; i < len; i++){
12843 tasks.remove(removeQueue[i]);
12846 if(tasks.length < 1){
12851 var now = new Date().getTime();
12852 for(var i = 0, len = tasks.length; i < len; ++i){
12854 var itime = now - t.taskRunTime;
12855 if(t.interval <= itime){
12856 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12857 t.taskRunTime = now;
12858 if(rt === false || t.taskRunCount === t.repeat){
12863 if(t.duration && t.duration <= (now - t.taskStartTime)){
12870 * Queues a new task.
12871 * @param {Object} task
12873 this.start = function(task){
12875 task.taskStartTime = new Date().getTime();
12876 task.taskRunTime = 0;
12877 task.taskRunCount = 0;
12882 this.stop = function(task){
12887 this.stopAll = function(){
12889 for(var i = 0, len = tasks.length; i < len; i++){
12890 if(tasks[i].onStop){
12899 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12901 * Ext JS Library 1.1.1
12902 * Copyright(c) 2006-2007, Ext JS, LLC.
12904 * Originally Released Under LGPL - original licence link has changed is not relivant.
12907 * <script type="text/javascript">
12912 * @class Roo.util.MixedCollection
12913 * @extends Roo.util.Observable
12914 * A Collection class that maintains both numeric indexes and keys and exposes events.
12916 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12917 * collection (defaults to false)
12918 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12919 * and return the key value for that item. This is used when available to look up the key on items that
12920 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
12921 * equivalent to providing an implementation for the {@link #getKey} method.
12923 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12931 * Fires when the collection is cleared.
12936 * Fires when an item is added to the collection.
12937 * @param {Number} index The index at which the item was added.
12938 * @param {Object} o The item added.
12939 * @param {String} key The key associated with the added item.
12944 * Fires when an item is replaced in the collection.
12945 * @param {String} key he key associated with the new added.
12946 * @param {Object} old The item being replaced.
12947 * @param {Object} new The new item.
12952 * Fires when an item is removed from the collection.
12953 * @param {Object} o The item being removed.
12954 * @param {String} key (optional) The key associated with the removed item.
12959 this.allowFunctions = allowFunctions === true;
12961 this.getKey = keyFn;
12963 Roo.util.MixedCollection.superclass.constructor.call(this);
12966 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12967 allowFunctions : false,
12970 * Adds an item to the collection.
12971 * @param {String} key The key to associate with the item
12972 * @param {Object} o The item to add.
12973 * @return {Object} The item added.
12975 add : function(key, o){
12976 if(arguments.length == 1){
12978 key = this.getKey(o);
12980 if(typeof key == "undefined" || key === null){
12982 this.items.push(o);
12983 this.keys.push(null);
12985 var old = this.map[key];
12987 return this.replace(key, o);
12990 this.items.push(o);
12992 this.keys.push(key);
12994 this.fireEvent("add", this.length-1, o, key);
12999 * MixedCollection has a generic way to fetch keys if you implement getKey.
13002 var mc = new Roo.util.MixedCollection();
13003 mc.add(someEl.dom.id, someEl);
13004 mc.add(otherEl.dom.id, otherEl);
13008 var mc = new Roo.util.MixedCollection();
13009 mc.getKey = function(el){
13015 // or via the constructor
13016 var mc = new Roo.util.MixedCollection(false, function(el){
13022 * @param o {Object} The item for which to find the key.
13023 * @return {Object} The key for the passed item.
13025 getKey : function(o){
13030 * Replaces an item in the collection.
13031 * @param {String} key The key associated with the item to replace, or the item to replace.
13032 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13033 * @return {Object} The new item.
13035 replace : function(key, o){
13036 if(arguments.length == 1){
13038 key = this.getKey(o);
13040 var old = this.item(key);
13041 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13042 return this.add(key, o);
13044 var index = this.indexOfKey(key);
13045 this.items[index] = o;
13047 this.fireEvent("replace", key, old, o);
13052 * Adds all elements of an Array or an Object to the collection.
13053 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13054 * an Array of values, each of which are added to the collection.
13056 addAll : function(objs){
13057 if(arguments.length > 1 || objs instanceof Array){
13058 var args = arguments.length > 1 ? arguments : objs;
13059 for(var i = 0, len = args.length; i < len; i++){
13063 for(var key in objs){
13064 if(this.allowFunctions || typeof objs[key] != "function"){
13065 this.add(key, objs[key]);
13072 * Executes the specified function once for every item in the collection, passing each
13073 * item as the first and only parameter. returning false from the function will stop the iteration.
13074 * @param {Function} fn The function to execute for each item.
13075 * @param {Object} scope (optional) The scope in which to execute the function.
13077 each : function(fn, scope){
13078 var items = [].concat(this.items); // each safe for removal
13079 for(var i = 0, len = items.length; i < len; i++){
13080 if(fn.call(scope || items[i], items[i], i, len) === false){
13087 * Executes the specified function once for every key in the collection, passing each
13088 * key, and its associated item as the first two parameters.
13089 * @param {Function} fn The function to execute for each item.
13090 * @param {Object} scope (optional) The scope in which to execute the function.
13092 eachKey : function(fn, scope){
13093 for(var i = 0, len = this.keys.length; i < len; i++){
13094 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13099 * Returns the first item in the collection which elicits a true return value from the
13100 * passed selection function.
13101 * @param {Function} fn The selection function to execute for each item.
13102 * @param {Object} scope (optional) The scope in which to execute the function.
13103 * @return {Object} The first item in the collection which returned true from the selection function.
13105 find : function(fn, scope){
13106 for(var i = 0, len = this.items.length; i < len; i++){
13107 if(fn.call(scope || window, this.items[i], this.keys[i])){
13108 return this.items[i];
13115 * Inserts an item at the specified index in the collection.
13116 * @param {Number} index The index to insert the item at.
13117 * @param {String} key The key to associate with the new item, or the item itself.
13118 * @param {Object} o (optional) If the second parameter was a key, the new item.
13119 * @return {Object} The item inserted.
13121 insert : function(index, key, o){
13122 if(arguments.length == 2){
13124 key = this.getKey(o);
13126 if(index >= this.length){
13127 return this.add(key, o);
13130 this.items.splice(index, 0, o);
13131 if(typeof key != "undefined" && key != null){
13134 this.keys.splice(index, 0, key);
13135 this.fireEvent("add", index, o, key);
13140 * Removed an item from the collection.
13141 * @param {Object} o The item to remove.
13142 * @return {Object} The item removed.
13144 remove : function(o){
13145 return this.removeAt(this.indexOf(o));
13149 * Remove an item from a specified index in the collection.
13150 * @param {Number} index The index within the collection of the item to remove.
13152 removeAt : function(index){
13153 if(index < this.length && index >= 0){
13155 var o = this.items[index];
13156 this.items.splice(index, 1);
13157 var key = this.keys[index];
13158 if(typeof key != "undefined"){
13159 delete this.map[key];
13161 this.keys.splice(index, 1);
13162 this.fireEvent("remove", o, key);
13167 * Removed an item associated with the passed key fom the collection.
13168 * @param {String} key The key of the item to remove.
13170 removeKey : function(key){
13171 return this.removeAt(this.indexOfKey(key));
13175 * Returns the number of items in the collection.
13176 * @return {Number} the number of items in the collection.
13178 getCount : function(){
13179 return this.length;
13183 * Returns index within the collection of the passed Object.
13184 * @param {Object} o The item to find the index of.
13185 * @return {Number} index of the item.
13187 indexOf : function(o){
13188 if(!this.items.indexOf){
13189 for(var i = 0, len = this.items.length; i < len; i++){
13190 if(this.items[i] == o) {
13196 return this.items.indexOf(o);
13201 * Returns index within the collection of the passed key.
13202 * @param {String} key The key to find the index of.
13203 * @return {Number} index of the key.
13205 indexOfKey : function(key){
13206 if(!this.keys.indexOf){
13207 for(var i = 0, len = this.keys.length; i < len; i++){
13208 if(this.keys[i] == key) {
13214 return this.keys.indexOf(key);
13219 * Returns the item associated with the passed key OR index. Key has priority over index.
13220 * @param {String/Number} key The key or index of the item.
13221 * @return {Object} The item associated with the passed key.
13223 item : function(key){
13224 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13225 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13229 * Returns the item at the specified index.
13230 * @param {Number} index The index of the item.
13233 itemAt : function(index){
13234 return this.items[index];
13238 * Returns the item associated with the passed key.
13239 * @param {String/Number} key The key of the item.
13240 * @return {Object} The item associated with the passed key.
13242 key : function(key){
13243 return this.map[key];
13247 * Returns true if the collection contains the passed Object as an item.
13248 * @param {Object} o The Object to look for in the collection.
13249 * @return {Boolean} True if the collection contains the Object as an item.
13251 contains : function(o){
13252 return this.indexOf(o) != -1;
13256 * Returns true if the collection contains the passed Object as a key.
13257 * @param {String} key The key to look for in the collection.
13258 * @return {Boolean} True if the collection contains the Object as a key.
13260 containsKey : function(key){
13261 return typeof this.map[key] != "undefined";
13265 * Removes all items from the collection.
13267 clear : function(){
13272 this.fireEvent("clear");
13276 * Returns the first item in the collection.
13277 * @return {Object} the first item in the collection..
13279 first : function(){
13280 return this.items[0];
13284 * Returns the last item in the collection.
13285 * @return {Object} the last item in the collection..
13288 return this.items[this.length-1];
13291 _sort : function(property, dir, fn){
13292 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13293 fn = fn || function(a, b){
13296 var c = [], k = this.keys, items = this.items;
13297 for(var i = 0, len = items.length; i < len; i++){
13298 c[c.length] = {key: k[i], value: items[i], index: i};
13300 c.sort(function(a, b){
13301 var v = fn(a[property], b[property]) * dsc;
13303 v = (a.index < b.index ? -1 : 1);
13307 for(var i = 0, len = c.length; i < len; i++){
13308 items[i] = c[i].value;
13311 this.fireEvent("sort", this);
13315 * Sorts this collection with the passed comparison function
13316 * @param {String} direction (optional) "ASC" or "DESC"
13317 * @param {Function} fn (optional) comparison function
13319 sort : function(dir, fn){
13320 this._sort("value", dir, fn);
13324 * Sorts this collection by keys
13325 * @param {String} direction (optional) "ASC" or "DESC"
13326 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13328 keySort : function(dir, fn){
13329 this._sort("key", dir, fn || function(a, b){
13330 return String(a).toUpperCase()-String(b).toUpperCase();
13335 * Returns a range of items in this collection
13336 * @param {Number} startIndex (optional) defaults to 0
13337 * @param {Number} endIndex (optional) default to the last item
13338 * @return {Array} An array of items
13340 getRange : function(start, end){
13341 var items = this.items;
13342 if(items.length < 1){
13345 start = start || 0;
13346 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13349 for(var i = start; i <= end; i++) {
13350 r[r.length] = items[i];
13353 for(var i = start; i >= end; i--) {
13354 r[r.length] = items[i];
13361 * Filter the <i>objects</i> in this collection by a specific property.
13362 * Returns a new collection that has been filtered.
13363 * @param {String} property A property on your objects
13364 * @param {String/RegExp} value Either string that the property values
13365 * should start with or a RegExp to test against the property
13366 * @return {MixedCollection} The new filtered collection
13368 filter : function(property, value){
13369 if(!value.exec){ // not a regex
13370 value = String(value);
13371 if(value.length == 0){
13372 return this.clone();
13374 value = new RegExp("^" + Roo.escapeRe(value), "i");
13376 return this.filterBy(function(o){
13377 return o && value.test(o[property]);
13382 * Filter by a function. * Returns a new collection that has been filtered.
13383 * The passed function will be called with each
13384 * object in the collection. If the function returns true, the value is included
13385 * otherwise it is filtered.
13386 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13387 * @param {Object} scope (optional) The scope of the function (defaults to this)
13388 * @return {MixedCollection} The new filtered collection
13390 filterBy : function(fn, scope){
13391 var r = new Roo.util.MixedCollection();
13392 r.getKey = this.getKey;
13393 var k = this.keys, it = this.items;
13394 for(var i = 0, len = it.length; i < len; i++){
13395 if(fn.call(scope||this, it[i], k[i])){
13396 r.add(k[i], it[i]);
13403 * Creates a duplicate of this collection
13404 * @return {MixedCollection}
13406 clone : function(){
13407 var r = new Roo.util.MixedCollection();
13408 var k = this.keys, it = this.items;
13409 for(var i = 0, len = it.length; i < len; i++){
13410 r.add(k[i], it[i]);
13412 r.getKey = this.getKey;
13417 * Returns the item associated with the passed key or index.
13419 * @param {String/Number} key The key or index of the item.
13420 * @return {Object} The item associated with the passed key.
13422 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13424 * Ext JS Library 1.1.1
13425 * Copyright(c) 2006-2007, Ext JS, LLC.
13427 * Originally Released Under LGPL - original licence link has changed is not relivant.
13430 * <script type="text/javascript">
13433 * @class Roo.util.JSON
13434 * Modified version of Douglas Crockford"s json.js that doesn"t
13435 * mess with the Object prototype
13436 * http://www.json.org/js.html
13439 Roo.util.JSON = new (function(){
13440 var useHasOwn = {}.hasOwnProperty ? true : false;
13442 // crashes Safari in some instances
13443 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13445 var pad = function(n) {
13446 return n < 10 ? "0" + n : n;
13459 var encodeString = function(s){
13460 if (/["\\\x00-\x1f]/.test(s)) {
13461 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13466 c = b.charCodeAt();
13468 Math.floor(c / 16).toString(16) +
13469 (c % 16).toString(16);
13472 return '"' + s + '"';
13475 var encodeArray = function(o){
13476 var a = ["["], b, i, l = o.length, v;
13477 for (i = 0; i < l; i += 1) {
13479 switch (typeof v) {
13488 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13496 var encodeDate = function(o){
13497 return '"' + o.getFullYear() + "-" +
13498 pad(o.getMonth() + 1) + "-" +
13499 pad(o.getDate()) + "T" +
13500 pad(o.getHours()) + ":" +
13501 pad(o.getMinutes()) + ":" +
13502 pad(o.getSeconds()) + '"';
13506 * Encodes an Object, Array or other value
13507 * @param {Mixed} o The variable to encode
13508 * @return {String} The JSON string
13510 this.encode = function(o)
13512 // should this be extended to fully wrap stringify..
13514 if(typeof o == "undefined" || o === null){
13516 }else if(o instanceof Array){
13517 return encodeArray(o);
13518 }else if(o instanceof Date){
13519 return encodeDate(o);
13520 }else if(typeof o == "string"){
13521 return encodeString(o);
13522 }else if(typeof o == "number"){
13523 return isFinite(o) ? String(o) : "null";
13524 }else if(typeof o == "boolean"){
13527 var a = ["{"], b, i, v;
13529 if(!useHasOwn || o.hasOwnProperty(i)) {
13531 switch (typeof v) {
13540 a.push(this.encode(i), ":",
13541 v === null ? "null" : this.encode(v));
13552 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13553 * @param {String} json The JSON string
13554 * @return {Object} The resulting object
13556 this.decode = function(json){
13558 return /** eval:var:json */ eval("(" + json + ')');
13562 * Shorthand for {@link Roo.util.JSON#encode}
13563 * @member Roo encode
13565 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13567 * Shorthand for {@link Roo.util.JSON#decode}
13568 * @member Roo decode
13570 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13573 * Ext JS Library 1.1.1
13574 * Copyright(c) 2006-2007, Ext JS, LLC.
13576 * Originally Released Under LGPL - original licence link has changed is not relivant.
13579 * <script type="text/javascript">
13583 * @class Roo.util.Format
13584 * Reusable data formatting functions
13587 Roo.util.Format = function(){
13588 var trimRe = /^\s+|\s+$/g;
13591 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13592 * @param {String} value The string to truncate
13593 * @param {Number} length The maximum length to allow before truncating
13594 * @return {String} The converted text
13596 ellipsis : function(value, len){
13597 if(value && value.length > len){
13598 return value.substr(0, len-3)+"...";
13604 * Checks a reference and converts it to empty string if it is undefined
13605 * @param {Mixed} value Reference to check
13606 * @return {Mixed} Empty string if converted, otherwise the original value
13608 undef : function(value){
13609 return typeof value != "undefined" ? value : "";
13613 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13614 * @param {String} value The string to encode
13615 * @return {String} The encoded text
13617 htmlEncode : function(value){
13618 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13622 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13623 * @param {String} value The string to decode
13624 * @return {String} The decoded text
13626 htmlDecode : function(value){
13627 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13631 * Trims any whitespace from either side of a string
13632 * @param {String} value The text to trim
13633 * @return {String} The trimmed text
13635 trim : function(value){
13636 return String(value).replace(trimRe, "");
13640 * Returns a substring from within an original string
13641 * @param {String} value The original text
13642 * @param {Number} start The start index of the substring
13643 * @param {Number} length The length of the substring
13644 * @return {String} The substring
13646 substr : function(value, start, length){
13647 return String(value).substr(start, length);
13651 * Converts a string to all lower case letters
13652 * @param {String} value The text to convert
13653 * @return {String} The converted text
13655 lowercase : function(value){
13656 return String(value).toLowerCase();
13660 * Converts a string to all upper case letters
13661 * @param {String} value The text to convert
13662 * @return {String} The converted text
13664 uppercase : function(value){
13665 return String(value).toUpperCase();
13669 * Converts the first character only of a string to upper case
13670 * @param {String} value The text to convert
13671 * @return {String} The converted text
13673 capitalize : function(value){
13674 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13678 call : function(value, fn){
13679 if(arguments.length > 2){
13680 var args = Array.prototype.slice.call(arguments, 2);
13681 args.unshift(value);
13683 return /** eval:var:value */ eval(fn).apply(window, args);
13685 /** eval:var:value */
13686 return /** eval:var:value */ eval(fn).call(window, value);
13692 * safer version of Math.toFixed..??/
13693 * @param {Number/String} value The numeric value to format
13694 * @param {Number/String} value Decimal places
13695 * @return {String} The formatted currency string
13697 toFixed : function(v, n)
13699 // why not use to fixed - precision is buggered???
13701 return Math.round(v-0);
13703 var fact = Math.pow(10,n+1);
13704 v = (Math.round((v-0)*fact))/fact;
13705 var z = (''+fact).substring(2);
13706 if (v == Math.floor(v)) {
13707 return Math.floor(v) + '.' + z;
13710 // now just padd decimals..
13711 var ps = String(v).split('.');
13712 var fd = (ps[1] + z);
13713 var r = fd.substring(0,n);
13714 var rm = fd.substring(n);
13716 return ps[0] + '.' + r;
13718 r*=1; // turn it into a number;
13720 if (String(r).length != n) {
13723 r = String(r).substring(1); // chop the end off.
13726 return ps[0] + '.' + r;
13731 * Format a number as US currency
13732 * @param {Number/String} value The numeric value to format
13733 * @return {String} The formatted currency string
13735 usMoney : function(v){
13736 return '$' + Roo.util.Format.number(v);
13741 * eventually this should probably emulate php's number_format
13742 * @param {Number/String} value The numeric value to format
13743 * @param {Number} decimals number of decimal places
13744 * @return {String} The formatted currency string
13746 number : function(v,decimals)
13748 // multiply and round.
13749 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13750 var mul = Math.pow(10, decimals);
13751 var zero = String(mul).substring(1);
13752 v = (Math.round((v-0)*mul))/mul;
13754 // if it's '0' number.. then
13756 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13758 var ps = v.split('.');
13762 var r = /(\d+)(\d{3})/;
13764 while (r.test(whole)) {
13765 whole = whole.replace(r, '$1' + ',' + '$2');
13771 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13772 // does not have decimals
13773 (decimals ? ('.' + zero) : '');
13776 return whole + sub ;
13780 * Parse a value into a formatted date using the specified format pattern.
13781 * @param {Mixed} value The value to format
13782 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13783 * @return {String} The formatted date string
13785 date : function(v, format){
13789 if(!(v instanceof Date)){
13790 v = new Date(Date.parse(v));
13792 return v.dateFormat(format || Roo.util.Format.defaults.date);
13796 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13797 * @param {String} format Any valid date format string
13798 * @return {Function} The date formatting function
13800 dateRenderer : function(format){
13801 return function(v){
13802 return Roo.util.Format.date(v, format);
13807 stripTagsRE : /<\/?[^>]+>/gi,
13810 * Strips all HTML tags
13811 * @param {Mixed} value The text from which to strip tags
13812 * @return {String} The stripped text
13814 stripTags : function(v){
13815 return !v ? v : String(v).replace(this.stripTagsRE, "");
13819 Roo.util.Format.defaults = {
13823 * Ext JS Library 1.1.1
13824 * Copyright(c) 2006-2007, Ext JS, LLC.
13826 * Originally Released Under LGPL - original licence link has changed is not relivant.
13829 * <script type="text/javascript">
13836 * @class Roo.MasterTemplate
13837 * @extends Roo.Template
13838 * Provides a template that can have child templates. The syntax is:
13840 var t = new Roo.MasterTemplate(
13841 '<select name="{name}">',
13842 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
13845 t.add('options', {value: 'foo', text: 'bar'});
13846 // or you can add multiple child elements in one shot
13847 t.addAll('options', [
13848 {value: 'foo', text: 'bar'},
13849 {value: 'foo2', text: 'bar2'},
13850 {value: 'foo3', text: 'bar3'}
13852 // then append, applying the master template values
13853 t.append('my-form', {name: 'my-select'});
13855 * A name attribute for the child template is not required if you have only one child
13856 * template or you want to refer to them by index.
13858 Roo.MasterTemplate = function(){
13859 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13860 this.originalHtml = this.html;
13862 var m, re = this.subTemplateRe;
13865 while(m = re.exec(this.html)){
13866 var name = m[1], content = m[2];
13871 tpl : new Roo.Template(content)
13874 st[name] = st[subIndex];
13876 st[subIndex].tpl.compile();
13877 st[subIndex].tpl.call = this.call.createDelegate(this);
13880 this.subCount = subIndex;
13883 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13885 * The regular expression used to match sub templates
13889 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13892 * Applies the passed values to a child template.
13893 * @param {String/Number} name (optional) The name or index of the child template
13894 * @param {Array/Object} values The values to be applied to the template
13895 * @return {MasterTemplate} this
13897 add : function(name, values){
13898 if(arguments.length == 1){
13899 values = arguments[0];
13902 var s = this.subs[name];
13903 s.buffer[s.buffer.length] = s.tpl.apply(values);
13908 * Applies all the passed values to a child template.
13909 * @param {String/Number} name (optional) The name or index of the child template
13910 * @param {Array} values The values to be applied to the template, this should be an array of objects.
13911 * @param {Boolean} reset (optional) True to reset the template first
13912 * @return {MasterTemplate} this
13914 fill : function(name, values, reset){
13916 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13924 for(var i = 0, len = values.length; i < len; i++){
13925 this.add(name, values[i]);
13931 * Resets the template for reuse
13932 * @return {MasterTemplate} this
13934 reset : function(){
13936 for(var i = 0; i < this.subCount; i++){
13942 applyTemplate : function(values){
13944 var replaceIndex = -1;
13945 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13946 return s[++replaceIndex].buffer.join("");
13948 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13951 apply : function(){
13952 return this.applyTemplate.apply(this, arguments);
13955 compile : function(){return this;}
13959 * Alias for fill().
13962 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13964 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13965 * var tpl = Roo.MasterTemplate.from('element-id');
13966 * @param {String/HTMLElement} el
13967 * @param {Object} config
13970 Roo.MasterTemplate.from = function(el, config){
13971 el = Roo.getDom(el);
13972 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13975 * Ext JS Library 1.1.1
13976 * Copyright(c) 2006-2007, Ext JS, LLC.
13978 * Originally Released Under LGPL - original licence link has changed is not relivant.
13981 * <script type="text/javascript">
13986 * @class Roo.util.CSS
13987 * Utility class for manipulating CSS rules
13990 Roo.util.CSS = function(){
13992 var doc = document;
13994 var camelRe = /(-[a-z])/gi;
13995 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13999 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14000 * tag and appended to the HEAD of the document.
14001 * @param {String|Object} cssText The text containing the css rules
14002 * @param {String} id An id to add to the stylesheet for later removal
14003 * @return {StyleSheet}
14005 createStyleSheet : function(cssText, id){
14007 var head = doc.getElementsByTagName("head")[0];
14008 var nrules = doc.createElement("style");
14009 nrules.setAttribute("type", "text/css");
14011 nrules.setAttribute("id", id);
14013 if (typeof(cssText) != 'string') {
14014 // support object maps..
14015 // not sure if this a good idea..
14016 // perhaps it should be merged with the general css handling
14017 // and handle js style props.
14018 var cssTextNew = [];
14019 for(var n in cssText) {
14021 for(var k in cssText[n]) {
14022 citems.push( k + ' : ' +cssText[n][k] + ';' );
14024 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14027 cssText = cssTextNew.join("\n");
14033 head.appendChild(nrules);
14034 ss = nrules.styleSheet;
14035 ss.cssText = cssText;
14038 nrules.appendChild(doc.createTextNode(cssText));
14040 nrules.cssText = cssText;
14042 head.appendChild(nrules);
14043 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14045 this.cacheStyleSheet(ss);
14050 * Removes a style or link tag by id
14051 * @param {String} id The id of the tag
14053 removeStyleSheet : function(id){
14054 var existing = doc.getElementById(id);
14056 existing.parentNode.removeChild(existing);
14061 * Dynamically swaps an existing stylesheet reference for a new one
14062 * @param {String} id The id of an existing link tag to remove
14063 * @param {String} url The href of the new stylesheet to include
14065 swapStyleSheet : function(id, url){
14066 this.removeStyleSheet(id);
14067 var ss = doc.createElement("link");
14068 ss.setAttribute("rel", "stylesheet");
14069 ss.setAttribute("type", "text/css");
14070 ss.setAttribute("id", id);
14071 ss.setAttribute("href", url);
14072 doc.getElementsByTagName("head")[0].appendChild(ss);
14076 * Refresh the rule cache if you have dynamically added stylesheets
14077 * @return {Object} An object (hash) of rules indexed by selector
14079 refreshCache : function(){
14080 return this.getRules(true);
14084 cacheStyleSheet : function(stylesheet){
14088 try{// try catch for cross domain access issue
14089 var ssRules = stylesheet.cssRules || stylesheet.rules;
14090 for(var j = ssRules.length-1; j >= 0; --j){
14091 rules[ssRules[j].selectorText] = ssRules[j];
14097 * Gets all css rules for the document
14098 * @param {Boolean} refreshCache true to refresh the internal cache
14099 * @return {Object} An object (hash) of rules indexed by selector
14101 getRules : function(refreshCache){
14102 if(rules == null || refreshCache){
14104 var ds = doc.styleSheets;
14105 for(var i =0, len = ds.length; i < len; i++){
14107 this.cacheStyleSheet(ds[i]);
14115 * Gets an an individual CSS rule by selector(s)
14116 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14117 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14118 * @return {CSSRule} The CSS rule or null if one is not found
14120 getRule : function(selector, refreshCache){
14121 var rs = this.getRules(refreshCache);
14122 if(!(selector instanceof Array)){
14123 return rs[selector];
14125 for(var i = 0; i < selector.length; i++){
14126 if(rs[selector[i]]){
14127 return rs[selector[i]];
14135 * Updates a rule property
14136 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14137 * @param {String} property The css property
14138 * @param {String} value The new value for the property
14139 * @return {Boolean} true If a rule was found and updated
14141 updateRule : function(selector, property, value){
14142 if(!(selector instanceof Array)){
14143 var rule = this.getRule(selector);
14145 rule.style[property.replace(camelRe, camelFn)] = value;
14149 for(var i = 0; i < selector.length; i++){
14150 if(this.updateRule(selector[i], property, value)){
14160 * Ext JS Library 1.1.1
14161 * Copyright(c) 2006-2007, Ext JS, LLC.
14163 * Originally Released Under LGPL - original licence link has changed is not relivant.
14166 * <script type="text/javascript">
14172 * @class Roo.util.ClickRepeater
14173 * @extends Roo.util.Observable
14175 * A wrapper class which can be applied to any element. Fires a "click" event while the
14176 * mouse is pressed. The interval between firings may be specified in the config but
14177 * defaults to 10 milliseconds.
14179 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14181 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14182 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14183 * Similar to an autorepeat key delay.
14184 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14185 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14186 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14187 * "interval" and "delay" are ignored. "immediate" is honored.
14188 * @cfg {Boolean} preventDefault True to prevent the default click event
14189 * @cfg {Boolean} stopDefault True to stop the default click event
14192 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14193 * 2007-02-02 jvs Renamed to ClickRepeater
14194 * 2007-02-03 jvs Modifications for FF Mac and Safari
14197 * @param {String/HTMLElement/Element} el The element to listen on
14198 * @param {Object} config
14200 Roo.util.ClickRepeater = function(el, config)
14202 this.el = Roo.get(el);
14203 this.el.unselectable();
14205 Roo.apply(this, config);
14210 * Fires when the mouse button is depressed.
14211 * @param {Roo.util.ClickRepeater} this
14213 "mousedown" : true,
14216 * Fires on a specified interval during the time the element is pressed.
14217 * @param {Roo.util.ClickRepeater} this
14222 * Fires when the mouse key is released.
14223 * @param {Roo.util.ClickRepeater} this
14228 this.el.on("mousedown", this.handleMouseDown, this);
14229 if(this.preventDefault || this.stopDefault){
14230 this.el.on("click", function(e){
14231 if(this.preventDefault){
14232 e.preventDefault();
14234 if(this.stopDefault){
14240 // allow inline handler
14242 this.on("click", this.handler, this.scope || this);
14245 Roo.util.ClickRepeater.superclass.constructor.call(this);
14248 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14251 preventDefault : true,
14252 stopDefault : false,
14256 handleMouseDown : function(){
14257 clearTimeout(this.timer);
14259 if(this.pressClass){
14260 this.el.addClass(this.pressClass);
14262 this.mousedownTime = new Date();
14264 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14265 this.el.on("mouseout", this.handleMouseOut, this);
14267 this.fireEvent("mousedown", this);
14268 this.fireEvent("click", this);
14270 this.timer = this.click.defer(this.delay || this.interval, this);
14274 click : function(){
14275 this.fireEvent("click", this);
14276 this.timer = this.click.defer(this.getInterval(), this);
14280 getInterval: function(){
14281 if(!this.accelerate){
14282 return this.interval;
14284 var pressTime = this.mousedownTime.getElapsed();
14285 if(pressTime < 500){
14287 }else if(pressTime < 1700){
14289 }else if(pressTime < 2600){
14291 }else if(pressTime < 3500){
14293 }else if(pressTime < 4400){
14295 }else if(pressTime < 5300){
14297 }else if(pressTime < 6200){
14305 handleMouseOut : function(){
14306 clearTimeout(this.timer);
14307 if(this.pressClass){
14308 this.el.removeClass(this.pressClass);
14310 this.el.on("mouseover", this.handleMouseReturn, this);
14314 handleMouseReturn : function(){
14315 this.el.un("mouseover", this.handleMouseReturn);
14316 if(this.pressClass){
14317 this.el.addClass(this.pressClass);
14323 handleMouseUp : function(){
14324 clearTimeout(this.timer);
14325 this.el.un("mouseover", this.handleMouseReturn);
14326 this.el.un("mouseout", this.handleMouseOut);
14327 Roo.get(document).un("mouseup", this.handleMouseUp);
14328 this.el.removeClass(this.pressClass);
14329 this.fireEvent("mouseup", this);
14333 * Ext JS Library 1.1.1
14334 * Copyright(c) 2006-2007, Ext JS, LLC.
14336 * Originally Released Under LGPL - original licence link has changed is not relivant.
14339 * <script type="text/javascript">
14344 * @class Roo.KeyNav
14345 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14346 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14347 * way to implement custom navigation schemes for any UI component.</p>
14348 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14349 * pageUp, pageDown, del, home, end. Usage:</p>
14351 var nav = new Roo.KeyNav("my-element", {
14352 "left" : function(e){
14353 this.moveLeft(e.ctrlKey);
14355 "right" : function(e){
14356 this.moveRight(e.ctrlKey);
14358 "enter" : function(e){
14365 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14366 * @param {Object} config The config
14368 Roo.KeyNav = function(el, config){
14369 this.el = Roo.get(el);
14370 Roo.apply(this, config);
14371 if(!this.disabled){
14372 this.disabled = true;
14377 Roo.KeyNav.prototype = {
14379 * @cfg {Boolean} disabled
14380 * True to disable this KeyNav instance (defaults to false)
14384 * @cfg {String} defaultEventAction
14385 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14386 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14387 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14389 defaultEventAction: "stopEvent",
14391 * @cfg {Boolean} forceKeyDown
14392 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14393 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14394 * handle keydown instead of keypress.
14396 forceKeyDown : false,
14399 prepareEvent : function(e){
14400 var k = e.getKey();
14401 var h = this.keyToHandler[k];
14402 //if(h && this[h]){
14403 // e.stopPropagation();
14405 if(Roo.isSafari && h && k >= 37 && k <= 40){
14411 relay : function(e){
14412 var k = e.getKey();
14413 var h = this.keyToHandler[k];
14415 if(this.doRelay(e, this[h], h) !== true){
14416 e[this.defaultEventAction]();
14422 doRelay : function(e, h, hname){
14423 return h.call(this.scope || this, e);
14426 // possible handlers
14440 // quick lookup hash
14457 * Enable this KeyNav
14459 enable: function(){
14461 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14462 // the EventObject will normalize Safari automatically
14463 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14464 this.el.on("keydown", this.relay, this);
14466 this.el.on("keydown", this.prepareEvent, this);
14467 this.el.on("keypress", this.relay, this);
14469 this.disabled = false;
14474 * Disable this KeyNav
14476 disable: function(){
14477 if(!this.disabled){
14478 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14479 this.el.un("keydown", this.relay);
14481 this.el.un("keydown", this.prepareEvent);
14482 this.el.un("keypress", this.relay);
14484 this.disabled = true;
14489 * Ext JS Library 1.1.1
14490 * Copyright(c) 2006-2007, Ext JS, LLC.
14492 * Originally Released Under LGPL - original licence link has changed is not relivant.
14495 * <script type="text/javascript">
14500 * @class Roo.KeyMap
14501 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14502 * The constructor accepts the same config object as defined by {@link #addBinding}.
14503 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14504 * combination it will call the function with this signature (if the match is a multi-key
14505 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14506 * A KeyMap can also handle a string representation of keys.<br />
14509 // map one key by key code
14510 var map = new Roo.KeyMap("my-element", {
14511 key: 13, // or Roo.EventObject.ENTER
14516 // map multiple keys to one action by string
14517 var map = new Roo.KeyMap("my-element", {
14523 // map multiple keys to multiple actions by strings and array of codes
14524 var map = new Roo.KeyMap("my-element", [
14527 fn: function(){ alert("Return was pressed"); }
14530 fn: function(){ alert('a, b or c was pressed'); }
14535 fn: function(){ alert('Control + shift + tab was pressed.'); }
14539 * <b>Note: A KeyMap starts enabled</b>
14541 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14542 * @param {Object} config The config (see {@link #addBinding})
14543 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14545 Roo.KeyMap = function(el, config, eventName){
14546 this.el = Roo.get(el);
14547 this.eventName = eventName || "keydown";
14548 this.bindings = [];
14550 this.addBinding(config);
14555 Roo.KeyMap.prototype = {
14557 * True to stop the event from bubbling and prevent the default browser action if the
14558 * key was handled by the KeyMap (defaults to false)
14564 * Add a new binding to this KeyMap. The following config object properties are supported:
14566 Property Type Description
14567 ---------- --------------- ----------------------------------------------------------------------
14568 key String/Array A single keycode or an array of keycodes to handle
14569 shift Boolean True to handle key only when shift is pressed (defaults to false)
14570 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14571 alt Boolean True to handle key only when alt is pressed (defaults to false)
14572 fn Function The function to call when KeyMap finds the expected key combination
14573 scope Object The scope of the callback function
14579 var map = new Roo.KeyMap(document, {
14580 key: Roo.EventObject.ENTER,
14585 //Add a new binding to the existing KeyMap later
14593 * @param {Object/Array} config A single KeyMap config or an array of configs
14595 addBinding : function(config){
14596 if(config instanceof Array){
14597 for(var i = 0, len = config.length; i < len; i++){
14598 this.addBinding(config[i]);
14602 var keyCode = config.key,
14603 shift = config.shift,
14604 ctrl = config.ctrl,
14607 scope = config.scope;
14608 if(typeof keyCode == "string"){
14610 var keyString = keyCode.toUpperCase();
14611 for(var j = 0, len = keyString.length; j < len; j++){
14612 ks.push(keyString.charCodeAt(j));
14616 var keyArray = keyCode instanceof Array;
14617 var handler = function(e){
14618 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14619 var k = e.getKey();
14621 for(var i = 0, len = keyCode.length; i < len; i++){
14622 if(keyCode[i] == k){
14623 if(this.stopEvent){
14626 fn.call(scope || window, k, e);
14632 if(this.stopEvent){
14635 fn.call(scope || window, k, e);
14640 this.bindings.push(handler);
14644 * Shorthand for adding a single key listener
14645 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14646 * following options:
14647 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14648 * @param {Function} fn The function to call
14649 * @param {Object} scope (optional) The scope of the function
14651 on : function(key, fn, scope){
14652 var keyCode, shift, ctrl, alt;
14653 if(typeof key == "object" && !(key instanceof Array)){
14672 handleKeyDown : function(e){
14673 if(this.enabled){ //just in case
14674 var b = this.bindings;
14675 for(var i = 0, len = b.length; i < len; i++){
14676 b[i].call(this, e);
14682 * Returns true if this KeyMap is enabled
14683 * @return {Boolean}
14685 isEnabled : function(){
14686 return this.enabled;
14690 * Enables this KeyMap
14692 enable: function(){
14694 this.el.on(this.eventName, this.handleKeyDown, this);
14695 this.enabled = true;
14700 * Disable this KeyMap
14702 disable: function(){
14704 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14705 this.enabled = false;
14710 * Ext JS Library 1.1.1
14711 * Copyright(c) 2006-2007, Ext JS, LLC.
14713 * Originally Released Under LGPL - original licence link has changed is not relivant.
14716 * <script type="text/javascript">
14721 * @class Roo.util.TextMetrics
14722 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14723 * wide, in pixels, a given block of text will be.
14726 Roo.util.TextMetrics = function(){
14730 * Measures the size of the specified text
14731 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14732 * that can affect the size of the rendered text
14733 * @param {String} text The text to measure
14734 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14735 * in order to accurately measure the text height
14736 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14738 measure : function(el, text, fixedWidth){
14740 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14743 shared.setFixedWidth(fixedWidth || 'auto');
14744 return shared.getSize(text);
14748 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
14749 * the overhead of multiple calls to initialize the style properties on each measurement.
14750 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14751 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14752 * in order to accurately measure the text height
14753 * @return {Roo.util.TextMetrics.Instance} instance The new instance
14755 createInstance : function(el, fixedWidth){
14756 return Roo.util.TextMetrics.Instance(el, fixedWidth);
14763 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14764 var ml = new Roo.Element(document.createElement('div'));
14765 document.body.appendChild(ml.dom);
14766 ml.position('absolute');
14767 ml.setLeftTop(-1000, -1000);
14771 ml.setWidth(fixedWidth);
14776 * Returns the size of the specified text based on the internal element's style and width properties
14777 * @memberOf Roo.util.TextMetrics.Instance#
14778 * @param {String} text The text to measure
14779 * @return {Object} An object containing the text's size {width: (width), height: (height)}
14781 getSize : function(text){
14783 var s = ml.getSize();
14789 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14790 * that can affect the size of the rendered text
14791 * @memberOf Roo.util.TextMetrics.Instance#
14792 * @param {String/HTMLElement} el The element, dom node or id
14794 bind : function(el){
14796 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14801 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
14802 * to set a fixed width in order to accurately measure the text height.
14803 * @memberOf Roo.util.TextMetrics.Instance#
14804 * @param {Number} width The width to set on the element
14806 setFixedWidth : function(width){
14807 ml.setWidth(width);
14811 * Returns the measured width of the specified text
14812 * @memberOf Roo.util.TextMetrics.Instance#
14813 * @param {String} text The text to measure
14814 * @return {Number} width The width in pixels
14816 getWidth : function(text){
14817 ml.dom.style.width = 'auto';
14818 return this.getSize(text).width;
14822 * Returns the measured height of the specified text. For multiline text, be sure to call
14823 * {@link #setFixedWidth} if necessary.
14824 * @memberOf Roo.util.TextMetrics.Instance#
14825 * @param {String} text The text to measure
14826 * @return {Number} height The height in pixels
14828 getHeight : function(text){
14829 return this.getSize(text).height;
14833 instance.bind(bindTo);
14838 // backwards compat
14839 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14841 * Ext JS Library 1.1.1
14842 * Copyright(c) 2006-2007, Ext JS, LLC.
14844 * Originally Released Under LGPL - original licence link has changed is not relivant.
14847 * <script type="text/javascript">
14851 * @class Roo.state.Provider
14852 * Abstract base class for state provider implementations. This class provides methods
14853 * for encoding and decoding <b>typed</b> variables including dates and defines the
14854 * Provider interface.
14856 Roo.state.Provider = function(){
14858 * @event statechange
14859 * Fires when a state change occurs.
14860 * @param {Provider} this This state provider
14861 * @param {String} key The state key which was changed
14862 * @param {String} value The encoded value for the state
14865 "statechange": true
14868 Roo.state.Provider.superclass.constructor.call(this);
14870 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14872 * Returns the current value for a key
14873 * @param {String} name The key name
14874 * @param {Mixed} defaultValue A default value to return if the key's value is not found
14875 * @return {Mixed} The state data
14877 get : function(name, defaultValue){
14878 return typeof this.state[name] == "undefined" ?
14879 defaultValue : this.state[name];
14883 * Clears a value from the state
14884 * @param {String} name The key name
14886 clear : function(name){
14887 delete this.state[name];
14888 this.fireEvent("statechange", this, name, null);
14892 * Sets the value for a key
14893 * @param {String} name The key name
14894 * @param {Mixed} value The value to set
14896 set : function(name, value){
14897 this.state[name] = value;
14898 this.fireEvent("statechange", this, name, value);
14902 * Decodes a string previously encoded with {@link #encodeValue}.
14903 * @param {String} value The value to decode
14904 * @return {Mixed} The decoded value
14906 decodeValue : function(cookie){
14907 var re = /^(a|n|d|b|s|o)\:(.*)$/;
14908 var matches = re.exec(unescape(cookie));
14909 if(!matches || !matches[1]) {
14910 return; // non state cookie
14912 var type = matches[1];
14913 var v = matches[2];
14916 return parseFloat(v);
14918 return new Date(Date.parse(v));
14923 var values = v.split("^");
14924 for(var i = 0, len = values.length; i < len; i++){
14925 all.push(this.decodeValue(values[i]));
14930 var values = v.split("^");
14931 for(var i = 0, len = values.length; i < len; i++){
14932 var kv = values[i].split("=");
14933 all[kv[0]] = this.decodeValue(kv[1]);
14942 * Encodes a value including type information. Decode with {@link #decodeValue}.
14943 * @param {Mixed} value The value to encode
14944 * @return {String} The encoded value
14946 encodeValue : function(v){
14948 if(typeof v == "number"){
14950 }else if(typeof v == "boolean"){
14951 enc = "b:" + (v ? "1" : "0");
14952 }else if(v instanceof Date){
14953 enc = "d:" + v.toGMTString();
14954 }else if(v instanceof Array){
14956 for(var i = 0, len = v.length; i < len; i++){
14957 flat += this.encodeValue(v[i]);
14963 }else if(typeof v == "object"){
14966 if(typeof v[key] != "function"){
14967 flat += key + "=" + this.encodeValue(v[key]) + "^";
14970 enc = "o:" + flat.substring(0, flat.length-1);
14974 return escape(enc);
14980 * Ext JS Library 1.1.1
14981 * Copyright(c) 2006-2007, Ext JS, LLC.
14983 * Originally Released Under LGPL - original licence link has changed is not relivant.
14986 * <script type="text/javascript">
14989 * @class Roo.state.Manager
14990 * This is the global state manager. By default all components that are "state aware" check this class
14991 * for state information if you don't pass them a custom state provider. In order for this class
14992 * to be useful, it must be initialized with a provider when your application initializes.
14994 // in your initialization function
14996 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14998 // supposed you have a {@link Roo.BorderLayout}
14999 var layout = new Roo.BorderLayout(...);
15000 layout.restoreState();
15001 // or a {Roo.BasicDialog}
15002 var dialog = new Roo.BasicDialog(...);
15003 dialog.restoreState();
15007 Roo.state.Manager = function(){
15008 var provider = new Roo.state.Provider();
15012 * Configures the default state provider for your application
15013 * @param {Provider} stateProvider The state provider to set
15015 setProvider : function(stateProvider){
15016 provider = stateProvider;
15020 * Returns the current value for a key
15021 * @param {String} name The key name
15022 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15023 * @return {Mixed} The state data
15025 get : function(key, defaultValue){
15026 return provider.get(key, defaultValue);
15030 * Sets the value for a key
15031 * @param {String} name The key name
15032 * @param {Mixed} value The state data
15034 set : function(key, value){
15035 provider.set(key, value);
15039 * Clears a value from the state
15040 * @param {String} name The key name
15042 clear : function(key){
15043 provider.clear(key);
15047 * Gets the currently configured state provider
15048 * @return {Provider} The state provider
15050 getProvider : function(){
15057 * Ext JS Library 1.1.1
15058 * Copyright(c) 2006-2007, Ext JS, LLC.
15060 * Originally Released Under LGPL - original licence link has changed is not relivant.
15063 * <script type="text/javascript">
15066 * @class Roo.state.CookieProvider
15067 * @extends Roo.state.Provider
15068 * The default Provider implementation which saves state via cookies.
15071 var cp = new Roo.state.CookieProvider({
15073 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15074 domain: "roojs.com"
15076 Roo.state.Manager.setProvider(cp);
15078 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15079 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15080 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15081 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15082 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15083 * domain the page is running on including the 'www' like 'www.roojs.com')
15084 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15086 * Create a new CookieProvider
15087 * @param {Object} config The configuration object
15089 Roo.state.CookieProvider = function(config){
15090 Roo.state.CookieProvider.superclass.constructor.call(this);
15092 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15093 this.domain = null;
15094 this.secure = false;
15095 Roo.apply(this, config);
15096 this.state = this.readCookies();
15099 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15101 set : function(name, value){
15102 if(typeof value == "undefined" || value === null){
15106 this.setCookie(name, value);
15107 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15111 clear : function(name){
15112 this.clearCookie(name);
15113 Roo.state.CookieProvider.superclass.clear.call(this, name);
15117 readCookies : function(){
15119 var c = document.cookie + ";";
15120 var re = /\s?(.*?)=(.*?);/g;
15122 while((matches = re.exec(c)) != null){
15123 var name = matches[1];
15124 var value = matches[2];
15125 if(name && name.substring(0,3) == "ys-"){
15126 cookies[name.substr(3)] = this.decodeValue(value);
15133 setCookie : function(name, value){
15134 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15135 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15136 ((this.path == null) ? "" : ("; path=" + this.path)) +
15137 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15138 ((this.secure == true) ? "; secure" : "");
15142 clearCookie : function(name){
15143 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15144 ((this.path == null) ? "" : ("; path=" + this.path)) +
15145 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15146 ((this.secure == true) ? "; secure" : "");
15150 * Ext JS Library 1.1.1
15151 * Copyright(c) 2006-2007, Ext JS, LLC.
15153 * Originally Released Under LGPL - original licence link has changed is not relivant.
15156 * <script type="text/javascript">
15161 * @class Roo.ComponentMgr
15162 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15165 Roo.ComponentMgr = function(){
15166 var all = new Roo.util.MixedCollection();
15170 * Registers a component.
15171 * @param {Roo.Component} c The component
15173 register : function(c){
15178 * Unregisters a component.
15179 * @param {Roo.Component} c The component
15181 unregister : function(c){
15186 * Returns a component by id
15187 * @param {String} id The component id
15189 get : function(id){
15190 return all.get(id);
15194 * Registers a function that will be called when a specified component is added to ComponentMgr
15195 * @param {String} id The component id
15196 * @param {Funtction} fn The callback function
15197 * @param {Object} scope The scope of the callback
15199 onAvailable : function(id, fn, scope){
15200 all.on("add", function(index, o){
15202 fn.call(scope || o, o);
15203 all.un("add", fn, scope);
15210 * Ext JS Library 1.1.1
15211 * Copyright(c) 2006-2007, Ext JS, LLC.
15213 * Originally Released Under LGPL - original licence link has changed is not relivant.
15216 * <script type="text/javascript">
15220 * @class Roo.Component
15221 * @extends Roo.util.Observable
15222 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15223 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15224 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15225 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15226 * All visual components (widgets) that require rendering into a layout should subclass Component.
15228 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15229 * 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
15230 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15232 Roo.Component = function(config){
15233 config = config || {};
15234 if(config.tagName || config.dom || typeof config == "string"){ // element object
15235 config = {el: config, id: config.id || config};
15237 this.initialConfig = config;
15239 Roo.apply(this, config);
15243 * Fires after the component is disabled.
15244 * @param {Roo.Component} this
15249 * Fires after the component is enabled.
15250 * @param {Roo.Component} this
15254 * @event beforeshow
15255 * Fires before the component is shown. Return false to stop the show.
15256 * @param {Roo.Component} this
15261 * Fires after the component is shown.
15262 * @param {Roo.Component} this
15266 * @event beforehide
15267 * Fires before the component is hidden. Return false to stop the hide.
15268 * @param {Roo.Component} this
15273 * Fires after the component is hidden.
15274 * @param {Roo.Component} this
15278 * @event beforerender
15279 * Fires before the component is rendered. Return false to stop the render.
15280 * @param {Roo.Component} this
15282 beforerender : true,
15285 * Fires after the component is rendered.
15286 * @param {Roo.Component} this
15290 * @event beforedestroy
15291 * Fires before the component is destroyed. Return false to stop the destroy.
15292 * @param {Roo.Component} this
15294 beforedestroy : true,
15297 * Fires after the component is destroyed.
15298 * @param {Roo.Component} this
15303 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15305 Roo.ComponentMgr.register(this);
15306 Roo.Component.superclass.constructor.call(this);
15307 this.initComponent();
15308 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15309 this.render(this.renderTo);
15310 delete this.renderTo;
15315 Roo.Component.AUTO_ID = 1000;
15317 Roo.extend(Roo.Component, Roo.util.Observable, {
15319 * @scope Roo.Component.prototype
15321 * true if this component is hidden. Read-only.
15326 * true if this component is disabled. Read-only.
15331 * true if this component has been rendered. Read-only.
15335 /** @cfg {String} disableClass
15336 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15338 disabledClass : "x-item-disabled",
15339 /** @cfg {Boolean} allowDomMove
15340 * Whether the component can move the Dom node when rendering (defaults to true).
15342 allowDomMove : true,
15343 /** @cfg {String} hideMode (display|visibility)
15344 * How this component should hidden. Supported values are
15345 * "visibility" (css visibility), "offsets" (negative offset position) and
15346 * "display" (css display) - defaults to "display".
15348 hideMode: 'display',
15351 ctype : "Roo.Component",
15354 * @cfg {String} actionMode
15355 * which property holds the element that used for hide() / show() / disable() / enable()
15361 getActionEl : function(){
15362 return this[this.actionMode];
15365 initComponent : Roo.emptyFn,
15367 * If this is a lazy rendering component, render it to its container element.
15368 * @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.
15370 render : function(container, position){
15371 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15372 if(!container && this.el){
15373 this.el = Roo.get(this.el);
15374 container = this.el.dom.parentNode;
15375 this.allowDomMove = false;
15377 this.container = Roo.get(container);
15378 this.rendered = true;
15379 if(position !== undefined){
15380 if(typeof position == 'number'){
15381 position = this.container.dom.childNodes[position];
15383 position = Roo.getDom(position);
15386 this.onRender(this.container, position || null);
15388 this.el.addClass(this.cls);
15392 this.el.applyStyles(this.style);
15395 this.fireEvent("render", this);
15396 this.afterRender(this.container);
15408 // default function is not really useful
15409 onRender : function(ct, position){
15411 this.el = Roo.get(this.el);
15412 if(this.allowDomMove !== false){
15413 ct.dom.insertBefore(this.el.dom, position);
15419 getAutoCreate : function(){
15420 var cfg = typeof this.autoCreate == "object" ?
15421 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15422 if(this.id && !cfg.id){
15429 afterRender : Roo.emptyFn,
15432 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15433 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15435 destroy : function(){
15436 if(this.fireEvent("beforedestroy", this) !== false){
15437 this.purgeListeners();
15438 this.beforeDestroy();
15440 this.el.removeAllListeners();
15442 if(this.actionMode == "container"){
15443 this.container.remove();
15447 Roo.ComponentMgr.unregister(this);
15448 this.fireEvent("destroy", this);
15453 beforeDestroy : function(){
15458 onDestroy : function(){
15463 * Returns the underlying {@link Roo.Element}.
15464 * @return {Roo.Element} The element
15466 getEl : function(){
15471 * Returns the id of this component.
15474 getId : function(){
15479 * Try to focus this component.
15480 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15481 * @return {Roo.Component} this
15483 focus : function(selectText){
15486 if(selectText === true){
15487 this.el.dom.select();
15502 * Disable this component.
15503 * @return {Roo.Component} this
15505 disable : function(){
15509 this.disabled = true;
15510 this.fireEvent("disable", this);
15515 onDisable : function(){
15516 this.getActionEl().addClass(this.disabledClass);
15517 this.el.dom.disabled = true;
15521 * Enable this component.
15522 * @return {Roo.Component} this
15524 enable : function(){
15528 this.disabled = false;
15529 this.fireEvent("enable", this);
15534 onEnable : function(){
15535 this.getActionEl().removeClass(this.disabledClass);
15536 this.el.dom.disabled = false;
15540 * Convenience function for setting disabled/enabled by boolean.
15541 * @param {Boolean} disabled
15543 setDisabled : function(disabled){
15544 this[disabled ? "disable" : "enable"]();
15548 * Show this component.
15549 * @return {Roo.Component} this
15552 if(this.fireEvent("beforeshow", this) !== false){
15553 this.hidden = false;
15557 this.fireEvent("show", this);
15563 onShow : function(){
15564 var ae = this.getActionEl();
15565 if(this.hideMode == 'visibility'){
15566 ae.dom.style.visibility = "visible";
15567 }else if(this.hideMode == 'offsets'){
15568 ae.removeClass('x-hidden');
15570 ae.dom.style.display = "";
15575 * Hide this component.
15576 * @return {Roo.Component} this
15579 if(this.fireEvent("beforehide", this) !== false){
15580 this.hidden = true;
15584 this.fireEvent("hide", this);
15590 onHide : function(){
15591 var ae = this.getActionEl();
15592 if(this.hideMode == 'visibility'){
15593 ae.dom.style.visibility = "hidden";
15594 }else if(this.hideMode == 'offsets'){
15595 ae.addClass('x-hidden');
15597 ae.dom.style.display = "none";
15602 * Convenience function to hide or show this component by boolean.
15603 * @param {Boolean} visible True to show, false to hide
15604 * @return {Roo.Component} this
15606 setVisible: function(visible){
15616 * Returns true if this component is visible.
15618 isVisible : function(){
15619 return this.getActionEl().isVisible();
15622 cloneConfig : function(overrides){
15623 overrides = overrides || {};
15624 var id = overrides.id || Roo.id();
15625 var cfg = Roo.applyIf(overrides, this.initialConfig);
15626 cfg.id = id; // prevent dup id
15627 return new this.constructor(cfg);
15631 * Ext JS Library 1.1.1
15632 * Copyright(c) 2006-2007, Ext JS, LLC.
15634 * Originally Released Under LGPL - original licence link has changed is not relivant.
15637 * <script type="text/javascript">
15641 * @class Roo.BoxComponent
15642 * @extends Roo.Component
15643 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15644 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15645 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15646 * layout containers.
15648 * @param {Roo.Element/String/Object} config The configuration options.
15650 Roo.BoxComponent = function(config){
15651 Roo.Component.call(this, config);
15655 * Fires after the component is resized.
15656 * @param {Roo.Component} this
15657 * @param {Number} adjWidth The box-adjusted width that was set
15658 * @param {Number} adjHeight The box-adjusted height that was set
15659 * @param {Number} rawWidth The width that was originally specified
15660 * @param {Number} rawHeight The height that was originally specified
15665 * Fires after the component is moved.
15666 * @param {Roo.Component} this
15667 * @param {Number} x The new x position
15668 * @param {Number} y The new y position
15674 Roo.extend(Roo.BoxComponent, Roo.Component, {
15675 // private, set in afterRender to signify that the component has been rendered
15677 // private, used to defer height settings to subclasses
15678 deferHeight: false,
15679 /** @cfg {Number} width
15680 * width (optional) size of component
15682 /** @cfg {Number} height
15683 * height (optional) size of component
15687 * Sets the width and height of the component. This method fires the resize event. This method can accept
15688 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15689 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15690 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15691 * @return {Roo.BoxComponent} this
15693 setSize : function(w, h){
15694 // support for standard size objects
15695 if(typeof w == 'object'){
15700 if(!this.boxReady){
15706 // prevent recalcs when not needed
15707 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15710 this.lastSize = {width: w, height: h};
15712 var adj = this.adjustSize(w, h);
15713 var aw = adj.width, ah = adj.height;
15714 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15715 var rz = this.getResizeEl();
15716 if(!this.deferHeight && aw !== undefined && ah !== undefined){
15717 rz.setSize(aw, ah);
15718 }else if(!this.deferHeight && ah !== undefined){
15720 }else if(aw !== undefined){
15723 this.onResize(aw, ah, w, h);
15724 this.fireEvent('resize', this, aw, ah, w, h);
15730 * Gets the current size of the component's underlying element.
15731 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15733 getSize : function(){
15734 return this.el.getSize();
15738 * Gets the current XY position of the component's underlying element.
15739 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15740 * @return {Array} The XY position of the element (e.g., [100, 200])
15742 getPosition : function(local){
15743 if(local === true){
15744 return [this.el.getLeft(true), this.el.getTop(true)];
15746 return this.xy || this.el.getXY();
15750 * Gets the current box measurements of the component's underlying element.
15751 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15752 * @returns {Object} box An object in the format {x, y, width, height}
15754 getBox : function(local){
15755 var s = this.el.getSize();
15757 s.x = this.el.getLeft(true);
15758 s.y = this.el.getTop(true);
15760 var xy = this.xy || this.el.getXY();
15768 * Sets the current box measurements of the component's underlying element.
15769 * @param {Object} box An object in the format {x, y, width, height}
15770 * @returns {Roo.BoxComponent} this
15772 updateBox : function(box){
15773 this.setSize(box.width, box.height);
15774 this.setPagePosition(box.x, box.y);
15779 getResizeEl : function(){
15780 return this.resizeEl || this.el;
15784 getPositionEl : function(){
15785 return this.positionEl || this.el;
15789 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
15790 * This method fires the move event.
15791 * @param {Number} left The new left
15792 * @param {Number} top The new top
15793 * @returns {Roo.BoxComponent} this
15795 setPosition : function(x, y){
15798 if(!this.boxReady){
15801 var adj = this.adjustPosition(x, y);
15802 var ax = adj.x, ay = adj.y;
15804 var el = this.getPositionEl();
15805 if(ax !== undefined || ay !== undefined){
15806 if(ax !== undefined && ay !== undefined){
15807 el.setLeftTop(ax, ay);
15808 }else if(ax !== undefined){
15810 }else if(ay !== undefined){
15813 this.onPosition(ax, ay);
15814 this.fireEvent('move', this, ax, ay);
15820 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
15821 * This method fires the move event.
15822 * @param {Number} x The new x position
15823 * @param {Number} y The new y position
15824 * @returns {Roo.BoxComponent} this
15826 setPagePosition : function(x, y){
15829 if(!this.boxReady){
15832 if(x === undefined || y === undefined){ // cannot translate undefined points
15835 var p = this.el.translatePoints(x, y);
15836 this.setPosition(p.left, p.top);
15841 onRender : function(ct, position){
15842 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15844 this.resizeEl = Roo.get(this.resizeEl);
15846 if(this.positionEl){
15847 this.positionEl = Roo.get(this.positionEl);
15852 afterRender : function(){
15853 Roo.BoxComponent.superclass.afterRender.call(this);
15854 this.boxReady = true;
15855 this.setSize(this.width, this.height);
15856 if(this.x || this.y){
15857 this.setPosition(this.x, this.y);
15859 if(this.pageX || this.pageY){
15860 this.setPagePosition(this.pageX, this.pageY);
15865 * Force the component's size to recalculate based on the underlying element's current height and width.
15866 * @returns {Roo.BoxComponent} this
15868 syncSize : function(){
15869 delete this.lastSize;
15870 this.setSize(this.el.getWidth(), this.el.getHeight());
15875 * Called after the component is resized, this method is empty by default but can be implemented by any
15876 * subclass that needs to perform custom logic after a resize occurs.
15877 * @param {Number} adjWidth The box-adjusted width that was set
15878 * @param {Number} adjHeight The box-adjusted height that was set
15879 * @param {Number} rawWidth The width that was originally specified
15880 * @param {Number} rawHeight The height that was originally specified
15882 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15887 * Called after the component is moved, this method is empty by default but can be implemented by any
15888 * subclass that needs to perform custom logic after a move occurs.
15889 * @param {Number} x The new x position
15890 * @param {Number} y The new y position
15892 onPosition : function(x, y){
15897 adjustSize : function(w, h){
15898 if(this.autoWidth){
15901 if(this.autoHeight){
15904 return {width : w, height: h};
15908 adjustPosition : function(x, y){
15909 return {x : x, y: y};
15912 * Original code for Roojs - LGPL
15913 * <script type="text/javascript">
15917 * @class Roo.XComponent
15918 * A delayed Element creator...
15919 * Or a way to group chunks of interface together.
15920 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15921 * used in conjunction with XComponent.build() it will create an instance of each element,
15922 * then call addxtype() to build the User interface.
15924 * Mypart.xyx = new Roo.XComponent({
15926 parent : 'Mypart.xyz', // empty == document.element.!!
15930 disabled : function() {}
15932 tree : function() { // return an tree of xtype declared components
15936 xtype : 'NestedLayoutPanel',
15943 * It can be used to build a big heiracy, with parent etc.
15944 * or you can just use this to render a single compoent to a dom element
15945 * MYPART.render(Roo.Element | String(id) | dom_element )
15952 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15953 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15955 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15957 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15958 * - if mulitple topModules exist, the last one is defined as the top module.
15962 * When the top level or multiple modules are to embedded into a existing HTML page,
15963 * the parent element can container '#id' of the element where the module will be drawn.
15967 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15968 * it relies more on a include mechanism, where sub modules are included into an outer page.
15969 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15971 * Bootstrap Roo Included elements
15973 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15974 * hence confusing the component builder as it thinks there are multiple top level elements.
15978 * @extends Roo.util.Observable
15980 * @param cfg {Object} configuration of component
15983 Roo.XComponent = function(cfg) {
15984 Roo.apply(this, cfg);
15988 * Fires when this the componnt is built
15989 * @param {Roo.XComponent} c the component
15994 this.region = this.region || 'center'; // default..
15995 Roo.XComponent.register(this);
15996 this.modules = false;
15997 this.el = false; // where the layout goes..
16001 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16004 * The created element (with Roo.factory())
16005 * @type {Roo.Layout}
16011 * for BC - use el in new code
16012 * @type {Roo.Layout}
16018 * for BC - use el in new code
16019 * @type {Roo.Layout}
16024 * @cfg {Function|boolean} disabled
16025 * If this module is disabled by some rule, return true from the funtion
16030 * @cfg {String} parent
16031 * Name of parent element which it get xtype added to..
16036 * @cfg {String} order
16037 * Used to set the order in which elements are created (usefull for multiple tabs)
16042 * @cfg {String} name
16043 * String to display while loading.
16047 * @cfg {String} region
16048 * Region to render component to (defaults to center)
16053 * @cfg {Array} items
16054 * A single item array - the first element is the root of the tree..
16055 * It's done this way to stay compatible with the Xtype system...
16061 * The method that retuns the tree of parts that make up this compoennt
16068 * render element to dom or tree
16069 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16072 render : function(el)
16076 var hp = this.parent ? 1 : 0;
16077 Roo.debug && Roo.log(this);
16079 var tree = this._tree ? this._tree() : this.tree();
16082 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16083 // if parent is a '#.....' string, then let's use that..
16084 var ename = this.parent.substr(1);
16085 this.parent = false;
16086 Roo.debug && Roo.log(ename);
16088 case 'bootstrap-body':
16089 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16090 // this is the BorderLayout standard?
16091 this.parent = { el : true };
16094 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16095 // need to insert stuff...
16097 el : new Roo.bootstrap.layout.Border({
16098 el : document.body,
16104 tabPosition: 'top',
16105 //resizeTabs: true,
16106 alwaysShowTabs: true,
16116 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16117 this.parent = { el : new Roo.bootstrap.Body() };
16118 Roo.debug && Roo.log("setting el to doc body");
16121 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16125 this.parent = { el : true};
16128 el = Roo.get(ename);
16129 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16130 this.parent = { el : true};
16137 if (!el && !this.parent) {
16138 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16143 Roo.debug && Roo.log("EL:");
16144 Roo.debug && Roo.log(el);
16145 Roo.debug && Roo.log("this.parent.el:");
16146 Roo.debug && Roo.log(this.parent.el);
16149 // altertive root elements ??? - we need a better way to indicate these.
16150 var is_alt = Roo.XComponent.is_alt ||
16151 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16152 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16153 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16157 if (!this.parent && is_alt) {
16158 //el = Roo.get(document.body);
16159 this.parent = { el : true };
16164 if (!this.parent) {
16166 Roo.debug && Roo.log("no parent - creating one");
16168 el = el ? Roo.get(el) : false;
16170 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16173 el : new Roo.bootstrap.layout.Border({
16174 el: el || document.body,
16180 tabPosition: 'top',
16181 //resizeTabs: true,
16182 alwaysShowTabs: false,
16185 overflow: 'visible'
16191 // it's a top level one..
16193 el : new Roo.BorderLayout(el || document.body, {
16198 tabPosition: 'top',
16199 //resizeTabs: true,
16200 alwaysShowTabs: el && hp? false : true,
16201 hideTabs: el || !hp ? true : false,
16209 if (!this.parent.el) {
16210 // probably an old style ctor, which has been disabled.
16214 // The 'tree' method is '_tree now'
16216 tree.region = tree.region || this.region;
16217 var is_body = false;
16218 if (this.parent.el === true) {
16219 // bootstrap... - body..
16223 this.parent.el = Roo.factory(tree);
16227 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16228 this.fireEvent('built', this);
16230 this.panel = this.el;
16231 this.layout = this.panel.layout;
16232 this.parentLayout = this.parent.layout || false;
16238 Roo.apply(Roo.XComponent, {
16240 * @property hideProgress
16241 * true to disable the building progress bar.. usefull on single page renders.
16244 hideProgress : false,
16246 * @property buildCompleted
16247 * True when the builder has completed building the interface.
16250 buildCompleted : false,
16253 * @property topModule
16254 * the upper most module - uses document.element as it's constructor.
16261 * @property modules
16262 * array of modules to be created by registration system.
16263 * @type {Array} of Roo.XComponent
16268 * @property elmodules
16269 * array of modules to be created by which use #ID
16270 * @type {Array} of Roo.XComponent
16277 * Is an alternative Root - normally used by bootstrap or other systems,
16278 * where the top element in the tree can wrap 'body'
16279 * @type {boolean} (default false)
16284 * @property build_from_html
16285 * Build elements from html - used by bootstrap HTML stuff
16286 * - this is cleared after build is completed
16287 * @type {boolean} (default false)
16290 build_from_html : false,
16292 * Register components to be built later.
16294 * This solves the following issues
16295 * - Building is not done on page load, but after an authentication process has occured.
16296 * - Interface elements are registered on page load
16297 * - Parent Interface elements may not be loaded before child, so this handles that..
16304 module : 'Pman.Tab.projectMgr',
16306 parent : 'Pman.layout',
16307 disabled : false, // or use a function..
16310 * * @param {Object} details about module
16312 register : function(obj) {
16314 Roo.XComponent.event.fireEvent('register', obj);
16315 switch(typeof(obj.disabled) ) {
16321 if ( obj.disabled() ) {
16327 if (obj.disabled) {
16333 this.modules.push(obj);
16337 * convert a string to an object..
16338 * eg. 'AAA.BBB' -> finds AAA.BBB
16342 toObject : function(str)
16344 if (!str || typeof(str) == 'object') {
16347 if (str.substring(0,1) == '#') {
16351 var ar = str.split('.');
16356 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16358 throw "Module not found : " + str;
16362 throw "Module not found : " + str;
16364 Roo.each(ar, function(e) {
16365 if (typeof(o[e]) == 'undefined') {
16366 throw "Module not found : " + str;
16377 * move modules into their correct place in the tree..
16380 preBuild : function ()
16383 Roo.each(this.modules , function (obj)
16385 Roo.XComponent.event.fireEvent('beforebuild', obj);
16387 var opar = obj.parent;
16389 obj.parent = this.toObject(opar);
16391 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16396 Roo.debug && Roo.log("GOT top level module");
16397 Roo.debug && Roo.log(obj);
16398 obj.modules = new Roo.util.MixedCollection(false,
16399 function(o) { return o.order + '' }
16401 this.topModule = obj;
16404 // parent is a string (usually a dom element name..)
16405 if (typeof(obj.parent) == 'string') {
16406 this.elmodules.push(obj);
16409 if (obj.parent.constructor != Roo.XComponent) {
16410 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16412 if (!obj.parent.modules) {
16413 obj.parent.modules = new Roo.util.MixedCollection(false,
16414 function(o) { return o.order + '' }
16417 if (obj.parent.disabled) {
16418 obj.disabled = true;
16420 obj.parent.modules.add(obj);
16425 * make a list of modules to build.
16426 * @return {Array} list of modules.
16429 buildOrder : function()
16432 var cmp = function(a,b) {
16433 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16435 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16436 throw "No top level modules to build";
16439 // make a flat list in order of modules to build.
16440 var mods = this.topModule ? [ this.topModule ] : [];
16443 // elmodules (is a list of DOM based modules )
16444 Roo.each(this.elmodules, function(e) {
16446 if (!this.topModule &&
16447 typeof(e.parent) == 'string' &&
16448 e.parent.substring(0,1) == '#' &&
16449 Roo.get(e.parent.substr(1))
16452 _this.topModule = e;
16458 // add modules to their parents..
16459 var addMod = function(m) {
16460 Roo.debug && Roo.log("build Order: add: " + m.name);
16463 if (m.modules && !m.disabled) {
16464 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16465 m.modules.keySort('ASC', cmp );
16466 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16468 m.modules.each(addMod);
16470 Roo.debug && Roo.log("build Order: no child modules");
16472 // not sure if this is used any more..
16474 m.finalize.name = m.name + " (clean up) ";
16475 mods.push(m.finalize);
16479 if (this.topModule && this.topModule.modules) {
16480 this.topModule.modules.keySort('ASC', cmp );
16481 this.topModule.modules.each(addMod);
16487 * Build the registered modules.
16488 * @param {Object} parent element.
16489 * @param {Function} optional method to call after module has been added.
16493 build : function(opts)
16496 if (typeof(opts) != 'undefined') {
16497 Roo.apply(this,opts);
16501 var mods = this.buildOrder();
16503 //this.allmods = mods;
16504 //Roo.debug && Roo.log(mods);
16506 if (!mods.length) { // should not happen
16507 throw "NO modules!!!";
16511 var msg = "Building Interface...";
16512 // flash it up as modal - so we store the mask!?
16513 if (!this.hideProgress && Roo.MessageBox) {
16514 Roo.MessageBox.show({ title: 'loading' });
16515 Roo.MessageBox.show({
16516 title: "Please wait...",
16525 var total = mods.length;
16528 var progressRun = function() {
16529 if (!mods.length) {
16530 Roo.debug && Roo.log('hide?');
16531 if (!this.hideProgress && Roo.MessageBox) {
16532 Roo.MessageBox.hide();
16534 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16536 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16542 var m = mods.shift();
16545 Roo.debug && Roo.log(m);
16546 // not sure if this is supported any more.. - modules that are are just function
16547 if (typeof(m) == 'function') {
16549 return progressRun.defer(10, _this);
16553 msg = "Building Interface " + (total - mods.length) +
16555 (m.name ? (' - ' + m.name) : '');
16556 Roo.debug && Roo.log(msg);
16557 if (!_this.hideProgress && Roo.MessageBox) {
16558 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
16562 // is the module disabled?
16563 var disabled = (typeof(m.disabled) == 'function') ?
16564 m.disabled.call(m.module.disabled) : m.disabled;
16568 return progressRun(); // we do not update the display!
16576 // it's 10 on top level, and 1 on others??? why...
16577 return progressRun.defer(10, _this);
16580 progressRun.defer(1, _this);
16594 * wrapper for event.on - aliased later..
16595 * Typically use to register a event handler for register:
16597 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16606 Roo.XComponent.event = new Roo.util.Observable({
16610 * Fires when an Component is registered,
16611 * set the disable property on the Component to stop registration.
16612 * @param {Roo.XComponent} c the component being registerd.
16617 * @event beforebuild
16618 * Fires before each Component is built
16619 * can be used to apply permissions.
16620 * @param {Roo.XComponent} c the component being registerd.
16623 'beforebuild' : true,
16625 * @event buildcomplete
16626 * Fires on the top level element when all elements have been built
16627 * @param {Roo.XComponent} the top level component.
16629 'buildcomplete' : true
16634 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
16637 * marked - a markdown parser
16638 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
16639 * https://github.com/chjj/marked
16645 * Roo.Markdown - is a very crude wrapper around marked..
16649 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
16651 * Note: move the sample code to the bottom of this
16652 * file before uncommenting it.
16657 Roo.Markdown.toHtml = function(text) {
16659 var c = new Roo.Markdown.marked.setOptions({
16660 renderer: new Roo.Markdown.marked.Renderer(),
16671 text = text.replace(/\\\n/g,' ');
16672 return Roo.Markdown.marked(text);
16677 // Wraps all "globals" so that the only thing
16678 // exposed is makeHtml().
16683 * Block-Level Grammar
16688 code: /^( {4}[^\n]+\n*)+/,
16690 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
16691 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
16693 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
16694 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
16695 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
16696 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
16697 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
16699 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
16703 block.bullet = /(?:[*+-]|\d+\.)/;
16704 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
16705 block.item = replace(block.item, 'gm')
16706 (/bull/g, block.bullet)
16709 block.list = replace(block.list)
16710 (/bull/g, block.bullet)
16711 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
16712 ('def', '\\n+(?=' + block.def.source + ')')
16715 block.blockquote = replace(block.blockquote)
16719 block._tag = '(?!(?:'
16720 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
16721 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
16722 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
16724 block.html = replace(block.html)
16725 ('comment', /<!--[\s\S]*?-->/)
16726 ('closed', /<(tag)[\s\S]+?<\/\1>/)
16727 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
16728 (/tag/g, block._tag)
16731 block.paragraph = replace(block.paragraph)
16733 ('heading', block.heading)
16734 ('lheading', block.lheading)
16735 ('blockquote', block.blockquote)
16736 ('tag', '<' + block._tag)
16741 * Normal Block Grammar
16744 block.normal = merge({}, block);
16747 * GFM Block Grammar
16750 block.gfm = merge({}, block.normal, {
16751 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
16753 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
16756 block.gfm.paragraph = replace(block.paragraph)
16758 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
16759 + block.list.source.replace('\\1', '\\3') + '|')
16763 * GFM + Tables Block Grammar
16766 block.tables = merge({}, block.gfm, {
16767 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
16768 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
16775 function Lexer(options) {
16777 this.tokens.links = {};
16778 this.options = options || marked.defaults;
16779 this.rules = block.normal;
16781 if (this.options.gfm) {
16782 if (this.options.tables) {
16783 this.rules = block.tables;
16785 this.rules = block.gfm;
16791 * Expose Block Rules
16794 Lexer.rules = block;
16797 * Static Lex Method
16800 Lexer.lex = function(src, options) {
16801 var lexer = new Lexer(options);
16802 return lexer.lex(src);
16809 Lexer.prototype.lex = function(src) {
16811 .replace(/\r\n|\r/g, '\n')
16812 .replace(/\t/g, ' ')
16813 .replace(/\u00a0/g, ' ')
16814 .replace(/\u2424/g, '\n');
16816 return this.token(src, true);
16823 Lexer.prototype.token = function(src, top, bq) {
16824 var src = src.replace(/^ +$/gm, '')
16837 if (cap = this.rules.newline.exec(src)) {
16838 src = src.substring(cap[0].length);
16839 if (cap[0].length > 1) {
16847 if (cap = this.rules.code.exec(src)) {
16848 src = src.substring(cap[0].length);
16849 cap = cap[0].replace(/^ {4}/gm, '');
16852 text: !this.options.pedantic
16853 ? cap.replace(/\n+$/, '')
16860 if (cap = this.rules.fences.exec(src)) {
16861 src = src.substring(cap[0].length);
16871 if (cap = this.rules.heading.exec(src)) {
16872 src = src.substring(cap[0].length);
16875 depth: cap[1].length,
16881 // table no leading pipe (gfm)
16882 if (top && (cap = this.rules.nptable.exec(src))) {
16883 src = src.substring(cap[0].length);
16887 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
16888 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
16889 cells: cap[3].replace(/\n$/, '').split('\n')
16892 for (i = 0; i < item.align.length; i++) {
16893 if (/^ *-+: *$/.test(item.align[i])) {
16894 item.align[i] = 'right';
16895 } else if (/^ *:-+: *$/.test(item.align[i])) {
16896 item.align[i] = 'center';
16897 } else if (/^ *:-+ *$/.test(item.align[i])) {
16898 item.align[i] = 'left';
16900 item.align[i] = null;
16904 for (i = 0; i < item.cells.length; i++) {
16905 item.cells[i] = item.cells[i].split(/ *\| */);
16908 this.tokens.push(item);
16914 if (cap = this.rules.lheading.exec(src)) {
16915 src = src.substring(cap[0].length);
16918 depth: cap[2] === '=' ? 1 : 2,
16925 if (cap = this.rules.hr.exec(src)) {
16926 src = src.substring(cap[0].length);
16934 if (cap = this.rules.blockquote.exec(src)) {
16935 src = src.substring(cap[0].length);
16938 type: 'blockquote_start'
16941 cap = cap[0].replace(/^ *> ?/gm, '');
16943 // Pass `top` to keep the current
16944 // "toplevel" state. This is exactly
16945 // how markdown.pl works.
16946 this.token(cap, top, true);
16949 type: 'blockquote_end'
16956 if (cap = this.rules.list.exec(src)) {
16957 src = src.substring(cap[0].length);
16961 type: 'list_start',
16962 ordered: bull.length > 1
16965 // Get each top-level item.
16966 cap = cap[0].match(this.rules.item);
16972 for (; i < l; i++) {
16975 // Remove the list item's bullet
16976 // so it is seen as the next token.
16977 space = item.length;
16978 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
16980 // Outdent whatever the
16981 // list item contains. Hacky.
16982 if (~item.indexOf('\n ')) {
16983 space -= item.length;
16984 item = !this.options.pedantic
16985 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
16986 : item.replace(/^ {1,4}/gm, '');
16989 // Determine whether the next list item belongs here.
16990 // Backpedal if it does not belong in this list.
16991 if (this.options.smartLists && i !== l - 1) {
16992 b = block.bullet.exec(cap[i + 1])[0];
16993 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
16994 src = cap.slice(i + 1).join('\n') + src;
16999 // Determine whether item is loose or not.
17000 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17001 // for discount behavior.
17002 loose = next || /\n\n(?!\s*$)/.test(item);
17004 next = item.charAt(item.length - 1) === '\n';
17005 if (!loose) { loose = next; }
17010 ? 'loose_item_start'
17011 : 'list_item_start'
17015 this.token(item, false, bq);
17018 type: 'list_item_end'
17030 if (cap = this.rules.html.exec(src)) {
17031 src = src.substring(cap[0].length);
17033 type: this.options.sanitize
17036 pre: !this.options.sanitizer
17037 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17044 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17045 src = src.substring(cap[0].length);
17046 this.tokens.links[cap[1].toLowerCase()] = {
17054 if (top && (cap = this.rules.table.exec(src))) {
17055 src = src.substring(cap[0].length);
17059 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17060 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17061 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17064 for (i = 0; i < item.align.length; i++) {
17065 if (/^ *-+: *$/.test(item.align[i])) {
17066 item.align[i] = 'right';
17067 } else if (/^ *:-+: *$/.test(item.align[i])) {
17068 item.align[i] = 'center';
17069 } else if (/^ *:-+ *$/.test(item.align[i])) {
17070 item.align[i] = 'left';
17072 item.align[i] = null;
17076 for (i = 0; i < item.cells.length; i++) {
17077 item.cells[i] = item.cells[i]
17078 .replace(/^ *\| *| *\| *$/g, '')
17082 this.tokens.push(item);
17087 // top-level paragraph
17088 if (top && (cap = this.rules.paragraph.exec(src))) {
17089 src = src.substring(cap[0].length);
17092 text: cap[1].charAt(cap[1].length - 1) === '\n'
17093 ? cap[1].slice(0, -1)
17100 if (cap = this.rules.text.exec(src)) {
17101 // Top-level should never reach here.
17102 src = src.substring(cap[0].length);
17112 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17116 return this.tokens;
17120 * Inline-Level Grammar
17124 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17125 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17127 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17128 link: /^!?\[(inside)\]\(href\)/,
17129 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17130 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17131 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17132 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
17133 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
17134 br: /^ {2,}\n(?!\s*$)/,
17136 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
17139 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
17140 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
17142 inline.link = replace(inline.link)
17143 ('inside', inline._inside)
17144 ('href', inline._href)
17147 inline.reflink = replace(inline.reflink)
17148 ('inside', inline._inside)
17152 * Normal Inline Grammar
17155 inline.normal = merge({}, inline);
17158 * Pedantic Inline Grammar
17161 inline.pedantic = merge({}, inline.normal, {
17162 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
17163 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
17167 * GFM Inline Grammar
17170 inline.gfm = merge({}, inline.normal, {
17171 escape: replace(inline.escape)('])', '~|])')(),
17172 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
17173 del: /^~~(?=\S)([\s\S]*?\S)~~/,
17174 text: replace(inline.text)
17176 ('|', '|https?://|')
17181 * GFM + Line Breaks Inline Grammar
17184 inline.breaks = merge({}, inline.gfm, {
17185 br: replace(inline.br)('{2,}', '*')(),
17186 text: replace(inline.gfm.text)('{2,}', '*')()
17190 * Inline Lexer & Compiler
17193 function InlineLexer(links, options) {
17194 this.options = options || marked.defaults;
17195 this.links = links;
17196 this.rules = inline.normal;
17197 this.renderer = this.options.renderer || new Renderer;
17198 this.renderer.options = this.options;
17202 Error('Tokens array requires a `links` property.');
17205 if (this.options.gfm) {
17206 if (this.options.breaks) {
17207 this.rules = inline.breaks;
17209 this.rules = inline.gfm;
17211 } else if (this.options.pedantic) {
17212 this.rules = inline.pedantic;
17217 * Expose Inline Rules
17220 InlineLexer.rules = inline;
17223 * Static Lexing/Compiling Method
17226 InlineLexer.output = function(src, links, options) {
17227 var inline = new InlineLexer(links, options);
17228 return inline.output(src);
17235 InlineLexer.prototype.output = function(src) {
17244 if (cap = this.rules.escape.exec(src)) {
17245 src = src.substring(cap[0].length);
17251 if (cap = this.rules.autolink.exec(src)) {
17252 src = src.substring(cap[0].length);
17253 if (cap[2] === '@') {
17254 text = cap[1].charAt(6) === ':'
17255 ? this.mangle(cap[1].substring(7))
17256 : this.mangle(cap[1]);
17257 href = this.mangle('mailto:') + text;
17259 text = escape(cap[1]);
17262 out += this.renderer.link(href, null, text);
17267 if (!this.inLink && (cap = this.rules.url.exec(src))) {
17268 src = src.substring(cap[0].length);
17269 text = escape(cap[1]);
17271 out += this.renderer.link(href, null, text);
17276 if (cap = this.rules.tag.exec(src)) {
17277 if (!this.inLink && /^<a /i.test(cap[0])) {
17278 this.inLink = true;
17279 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
17280 this.inLink = false;
17282 src = src.substring(cap[0].length);
17283 out += this.options.sanitize
17284 ? this.options.sanitizer
17285 ? this.options.sanitizer(cap[0])
17292 if (cap = this.rules.link.exec(src)) {
17293 src = src.substring(cap[0].length);
17294 this.inLink = true;
17295 out += this.outputLink(cap, {
17299 this.inLink = false;
17304 if ((cap = this.rules.reflink.exec(src))
17305 || (cap = this.rules.nolink.exec(src))) {
17306 src = src.substring(cap[0].length);
17307 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
17308 link = this.links[link.toLowerCase()];
17309 if (!link || !link.href) {
17310 out += cap[0].charAt(0);
17311 src = cap[0].substring(1) + src;
17314 this.inLink = true;
17315 out += this.outputLink(cap, link);
17316 this.inLink = false;
17321 if (cap = this.rules.strong.exec(src)) {
17322 src = src.substring(cap[0].length);
17323 out += this.renderer.strong(this.output(cap[2] || cap[1]));
17328 if (cap = this.rules.em.exec(src)) {
17329 src = src.substring(cap[0].length);
17330 out += this.renderer.em(this.output(cap[2] || cap[1]));
17335 if (cap = this.rules.code.exec(src)) {
17336 src = src.substring(cap[0].length);
17337 out += this.renderer.codespan(escape(cap[2], true));
17342 if (cap = this.rules.br.exec(src)) {
17343 src = src.substring(cap[0].length);
17344 out += this.renderer.br();
17349 if (cap = this.rules.del.exec(src)) {
17350 src = src.substring(cap[0].length);
17351 out += this.renderer.del(this.output(cap[1]));
17356 if (cap = this.rules.text.exec(src)) {
17357 src = src.substring(cap[0].length);
17358 out += this.renderer.text(escape(this.smartypants(cap[0])));
17364 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17375 InlineLexer.prototype.outputLink = function(cap, link) {
17376 var href = escape(link.href)
17377 , title = link.title ? escape(link.title) : null;
17379 return cap[0].charAt(0) !== '!'
17380 ? this.renderer.link(href, title, this.output(cap[1]))
17381 : this.renderer.image(href, title, escape(cap[1]));
17385 * Smartypants Transformations
17388 InlineLexer.prototype.smartypants = function(text) {
17389 if (!this.options.smartypants) { return text; }
17392 .replace(/---/g, '\u2014')
17394 .replace(/--/g, '\u2013')
17396 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
17397 // closing singles & apostrophes
17398 .replace(/'/g, '\u2019')
17400 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
17402 .replace(/"/g, '\u201d')
17404 .replace(/\.{3}/g, '\u2026');
17411 InlineLexer.prototype.mangle = function(text) {
17412 if (!this.options.mangle) { return text; }
17418 for (; i < l; i++) {
17419 ch = text.charCodeAt(i);
17420 if (Math.random() > 0.5) {
17421 ch = 'x' + ch.toString(16);
17423 out += '&#' + ch + ';';
17433 function Renderer(options) {
17434 this.options = options || {};
17437 Renderer.prototype.code = function(code, lang, escaped) {
17438 if (this.options.highlight) {
17439 var out = this.options.highlight(code, lang);
17440 if (out != null && out !== code) {
17445 // hack!!! - it's already escapeD?
17450 return '<pre><code>'
17451 + (escaped ? code : escape(code, true))
17452 + '\n</code></pre>';
17455 return '<pre><code class="'
17456 + this.options.langPrefix
17457 + escape(lang, true)
17459 + (escaped ? code : escape(code, true))
17460 + '\n</code></pre>\n';
17463 Renderer.prototype.blockquote = function(quote) {
17464 return '<blockquote>\n' + quote + '</blockquote>\n';
17467 Renderer.prototype.html = function(html) {
17471 Renderer.prototype.heading = function(text, level, raw) {
17475 + this.options.headerPrefix
17476 + raw.toLowerCase().replace(/[^\w]+/g, '-')
17484 Renderer.prototype.hr = function() {
17485 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
17488 Renderer.prototype.list = function(body, ordered) {
17489 var type = ordered ? 'ol' : 'ul';
17490 return '<' + type + '>\n' + body + '</' + type + '>\n';
17493 Renderer.prototype.listitem = function(text) {
17494 return '<li>' + text + '</li>\n';
17497 Renderer.prototype.paragraph = function(text) {
17498 return '<p>' + text + '</p>\n';
17501 Renderer.prototype.table = function(header, body) {
17502 return '<table class="table table-striped">\n'
17512 Renderer.prototype.tablerow = function(content) {
17513 return '<tr>\n' + content + '</tr>\n';
17516 Renderer.prototype.tablecell = function(content, flags) {
17517 var type = flags.header ? 'th' : 'td';
17518 var tag = flags.align
17519 ? '<' + type + ' style="text-align:' + flags.align + '">'
17520 : '<' + type + '>';
17521 return tag + content + '</' + type + '>\n';
17524 // span level renderer
17525 Renderer.prototype.strong = function(text) {
17526 return '<strong>' + text + '</strong>';
17529 Renderer.prototype.em = function(text) {
17530 return '<em>' + text + '</em>';
17533 Renderer.prototype.codespan = function(text) {
17534 return '<code>' + text + '</code>';
17537 Renderer.prototype.br = function() {
17538 return this.options.xhtml ? '<br/>' : '<br>';
17541 Renderer.prototype.del = function(text) {
17542 return '<del>' + text + '</del>';
17545 Renderer.prototype.link = function(href, title, text) {
17546 if (this.options.sanitize) {
17548 var prot = decodeURIComponent(unescape(href))
17549 .replace(/[^\w:]/g, '')
17554 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
17558 var out = '<a href="' + href + '"';
17560 out += ' title="' + title + '"';
17562 out += '>' + text + '</a>';
17566 Renderer.prototype.image = function(href, title, text) {
17567 var out = '<img src="' + href + '" alt="' + text + '"';
17569 out += ' title="' + title + '"';
17571 out += this.options.xhtml ? '/>' : '>';
17575 Renderer.prototype.text = function(text) {
17580 * Parsing & Compiling
17583 function Parser(options) {
17586 this.options = options || marked.defaults;
17587 this.options.renderer = this.options.renderer || new Renderer;
17588 this.renderer = this.options.renderer;
17589 this.renderer.options = this.options;
17593 * Static Parse Method
17596 Parser.parse = function(src, options, renderer) {
17597 var parser = new Parser(options, renderer);
17598 return parser.parse(src);
17605 Parser.prototype.parse = function(src) {
17606 this.inline = new InlineLexer(src.links, this.options, this.renderer);
17607 this.tokens = src.reverse();
17610 while (this.next()) {
17621 Parser.prototype.next = function() {
17622 return this.token = this.tokens.pop();
17626 * Preview Next Token
17629 Parser.prototype.peek = function() {
17630 return this.tokens[this.tokens.length - 1] || 0;
17634 * Parse Text Tokens
17637 Parser.prototype.parseText = function() {
17638 var body = this.token.text;
17640 while (this.peek().type === 'text') {
17641 body += '\n' + this.next().text;
17644 return this.inline.output(body);
17648 * Parse Current Token
17651 Parser.prototype.tok = function() {
17652 switch (this.token.type) {
17657 return this.renderer.hr();
17660 return this.renderer.heading(
17661 this.inline.output(this.token.text),
17666 return this.renderer.code(this.token.text,
17668 this.token.escaped);
17681 for (i = 0; i < this.token.header.length; i++) {
17682 flags = { header: true, align: this.token.align[i] };
17683 cell += this.renderer.tablecell(
17684 this.inline.output(this.token.header[i]),
17685 { header: true, align: this.token.align[i] }
17688 header += this.renderer.tablerow(cell);
17690 for (i = 0; i < this.token.cells.length; i++) {
17691 row = this.token.cells[i];
17694 for (j = 0; j < row.length; j++) {
17695 cell += this.renderer.tablecell(
17696 this.inline.output(row[j]),
17697 { header: false, align: this.token.align[j] }
17701 body += this.renderer.tablerow(cell);
17703 return this.renderer.table(header, body);
17705 case 'blockquote_start': {
17708 while (this.next().type !== 'blockquote_end') {
17709 body += this.tok();
17712 return this.renderer.blockquote(body);
17714 case 'list_start': {
17716 , ordered = this.token.ordered;
17718 while (this.next().type !== 'list_end') {
17719 body += this.tok();
17722 return this.renderer.list(body, ordered);
17724 case 'list_item_start': {
17727 while (this.next().type !== 'list_item_end') {
17728 body += this.token.type === 'text'
17733 return this.renderer.listitem(body);
17735 case 'loose_item_start': {
17738 while (this.next().type !== 'list_item_end') {
17739 body += this.tok();
17742 return this.renderer.listitem(body);
17745 var html = !this.token.pre && !this.options.pedantic
17746 ? this.inline.output(this.token.text)
17748 return this.renderer.html(html);
17750 case 'paragraph': {
17751 return this.renderer.paragraph(this.inline.output(this.token.text));
17754 return this.renderer.paragraph(this.parseText());
17763 function escape(html, encode) {
17765 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17766 .replace(/</g, '<')
17767 .replace(/>/g, '>')
17768 .replace(/"/g, '"')
17769 .replace(/'/g, ''');
17772 function unescape(html) {
17773 // explicitly match decimal, hex, and named HTML entities
17774 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17775 n = n.toLowerCase();
17776 if (n === 'colon') { return ':'; }
17777 if (n.charAt(0) === '#') {
17778 return n.charAt(1) === 'x'
17779 ? String.fromCharCode(parseInt(n.substring(2), 16))
17780 : String.fromCharCode(+n.substring(1));
17786 function replace(regex, opt) {
17787 regex = regex.source;
17789 return function self(name, val) {
17790 if (!name) { return new RegExp(regex, opt); }
17791 val = val.source || val;
17792 val = val.replace(/(^|[^\[])\^/g, '$1');
17793 regex = regex.replace(name, val);
17801 function merge(obj) {
17806 for (; i < arguments.length; i++) {
17807 target = arguments[i];
17808 for (key in target) {
17809 if (Object.prototype.hasOwnProperty.call(target, key)) {
17810 obj[key] = target[key];
17823 function marked(src, opt, callback) {
17824 if (callback || typeof opt === 'function') {
17830 opt = merge({}, marked.defaults, opt || {});
17832 var highlight = opt.highlight
17838 tokens = Lexer.lex(src, opt)
17840 return callback(e);
17843 pending = tokens.length;
17845 var done = function(err) {
17847 opt.highlight = highlight;
17848 return callback(err);
17854 out = Parser.parse(tokens, opt);
17859 opt.highlight = highlight;
17863 : callback(null, out);
17866 if (!highlight || highlight.length < 3) {
17870 delete opt.highlight;
17872 if (!pending) { return done(); }
17874 for (; i < tokens.length; i++) {
17876 if (token.type !== 'code') {
17877 return --pending || done();
17879 return highlight(token.text, token.lang, function(err, code) {
17880 if (err) { return done(err); }
17881 if (code == null || code === token.text) {
17882 return --pending || done();
17885 token.escaped = true;
17886 --pending || done();
17894 if (opt) { opt = merge({}, marked.defaults, opt); }
17895 return Parser.parse(Lexer.lex(src, opt), opt);
17897 e.message += '\nPlease report this to https://github.com/chjj/marked.';
17898 if ((opt || marked.defaults).silent) {
17899 return '<p>An error occured:</p><pre>'
17900 + escape(e.message + '', true)
17912 marked.setOptions = function(opt) {
17913 merge(marked.defaults, opt);
17917 marked.defaults = {
17928 langPrefix: 'lang-',
17929 smartypants: false,
17931 renderer: new Renderer,
17939 marked.Parser = Parser;
17940 marked.parser = Parser.parse;
17942 marked.Renderer = Renderer;
17944 marked.Lexer = Lexer;
17945 marked.lexer = Lexer.lex;
17947 marked.InlineLexer = InlineLexer;
17948 marked.inlineLexer = InlineLexer.output;
17950 marked.parse = marked;
17952 Roo.Markdown.marked = marked;
17956 * Ext JS Library 1.1.1
17957 * Copyright(c) 2006-2007, Ext JS, LLC.
17959 * Originally Released Under LGPL - original licence link has changed is not relivant.
17962 * <script type="text/javascript">
17968 * These classes are derivatives of the similarly named classes in the YUI Library.
17969 * The original license:
17970 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
17971 * Code licensed under the BSD License:
17972 * http://developer.yahoo.net/yui/license.txt
17977 var Event=Roo.EventManager;
17978 var Dom=Roo.lib.Dom;
17981 * @class Roo.dd.DragDrop
17982 * @extends Roo.util.Observable
17983 * Defines the interface and base operation of items that that can be
17984 * dragged or can be drop targets. It was designed to be extended, overriding
17985 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
17986 * Up to three html elements can be associated with a DragDrop instance:
17988 * <li>linked element: the element that is passed into the constructor.
17989 * This is the element which defines the boundaries for interaction with
17990 * other DragDrop objects.</li>
17991 * <li>handle element(s): The drag operation only occurs if the element that
17992 * was clicked matches a handle element. By default this is the linked
17993 * element, but there are times that you will want only a portion of the
17994 * linked element to initiate the drag operation, and the setHandleElId()
17995 * method provides a way to define this.</li>
17996 * <li>drag element: this represents the element that would be moved along
17997 * with the cursor during a drag operation. By default, this is the linked
17998 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
17999 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18002 * This class should not be instantiated until the onload event to ensure that
18003 * the associated elements are available.
18004 * The following would define a DragDrop obj that would interact with any
18005 * other DragDrop obj in the "group1" group:
18007 * dd = new Roo.dd.DragDrop("div1", "group1");
18009 * Since none of the event handlers have been implemented, nothing would
18010 * actually happen if you were to run the code above. Normally you would
18011 * override this class or one of the default implementations, but you can
18012 * also override the methods you want on an instance of the class...
18014 * dd.onDragDrop = function(e, id) {
18015 * alert("dd was dropped on " + id);
18019 * @param {String} id of the element that is linked to this instance
18020 * @param {String} sGroup the group of related DragDrop objects
18021 * @param {object} config an object containing configurable attributes
18022 * Valid properties for DragDrop:
18023 * padding, isTarget, maintainOffset, primaryButtonOnly
18025 Roo.dd.DragDrop = function(id, sGroup, config) {
18027 this.init(id, sGroup, config);
18032 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18035 * The id of the element associated with this object. This is what we
18036 * refer to as the "linked element" because the size and position of
18037 * this element is used to determine when the drag and drop objects have
18045 * Configuration attributes passed into the constructor
18052 * The id of the element that will be dragged. By default this is same
18053 * as the linked element , but could be changed to another element. Ex:
18055 * @property dragElId
18062 * the id of the element that initiates the drag operation. By default
18063 * this is the linked element, but could be changed to be a child of this
18064 * element. This lets us do things like only starting the drag when the
18065 * header element within the linked html element is clicked.
18066 * @property handleElId
18073 * An associative array of HTML tags that will be ignored if clicked.
18074 * @property invalidHandleTypes
18075 * @type {string: string}
18077 invalidHandleTypes: null,
18080 * An associative array of ids for elements that will be ignored if clicked
18081 * @property invalidHandleIds
18082 * @type {string: string}
18084 invalidHandleIds: null,
18087 * An indexted array of css class names for elements that will be ignored
18089 * @property invalidHandleClasses
18092 invalidHandleClasses: null,
18095 * The linked element's absolute X position at the time the drag was
18097 * @property startPageX
18104 * The linked element's absolute X position at the time the drag was
18106 * @property startPageY
18113 * The group defines a logical collection of DragDrop objects that are
18114 * related. Instances only get events when interacting with other
18115 * DragDrop object in the same group. This lets us define multiple
18116 * groups using a single DragDrop subclass if we want.
18118 * @type {string: string}
18123 * Individual drag/drop instances can be locked. This will prevent
18124 * onmousedown start drag.
18132 * Lock this instance
18135 lock: function() { this.locked = true; },
18138 * Unlock this instace
18141 unlock: function() { this.locked = false; },
18144 * By default, all insances can be a drop target. This can be disabled by
18145 * setting isTarget to false.
18152 * The padding configured for this drag and drop object for calculating
18153 * the drop zone intersection with this object.
18160 * Cached reference to the linked element
18161 * @property _domRef
18167 * Internal typeof flag
18168 * @property __ygDragDrop
18171 __ygDragDrop: true,
18174 * Set to true when horizontal contraints are applied
18175 * @property constrainX
18182 * Set to true when vertical contraints are applied
18183 * @property constrainY
18190 * The left constraint
18198 * The right constraint
18206 * The up constraint
18215 * The down constraint
18223 * Maintain offsets when we resetconstraints. Set to true when you want
18224 * the position of the element relative to its parent to stay the same
18225 * when the page changes
18227 * @property maintainOffset
18230 maintainOffset: false,
18233 * Array of pixel locations the element will snap to if we specified a
18234 * horizontal graduation/interval. This array is generated automatically
18235 * when you define a tick interval.
18242 * Array of pixel locations the element will snap to if we specified a
18243 * vertical graduation/interval. This array is generated automatically
18244 * when you define a tick interval.
18251 * By default the drag and drop instance will only respond to the primary
18252 * button click (left button for a right-handed mouse). Set to true to
18253 * allow drag and drop to start with any mouse click that is propogated
18255 * @property primaryButtonOnly
18258 primaryButtonOnly: true,
18261 * The availabe property is false until the linked dom element is accessible.
18262 * @property available
18268 * By default, drags can only be initiated if the mousedown occurs in the
18269 * region the linked element is. This is done in part to work around a
18270 * bug in some browsers that mis-report the mousedown if the previous
18271 * mouseup happened outside of the window. This property is set to true
18272 * if outer handles are defined.
18274 * @property hasOuterHandles
18278 hasOuterHandles: false,
18281 * Code that executes immediately before the startDrag event
18282 * @method b4StartDrag
18285 b4StartDrag: function(x, y) { },
18288 * Abstract method called after a drag/drop object is clicked
18289 * and the drag or mousedown time thresholds have beeen met.
18290 * @method startDrag
18291 * @param {int} X click location
18292 * @param {int} Y click location
18294 startDrag: function(x, y) { /* override this */ },
18297 * Code that executes immediately before the onDrag event
18301 b4Drag: function(e) { },
18304 * Abstract method called during the onMouseMove event while dragging an
18307 * @param {Event} e the mousemove event
18309 onDrag: function(e) { /* override this */ },
18312 * Abstract method called when this element fist begins hovering over
18313 * another DragDrop obj
18314 * @method onDragEnter
18315 * @param {Event} e the mousemove event
18316 * @param {String|DragDrop[]} id In POINT mode, the element
18317 * id this is hovering over. In INTERSECT mode, an array of one or more
18318 * dragdrop items being hovered over.
18320 onDragEnter: function(e, id) { /* override this */ },
18323 * Code that executes immediately before the onDragOver event
18324 * @method b4DragOver
18327 b4DragOver: function(e) { },
18330 * Abstract method called when this element is hovering over another
18332 * @method onDragOver
18333 * @param {Event} e the mousemove event
18334 * @param {String|DragDrop[]} id In POINT mode, the element
18335 * id this is hovering over. In INTERSECT mode, an array of dd items
18336 * being hovered over.
18338 onDragOver: function(e, id) { /* override this */ },
18341 * Code that executes immediately before the onDragOut event
18342 * @method b4DragOut
18345 b4DragOut: function(e) { },
18348 * Abstract method called when we are no longer hovering over an element
18349 * @method onDragOut
18350 * @param {Event} e the mousemove event
18351 * @param {String|DragDrop[]} id In POINT mode, the element
18352 * id this was hovering over. In INTERSECT mode, an array of dd items
18353 * that the mouse is no longer over.
18355 onDragOut: function(e, id) { /* override this */ },
18358 * Code that executes immediately before the onDragDrop event
18359 * @method b4DragDrop
18362 b4DragDrop: function(e) { },
18365 * Abstract method called when this item is dropped on another DragDrop
18367 * @method onDragDrop
18368 * @param {Event} e the mouseup event
18369 * @param {String|DragDrop[]} id In POINT mode, the element
18370 * id this was dropped on. In INTERSECT mode, an array of dd items this
18373 onDragDrop: function(e, id) { /* override this */ },
18376 * Abstract method called when this item is dropped on an area with no
18378 * @method onInvalidDrop
18379 * @param {Event} e the mouseup event
18381 onInvalidDrop: function(e) { /* override this */ },
18384 * Code that executes immediately before the endDrag event
18385 * @method b4EndDrag
18388 b4EndDrag: function(e) { },
18391 * Fired when we are done dragging the object
18393 * @param {Event} e the mouseup event
18395 endDrag: function(e) { /* override this */ },
18398 * Code executed immediately before the onMouseDown event
18399 * @method b4MouseDown
18400 * @param {Event} e the mousedown event
18403 b4MouseDown: function(e) { },
18406 * Event handler that fires when a drag/drop obj gets a mousedown
18407 * @method onMouseDown
18408 * @param {Event} e the mousedown event
18410 onMouseDown: function(e) { /* override this */ },
18413 * Event handler that fires when a drag/drop obj gets a mouseup
18414 * @method onMouseUp
18415 * @param {Event} e the mouseup event
18417 onMouseUp: function(e) { /* override this */ },
18420 * Override the onAvailable method to do what is needed after the initial
18421 * position was determined.
18422 * @method onAvailable
18424 onAvailable: function () {
18428 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
18431 defaultPadding : {left:0, right:0, top:0, bottom:0},
18434 * Initializes the drag drop object's constraints to restrict movement to a certain element.
18438 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
18439 { dragElId: "existingProxyDiv" });
18440 dd.startDrag = function(){
18441 this.constrainTo("parent-id");
18444 * Or you can initalize it using the {@link Roo.Element} object:
18446 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
18447 startDrag : function(){
18448 this.constrainTo("parent-id");
18452 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
18453 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
18454 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
18455 * an object containing the sides to pad. For example: {right:10, bottom:10}
18456 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
18458 constrainTo : function(constrainTo, pad, inContent){
18459 if(typeof pad == "number"){
18460 pad = {left: pad, right:pad, top:pad, bottom:pad};
18462 pad = pad || this.defaultPadding;
18463 var b = Roo.get(this.getEl()).getBox();
18464 var ce = Roo.get(constrainTo);
18465 var s = ce.getScroll();
18466 var c, cd = ce.dom;
18467 if(cd == document.body){
18468 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
18471 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
18475 var topSpace = b.y - c.y;
18476 var leftSpace = b.x - c.x;
18478 this.resetConstraints();
18479 this.setXConstraint(leftSpace - (pad.left||0), // left
18480 c.width - leftSpace - b.width - (pad.right||0) //right
18482 this.setYConstraint(topSpace - (pad.top||0), //top
18483 c.height - topSpace - b.height - (pad.bottom||0) //bottom
18488 * Returns a reference to the linked element
18490 * @return {HTMLElement} the html element
18492 getEl: function() {
18493 if (!this._domRef) {
18494 this._domRef = Roo.getDom(this.id);
18497 return this._domRef;
18501 * Returns a reference to the actual element to drag. By default this is
18502 * the same as the html element, but it can be assigned to another
18503 * element. An example of this can be found in Roo.dd.DDProxy
18504 * @method getDragEl
18505 * @return {HTMLElement} the html element
18507 getDragEl: function() {
18508 return Roo.getDom(this.dragElId);
18512 * Sets up the DragDrop object. Must be called in the constructor of any
18513 * Roo.dd.DragDrop subclass
18515 * @param id the id of the linked element
18516 * @param {String} sGroup the group of related items
18517 * @param {object} config configuration attributes
18519 init: function(id, sGroup, config) {
18520 this.initTarget(id, sGroup, config);
18521 if (!Roo.isTouch) {
18522 Event.on(this.id, "mousedown", this.handleMouseDown, this);
18524 Event.on(this.id, "touchstart", this.handleMouseDown, this);
18525 // Event.on(this.id, "selectstart", Event.preventDefault);
18529 * Initializes Targeting functionality only... the object does not
18530 * get a mousedown handler.
18531 * @method initTarget
18532 * @param id the id of the linked element
18533 * @param {String} sGroup the group of related items
18534 * @param {object} config configuration attributes
18536 initTarget: function(id, sGroup, config) {
18538 // configuration attributes
18539 this.config = config || {};
18541 // create a local reference to the drag and drop manager
18542 this.DDM = Roo.dd.DDM;
18543 // initialize the groups array
18546 // assume that we have an element reference instead of an id if the
18547 // parameter is not a string
18548 if (typeof id !== "string") {
18555 // add to an interaction group
18556 this.addToGroup((sGroup) ? sGroup : "default");
18558 // We don't want to register this as the handle with the manager
18559 // so we just set the id rather than calling the setter.
18560 this.handleElId = id;
18562 // the linked element is the element that gets dragged by default
18563 this.setDragElId(id);
18565 // by default, clicked anchors will not start drag operations.
18566 this.invalidHandleTypes = { A: "A" };
18567 this.invalidHandleIds = {};
18568 this.invalidHandleClasses = [];
18570 this.applyConfig();
18572 this.handleOnAvailable();
18576 * Applies the configuration parameters that were passed into the constructor.
18577 * This is supposed to happen at each level through the inheritance chain. So
18578 * a DDProxy implentation will execute apply config on DDProxy, DD, and
18579 * DragDrop in order to get all of the parameters that are available in
18581 * @method applyConfig
18583 applyConfig: function() {
18585 // configurable properties:
18586 // padding, isTarget, maintainOffset, primaryButtonOnly
18587 this.padding = this.config.padding || [0, 0, 0, 0];
18588 this.isTarget = (this.config.isTarget !== false);
18589 this.maintainOffset = (this.config.maintainOffset);
18590 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
18595 * Executed when the linked element is available
18596 * @method handleOnAvailable
18599 handleOnAvailable: function() {
18600 this.available = true;
18601 this.resetConstraints();
18602 this.onAvailable();
18606 * Configures the padding for the target zone in px. Effectively expands
18607 * (or reduces) the virtual object size for targeting calculations.
18608 * Supports css-style shorthand; if only one parameter is passed, all sides
18609 * will have that padding, and if only two are passed, the top and bottom
18610 * will have the first param, the left and right the second.
18611 * @method setPadding
18612 * @param {int} iTop Top pad
18613 * @param {int} iRight Right pad
18614 * @param {int} iBot Bot pad
18615 * @param {int} iLeft Left pad
18617 setPadding: function(iTop, iRight, iBot, iLeft) {
18618 // this.padding = [iLeft, iRight, iTop, iBot];
18619 if (!iRight && 0 !== iRight) {
18620 this.padding = [iTop, iTop, iTop, iTop];
18621 } else if (!iBot && 0 !== iBot) {
18622 this.padding = [iTop, iRight, iTop, iRight];
18624 this.padding = [iTop, iRight, iBot, iLeft];
18629 * Stores the initial placement of the linked element.
18630 * @method setInitialPosition
18631 * @param {int} diffX the X offset, default 0
18632 * @param {int} diffY the Y offset, default 0
18634 setInitPosition: function(diffX, diffY) {
18635 var el = this.getEl();
18637 if (!this.DDM.verifyEl(el)) {
18641 var dx = diffX || 0;
18642 var dy = diffY || 0;
18644 var p = Dom.getXY( el );
18646 this.initPageX = p[0] - dx;
18647 this.initPageY = p[1] - dy;
18649 this.lastPageX = p[0];
18650 this.lastPageY = p[1];
18653 this.setStartPosition(p);
18657 * Sets the start position of the element. This is set when the obj
18658 * is initialized, the reset when a drag is started.
18659 * @method setStartPosition
18660 * @param pos current position (from previous lookup)
18663 setStartPosition: function(pos) {
18664 var p = pos || Dom.getXY( this.getEl() );
18665 this.deltaSetXY = null;
18667 this.startPageX = p[0];
18668 this.startPageY = p[1];
18672 * Add this instance to a group of related drag/drop objects. All
18673 * instances belong to at least one group, and can belong to as many
18674 * groups as needed.
18675 * @method addToGroup
18676 * @param sGroup {string} the name of the group
18678 addToGroup: function(sGroup) {
18679 this.groups[sGroup] = true;
18680 this.DDM.regDragDrop(this, sGroup);
18684 * Remove's this instance from the supplied interaction group
18685 * @method removeFromGroup
18686 * @param {string} sGroup The group to drop
18688 removeFromGroup: function(sGroup) {
18689 if (this.groups[sGroup]) {
18690 delete this.groups[sGroup];
18693 this.DDM.removeDDFromGroup(this, sGroup);
18697 * Allows you to specify that an element other than the linked element
18698 * will be moved with the cursor during a drag
18699 * @method setDragElId
18700 * @param id {string} the id of the element that will be used to initiate the drag
18702 setDragElId: function(id) {
18703 this.dragElId = id;
18707 * Allows you to specify a child of the linked element that should be
18708 * used to initiate the drag operation. An example of this would be if
18709 * you have a content div with text and links. Clicking anywhere in the
18710 * content area would normally start the drag operation. Use this method
18711 * to specify that an element inside of the content div is the element
18712 * that starts the drag operation.
18713 * @method setHandleElId
18714 * @param id {string} the id of the element that will be used to
18715 * initiate the drag.
18717 setHandleElId: function(id) {
18718 if (typeof id !== "string") {
18721 this.handleElId = id;
18722 this.DDM.regHandle(this.id, id);
18726 * Allows you to set an element outside of the linked element as a drag
18728 * @method setOuterHandleElId
18729 * @param id the id of the element that will be used to initiate the drag
18731 setOuterHandleElId: function(id) {
18732 if (typeof id !== "string") {
18735 Event.on(id, "mousedown",
18736 this.handleMouseDown, this);
18737 this.setHandleElId(id);
18739 this.hasOuterHandles = true;
18743 * Remove all drag and drop hooks for this element
18746 unreg: function() {
18747 Event.un(this.id, "mousedown",
18748 this.handleMouseDown);
18749 Event.un(this.id, "touchstart",
18750 this.handleMouseDown);
18751 this._domRef = null;
18752 this.DDM._remove(this);
18755 destroy : function(){
18760 * Returns true if this instance is locked, or the drag drop mgr is locked
18761 * (meaning that all drag/drop is disabled on the page.)
18763 * @return {boolean} true if this obj or all drag/drop is locked, else
18766 isLocked: function() {
18767 return (this.DDM.isLocked() || this.locked);
18771 * Fired when this object is clicked
18772 * @method handleMouseDown
18774 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
18777 handleMouseDown: function(e, oDD){
18779 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
18780 //Roo.log('not touch/ button !=0');
18783 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
18784 return; // double touch..
18788 if (this.isLocked()) {
18789 //Roo.log('locked');
18793 this.DDM.refreshCache(this.groups);
18794 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
18795 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
18796 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
18797 //Roo.log('no outer handes or not over target');
18800 // Roo.log('check validator');
18801 if (this.clickValidator(e)) {
18802 // Roo.log('validate success');
18803 // set the initial element position
18804 this.setStartPosition();
18807 this.b4MouseDown(e);
18808 this.onMouseDown(e);
18810 this.DDM.handleMouseDown(e, this);
18812 this.DDM.stopEvent(e);
18820 clickValidator: function(e) {
18821 var target = e.getTarget();
18822 return ( this.isValidHandleChild(target) &&
18823 (this.id == this.handleElId ||
18824 this.DDM.handleWasClicked(target, this.id)) );
18828 * Allows you to specify a tag name that should not start a drag operation
18829 * when clicked. This is designed to facilitate embedding links within a
18830 * drag handle that do something other than start the drag.
18831 * @method addInvalidHandleType
18832 * @param {string} tagName the type of element to exclude
18834 addInvalidHandleType: function(tagName) {
18835 var type = tagName.toUpperCase();
18836 this.invalidHandleTypes[type] = type;
18840 * Lets you to specify an element id for a child of a drag handle
18841 * that should not initiate a drag
18842 * @method addInvalidHandleId
18843 * @param {string} id the element id of the element you wish to ignore
18845 addInvalidHandleId: function(id) {
18846 if (typeof id !== "string") {
18849 this.invalidHandleIds[id] = id;
18853 * Lets you specify a css class of elements that will not initiate a drag
18854 * @method addInvalidHandleClass
18855 * @param {string} cssClass the class of the elements you wish to ignore
18857 addInvalidHandleClass: function(cssClass) {
18858 this.invalidHandleClasses.push(cssClass);
18862 * Unsets an excluded tag name set by addInvalidHandleType
18863 * @method removeInvalidHandleType
18864 * @param {string} tagName the type of element to unexclude
18866 removeInvalidHandleType: function(tagName) {
18867 var type = tagName.toUpperCase();
18868 // this.invalidHandleTypes[type] = null;
18869 delete this.invalidHandleTypes[type];
18873 * Unsets an invalid handle id
18874 * @method removeInvalidHandleId
18875 * @param {string} id the id of the element to re-enable
18877 removeInvalidHandleId: function(id) {
18878 if (typeof id !== "string") {
18881 delete this.invalidHandleIds[id];
18885 * Unsets an invalid css class
18886 * @method removeInvalidHandleClass
18887 * @param {string} cssClass the class of the element(s) you wish to
18890 removeInvalidHandleClass: function(cssClass) {
18891 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
18892 if (this.invalidHandleClasses[i] == cssClass) {
18893 delete this.invalidHandleClasses[i];
18899 * Checks the tag exclusion list to see if this click should be ignored
18900 * @method isValidHandleChild
18901 * @param {HTMLElement} node the HTMLElement to evaluate
18902 * @return {boolean} true if this is a valid tag type, false if not
18904 isValidHandleChild: function(node) {
18907 // var n = (node.nodeName == "#text") ? node.parentNode : node;
18910 nodeName = node.nodeName.toUpperCase();
18912 nodeName = node.nodeName;
18914 valid = valid && !this.invalidHandleTypes[nodeName];
18915 valid = valid && !this.invalidHandleIds[node.id];
18917 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
18918 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
18927 * Create the array of horizontal tick marks if an interval was specified
18928 * in setXConstraint().
18929 * @method setXTicks
18932 setXTicks: function(iStartX, iTickSize) {
18934 this.xTickSize = iTickSize;
18938 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
18940 this.xTicks[this.xTicks.length] = i;
18945 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
18947 this.xTicks[this.xTicks.length] = i;
18952 this.xTicks.sort(this.DDM.numericSort) ;
18956 * Create the array of vertical tick marks if an interval was specified in
18957 * setYConstraint().
18958 * @method setYTicks
18961 setYTicks: function(iStartY, iTickSize) {
18963 this.yTickSize = iTickSize;
18967 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
18969 this.yTicks[this.yTicks.length] = i;
18974 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
18976 this.yTicks[this.yTicks.length] = i;
18981 this.yTicks.sort(this.DDM.numericSort) ;
18985 * By default, the element can be dragged any place on the screen. Use
18986 * this method to limit the horizontal travel of the element. Pass in
18987 * 0,0 for the parameters if you want to lock the drag to the y axis.
18988 * @method setXConstraint
18989 * @param {int} iLeft the number of pixels the element can move to the left
18990 * @param {int} iRight the number of pixels the element can move to the
18992 * @param {int} iTickSize optional parameter for specifying that the
18994 * should move iTickSize pixels at a time.
18996 setXConstraint: function(iLeft, iRight, iTickSize) {
18997 this.leftConstraint = iLeft;
18998 this.rightConstraint = iRight;
19000 this.minX = this.initPageX - iLeft;
19001 this.maxX = this.initPageX + iRight;
19002 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19004 this.constrainX = true;
19008 * Clears any constraints applied to this instance. Also clears ticks
19009 * since they can't exist independent of a constraint at this time.
19010 * @method clearConstraints
19012 clearConstraints: function() {
19013 this.constrainX = false;
19014 this.constrainY = false;
19019 * Clears any tick interval defined for this instance
19020 * @method clearTicks
19022 clearTicks: function() {
19023 this.xTicks = null;
19024 this.yTicks = null;
19025 this.xTickSize = 0;
19026 this.yTickSize = 0;
19030 * By default, the element can be dragged any place on the screen. Set
19031 * this to limit the vertical travel of the element. Pass in 0,0 for the
19032 * parameters if you want to lock the drag to the x axis.
19033 * @method setYConstraint
19034 * @param {int} iUp the number of pixels the element can move up
19035 * @param {int} iDown the number of pixels the element can move down
19036 * @param {int} iTickSize optional parameter for specifying that the
19037 * element should move iTickSize pixels at a time.
19039 setYConstraint: function(iUp, iDown, iTickSize) {
19040 this.topConstraint = iUp;
19041 this.bottomConstraint = iDown;
19043 this.minY = this.initPageY - iUp;
19044 this.maxY = this.initPageY + iDown;
19045 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19047 this.constrainY = true;
19052 * resetConstraints must be called if you manually reposition a dd element.
19053 * @method resetConstraints
19054 * @param {boolean} maintainOffset
19056 resetConstraints: function() {
19059 // Maintain offsets if necessary
19060 if (this.initPageX || this.initPageX === 0) {
19061 // figure out how much this thing has moved
19062 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19063 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19065 this.setInitPosition(dx, dy);
19067 // This is the first time we have detected the element's position
19069 this.setInitPosition();
19072 if (this.constrainX) {
19073 this.setXConstraint( this.leftConstraint,
19074 this.rightConstraint,
19078 if (this.constrainY) {
19079 this.setYConstraint( this.topConstraint,
19080 this.bottomConstraint,
19086 * Normally the drag element is moved pixel by pixel, but we can specify
19087 * that it move a number of pixels at a time. This method resolves the
19088 * location when we have it set up like this.
19090 * @param {int} val where we want to place the object
19091 * @param {int[]} tickArray sorted array of valid points
19092 * @return {int} the closest tick
19095 getTick: function(val, tickArray) {
19098 // If tick interval is not defined, it is effectively 1 pixel,
19099 // so we return the value passed to us.
19101 } else if (tickArray[0] >= val) {
19102 // The value is lower than the first tick, so we return the first
19104 return tickArray[0];
19106 for (var i=0, len=tickArray.length; i<len; ++i) {
19108 if (tickArray[next] && tickArray[next] >= val) {
19109 var diff1 = val - tickArray[i];
19110 var diff2 = tickArray[next] - val;
19111 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19115 // The value is larger than the last tick, so we return the last
19117 return tickArray[tickArray.length - 1];
19124 * @return {string} string representation of the dd obj
19126 toString: function() {
19127 return ("DragDrop " + this.id);
19135 * Ext JS Library 1.1.1
19136 * Copyright(c) 2006-2007, Ext JS, LLC.
19138 * Originally Released Under LGPL - original licence link has changed is not relivant.
19141 * <script type="text/javascript">
19146 * The drag and drop utility provides a framework for building drag and drop
19147 * applications. In addition to enabling drag and drop for specific elements,
19148 * the drag and drop elements are tracked by the manager class, and the
19149 * interactions between the various elements are tracked during the drag and
19150 * the implementing code is notified about these important moments.
19153 // Only load the library once. Rewriting the manager class would orphan
19154 // existing drag and drop instances.
19155 if (!Roo.dd.DragDropMgr) {
19158 * @class Roo.dd.DragDropMgr
19159 * DragDropMgr is a singleton that tracks the element interaction for
19160 * all DragDrop items in the window. Generally, you will not call
19161 * this class directly, but it does have helper methods that could
19162 * be useful in your DragDrop implementations.
19165 Roo.dd.DragDropMgr = function() {
19167 var Event = Roo.EventManager;
19172 * Two dimensional Array of registered DragDrop objects. The first
19173 * dimension is the DragDrop item group, the second the DragDrop
19176 * @type {string: string}
19183 * Array of element ids defined as drag handles. Used to determine
19184 * if the element that generated the mousedown event is actually the
19185 * handle and not the html element itself.
19186 * @property handleIds
19187 * @type {string: string}
19194 * the DragDrop object that is currently being dragged
19195 * @property dragCurrent
19203 * the DragDrop object(s) that are being hovered over
19204 * @property dragOvers
19212 * the X distance between the cursor and the object being dragged
19221 * the Y distance between the cursor and the object being dragged
19230 * Flag to determine if we should prevent the default behavior of the
19231 * events we define. By default this is true, but this can be set to
19232 * false if you need the default behavior (not recommended)
19233 * @property preventDefault
19237 preventDefault: true,
19240 * Flag to determine if we should stop the propagation of the events
19241 * we generate. This is true by default but you may want to set it to
19242 * false if the html element contains other features that require the
19244 * @property stopPropagation
19248 stopPropagation: true,
19251 * Internal flag that is set to true when drag and drop has been
19253 * @property initialized
19260 * All drag and drop can be disabled.
19268 * Called the first time an element is registered.
19274 this.initialized = true;
19278 * In point mode, drag and drop interaction is defined by the
19279 * location of the cursor during the drag/drop
19287 * In intersect mode, drag and drop interactio nis defined by the
19288 * overlap of two or more drag and drop objects.
19289 * @property INTERSECT
19296 * The current drag and drop mode. Default: POINT
19304 * Runs method on all drag and drop objects
19305 * @method _execOnAll
19309 _execOnAll: function(sMethod, args) {
19310 for (var i in this.ids) {
19311 for (var j in this.ids[i]) {
19312 var oDD = this.ids[i][j];
19313 if (! this.isTypeOfDD(oDD)) {
19316 oDD[sMethod].apply(oDD, args);
19322 * Drag and drop initialization. Sets up the global event handlers
19327 _onLoad: function() {
19331 if (!Roo.isTouch) {
19332 Event.on(document, "mouseup", this.handleMouseUp, this, true);
19333 Event.on(document, "mousemove", this.handleMouseMove, this, true);
19335 Event.on(document, "touchend", this.handleMouseUp, this, true);
19336 Event.on(document, "touchmove", this.handleMouseMove, this, true);
19338 Event.on(window, "unload", this._onUnload, this, true);
19339 Event.on(window, "resize", this._onResize, this, true);
19340 // Event.on(window, "mouseout", this._test);
19345 * Reset constraints on all drag and drop objs
19346 * @method _onResize
19350 _onResize: function(e) {
19351 this._execOnAll("resetConstraints", []);
19355 * Lock all drag and drop functionality
19359 lock: function() { this.locked = true; },
19362 * Unlock all drag and drop functionality
19366 unlock: function() { this.locked = false; },
19369 * Is drag and drop locked?
19371 * @return {boolean} True if drag and drop is locked, false otherwise.
19374 isLocked: function() { return this.locked; },
19377 * Location cache that is set for all drag drop objects when a drag is
19378 * initiated, cleared when the drag is finished.
19379 * @property locationCache
19386 * Set useCache to false if you want to force object the lookup of each
19387 * drag and drop linked element constantly during a drag.
19388 * @property useCache
19395 * The number of pixels that the mouse needs to move after the
19396 * mousedown before the drag is initiated. Default=3;
19397 * @property clickPixelThresh
19401 clickPixelThresh: 3,
19404 * The number of milliseconds after the mousedown event to initiate the
19405 * drag if we don't get a mouseup event. Default=1000
19406 * @property clickTimeThresh
19410 clickTimeThresh: 350,
19413 * Flag that indicates that either the drag pixel threshold or the
19414 * mousdown time threshold has been met
19415 * @property dragThreshMet
19420 dragThreshMet: false,
19423 * Timeout used for the click time threshold
19424 * @property clickTimeout
19429 clickTimeout: null,
19432 * The X position of the mousedown event stored for later use when a
19433 * drag threshold is met.
19442 * The Y position of the mousedown event stored for later use when a
19443 * drag threshold is met.
19452 * Each DragDrop instance must be registered with the DragDropMgr.
19453 * This is executed in DragDrop.init()
19454 * @method regDragDrop
19455 * @param {DragDrop} oDD the DragDrop object to register
19456 * @param {String} sGroup the name of the group this element belongs to
19459 regDragDrop: function(oDD, sGroup) {
19460 if (!this.initialized) { this.init(); }
19462 if (!this.ids[sGroup]) {
19463 this.ids[sGroup] = {};
19465 this.ids[sGroup][oDD.id] = oDD;
19469 * Removes the supplied dd instance from the supplied group. Executed
19470 * by DragDrop.removeFromGroup, so don't call this function directly.
19471 * @method removeDDFromGroup
19475 removeDDFromGroup: function(oDD, sGroup) {
19476 if (!this.ids[sGroup]) {
19477 this.ids[sGroup] = {};
19480 var obj = this.ids[sGroup];
19481 if (obj && obj[oDD.id]) {
19482 delete obj[oDD.id];
19487 * Unregisters a drag and drop item. This is executed in
19488 * DragDrop.unreg, use that method instead of calling this directly.
19493 _remove: function(oDD) {
19494 for (var g in oDD.groups) {
19495 if (g && this.ids[g][oDD.id]) {
19496 delete this.ids[g][oDD.id];
19499 delete this.handleIds[oDD.id];
19503 * Each DragDrop handle element must be registered. This is done
19504 * automatically when executing DragDrop.setHandleElId()
19505 * @method regHandle
19506 * @param {String} sDDId the DragDrop id this element is a handle for
19507 * @param {String} sHandleId the id of the element that is the drag
19511 regHandle: function(sDDId, sHandleId) {
19512 if (!this.handleIds[sDDId]) {
19513 this.handleIds[sDDId] = {};
19515 this.handleIds[sDDId][sHandleId] = sHandleId;
19519 * Utility function to determine if a given element has been
19520 * registered as a drag drop item.
19521 * @method isDragDrop
19522 * @param {String} id the element id to check
19523 * @return {boolean} true if this element is a DragDrop item,
19527 isDragDrop: function(id) {
19528 return ( this.getDDById(id) ) ? true : false;
19532 * Returns the drag and drop instances that are in all groups the
19533 * passed in instance belongs to.
19534 * @method getRelated
19535 * @param {DragDrop} p_oDD the obj to get related data for
19536 * @param {boolean} bTargetsOnly if true, only return targetable objs
19537 * @return {DragDrop[]} the related instances
19540 getRelated: function(p_oDD, bTargetsOnly) {
19542 for (var i in p_oDD.groups) {
19543 for (j in this.ids[i]) {
19544 var dd = this.ids[i][j];
19545 if (! this.isTypeOfDD(dd)) {
19548 if (!bTargetsOnly || dd.isTarget) {
19549 oDDs[oDDs.length] = dd;
19558 * Returns true if the specified dd target is a legal target for
19559 * the specifice drag obj
19560 * @method isLegalTarget
19561 * @param {DragDrop} the drag obj
19562 * @param {DragDrop} the target
19563 * @return {boolean} true if the target is a legal target for the
19567 isLegalTarget: function (oDD, oTargetDD) {
19568 var targets = this.getRelated(oDD, true);
19569 for (var i=0, len=targets.length;i<len;++i) {
19570 if (targets[i].id == oTargetDD.id) {
19579 * My goal is to be able to transparently determine if an object is
19580 * typeof DragDrop, and the exact subclass of DragDrop. typeof
19581 * returns "object", oDD.constructor.toString() always returns
19582 * "DragDrop" and not the name of the subclass. So for now it just
19583 * evaluates a well-known variable in DragDrop.
19584 * @method isTypeOfDD
19585 * @param {Object} the object to evaluate
19586 * @return {boolean} true if typeof oDD = DragDrop
19589 isTypeOfDD: function (oDD) {
19590 return (oDD && oDD.__ygDragDrop);
19594 * Utility function to determine if a given element has been
19595 * registered as a drag drop handle for the given Drag Drop object.
19597 * @param {String} id the element id to check
19598 * @return {boolean} true if this element is a DragDrop handle, false
19602 isHandle: function(sDDId, sHandleId) {
19603 return ( this.handleIds[sDDId] &&
19604 this.handleIds[sDDId][sHandleId] );
19608 * Returns the DragDrop instance for a given id
19609 * @method getDDById
19610 * @param {String} id the id of the DragDrop object
19611 * @return {DragDrop} the drag drop object, null if it is not found
19614 getDDById: function(id) {
19615 for (var i in this.ids) {
19616 if (this.ids[i][id]) {
19617 return this.ids[i][id];
19624 * Fired after a registered DragDrop object gets the mousedown event.
19625 * Sets up the events required to track the object being dragged
19626 * @method handleMouseDown
19627 * @param {Event} e the event
19628 * @param oDD the DragDrop object being dragged
19632 handleMouseDown: function(e, oDD) {
19634 Roo.QuickTips.disable();
19636 this.currentTarget = e.getTarget();
19638 this.dragCurrent = oDD;
19640 var el = oDD.getEl();
19642 // track start position
19643 this.startX = e.getPageX();
19644 this.startY = e.getPageY();
19646 this.deltaX = this.startX - el.offsetLeft;
19647 this.deltaY = this.startY - el.offsetTop;
19649 this.dragThreshMet = false;
19651 this.clickTimeout = setTimeout(
19653 var DDM = Roo.dd.DDM;
19654 DDM.startDrag(DDM.startX, DDM.startY);
19656 this.clickTimeThresh );
19660 * Fired when either the drag pixel threshol or the mousedown hold
19661 * time threshold has been met.
19662 * @method startDrag
19663 * @param x {int} the X position of the original mousedown
19664 * @param y {int} the Y position of the original mousedown
19667 startDrag: function(x, y) {
19668 clearTimeout(this.clickTimeout);
19669 if (this.dragCurrent) {
19670 this.dragCurrent.b4StartDrag(x, y);
19671 this.dragCurrent.startDrag(x, y);
19673 this.dragThreshMet = true;
19677 * Internal function to handle the mouseup event. Will be invoked
19678 * from the context of the document.
19679 * @method handleMouseUp
19680 * @param {Event} e the event
19684 handleMouseUp: function(e) {
19687 Roo.QuickTips.enable();
19689 if (! this.dragCurrent) {
19693 clearTimeout(this.clickTimeout);
19695 if (this.dragThreshMet) {
19696 this.fireEvents(e, true);
19706 * Utility to stop event propagation and event default, if these
19707 * features are turned on.
19708 * @method stopEvent
19709 * @param {Event} e the event as returned by this.getEvent()
19712 stopEvent: function(e){
19713 if(this.stopPropagation) {
19714 e.stopPropagation();
19717 if (this.preventDefault) {
19718 e.preventDefault();
19723 * Internal function to clean up event handlers after the drag
19724 * operation is complete
19726 * @param {Event} e the event
19730 stopDrag: function(e) {
19731 // Fire the drag end event for the item that was dragged
19732 if (this.dragCurrent) {
19733 if (this.dragThreshMet) {
19734 this.dragCurrent.b4EndDrag(e);
19735 this.dragCurrent.endDrag(e);
19738 this.dragCurrent.onMouseUp(e);
19741 this.dragCurrent = null;
19742 this.dragOvers = {};
19746 * Internal function to handle the mousemove event. Will be invoked
19747 * from the context of the html element.
19749 * @TODO figure out what we can do about mouse events lost when the
19750 * user drags objects beyond the window boundary. Currently we can
19751 * detect this in internet explorer by verifying that the mouse is
19752 * down during the mousemove event. Firefox doesn't give us the
19753 * button state on the mousemove event.
19754 * @method handleMouseMove
19755 * @param {Event} e the event
19759 handleMouseMove: function(e) {
19760 if (! this.dragCurrent) {
19764 // var button = e.which || e.button;
19766 // check for IE mouseup outside of page boundary
19767 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
19769 return this.handleMouseUp(e);
19772 if (!this.dragThreshMet) {
19773 var diffX = Math.abs(this.startX - e.getPageX());
19774 var diffY = Math.abs(this.startY - e.getPageY());
19775 if (diffX > this.clickPixelThresh ||
19776 diffY > this.clickPixelThresh) {
19777 this.startDrag(this.startX, this.startY);
19781 if (this.dragThreshMet) {
19782 this.dragCurrent.b4Drag(e);
19783 this.dragCurrent.onDrag(e);
19784 if(!this.dragCurrent.moveOnly){
19785 this.fireEvents(e, false);
19795 * Iterates over all of the DragDrop elements to find ones we are
19796 * hovering over or dropping on
19797 * @method fireEvents
19798 * @param {Event} e the event
19799 * @param {boolean} isDrop is this a drop op or a mouseover op?
19803 fireEvents: function(e, isDrop) {
19804 var dc = this.dragCurrent;
19806 // If the user did the mouse up outside of the window, we could
19807 // get here even though we have ended the drag.
19808 if (!dc || dc.isLocked()) {
19812 var pt = e.getPoint();
19814 // cache the previous dragOver array
19820 var enterEvts = [];
19822 // Check to see if the object(s) we were hovering over is no longer
19823 // being hovered over so we can fire the onDragOut event
19824 for (var i in this.dragOvers) {
19826 var ddo = this.dragOvers[i];
19828 if (! this.isTypeOfDD(ddo)) {
19832 if (! this.isOverTarget(pt, ddo, this.mode)) {
19833 outEvts.push( ddo );
19836 oldOvers[i] = true;
19837 delete this.dragOvers[i];
19840 for (var sGroup in dc.groups) {
19842 if ("string" != typeof sGroup) {
19846 for (i in this.ids[sGroup]) {
19847 var oDD = this.ids[sGroup][i];
19848 if (! this.isTypeOfDD(oDD)) {
19852 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
19853 if (this.isOverTarget(pt, oDD, this.mode)) {
19854 // look for drop interactions
19856 dropEvts.push( oDD );
19857 // look for drag enter and drag over interactions
19860 // initial drag over: dragEnter fires
19861 if (!oldOvers[oDD.id]) {
19862 enterEvts.push( oDD );
19863 // subsequent drag overs: dragOver fires
19865 overEvts.push( oDD );
19868 this.dragOvers[oDD.id] = oDD;
19876 if (outEvts.length) {
19877 dc.b4DragOut(e, outEvts);
19878 dc.onDragOut(e, outEvts);
19881 if (enterEvts.length) {
19882 dc.onDragEnter(e, enterEvts);
19885 if (overEvts.length) {
19886 dc.b4DragOver(e, overEvts);
19887 dc.onDragOver(e, overEvts);
19890 if (dropEvts.length) {
19891 dc.b4DragDrop(e, dropEvts);
19892 dc.onDragDrop(e, dropEvts);
19896 // fire dragout events
19898 for (i=0, len=outEvts.length; i<len; ++i) {
19899 dc.b4DragOut(e, outEvts[i].id);
19900 dc.onDragOut(e, outEvts[i].id);
19903 // fire enter events
19904 for (i=0,len=enterEvts.length; i<len; ++i) {
19905 // dc.b4DragEnter(e, oDD.id);
19906 dc.onDragEnter(e, enterEvts[i].id);
19909 // fire over events
19910 for (i=0,len=overEvts.length; i<len; ++i) {
19911 dc.b4DragOver(e, overEvts[i].id);
19912 dc.onDragOver(e, overEvts[i].id);
19915 // fire drop events
19916 for (i=0, len=dropEvts.length; i<len; ++i) {
19917 dc.b4DragDrop(e, dropEvts[i].id);
19918 dc.onDragDrop(e, dropEvts[i].id);
19923 // notify about a drop that did not find a target
19924 if (isDrop && !dropEvts.length) {
19925 dc.onInvalidDrop(e);
19931 * Helper function for getting the best match from the list of drag
19932 * and drop objects returned by the drag and drop events when we are
19933 * in INTERSECT mode. It returns either the first object that the
19934 * cursor is over, or the object that has the greatest overlap with
19935 * the dragged element.
19936 * @method getBestMatch
19937 * @param {DragDrop[]} dds The array of drag and drop objects
19939 * @return {DragDrop} The best single match
19942 getBestMatch: function(dds) {
19944 // Return null if the input is not what we expect
19945 //if (!dds || !dds.length || dds.length == 0) {
19947 // If there is only one item, it wins
19948 //} else if (dds.length == 1) {
19950 var len = dds.length;
19955 // Loop through the targeted items
19956 for (var i=0; i<len; ++i) {
19958 // If the cursor is over the object, it wins. If the
19959 // cursor is over multiple matches, the first one we come
19961 if (dd.cursorIsOver) {
19964 // Otherwise the object with the most overlap wins
19967 winner.overlap.getArea() < dd.overlap.getArea()) {
19978 * Refreshes the cache of the top-left and bottom-right points of the
19979 * drag and drop objects in the specified group(s). This is in the
19980 * format that is stored in the drag and drop instance, so typical
19983 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
19987 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
19989 * @TODO this really should be an indexed array. Alternatively this
19990 * method could accept both.
19991 * @method refreshCache
19992 * @param {Object} groups an associative array of groups to refresh
19995 refreshCache: function(groups) {
19996 for (var sGroup in groups) {
19997 if ("string" != typeof sGroup) {
20000 for (var i in this.ids[sGroup]) {
20001 var oDD = this.ids[sGroup][i];
20003 if (this.isTypeOfDD(oDD)) {
20004 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20005 var loc = this.getLocation(oDD);
20007 this.locationCache[oDD.id] = loc;
20009 delete this.locationCache[oDD.id];
20010 // this will unregister the drag and drop object if
20011 // the element is not in a usable state
20020 * This checks to make sure an element exists and is in the DOM. The
20021 * main purpose is to handle cases where innerHTML is used to remove
20022 * drag and drop objects from the DOM. IE provides an 'unspecified
20023 * error' when trying to access the offsetParent of such an element
20025 * @param {HTMLElement} el the element to check
20026 * @return {boolean} true if the element looks usable
20029 verifyEl: function(el) {
20034 parent = el.offsetParent;
20037 parent = el.offsetParent;
20048 * Returns a Region object containing the drag and drop element's position
20049 * and size, including the padding configured for it
20050 * @method getLocation
20051 * @param {DragDrop} oDD the drag and drop object to get the
20053 * @return {Roo.lib.Region} a Region object representing the total area
20054 * the element occupies, including any padding
20055 * the instance is configured for.
20058 getLocation: function(oDD) {
20059 if (! this.isTypeOfDD(oDD)) {
20063 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20066 pos= Roo.lib.Dom.getXY(el);
20074 x2 = x1 + el.offsetWidth;
20076 y2 = y1 + el.offsetHeight;
20078 t = y1 - oDD.padding[0];
20079 r = x2 + oDD.padding[1];
20080 b = y2 + oDD.padding[2];
20081 l = x1 - oDD.padding[3];
20083 return new Roo.lib.Region( t, r, b, l );
20087 * Checks the cursor location to see if it over the target
20088 * @method isOverTarget
20089 * @param {Roo.lib.Point} pt The point to evaluate
20090 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20091 * @return {boolean} true if the mouse is over the target
20095 isOverTarget: function(pt, oTarget, intersect) {
20096 // use cache if available
20097 var loc = this.locationCache[oTarget.id];
20098 if (!loc || !this.useCache) {
20099 loc = this.getLocation(oTarget);
20100 this.locationCache[oTarget.id] = loc;
20108 oTarget.cursorIsOver = loc.contains( pt );
20110 // DragDrop is using this as a sanity check for the initial mousedown
20111 // in this case we are done. In POINT mode, if the drag obj has no
20112 // contraints, we are also done. Otherwise we need to evaluate the
20113 // location of the target as related to the actual location of the
20114 // dragged element.
20115 var dc = this.dragCurrent;
20116 if (!dc || !dc.getTargetCoord ||
20117 (!intersect && !dc.constrainX && !dc.constrainY)) {
20118 return oTarget.cursorIsOver;
20121 oTarget.overlap = null;
20123 // Get the current location of the drag element, this is the
20124 // location of the mouse event less the delta that represents
20125 // where the original mousedown happened on the element. We
20126 // need to consider constraints and ticks as well.
20127 var pos = dc.getTargetCoord(pt.x, pt.y);
20129 var el = dc.getDragEl();
20130 var curRegion = new Roo.lib.Region( pos.y,
20131 pos.x + el.offsetWidth,
20132 pos.y + el.offsetHeight,
20135 var overlap = curRegion.intersect(loc);
20138 oTarget.overlap = overlap;
20139 return (intersect) ? true : oTarget.cursorIsOver;
20146 * unload event handler
20147 * @method _onUnload
20151 _onUnload: function(e, me) {
20152 Roo.dd.DragDropMgr.unregAll();
20156 * Cleans up the drag and drop events and objects.
20161 unregAll: function() {
20163 if (this.dragCurrent) {
20165 this.dragCurrent = null;
20168 this._execOnAll("unreg", []);
20170 for (i in this.elementCache) {
20171 delete this.elementCache[i];
20174 this.elementCache = {};
20179 * A cache of DOM elements
20180 * @property elementCache
20187 * Get the wrapper for the DOM element specified
20188 * @method getElWrapper
20189 * @param {String} id the id of the element to get
20190 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
20192 * @deprecated This wrapper isn't that useful
20195 getElWrapper: function(id) {
20196 var oWrapper = this.elementCache[id];
20197 if (!oWrapper || !oWrapper.el) {
20198 oWrapper = this.elementCache[id] =
20199 new this.ElementWrapper(Roo.getDom(id));
20205 * Returns the actual DOM element
20206 * @method getElement
20207 * @param {String} id the id of the elment to get
20208 * @return {Object} The element
20209 * @deprecated use Roo.getDom instead
20212 getElement: function(id) {
20213 return Roo.getDom(id);
20217 * Returns the style property for the DOM element (i.e.,
20218 * document.getElById(id).style)
20220 * @param {String} id the id of the elment to get
20221 * @return {Object} The style property of the element
20222 * @deprecated use Roo.getDom instead
20225 getCss: function(id) {
20226 var el = Roo.getDom(id);
20227 return (el) ? el.style : null;
20231 * Inner class for cached elements
20232 * @class DragDropMgr.ElementWrapper
20237 ElementWrapper: function(el) {
20242 this.el = el || null;
20247 this.id = this.el && el.id;
20249 * A reference to the style property
20252 this.css = this.el && el.style;
20256 * Returns the X position of an html element
20258 * @param el the element for which to get the position
20259 * @return {int} the X coordinate
20261 * @deprecated use Roo.lib.Dom.getX instead
20264 getPosX: function(el) {
20265 return Roo.lib.Dom.getX(el);
20269 * Returns the Y position of an html element
20271 * @param el the element for which to get the position
20272 * @return {int} the Y coordinate
20273 * @deprecated use Roo.lib.Dom.getY instead
20276 getPosY: function(el) {
20277 return Roo.lib.Dom.getY(el);
20281 * Swap two nodes. In IE, we use the native method, for others we
20282 * emulate the IE behavior
20284 * @param n1 the first node to swap
20285 * @param n2 the other node to swap
20288 swapNode: function(n1, n2) {
20292 var p = n2.parentNode;
20293 var s = n2.nextSibling;
20296 p.insertBefore(n1, n2);
20297 } else if (n2 == n1.nextSibling) {
20298 p.insertBefore(n2, n1);
20300 n1.parentNode.replaceChild(n2, n1);
20301 p.insertBefore(n1, s);
20307 * Returns the current scroll position
20308 * @method getScroll
20312 getScroll: function () {
20313 var t, l, dde=document.documentElement, db=document.body;
20314 if (dde && (dde.scrollTop || dde.scrollLeft)) {
20316 l = dde.scrollLeft;
20323 return { top: t, left: l };
20327 * Returns the specified element style property
20329 * @param {HTMLElement} el the element
20330 * @param {string} styleProp the style property
20331 * @return {string} The value of the style property
20332 * @deprecated use Roo.lib.Dom.getStyle
20335 getStyle: function(el, styleProp) {
20336 return Roo.fly(el).getStyle(styleProp);
20340 * Gets the scrollTop
20341 * @method getScrollTop
20342 * @return {int} the document's scrollTop
20345 getScrollTop: function () { return this.getScroll().top; },
20348 * Gets the scrollLeft
20349 * @method getScrollLeft
20350 * @return {int} the document's scrollTop
20353 getScrollLeft: function () { return this.getScroll().left; },
20356 * Sets the x/y position of an element to the location of the
20359 * @param {HTMLElement} moveEl The element to move
20360 * @param {HTMLElement} targetEl The position reference element
20363 moveToEl: function (moveEl, targetEl) {
20364 var aCoord = Roo.lib.Dom.getXY(targetEl);
20365 Roo.lib.Dom.setXY(moveEl, aCoord);
20369 * Numeric array sort function
20370 * @method numericSort
20373 numericSort: function(a, b) { return (a - b); },
20377 * @property _timeoutCount
20384 * Trying to make the load order less important. Without this we get
20385 * an error if this file is loaded before the Event Utility.
20386 * @method _addListeners
20390 _addListeners: function() {
20391 var DDM = Roo.dd.DDM;
20392 if ( Roo.lib.Event && document ) {
20395 if (DDM._timeoutCount > 2000) {
20397 setTimeout(DDM._addListeners, 10);
20398 if (document && document.body) {
20399 DDM._timeoutCount += 1;
20406 * Recursively searches the immediate parent and all child nodes for
20407 * the handle element in order to determine wheter or not it was
20409 * @method handleWasClicked
20410 * @param node the html element to inspect
20413 handleWasClicked: function(node, id) {
20414 if (this.isHandle(id, node.id)) {
20417 // check to see if this is a text node child of the one we want
20418 var p = node.parentNode;
20421 if (this.isHandle(id, p.id)) {
20436 // shorter alias, save a few bytes
20437 Roo.dd.DDM = Roo.dd.DragDropMgr;
20438 Roo.dd.DDM._addListeners();
20442 * Ext JS Library 1.1.1
20443 * Copyright(c) 2006-2007, Ext JS, LLC.
20445 * Originally Released Under LGPL - original licence link has changed is not relivant.
20448 * <script type="text/javascript">
20453 * A DragDrop implementation where the linked element follows the
20454 * mouse cursor during a drag.
20455 * @extends Roo.dd.DragDrop
20457 * @param {String} id the id of the linked element
20458 * @param {String} sGroup the group of related DragDrop items
20459 * @param {object} config an object containing configurable attributes
20460 * Valid properties for DD:
20463 Roo.dd.DD = function(id, sGroup, config) {
20465 this.init(id, sGroup, config);
20469 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
20472 * When set to true, the utility automatically tries to scroll the browser
20473 * window wehn a drag and drop element is dragged near the viewport boundary.
20474 * Defaults to true.
20481 * Sets the pointer offset to the distance between the linked element's top
20482 * left corner and the location the element was clicked
20483 * @method autoOffset
20484 * @param {int} iPageX the X coordinate of the click
20485 * @param {int} iPageY the Y coordinate of the click
20487 autoOffset: function(iPageX, iPageY) {
20488 var x = iPageX - this.startPageX;
20489 var y = iPageY - this.startPageY;
20490 this.setDelta(x, y);
20494 * Sets the pointer offset. You can call this directly to force the
20495 * offset to be in a particular location (e.g., pass in 0,0 to set it
20496 * to the center of the object)
20498 * @param {int} iDeltaX the distance from the left
20499 * @param {int} iDeltaY the distance from the top
20501 setDelta: function(iDeltaX, iDeltaY) {
20502 this.deltaX = iDeltaX;
20503 this.deltaY = iDeltaY;
20507 * Sets the drag element to the location of the mousedown or click event,
20508 * maintaining the cursor location relative to the location on the element
20509 * that was clicked. Override this if you want to place the element in a
20510 * location other than where the cursor is.
20511 * @method setDragElPos
20512 * @param {int} iPageX the X coordinate of the mousedown or drag event
20513 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20515 setDragElPos: function(iPageX, iPageY) {
20516 // the first time we do this, we are going to check to make sure
20517 // the element has css positioning
20519 var el = this.getDragEl();
20520 this.alignElWithMouse(el, iPageX, iPageY);
20524 * Sets the element to the location of the mousedown or click event,
20525 * maintaining the cursor location relative to the location on the element
20526 * that was clicked. Override this if you want to place the element in a
20527 * location other than where the cursor is.
20528 * @method alignElWithMouse
20529 * @param {HTMLElement} el the element to move
20530 * @param {int} iPageX the X coordinate of the mousedown or drag event
20531 * @param {int} iPageY the Y coordinate of the mousedown or drag event
20533 alignElWithMouse: function(el, iPageX, iPageY) {
20534 var oCoord = this.getTargetCoord(iPageX, iPageY);
20535 var fly = el.dom ? el : Roo.fly(el);
20536 if (!this.deltaSetXY) {
20537 var aCoord = [oCoord.x, oCoord.y];
20539 var newLeft = fly.getLeft(true);
20540 var newTop = fly.getTop(true);
20541 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
20543 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
20546 this.cachePosition(oCoord.x, oCoord.y);
20547 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
20552 * Saves the most recent position so that we can reset the constraints and
20553 * tick marks on-demand. We need to know this so that we can calculate the
20554 * number of pixels the element is offset from its original position.
20555 * @method cachePosition
20556 * @param iPageX the current x position (optional, this just makes it so we
20557 * don't have to look it up again)
20558 * @param iPageY the current y position (optional, this just makes it so we
20559 * don't have to look it up again)
20561 cachePosition: function(iPageX, iPageY) {
20563 this.lastPageX = iPageX;
20564 this.lastPageY = iPageY;
20566 var aCoord = Roo.lib.Dom.getXY(this.getEl());
20567 this.lastPageX = aCoord[0];
20568 this.lastPageY = aCoord[1];
20573 * Auto-scroll the window if the dragged object has been moved beyond the
20574 * visible window boundary.
20575 * @method autoScroll
20576 * @param {int} x the drag element's x position
20577 * @param {int} y the drag element's y position
20578 * @param {int} h the height of the drag element
20579 * @param {int} w the width of the drag element
20582 autoScroll: function(x, y, h, w) {
20585 // The client height
20586 var clientH = Roo.lib.Dom.getViewWidth();
20588 // The client width
20589 var clientW = Roo.lib.Dom.getViewHeight();
20591 // The amt scrolled down
20592 var st = this.DDM.getScrollTop();
20594 // The amt scrolled right
20595 var sl = this.DDM.getScrollLeft();
20597 // Location of the bottom of the element
20600 // Location of the right of the element
20603 // The distance from the cursor to the bottom of the visible area,
20604 // adjusted so that we don't scroll if the cursor is beyond the
20605 // element drag constraints
20606 var toBot = (clientH + st - y - this.deltaY);
20608 // The distance from the cursor to the right of the visible area
20609 var toRight = (clientW + sl - x - this.deltaX);
20612 // How close to the edge the cursor must be before we scroll
20613 // var thresh = (document.all) ? 100 : 40;
20616 // How many pixels to scroll per autoscroll op. This helps to reduce
20617 // clunky scrolling. IE is more sensitive about this ... it needs this
20618 // value to be higher.
20619 var scrAmt = (document.all) ? 80 : 30;
20621 // Scroll down if we are near the bottom of the visible page and the
20622 // obj extends below the crease
20623 if ( bot > clientH && toBot < thresh ) {
20624 window.scrollTo(sl, st + scrAmt);
20627 // Scroll up if the window is scrolled down and the top of the object
20628 // goes above the top border
20629 if ( y < st && st > 0 && y - st < thresh ) {
20630 window.scrollTo(sl, st - scrAmt);
20633 // Scroll right if the obj is beyond the right border and the cursor is
20634 // near the border.
20635 if ( right > clientW && toRight < thresh ) {
20636 window.scrollTo(sl + scrAmt, st);
20639 // Scroll left if the window has been scrolled to the right and the obj
20640 // extends past the left border
20641 if ( x < sl && sl > 0 && x - sl < thresh ) {
20642 window.scrollTo(sl - scrAmt, st);
20648 * Finds the location the element should be placed if we want to move
20649 * it to where the mouse location less the click offset would place us.
20650 * @method getTargetCoord
20651 * @param {int} iPageX the X coordinate of the click
20652 * @param {int} iPageY the Y coordinate of the click
20653 * @return an object that contains the coordinates (Object.x and Object.y)
20656 getTargetCoord: function(iPageX, iPageY) {
20659 var x = iPageX - this.deltaX;
20660 var y = iPageY - this.deltaY;
20662 if (this.constrainX) {
20663 if (x < this.minX) { x = this.minX; }
20664 if (x > this.maxX) { x = this.maxX; }
20667 if (this.constrainY) {
20668 if (y < this.minY) { y = this.minY; }
20669 if (y > this.maxY) { y = this.maxY; }
20672 x = this.getTick(x, this.xTicks);
20673 y = this.getTick(y, this.yTicks);
20680 * Sets up config options specific to this class. Overrides
20681 * Roo.dd.DragDrop, but all versions of this method through the
20682 * inheritance chain are called
20684 applyConfig: function() {
20685 Roo.dd.DD.superclass.applyConfig.call(this);
20686 this.scroll = (this.config.scroll !== false);
20690 * Event that fires prior to the onMouseDown event. Overrides
20693 b4MouseDown: function(e) {
20694 // this.resetConstraints();
20695 this.autoOffset(e.getPageX(),
20700 * Event that fires prior to the onDrag event. Overrides
20703 b4Drag: function(e) {
20704 this.setDragElPos(e.getPageX(),
20708 toString: function() {
20709 return ("DD " + this.id);
20712 //////////////////////////////////////////////////////////////////////////
20713 // Debugging ygDragDrop events that can be overridden
20714 //////////////////////////////////////////////////////////////////////////
20716 startDrag: function(x, y) {
20719 onDrag: function(e) {
20722 onDragEnter: function(e, id) {
20725 onDragOver: function(e, id) {
20728 onDragOut: function(e, id) {
20731 onDragDrop: function(e, id) {
20734 endDrag: function(e) {
20741 * Ext JS Library 1.1.1
20742 * Copyright(c) 2006-2007, Ext JS, LLC.
20744 * Originally Released Under LGPL - original licence link has changed is not relivant.
20747 * <script type="text/javascript">
20751 * @class Roo.dd.DDProxy
20752 * A DragDrop implementation that inserts an empty, bordered div into
20753 * the document that follows the cursor during drag operations. At the time of
20754 * the click, the frame div is resized to the dimensions of the linked html
20755 * element, and moved to the exact location of the linked element.
20757 * References to the "frame" element refer to the single proxy element that
20758 * was created to be dragged in place of all DDProxy elements on the
20761 * @extends Roo.dd.DD
20763 * @param {String} id the id of the linked html element
20764 * @param {String} sGroup the group of related DragDrop objects
20765 * @param {object} config an object containing configurable attributes
20766 * Valid properties for DDProxy in addition to those in DragDrop:
20767 * resizeFrame, centerFrame, dragElId
20769 Roo.dd.DDProxy = function(id, sGroup, config) {
20771 this.init(id, sGroup, config);
20777 * The default drag frame div id
20778 * @property Roo.dd.DDProxy.dragElId
20782 Roo.dd.DDProxy.dragElId = "ygddfdiv";
20784 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
20787 * By default we resize the drag frame to be the same size as the element
20788 * we want to drag (this is to get the frame effect). We can turn it off
20789 * if we want a different behavior.
20790 * @property resizeFrame
20796 * By default the frame is positioned exactly where the drag element is, so
20797 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
20798 * you do not have constraints on the obj is to have the drag frame centered
20799 * around the cursor. Set centerFrame to true for this effect.
20800 * @property centerFrame
20803 centerFrame: false,
20806 * Creates the proxy element if it does not yet exist
20807 * @method createFrame
20809 createFrame: function() {
20811 var body = document.body;
20813 if (!body || !body.firstChild) {
20814 setTimeout( function() { self.createFrame(); }, 50 );
20818 var div = this.getDragEl();
20821 div = document.createElement("div");
20822 div.id = this.dragElId;
20825 s.position = "absolute";
20826 s.visibility = "hidden";
20828 s.border = "2px solid #aaa";
20831 // appendChild can blow up IE if invoked prior to the window load event
20832 // while rendering a table. It is possible there are other scenarios
20833 // that would cause this to happen as well.
20834 body.insertBefore(div, body.firstChild);
20839 * Initialization for the drag frame element. Must be called in the
20840 * constructor of all subclasses
20841 * @method initFrame
20843 initFrame: function() {
20844 this.createFrame();
20847 applyConfig: function() {
20848 Roo.dd.DDProxy.superclass.applyConfig.call(this);
20850 this.resizeFrame = (this.config.resizeFrame !== false);
20851 this.centerFrame = (this.config.centerFrame);
20852 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
20856 * Resizes the drag frame to the dimensions of the clicked object, positions
20857 * it over the object, and finally displays it
20858 * @method showFrame
20859 * @param {int} iPageX X click position
20860 * @param {int} iPageY Y click position
20863 showFrame: function(iPageX, iPageY) {
20864 var el = this.getEl();
20865 var dragEl = this.getDragEl();
20866 var s = dragEl.style;
20868 this._resizeProxy();
20870 if (this.centerFrame) {
20871 this.setDelta( Math.round(parseInt(s.width, 10)/2),
20872 Math.round(parseInt(s.height, 10)/2) );
20875 this.setDragElPos(iPageX, iPageY);
20877 Roo.fly(dragEl).show();
20881 * The proxy is automatically resized to the dimensions of the linked
20882 * element when a drag is initiated, unless resizeFrame is set to false
20883 * @method _resizeProxy
20886 _resizeProxy: function() {
20887 if (this.resizeFrame) {
20888 var el = this.getEl();
20889 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
20893 // overrides Roo.dd.DragDrop
20894 b4MouseDown: function(e) {
20895 var x = e.getPageX();
20896 var y = e.getPageY();
20897 this.autoOffset(x, y);
20898 this.setDragElPos(x, y);
20901 // overrides Roo.dd.DragDrop
20902 b4StartDrag: function(x, y) {
20903 // show the drag frame
20904 this.showFrame(x, y);
20907 // overrides Roo.dd.DragDrop
20908 b4EndDrag: function(e) {
20909 Roo.fly(this.getDragEl()).hide();
20912 // overrides Roo.dd.DragDrop
20913 // By default we try to move the element to the last location of the frame.
20914 // This is so that the default behavior mirrors that of Roo.dd.DD.
20915 endDrag: function(e) {
20917 var lel = this.getEl();
20918 var del = this.getDragEl();
20920 // Show the drag frame briefly so we can get its position
20921 del.style.visibility = "";
20924 // Hide the linked element before the move to get around a Safari
20926 lel.style.visibility = "hidden";
20927 Roo.dd.DDM.moveToEl(lel, del);
20928 del.style.visibility = "hidden";
20929 lel.style.visibility = "";
20934 beforeMove : function(){
20938 afterDrag : function(){
20942 toString: function() {
20943 return ("DDProxy " + this.id);
20949 * Ext JS Library 1.1.1
20950 * Copyright(c) 2006-2007, Ext JS, LLC.
20952 * Originally Released Under LGPL - original licence link has changed is not relivant.
20955 * <script type="text/javascript">
20959 * @class Roo.dd.DDTarget
20960 * A DragDrop implementation that does not move, but can be a drop
20961 * target. You would get the same result by simply omitting implementation
20962 * for the event callbacks, but this way we reduce the processing cost of the
20963 * event listener and the callbacks.
20964 * @extends Roo.dd.DragDrop
20966 * @param {String} id the id of the element that is a drop target
20967 * @param {String} sGroup the group of related DragDrop objects
20968 * @param {object} config an object containing configurable attributes
20969 * Valid properties for DDTarget in addition to those in
20973 Roo.dd.DDTarget = function(id, sGroup, config) {
20975 this.initTarget(id, sGroup, config);
20977 if (config.listeners || config.events) {
20978 Roo.dd.DragDrop.superclass.constructor.call(this, {
20979 listeners : config.listeners || {},
20980 events : config.events || {}
20985 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
20986 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
20987 toString: function() {
20988 return ("DDTarget " + this.id);
20993 * Ext JS Library 1.1.1
20994 * Copyright(c) 2006-2007, Ext JS, LLC.
20996 * Originally Released Under LGPL - original licence link has changed is not relivant.
20999 * <script type="text/javascript">
21004 * @class Roo.dd.ScrollManager
21005 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21006 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21009 Roo.dd.ScrollManager = function(){
21010 var ddm = Roo.dd.DragDropMgr;
21017 var onStop = function(e){
21022 var triggerRefresh = function(){
21023 if(ddm.dragCurrent){
21024 ddm.refreshCache(ddm.dragCurrent.groups);
21028 var doScroll = function(){
21029 if(ddm.dragCurrent){
21030 var dds = Roo.dd.ScrollManager;
21032 if(proc.el.scroll(proc.dir, dds.increment)){
21036 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21041 var clearProc = function(){
21043 clearInterval(proc.id);
21050 var startProc = function(el, dir){
21051 Roo.log('scroll startproc');
21055 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21058 var onFire = function(e, isDrop){
21060 if(isDrop || !ddm.dragCurrent){ return; }
21061 var dds = Roo.dd.ScrollManager;
21062 if(!dragEl || dragEl != ddm.dragCurrent){
21063 dragEl = ddm.dragCurrent;
21064 // refresh regions on drag start
21065 dds.refreshCache();
21068 var xy = Roo.lib.Event.getXY(e);
21069 var pt = new Roo.lib.Point(xy[0], xy[1]);
21070 for(var id in els){
21071 var el = els[id], r = el._region;
21072 if(r && r.contains(pt) && el.isScrollable()){
21073 if(r.bottom - pt.y <= dds.thresh){
21075 startProc(el, "down");
21078 }else if(r.right - pt.x <= dds.thresh){
21080 startProc(el, "left");
21083 }else if(pt.y - r.top <= dds.thresh){
21085 startProc(el, "up");
21088 }else if(pt.x - r.left <= dds.thresh){
21090 startProc(el, "right");
21099 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21100 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21104 * Registers new overflow element(s) to auto scroll
21105 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21107 register : function(el){
21108 if(el instanceof Array){
21109 for(var i = 0, len = el.length; i < len; i++) {
21110 this.register(el[i]);
21116 Roo.dd.ScrollManager.els = els;
21120 * Unregisters overflow element(s) so they are no longer scrolled
21121 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21123 unregister : function(el){
21124 if(el instanceof Array){
21125 for(var i = 0, len = el.length; i < len; i++) {
21126 this.unregister(el[i]);
21135 * The number of pixels from the edge of a container the pointer needs to be to
21136 * trigger scrolling (defaults to 25)
21142 * The number of pixels to scroll in each scroll increment (defaults to 50)
21148 * The frequency of scrolls in milliseconds (defaults to 500)
21154 * True to animate the scroll (defaults to true)
21160 * The animation duration in seconds -
21161 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21167 * Manually trigger a cache refresh.
21169 refreshCache : function(){
21170 for(var id in els){
21171 if(typeof els[id] == 'object'){ // for people extending the object prototype
21172 els[id]._region = els[id].getRegion();
21179 * Ext JS Library 1.1.1
21180 * Copyright(c) 2006-2007, Ext JS, LLC.
21182 * Originally Released Under LGPL - original licence link has changed is not relivant.
21185 * <script type="text/javascript">
21190 * @class Roo.dd.Registry
21191 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
21192 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
21195 Roo.dd.Registry = function(){
21198 var autoIdSeed = 0;
21200 var getId = function(el, autogen){
21201 if(typeof el == "string"){
21205 if(!id && autogen !== false){
21206 id = "roodd-" + (++autoIdSeed);
21214 * Register a drag drop element
21215 * @param {String|HTMLElement} element The id or DOM node to register
21216 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
21217 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
21218 * knows how to interpret, plus there are some specific properties known to the Registry that should be
21219 * populated in the data object (if applicable):
21221 Value Description<br />
21222 --------- ------------------------------------------<br />
21223 handles Array of DOM nodes that trigger dragging<br />
21224 for the element being registered<br />
21225 isHandle True if the element passed in triggers<br />
21226 dragging itself, else false
21229 register : function(el, data){
21231 if(typeof el == "string"){
21232 el = document.getElementById(el);
21235 elements[getId(el)] = data;
21236 if(data.isHandle !== false){
21237 handles[data.ddel.id] = data;
21240 var hs = data.handles;
21241 for(var i = 0, len = hs.length; i < len; i++){
21242 handles[getId(hs[i])] = data;
21248 * Unregister a drag drop element
21249 * @param {String|HTMLElement} element The id or DOM node to unregister
21251 unregister : function(el){
21252 var id = getId(el, false);
21253 var data = elements[id];
21255 delete elements[id];
21257 var hs = data.handles;
21258 for(var i = 0, len = hs.length; i < len; i++){
21259 delete handles[getId(hs[i], false)];
21266 * Returns the handle registered for a DOM Node by id
21267 * @param {String|HTMLElement} id The DOM node or id to look up
21268 * @return {Object} handle The custom handle data
21270 getHandle : function(id){
21271 if(typeof id != "string"){ // must be element?
21274 return handles[id];
21278 * Returns the handle that is registered for the DOM node that is the target of the event
21279 * @param {Event} e The event
21280 * @return {Object} handle The custom handle data
21282 getHandleFromEvent : function(e){
21283 var t = Roo.lib.Event.getTarget(e);
21284 return t ? handles[t.id] : null;
21288 * Returns a custom data object that is registered for a DOM node by id
21289 * @param {String|HTMLElement} id The DOM node or id to look up
21290 * @return {Object} data The custom data
21292 getTarget : function(id){
21293 if(typeof id != "string"){ // must be element?
21296 return elements[id];
21300 * Returns a custom data object that is registered for the DOM node that is the target of the event
21301 * @param {Event} e The event
21302 * @return {Object} data The custom data
21304 getTargetFromEvent : function(e){
21305 var t = Roo.lib.Event.getTarget(e);
21306 return t ? elements[t.id] || handles[t.id] : null;
21311 * Ext JS Library 1.1.1
21312 * Copyright(c) 2006-2007, Ext JS, LLC.
21314 * Originally Released Under LGPL - original licence link has changed is not relivant.
21317 * <script type="text/javascript">
21322 * @class Roo.dd.StatusProxy
21323 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
21324 * default drag proxy used by all Roo.dd components.
21326 * @param {Object} config
21328 Roo.dd.StatusProxy = function(config){
21329 Roo.apply(this, config);
21330 this.id = this.id || Roo.id();
21331 this.el = new Roo.Layer({
21333 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
21334 {tag: "div", cls: "x-dd-drop-icon"},
21335 {tag: "div", cls: "x-dd-drag-ghost"}
21338 shadow: !config || config.shadow !== false
21340 this.ghost = Roo.get(this.el.dom.childNodes[1]);
21341 this.dropStatus = this.dropNotAllowed;
21344 Roo.dd.StatusProxy.prototype = {
21346 * @cfg {String} dropAllowed
21347 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
21349 dropAllowed : "x-dd-drop-ok",
21351 * @cfg {String} dropNotAllowed
21352 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
21354 dropNotAllowed : "x-dd-drop-nodrop",
21357 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
21358 * over the current target element.
21359 * @param {String} cssClass The css class for the new drop status indicator image
21361 setStatus : function(cssClass){
21362 cssClass = cssClass || this.dropNotAllowed;
21363 if(this.dropStatus != cssClass){
21364 this.el.replaceClass(this.dropStatus, cssClass);
21365 this.dropStatus = cssClass;
21370 * Resets the status indicator to the default dropNotAllowed value
21371 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
21373 reset : function(clearGhost){
21374 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
21375 this.dropStatus = this.dropNotAllowed;
21377 this.ghost.update("");
21382 * Updates the contents of the ghost element
21383 * @param {String} html The html that will replace the current innerHTML of the ghost element
21385 update : function(html){
21386 if(typeof html == "string"){
21387 this.ghost.update(html);
21389 this.ghost.update("");
21390 html.style.margin = "0";
21391 this.ghost.dom.appendChild(html);
21393 // ensure float = none set?? cant remember why though.
21394 var el = this.ghost.dom.firstChild;
21396 Roo.fly(el).setStyle('float', 'none');
21401 * Returns the underlying proxy {@link Roo.Layer}
21402 * @return {Roo.Layer} el
21404 getEl : function(){
21409 * Returns the ghost element
21410 * @return {Roo.Element} el
21412 getGhost : function(){
21418 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
21420 hide : function(clear){
21428 * Stops the repair animation if it's currently running
21431 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
21437 * Displays this proxy
21444 * Force the Layer to sync its shadow and shim positions to the element
21451 * Causes the proxy to return to its position of origin via an animation. Should be called after an
21452 * invalid drop operation by the item being dragged.
21453 * @param {Array} xy The XY position of the element ([x, y])
21454 * @param {Function} callback The function to call after the repair is complete
21455 * @param {Object} scope The scope in which to execute the callback
21457 repair : function(xy, callback, scope){
21458 this.callback = callback;
21459 this.scope = scope;
21460 if(xy && this.animRepair !== false){
21461 this.el.addClass("x-dd-drag-repair");
21462 this.el.hideUnders(true);
21463 this.anim = this.el.shift({
21464 duration: this.repairDuration || .5,
21468 callback: this.afterRepair,
21472 this.afterRepair();
21477 afterRepair : function(){
21479 if(typeof this.callback == "function"){
21480 this.callback.call(this.scope || this);
21482 this.callback = null;
21487 * Ext JS Library 1.1.1
21488 * Copyright(c) 2006-2007, Ext JS, LLC.
21490 * Originally Released Under LGPL - original licence link has changed is not relivant.
21493 * <script type="text/javascript">
21497 * @class Roo.dd.DragSource
21498 * @extends Roo.dd.DDProxy
21499 * A simple class that provides the basic implementation needed to make any element draggable.
21501 * @param {String/HTMLElement/Element} el The container element
21502 * @param {Object} config
21504 Roo.dd.DragSource = function(el, config){
21505 this.el = Roo.get(el);
21506 this.dragData = {};
21508 Roo.apply(this, config);
21511 this.proxy = new Roo.dd.StatusProxy();
21514 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
21515 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
21517 this.dragging = false;
21520 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
21522 * @cfg {String} dropAllowed
21523 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21525 dropAllowed : "x-dd-drop-ok",
21527 * @cfg {String} dropNotAllowed
21528 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21530 dropNotAllowed : "x-dd-drop-nodrop",
21533 * Returns the data object associated with this drag source
21534 * @return {Object} data An object containing arbitrary data
21536 getDragData : function(e){
21537 return this.dragData;
21541 onDragEnter : function(e, id){
21542 var target = Roo.dd.DragDropMgr.getDDById(id);
21543 this.cachedTarget = target;
21544 if(this.beforeDragEnter(target, e, id) !== false){
21545 if(target.isNotifyTarget){
21546 var status = target.notifyEnter(this, e, this.dragData);
21547 this.proxy.setStatus(status);
21549 this.proxy.setStatus(this.dropAllowed);
21552 if(this.afterDragEnter){
21554 * An empty function by default, but provided so that you can perform a custom action
21555 * when the dragged item enters the drop target by providing an implementation.
21556 * @param {Roo.dd.DragDrop} target The drop target
21557 * @param {Event} e The event object
21558 * @param {String} id The id of the dragged element
21559 * @method afterDragEnter
21561 this.afterDragEnter(target, e, id);
21567 * An empty function by default, but provided so that you can perform a custom action
21568 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
21569 * @param {Roo.dd.DragDrop} target The drop target
21570 * @param {Event} e The event object
21571 * @param {String} id The id of the dragged element
21572 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21574 beforeDragEnter : function(target, e, id){
21579 alignElWithMouse: function() {
21580 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
21585 onDragOver : function(e, id){
21586 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21587 if(this.beforeDragOver(target, e, id) !== false){
21588 if(target.isNotifyTarget){
21589 var status = target.notifyOver(this, e, this.dragData);
21590 this.proxy.setStatus(status);
21593 if(this.afterDragOver){
21595 * An empty function by default, but provided so that you can perform a custom action
21596 * while the dragged item is over the drop target by providing an implementation.
21597 * @param {Roo.dd.DragDrop} target The drop target
21598 * @param {Event} e The event object
21599 * @param {String} id The id of the dragged element
21600 * @method afterDragOver
21602 this.afterDragOver(target, e, id);
21608 * An empty function by default, but provided so that you can perform a custom action
21609 * while the dragged item is over the drop target and optionally cancel the onDragOver.
21610 * @param {Roo.dd.DragDrop} target The drop target
21611 * @param {Event} e The event object
21612 * @param {String} id The id of the dragged element
21613 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21615 beforeDragOver : function(target, e, id){
21620 onDragOut : function(e, id){
21621 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21622 if(this.beforeDragOut(target, e, id) !== false){
21623 if(target.isNotifyTarget){
21624 target.notifyOut(this, e, this.dragData);
21626 this.proxy.reset();
21627 if(this.afterDragOut){
21629 * An empty function by default, but provided so that you can perform a custom action
21630 * after the dragged item is dragged out of the target without dropping.
21631 * @param {Roo.dd.DragDrop} target The drop target
21632 * @param {Event} e The event object
21633 * @param {String} id The id of the dragged element
21634 * @method afterDragOut
21636 this.afterDragOut(target, e, id);
21639 this.cachedTarget = null;
21643 * An empty function by default, but provided so that you can perform a custom action before the dragged
21644 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
21645 * @param {Roo.dd.DragDrop} target The drop target
21646 * @param {Event} e The event object
21647 * @param {String} id The id of the dragged element
21648 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21650 beforeDragOut : function(target, e, id){
21655 onDragDrop : function(e, id){
21656 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
21657 if(this.beforeDragDrop(target, e, id) !== false){
21658 if(target.isNotifyTarget){
21659 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
21660 this.onValidDrop(target, e, id);
21662 this.onInvalidDrop(target, e, id);
21665 this.onValidDrop(target, e, id);
21668 if(this.afterDragDrop){
21670 * An empty function by default, but provided so that you can perform a custom action
21671 * after a valid drag drop has occurred by providing an implementation.
21672 * @param {Roo.dd.DragDrop} target The drop target
21673 * @param {Event} e The event object
21674 * @param {String} id The id of the dropped element
21675 * @method afterDragDrop
21677 this.afterDragDrop(target, e, id);
21680 delete this.cachedTarget;
21684 * An empty function by default, but provided so that you can perform a custom action before the dragged
21685 * item is dropped onto the target and optionally cancel the onDragDrop.
21686 * @param {Roo.dd.DragDrop} target The drop target
21687 * @param {Event} e The event object
21688 * @param {String} id The id of the dragged element
21689 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
21691 beforeDragDrop : function(target, e, id){
21696 onValidDrop : function(target, e, id){
21698 if(this.afterValidDrop){
21700 * An empty function by default, but provided so that you can perform a custom action
21701 * after a valid drop has occurred by providing an implementation.
21702 * @param {Object} target The target DD
21703 * @param {Event} e The event object
21704 * @param {String} id The id of the dropped element
21705 * @method afterInvalidDrop
21707 this.afterValidDrop(target, e, id);
21712 getRepairXY : function(e, data){
21713 return this.el.getXY();
21717 onInvalidDrop : function(target, e, id){
21718 this.beforeInvalidDrop(target, e, id);
21719 if(this.cachedTarget){
21720 if(this.cachedTarget.isNotifyTarget){
21721 this.cachedTarget.notifyOut(this, e, this.dragData);
21723 this.cacheTarget = null;
21725 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
21727 if(this.afterInvalidDrop){
21729 * An empty function by default, but provided so that you can perform a custom action
21730 * after an invalid drop has occurred by providing an implementation.
21731 * @param {Event} e The event object
21732 * @param {String} id The id of the dropped element
21733 * @method afterInvalidDrop
21735 this.afterInvalidDrop(e, id);
21740 afterRepair : function(){
21742 this.el.highlight(this.hlColor || "c3daf9");
21744 this.dragging = false;
21748 * An empty function by default, but provided so that you can perform a custom action after an invalid
21749 * drop has occurred.
21750 * @param {Roo.dd.DragDrop} target The drop target
21751 * @param {Event} e The event object
21752 * @param {String} id The id of the dragged element
21753 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
21755 beforeInvalidDrop : function(target, e, id){
21760 handleMouseDown : function(e){
21761 if(this.dragging) {
21764 var data = this.getDragData(e);
21765 if(data && this.onBeforeDrag(data, e) !== false){
21766 this.dragData = data;
21768 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
21773 * An empty function by default, but provided so that you can perform a custom action before the initial
21774 * drag event begins and optionally cancel it.
21775 * @param {Object} data An object containing arbitrary data to be shared with drop targets
21776 * @param {Event} e The event object
21777 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
21779 onBeforeDrag : function(data, e){
21784 * An empty function by default, but provided so that you can perform a custom action once the initial
21785 * drag event has begun. The drag cannot be canceled from this function.
21786 * @param {Number} x The x position of the click on the dragged object
21787 * @param {Number} y The y position of the click on the dragged object
21789 onStartDrag : Roo.emptyFn,
21791 // private - YUI override
21792 startDrag : function(x, y){
21793 this.proxy.reset();
21794 this.dragging = true;
21795 this.proxy.update("");
21796 this.onInitDrag(x, y);
21801 onInitDrag : function(x, y){
21802 var clone = this.el.dom.cloneNode(true);
21803 clone.id = Roo.id(); // prevent duplicate ids
21804 this.proxy.update(clone);
21805 this.onStartDrag(x, y);
21810 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
21811 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
21813 getProxy : function(){
21818 * Hides the drag source's {@link Roo.dd.StatusProxy}
21820 hideProxy : function(){
21822 this.proxy.reset(true);
21823 this.dragging = false;
21827 triggerCacheRefresh : function(){
21828 Roo.dd.DDM.refreshCache(this.groups);
21831 // private - override to prevent hiding
21832 b4EndDrag: function(e) {
21835 // private - override to prevent moving
21836 endDrag : function(e){
21837 this.onEndDrag(this.dragData, e);
21841 onEndDrag : function(data, e){
21844 // private - pin to cursor
21845 autoOffset : function(x, y) {
21846 this.setDelta(-12, -20);
21850 * Ext JS Library 1.1.1
21851 * Copyright(c) 2006-2007, Ext JS, LLC.
21853 * Originally Released Under LGPL - original licence link has changed is not relivant.
21856 * <script type="text/javascript">
21861 * @class Roo.dd.DropTarget
21862 * @extends Roo.dd.DDTarget
21863 * A simple class that provides the basic implementation needed to make any element a drop target that can have
21864 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
21866 * @param {String/HTMLElement/Element} el The container element
21867 * @param {Object} config
21869 Roo.dd.DropTarget = function(el, config){
21870 this.el = Roo.get(el);
21872 var listeners = false; ;
21873 if (config && config.listeners) {
21874 listeners= config.listeners;
21875 delete config.listeners;
21877 Roo.apply(this, config);
21879 if(this.containerScroll){
21880 Roo.dd.ScrollManager.register(this.el);
21884 * @scope Roo.dd.DropTarget
21889 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
21890 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
21891 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
21893 * IMPORTANT : it should set this.overClass and this.dropAllowed
21895 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21896 * @param {Event} e The event
21897 * @param {Object} data An object containing arbitrary data supplied by the drag source
21903 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
21904 * This method will be called on every mouse movement while the drag source is over the drop target.
21905 * This default implementation simply returns the dropAllowed config value.
21907 * IMPORTANT : it should set this.dropAllowed
21909 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21910 * @param {Event} e The event
21911 * @param {Object} data An object containing arbitrary data supplied by the drag source
21917 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
21918 * out of the target without dropping. This default implementation simply removes the CSS class specified by
21919 * overClass (if any) from the drop element.
21921 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21922 * @param {Event} e The event
21923 * @param {Object} data An object containing arbitrary data supplied by the drag source
21929 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
21930 * been dropped on it. This method has no default implementation and returns false, so you must provide an
21931 * implementation that does something to process the drop event and returns true so that the drag source's
21932 * repair action does not run.
21934 * IMPORTANT : it should set this.success
21936 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
21937 * @param {Event} e The event
21938 * @param {Object} data An object containing arbitrary data supplied by the drag source
21944 Roo.dd.DropTarget.superclass.constructor.call( this,
21946 this.ddGroup || this.group,
21949 listeners : listeners || {}
21957 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
21959 * @cfg {String} overClass
21960 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
21963 * @cfg {String} ddGroup
21964 * The drag drop group to handle drop events for
21968 * @cfg {String} dropAllowed
21969 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
21971 dropAllowed : "x-dd-drop-ok",
21973 * @cfg {String} dropNotAllowed
21974 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
21976 dropNotAllowed : "x-dd-drop-nodrop",
21978 * @cfg {boolean} success
21979 * set this after drop listener..
21983 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
21984 * if the drop point is valid for over/enter..
21991 isNotifyTarget : true,
21996 notifyEnter : function(dd, e, data)
21999 this.fireEvent('enter', dd, e, data);
22000 if(this.overClass){
22001 this.el.addClass(this.overClass);
22003 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22004 this.valid ? this.dropAllowed : this.dropNotAllowed
22011 notifyOver : function(dd, e, data)
22014 this.fireEvent('over', dd, e, data);
22015 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22016 this.valid ? this.dropAllowed : this.dropNotAllowed
22023 notifyOut : function(dd, e, data)
22025 this.fireEvent('out', dd, e, data);
22026 if(this.overClass){
22027 this.el.removeClass(this.overClass);
22034 notifyDrop : function(dd, e, data)
22036 this.success = false;
22037 this.fireEvent('drop', dd, e, data);
22038 return this.success;
22042 * Ext JS Library 1.1.1
22043 * Copyright(c) 2006-2007, Ext JS, LLC.
22045 * Originally Released Under LGPL - original licence link has changed is not relivant.
22048 * <script type="text/javascript">
22053 * @class Roo.dd.DragZone
22054 * @extends Roo.dd.DragSource
22055 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22056 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22058 * @param {String/HTMLElement/Element} el The container element
22059 * @param {Object} config
22061 Roo.dd.DragZone = function(el, config){
22062 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22063 if(this.containerScroll){
22064 Roo.dd.ScrollManager.register(this.el);
22068 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22070 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22071 * for auto scrolling during drag operations.
22074 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22075 * method after a failed drop (defaults to "c3daf9" - light blue)
22079 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22080 * for a valid target to drag based on the mouse down. Override this method
22081 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22082 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22083 * @param {EventObject} e The mouse down event
22084 * @return {Object} The dragData
22086 getDragData : function(e){
22087 return Roo.dd.Registry.getHandleFromEvent(e);
22091 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22092 * this.dragData.ddel
22093 * @param {Number} x The x position of the click on the dragged object
22094 * @param {Number} y The y position of the click on the dragged object
22095 * @return {Boolean} true to continue the drag, false to cancel
22097 onInitDrag : function(x, y){
22098 this.proxy.update(this.dragData.ddel.cloneNode(true));
22099 this.onStartDrag(x, y);
22104 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22106 afterRepair : function(){
22108 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22110 this.dragging = false;
22114 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22115 * the XY of this.dragData.ddel
22116 * @param {EventObject} e The mouse up event
22117 * @return {Array} The xy location (e.g. [100, 200])
22119 getRepairXY : function(e){
22120 return Roo.Element.fly(this.dragData.ddel).getXY();
22124 * Ext JS Library 1.1.1
22125 * Copyright(c) 2006-2007, Ext JS, LLC.
22127 * Originally Released Under LGPL - original licence link has changed is not relivant.
22130 * <script type="text/javascript">
22133 * @class Roo.dd.DropZone
22134 * @extends Roo.dd.DropTarget
22135 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22136 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22138 * @param {String/HTMLElement/Element} el The container element
22139 * @param {Object} config
22141 Roo.dd.DropZone = function(el, config){
22142 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22145 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22147 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22148 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22149 * provide your own custom lookup.
22150 * @param {Event} e The event
22151 * @return {Object} data The custom data
22153 getTargetFromEvent : function(e){
22154 return Roo.dd.Registry.getTargetFromEvent(e);
22158 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22159 * that it has registered. This method has no default implementation and should be overridden to provide
22160 * node-specific processing if necessary.
22161 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22162 * {@link #getTargetFromEvent} for this node)
22163 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22164 * @param {Event} e The event
22165 * @param {Object} data An object containing arbitrary data supplied by the drag source
22167 onNodeEnter : function(n, dd, e, data){
22172 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22173 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22174 * overridden to provide the proper feedback.
22175 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22176 * {@link #getTargetFromEvent} for this node)
22177 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22178 * @param {Event} e The event
22179 * @param {Object} data An object containing arbitrary data supplied by the drag source
22180 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22181 * underlying {@link Roo.dd.StatusProxy} can be updated
22183 onNodeOver : function(n, dd, e, data){
22184 return this.dropAllowed;
22188 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
22189 * the drop node without dropping. This method has no default implementation and should be overridden to provide
22190 * node-specific processing if necessary.
22191 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22192 * {@link #getTargetFromEvent} for this node)
22193 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22194 * @param {Event} e The event
22195 * @param {Object} data An object containing arbitrary data supplied by the drag source
22197 onNodeOut : function(n, dd, e, data){
22202 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
22203 * the drop node. The default implementation returns false, so it should be overridden to provide the
22204 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
22205 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22206 * {@link #getTargetFromEvent} for this node)
22207 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22208 * @param {Event} e The event
22209 * @param {Object} data An object containing arbitrary data supplied by the drag source
22210 * @return {Boolean} True if the drop was valid, else false
22212 onNodeDrop : function(n, dd, e, data){
22217 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
22218 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
22219 * it should be overridden to provide the proper feedback if necessary.
22220 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22221 * @param {Event} e The event
22222 * @param {Object} data An object containing arbitrary data supplied by the drag source
22223 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22224 * underlying {@link Roo.dd.StatusProxy} can be updated
22226 onContainerOver : function(dd, e, data){
22227 return this.dropNotAllowed;
22231 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
22232 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
22233 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
22234 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
22235 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22236 * @param {Event} e The event
22237 * @param {Object} data An object containing arbitrary data supplied by the drag source
22238 * @return {Boolean} True if the drop was valid, else false
22240 onContainerDrop : function(dd, e, data){
22245 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
22246 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
22247 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
22248 * you should override this method and provide a custom implementation.
22249 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22250 * @param {Event} e The event
22251 * @param {Object} data An object containing arbitrary data supplied by the drag source
22252 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22253 * underlying {@link Roo.dd.StatusProxy} can be updated
22255 notifyEnter : function(dd, e, data){
22256 return this.dropNotAllowed;
22260 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
22261 * This method will be called on every mouse movement while the drag source is over the drop zone.
22262 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
22263 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
22264 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
22265 * registered node, it will call {@link #onContainerOver}.
22266 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22267 * @param {Event} e The event
22268 * @param {Object} data An object containing arbitrary data supplied by the drag source
22269 * @return {String} status The CSS class that communicates the drop status back to the source so that the
22270 * underlying {@link Roo.dd.StatusProxy} can be updated
22272 notifyOver : function(dd, e, data){
22273 var n = this.getTargetFromEvent(e);
22274 if(!n){ // not over valid drop target
22275 if(this.lastOverNode){
22276 this.onNodeOut(this.lastOverNode, dd, e, data);
22277 this.lastOverNode = null;
22279 return this.onContainerOver(dd, e, data);
22281 if(this.lastOverNode != n){
22282 if(this.lastOverNode){
22283 this.onNodeOut(this.lastOverNode, dd, e, data);
22285 this.onNodeEnter(n, dd, e, data);
22286 this.lastOverNode = n;
22288 return this.onNodeOver(n, dd, e, data);
22292 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
22293 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
22294 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
22295 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22296 * @param {Event} e The event
22297 * @param {Object} data An object containing arbitrary data supplied by the drag zone
22299 notifyOut : function(dd, e, data){
22300 if(this.lastOverNode){
22301 this.onNodeOut(this.lastOverNode, dd, e, data);
22302 this.lastOverNode = null;
22307 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
22308 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
22309 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
22310 * otherwise it will call {@link #onContainerDrop}.
22311 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22312 * @param {Event} e The event
22313 * @param {Object} data An object containing arbitrary data supplied by the drag source
22314 * @return {Boolean} True if the drop was valid, else false
22316 notifyDrop : function(dd, e, data){
22317 if(this.lastOverNode){
22318 this.onNodeOut(this.lastOverNode, dd, e, data);
22319 this.lastOverNode = null;
22321 var n = this.getTargetFromEvent(e);
22323 this.onNodeDrop(n, dd, e, data) :
22324 this.onContainerDrop(dd, e, data);
22328 triggerCacheRefresh : function(){
22329 Roo.dd.DDM.refreshCache(this.groups);
22333 * Ext JS Library 1.1.1
22334 * Copyright(c) 2006-2007, Ext JS, LLC.
22336 * Originally Released Under LGPL - original licence link has changed is not relivant.
22339 * <script type="text/javascript">
22344 * @class Roo.data.SortTypes
22346 * Defines the default sorting (casting?) comparison functions used when sorting data.
22348 Roo.data.SortTypes = {
22350 * Default sort that does nothing
22351 * @param {Mixed} s The value being converted
22352 * @return {Mixed} The comparison value
22354 none : function(s){
22359 * The regular expression used to strip tags
22363 stripTagsRE : /<\/?[^>]+>/gi,
22366 * Strips all HTML tags to sort on text only
22367 * @param {Mixed} s The value being converted
22368 * @return {String} The comparison value
22370 asText : function(s){
22371 return String(s).replace(this.stripTagsRE, "");
22375 * Strips all HTML tags to sort on text only - Case insensitive
22376 * @param {Mixed} s The value being converted
22377 * @return {String} The comparison value
22379 asUCText : function(s){
22380 return String(s).toUpperCase().replace(this.stripTagsRE, "");
22384 * Case insensitive string
22385 * @param {Mixed} s The value being converted
22386 * @return {String} The comparison value
22388 asUCString : function(s) {
22389 return String(s).toUpperCase();
22394 * @param {Mixed} s The value being converted
22395 * @return {Number} The comparison value
22397 asDate : function(s) {
22401 if(s instanceof Date){
22402 return s.getTime();
22404 return Date.parse(String(s));
22409 * @param {Mixed} s The value being converted
22410 * @return {Float} The comparison value
22412 asFloat : function(s) {
22413 var val = parseFloat(String(s).replace(/,/g, ""));
22422 * @param {Mixed} s The value being converted
22423 * @return {Number} The comparison value
22425 asInt : function(s) {
22426 var val = parseInt(String(s).replace(/,/g, ""));
22434 * Ext JS Library 1.1.1
22435 * Copyright(c) 2006-2007, Ext JS, LLC.
22437 * Originally Released Under LGPL - original licence link has changed is not relivant.
22440 * <script type="text/javascript">
22444 * @class Roo.data.Record
22445 * Instances of this class encapsulate both record <em>definition</em> information, and record
22446 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
22447 * to access Records cached in an {@link Roo.data.Store} object.<br>
22449 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
22450 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
22453 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
22455 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
22456 * {@link #create}. The parameters are the same.
22457 * @param {Array} data An associative Array of data values keyed by the field name.
22458 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
22459 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
22460 * not specified an integer id is generated.
22462 Roo.data.Record = function(data, id){
22463 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
22468 * Generate a constructor for a specific record layout.
22469 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
22470 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
22471 * Each field definition object may contain the following properties: <ul>
22472 * <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,
22473 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
22474 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
22475 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
22476 * is being used, then this is a string containing the javascript expression to reference the data relative to
22477 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
22478 * to the data item relative to the record element. If the mapping expression is the same as the field name,
22479 * this may be omitted.</p></li>
22480 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
22481 * <ul><li>auto (Default, implies no conversion)</li>
22486 * <li>date</li></ul></p></li>
22487 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
22488 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
22489 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
22490 * by the Reader into an object that will be stored in the Record. It is passed the
22491 * following parameters:<ul>
22492 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
22494 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
22496 * <br>usage:<br><pre><code>
22497 var TopicRecord = Roo.data.Record.create(
22498 {name: 'title', mapping: 'topic_title'},
22499 {name: 'author', mapping: 'username'},
22500 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
22501 {name: 'lastPost', mapping: 'post_time', type: 'date'},
22502 {name: 'lastPoster', mapping: 'user2'},
22503 {name: 'excerpt', mapping: 'post_text'}
22506 var myNewRecord = new TopicRecord({
22507 title: 'Do my job please',
22510 lastPost: new Date(),
22511 lastPoster: 'Animal',
22512 excerpt: 'No way dude!'
22514 myStore.add(myNewRecord);
22519 Roo.data.Record.create = function(o){
22520 var f = function(){
22521 f.superclass.constructor.apply(this, arguments);
22523 Roo.extend(f, Roo.data.Record);
22524 var p = f.prototype;
22525 p.fields = new Roo.util.MixedCollection(false, function(field){
22528 for(var i = 0, len = o.length; i < len; i++){
22529 p.fields.add(new Roo.data.Field(o[i]));
22531 f.getField = function(name){
22532 return p.fields.get(name);
22537 Roo.data.Record.AUTO_ID = 1000;
22538 Roo.data.Record.EDIT = 'edit';
22539 Roo.data.Record.REJECT = 'reject';
22540 Roo.data.Record.COMMIT = 'commit';
22542 Roo.data.Record.prototype = {
22544 * Readonly flag - true if this record has been modified.
22553 join : function(store){
22554 this.store = store;
22558 * Set the named field to the specified value.
22559 * @param {String} name The name of the field to set.
22560 * @param {Object} value The value to set the field to.
22562 set : function(name, value){
22563 if(this.data[name] == value){
22567 if(!this.modified){
22568 this.modified = {};
22570 if(typeof this.modified[name] == 'undefined'){
22571 this.modified[name] = this.data[name];
22573 this.data[name] = value;
22574 if(!this.editing && this.store){
22575 this.store.afterEdit(this);
22580 * Get the value of the named field.
22581 * @param {String} name The name of the field to get the value of.
22582 * @return {Object} The value of the field.
22584 get : function(name){
22585 return this.data[name];
22589 beginEdit : function(){
22590 this.editing = true;
22591 this.modified = {};
22595 cancelEdit : function(){
22596 this.editing = false;
22597 delete this.modified;
22601 endEdit : function(){
22602 this.editing = false;
22603 if(this.dirty && this.store){
22604 this.store.afterEdit(this);
22609 * Usually called by the {@link Roo.data.Store} which owns the Record.
22610 * Rejects all changes made to the Record since either creation, or the last commit operation.
22611 * Modified fields are reverted to their original values.
22613 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22614 * of reject operations.
22616 reject : function(){
22617 var m = this.modified;
22619 if(typeof m[n] != "function"){
22620 this.data[n] = m[n];
22623 this.dirty = false;
22624 delete this.modified;
22625 this.editing = false;
22627 this.store.afterReject(this);
22632 * Usually called by the {@link Roo.data.Store} which owns the Record.
22633 * Commits all changes made to the Record since either creation, or the last commit operation.
22635 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
22636 * of commit operations.
22638 commit : function(){
22639 this.dirty = false;
22640 delete this.modified;
22641 this.editing = false;
22643 this.store.afterCommit(this);
22648 hasError : function(){
22649 return this.error != null;
22653 clearError : function(){
22658 * Creates a copy of this record.
22659 * @param {String} id (optional) A new record id if you don't want to use this record's id
22662 copy : function(newId) {
22663 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
22667 * Ext JS Library 1.1.1
22668 * Copyright(c) 2006-2007, Ext JS, LLC.
22670 * Originally Released Under LGPL - original licence link has changed is not relivant.
22673 * <script type="text/javascript">
22679 * @class Roo.data.Store
22680 * @extends Roo.util.Observable
22681 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
22682 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
22684 * 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
22685 * has no knowledge of the format of the data returned by the Proxy.<br>
22687 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
22688 * instances from the data object. These records are cached and made available through accessor functions.
22690 * Creates a new Store.
22691 * @param {Object} config A config object containing the objects needed for the Store to access data,
22692 * and read the data into Records.
22694 Roo.data.Store = function(config){
22695 this.data = new Roo.util.MixedCollection(false);
22696 this.data.getKey = function(o){
22699 this.baseParams = {};
22701 this.paramNames = {
22706 "multisort" : "_multisort"
22709 if(config && config.data){
22710 this.inlineData = config.data;
22711 delete config.data;
22714 Roo.apply(this, config);
22716 if(this.reader){ // reader passed
22717 this.reader = Roo.factory(this.reader, Roo.data);
22718 this.reader.xmodule = this.xmodule || false;
22719 if(!this.recordType){
22720 this.recordType = this.reader.recordType;
22722 if(this.reader.onMetaChange){
22723 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
22727 if(this.recordType){
22728 this.fields = this.recordType.prototype.fields;
22730 this.modified = [];
22734 * @event datachanged
22735 * Fires when the data cache has changed, and a widget which is using this Store
22736 * as a Record cache should refresh its view.
22737 * @param {Store} this
22739 datachanged : true,
22741 * @event metachange
22742 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
22743 * @param {Store} this
22744 * @param {Object} meta The JSON metadata
22749 * Fires when Records have been added to the Store
22750 * @param {Store} this
22751 * @param {Roo.data.Record[]} records The array of Records added
22752 * @param {Number} index The index at which the record(s) were added
22757 * Fires when a Record has been removed from the Store
22758 * @param {Store} this
22759 * @param {Roo.data.Record} record The Record that was removed
22760 * @param {Number} index The index at which the record was removed
22765 * Fires when a Record has been updated
22766 * @param {Store} this
22767 * @param {Roo.data.Record} record The Record that was updated
22768 * @param {String} operation The update operation being performed. Value may be one of:
22770 Roo.data.Record.EDIT
22771 Roo.data.Record.REJECT
22772 Roo.data.Record.COMMIT
22778 * Fires when the data cache has been cleared.
22779 * @param {Store} this
22783 * @event beforeload
22784 * Fires before a request is made for a new data object. If the beforeload handler returns false
22785 * the load action will be canceled.
22786 * @param {Store} this
22787 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22791 * @event beforeloadadd
22792 * Fires after a new set of Records has been loaded.
22793 * @param {Store} this
22794 * @param {Roo.data.Record[]} records The Records that were loaded
22795 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22797 beforeloadadd : true,
22800 * Fires after a new set of Records has been loaded, before they are added to the store.
22801 * @param {Store} this
22802 * @param {Roo.data.Record[]} records The Records that were loaded
22803 * @param {Object} options The loading options that were specified (see {@link #load} for details)
22804 * @params {Object} return from reader
22808 * @event loadexception
22809 * Fires if an exception occurs in the Proxy during loading.
22810 * Called with the signature of the Proxy's "loadexception" event.
22811 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
22814 * @param {Object} return from JsonData.reader() - success, totalRecords, records
22815 * @param {Object} load options
22816 * @param {Object} jsonData from your request (normally this contains the Exception)
22818 loadexception : true
22822 this.proxy = Roo.factory(this.proxy, Roo.data);
22823 this.proxy.xmodule = this.xmodule || false;
22824 this.relayEvents(this.proxy, ["loadexception"]);
22826 this.sortToggle = {};
22827 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
22829 Roo.data.Store.superclass.constructor.call(this);
22831 if(this.inlineData){
22832 this.loadData(this.inlineData);
22833 delete this.inlineData;
22837 Roo.extend(Roo.data.Store, Roo.util.Observable, {
22839 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
22840 * without a remote query - used by combo/forms at present.
22844 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
22847 * @cfg {Array} data Inline data to be loaded when the store is initialized.
22850 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
22851 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
22854 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
22855 * on any HTTP request
22858 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
22861 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
22865 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
22866 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
22868 remoteSort : false,
22871 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
22872 * loaded or when a record is removed. (defaults to false).
22874 pruneModifiedRecords : false,
22877 lastOptions : null,
22880 * Add Records to the Store and fires the add event.
22881 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22883 add : function(records){
22884 records = [].concat(records);
22885 for(var i = 0, len = records.length; i < len; i++){
22886 records[i].join(this);
22888 var index = this.data.length;
22889 this.data.addAll(records);
22890 this.fireEvent("add", this, records, index);
22894 * Remove a Record from the Store and fires the remove event.
22895 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
22897 remove : function(record){
22898 var index = this.data.indexOf(record);
22899 this.data.removeAt(index);
22900 if(this.pruneModifiedRecords){
22901 this.modified.remove(record);
22903 this.fireEvent("remove", this, record, index);
22907 * Remove all Records from the Store and fires the clear event.
22909 removeAll : function(){
22911 if(this.pruneModifiedRecords){
22912 this.modified = [];
22914 this.fireEvent("clear", this);
22918 * Inserts Records to the Store at the given index and fires the add event.
22919 * @param {Number} index The start index at which to insert the passed Records.
22920 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
22922 insert : function(index, records){
22923 records = [].concat(records);
22924 for(var i = 0, len = records.length; i < len; i++){
22925 this.data.insert(index, records[i]);
22926 records[i].join(this);
22928 this.fireEvent("add", this, records, index);
22932 * Get the index within the cache of the passed Record.
22933 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
22934 * @return {Number} The index of the passed Record. Returns -1 if not found.
22936 indexOf : function(record){
22937 return this.data.indexOf(record);
22941 * Get the index within the cache of the Record with the passed id.
22942 * @param {String} id The id of the Record to find.
22943 * @return {Number} The index of the Record. Returns -1 if not found.
22945 indexOfId : function(id){
22946 return this.data.indexOfKey(id);
22950 * Get the Record with the specified id.
22951 * @param {String} id The id of the Record to find.
22952 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
22954 getById : function(id){
22955 return this.data.key(id);
22959 * Get the Record at the specified index.
22960 * @param {Number} index The index of the Record to find.
22961 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
22963 getAt : function(index){
22964 return this.data.itemAt(index);
22968 * Returns a range of Records between specified indices.
22969 * @param {Number} startIndex (optional) The starting index (defaults to 0)
22970 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
22971 * @return {Roo.data.Record[]} An array of Records
22973 getRange : function(start, end){
22974 return this.data.getRange(start, end);
22978 storeOptions : function(o){
22979 o = Roo.apply({}, o);
22982 this.lastOptions = o;
22986 * Loads the Record cache from the configured Proxy using the configured Reader.
22988 * If using remote paging, then the first load call must specify the <em>start</em>
22989 * and <em>limit</em> properties in the options.params property to establish the initial
22990 * position within the dataset, and the number of Records to cache on each read from the Proxy.
22992 * <strong>It is important to note that for remote data sources, loading is asynchronous,
22993 * and this call will return before the new data has been loaded. Perform any post-processing
22994 * in a callback function, or in a "load" event handler.</strong>
22996 * @param {Object} options An object containing properties which control loading options:<ul>
22997 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
22998 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
22999 * passed the following arguments:<ul>
23000 * <li>r : Roo.data.Record[]</li>
23001 * <li>options: Options object from the load call</li>
23002 * <li>success: Boolean success indicator</li></ul></li>
23003 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23004 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23007 load : function(options){
23008 options = options || {};
23009 if(this.fireEvent("beforeload", this, options) !== false){
23010 this.storeOptions(options);
23011 var p = Roo.apply(options.params || {}, this.baseParams);
23012 // if meta was not loaded from remote source.. try requesting it.
23013 if (!this.reader.metaFromRemote) {
23014 p._requestMeta = 1;
23016 if(this.sortInfo && this.remoteSort){
23017 var pn = this.paramNames;
23018 p[pn["sort"]] = this.sortInfo.field;
23019 p[pn["dir"]] = this.sortInfo.direction;
23021 if (this.multiSort) {
23022 var pn = this.paramNames;
23023 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23026 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23031 * Reloads the Record cache from the configured Proxy using the configured Reader and
23032 * the options from the last load operation performed.
23033 * @param {Object} options (optional) An object containing properties which may override the options
23034 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23035 * the most recently used options are reused).
23037 reload : function(options){
23038 this.load(Roo.applyIf(options||{}, this.lastOptions));
23042 // Called as a callback by the Reader during a load operation.
23043 loadRecords : function(o, options, success){
23044 if(!o || success === false){
23045 if(success !== false){
23046 this.fireEvent("load", this, [], options, o);
23048 if(options.callback){
23049 options.callback.call(options.scope || this, [], options, false);
23053 // if data returned failure - throw an exception.
23054 if (o.success === false) {
23055 // show a message if no listener is registered.
23056 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23057 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23059 // loadmask wil be hooked into this..
23060 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23063 var r = o.records, t = o.totalRecords || r.length;
23065 this.fireEvent("beforeloadadd", this, r, options, o);
23067 if(!options || options.add !== true){
23068 if(this.pruneModifiedRecords){
23069 this.modified = [];
23071 for(var i = 0, len = r.length; i < len; i++){
23075 this.data = this.snapshot;
23076 delete this.snapshot;
23079 this.data.addAll(r);
23080 this.totalLength = t;
23082 this.fireEvent("datachanged", this);
23084 this.totalLength = Math.max(t, this.data.length+r.length);
23088 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23090 var e = new Roo.data.Record({});
23092 e.set(this.parent.displayField, this.parent.emptyTitle);
23093 e.set(this.parent.valueField, '');
23098 this.fireEvent("load", this, r, options, o);
23099 if(options.callback){
23100 options.callback.call(options.scope || this, r, options, true);
23106 * Loads data from a passed data block. A Reader which understands the format of the data
23107 * must have been configured in the constructor.
23108 * @param {Object} data The data block from which to read the Records. The format of the data expected
23109 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23110 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23112 loadData : function(o, append){
23113 var r = this.reader.readRecords(o);
23114 this.loadRecords(r, {add: append}, true);
23118 * Gets the number of cached records.
23120 * <em>If using paging, this may not be the total size of the dataset. If the data object
23121 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23122 * the data set size</em>
23124 getCount : function(){
23125 return this.data.length || 0;
23129 * Gets the total number of records in the dataset as returned by the server.
23131 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23132 * the dataset size</em>
23134 getTotalCount : function(){
23135 return this.totalLength || 0;
23139 * Returns the sort state of the Store as an object with two properties:
23141 field {String} The name of the field by which the Records are sorted
23142 direction {String} The sort order, "ASC" or "DESC"
23145 getSortState : function(){
23146 return this.sortInfo;
23150 applySort : function(){
23151 if(this.sortInfo && !this.remoteSort){
23152 var s = this.sortInfo, f = s.field;
23153 var st = this.fields.get(f).sortType;
23154 var fn = function(r1, r2){
23155 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23156 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23158 this.data.sort(s.direction, fn);
23159 if(this.snapshot && this.snapshot != this.data){
23160 this.snapshot.sort(s.direction, fn);
23166 * Sets the default sort column and order to be used by the next load operation.
23167 * @param {String} fieldName The name of the field to sort by.
23168 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23170 setDefaultSort : function(field, dir){
23171 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
23175 * Sort the Records.
23176 * If remote sorting is used, the sort is performed on the server, and the cache is
23177 * reloaded. If local sorting is used, the cache is sorted internally.
23178 * @param {String} fieldName The name of the field to sort by.
23179 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
23181 sort : function(fieldName, dir){
23182 var f = this.fields.get(fieldName);
23184 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
23186 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
23187 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
23192 this.sortToggle[f.name] = dir;
23193 this.sortInfo = {field: f.name, direction: dir};
23194 if(!this.remoteSort){
23196 this.fireEvent("datachanged", this);
23198 this.load(this.lastOptions);
23203 * Calls the specified function for each of the Records in the cache.
23204 * @param {Function} fn The function to call. The Record is passed as the first parameter.
23205 * Returning <em>false</em> aborts and exits the iteration.
23206 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
23208 each : function(fn, scope){
23209 this.data.each(fn, scope);
23213 * Gets all records modified since the last commit. Modified records are persisted across load operations
23214 * (e.g., during paging).
23215 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
23217 getModifiedRecords : function(){
23218 return this.modified;
23222 createFilterFn : function(property, value, anyMatch){
23223 if(!value.exec){ // not a regex
23224 value = String(value);
23225 if(value.length == 0){
23228 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
23230 return function(r){
23231 return value.test(r.data[property]);
23236 * Sums the value of <i>property</i> for each record between start and end and returns the result.
23237 * @param {String} property A field on your records
23238 * @param {Number} start The record index to start at (defaults to 0)
23239 * @param {Number} end The last record index to include (defaults to length - 1)
23240 * @return {Number} The sum
23242 sum : function(property, start, end){
23243 var rs = this.data.items, v = 0;
23244 start = start || 0;
23245 end = (end || end === 0) ? end : rs.length-1;
23247 for(var i = start; i <= end; i++){
23248 v += (rs[i].data[property] || 0);
23254 * Filter the records by a specified property.
23255 * @param {String} field A field on your records
23256 * @param {String/RegExp} value Either a string that the field
23257 * should start with or a RegExp to test against the field
23258 * @param {Boolean} anyMatch True to match any part not just the beginning
23260 filter : function(property, value, anyMatch){
23261 var fn = this.createFilterFn(property, value, anyMatch);
23262 return fn ? this.filterBy(fn) : this.clearFilter();
23266 * Filter by a function. The specified function will be called with each
23267 * record in this data source. If the function returns true the record is included,
23268 * otherwise it is filtered.
23269 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23270 * @param {Object} scope (optional) The scope of the function (defaults to this)
23272 filterBy : function(fn, scope){
23273 this.snapshot = this.snapshot || this.data;
23274 this.data = this.queryBy(fn, scope||this);
23275 this.fireEvent("datachanged", this);
23279 * Query the records by a specified property.
23280 * @param {String} field A field on your records
23281 * @param {String/RegExp} value Either a string that the field
23282 * should start with or a RegExp to test against the field
23283 * @param {Boolean} anyMatch True to match any part not just the beginning
23284 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23286 query : function(property, value, anyMatch){
23287 var fn = this.createFilterFn(property, value, anyMatch);
23288 return fn ? this.queryBy(fn) : this.data.clone();
23292 * Query by a function. The specified function will be called with each
23293 * record in this data source. If the function returns true the record is included
23295 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
23296 * @param {Object} scope (optional) The scope of the function (defaults to this)
23297 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
23299 queryBy : function(fn, scope){
23300 var data = this.snapshot || this.data;
23301 return data.filterBy(fn, scope||this);
23305 * Collects unique values for a particular dataIndex from this store.
23306 * @param {String} dataIndex The property to collect
23307 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
23308 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
23309 * @return {Array} An array of the unique values
23311 collect : function(dataIndex, allowNull, bypassFilter){
23312 var d = (bypassFilter === true && this.snapshot) ?
23313 this.snapshot.items : this.data.items;
23314 var v, sv, r = [], l = {};
23315 for(var i = 0, len = d.length; i < len; i++){
23316 v = d[i].data[dataIndex];
23318 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
23327 * Revert to a view of the Record cache with no filtering applied.
23328 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
23330 clearFilter : function(suppressEvent){
23331 if(this.snapshot && this.snapshot != this.data){
23332 this.data = this.snapshot;
23333 delete this.snapshot;
23334 if(suppressEvent !== true){
23335 this.fireEvent("datachanged", this);
23341 afterEdit : function(record){
23342 if(this.modified.indexOf(record) == -1){
23343 this.modified.push(record);
23345 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
23349 afterReject : function(record){
23350 this.modified.remove(record);
23351 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
23355 afterCommit : function(record){
23356 this.modified.remove(record);
23357 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
23361 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
23362 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
23364 commitChanges : function(){
23365 var m = this.modified.slice(0);
23366 this.modified = [];
23367 for(var i = 0, len = m.length; i < len; i++){
23373 * Cancel outstanding changes on all changed records.
23375 rejectChanges : function(){
23376 var m = this.modified.slice(0);
23377 this.modified = [];
23378 for(var i = 0, len = m.length; i < len; i++){
23383 onMetaChange : function(meta, rtype, o){
23384 this.recordType = rtype;
23385 this.fields = rtype.prototype.fields;
23386 delete this.snapshot;
23387 this.sortInfo = meta.sortInfo || this.sortInfo;
23388 this.modified = [];
23389 this.fireEvent('metachange', this, this.reader.meta);
23392 moveIndex : function(data, type)
23394 var index = this.indexOf(data);
23396 var newIndex = index + type;
23400 this.insert(newIndex, data);
23405 * Ext JS Library 1.1.1
23406 * Copyright(c) 2006-2007, Ext JS, LLC.
23408 * Originally Released Under LGPL - original licence link has changed is not relivant.
23411 * <script type="text/javascript">
23415 * @class Roo.data.SimpleStore
23416 * @extends Roo.data.Store
23417 * Small helper class to make creating Stores from Array data easier.
23418 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
23419 * @cfg {Array} fields An array of field definition objects, or field name strings.
23420 * @cfg {Array} data The multi-dimensional array of data
23422 * @param {Object} config
23424 Roo.data.SimpleStore = function(config){
23425 Roo.data.SimpleStore.superclass.constructor.call(this, {
23427 reader: new Roo.data.ArrayReader({
23430 Roo.data.Record.create(config.fields)
23432 proxy : new Roo.data.MemoryProxy(config.data)
23436 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
23438 * Ext JS Library 1.1.1
23439 * Copyright(c) 2006-2007, Ext JS, LLC.
23441 * Originally Released Under LGPL - original licence link has changed is not relivant.
23444 * <script type="text/javascript">
23449 * @extends Roo.data.Store
23450 * @class Roo.data.JsonStore
23451 * Small helper class to make creating Stores for JSON data easier. <br/>
23453 var store = new Roo.data.JsonStore({
23454 url: 'get-images.php',
23456 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
23459 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
23460 * JsonReader and HttpProxy (unless inline data is provided).</b>
23461 * @cfg {Array} fields An array of field definition objects, or field name strings.
23463 * @param {Object} config
23465 Roo.data.JsonStore = function(c){
23466 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
23467 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
23468 reader: new Roo.data.JsonReader(c, c.fields)
23471 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
23473 * Ext JS Library 1.1.1
23474 * Copyright(c) 2006-2007, Ext JS, LLC.
23476 * Originally Released Under LGPL - original licence link has changed is not relivant.
23479 * <script type="text/javascript">
23483 Roo.data.Field = function(config){
23484 if(typeof config == "string"){
23485 config = {name: config};
23487 Roo.apply(this, config);
23490 this.type = "auto";
23493 var st = Roo.data.SortTypes;
23494 // named sortTypes are supported, here we look them up
23495 if(typeof this.sortType == "string"){
23496 this.sortType = st[this.sortType];
23499 // set default sortType for strings and dates
23500 if(!this.sortType){
23503 this.sortType = st.asUCString;
23506 this.sortType = st.asDate;
23509 this.sortType = st.none;
23514 var stripRe = /[\$,%]/g;
23516 // prebuilt conversion function for this field, instead of
23517 // switching every time we're reading a value
23519 var cv, dateFormat = this.dateFormat;
23524 cv = function(v){ return v; };
23527 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
23531 return v !== undefined && v !== null && v !== '' ?
23532 parseInt(String(v).replace(stripRe, ""), 10) : '';
23537 return v !== undefined && v !== null && v !== '' ?
23538 parseFloat(String(v).replace(stripRe, ""), 10) : '';
23543 cv = function(v){ return v === true || v === "true" || v == 1; };
23550 if(v instanceof Date){
23554 if(dateFormat == "timestamp"){
23555 return new Date(v*1000);
23557 return Date.parseDate(v, dateFormat);
23559 var parsed = Date.parse(v);
23560 return parsed ? new Date(parsed) : null;
23569 Roo.data.Field.prototype = {
23577 * Ext JS Library 1.1.1
23578 * Copyright(c) 2006-2007, Ext JS, LLC.
23580 * Originally Released Under LGPL - original licence link has changed is not relivant.
23583 * <script type="text/javascript">
23586 // Base class for reading structured data from a data source. This class is intended to be
23587 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
23590 * @class Roo.data.DataReader
23591 * Base class for reading structured data from a data source. This class is intended to be
23592 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
23595 Roo.data.DataReader = function(meta, recordType){
23599 this.recordType = recordType instanceof Array ?
23600 Roo.data.Record.create(recordType) : recordType;
23603 Roo.data.DataReader.prototype = {
23605 * Create an empty record
23606 * @param {Object} data (optional) - overlay some values
23607 * @return {Roo.data.Record} record created.
23609 newRow : function(d) {
23611 this.recordType.prototype.fields.each(function(c) {
23613 case 'int' : da[c.name] = 0; break;
23614 case 'date' : da[c.name] = new Date(); break;
23615 case 'float' : da[c.name] = 0.0; break;
23616 case 'boolean' : da[c.name] = false; break;
23617 default : da[c.name] = ""; break;
23621 return new this.recordType(Roo.apply(da, d));
23626 * Ext JS Library 1.1.1
23627 * Copyright(c) 2006-2007, Ext JS, LLC.
23629 * Originally Released Under LGPL - original licence link has changed is not relivant.
23632 * <script type="text/javascript">
23636 * @class Roo.data.DataProxy
23637 * @extends Roo.data.Observable
23638 * This class is an abstract base class for implementations which provide retrieval of
23639 * unformatted data objects.<br>
23641 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
23642 * (of the appropriate type which knows how to parse the data object) to provide a block of
23643 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
23645 * Custom implementations must implement the load method as described in
23646 * {@link Roo.data.HttpProxy#load}.
23648 Roo.data.DataProxy = function(){
23651 * @event beforeload
23652 * Fires before a network request is made to retrieve a data object.
23653 * @param {Object} This DataProxy object.
23654 * @param {Object} params The params parameter to the load function.
23659 * Fires before the load method's callback is called.
23660 * @param {Object} This DataProxy object.
23661 * @param {Object} o The data object.
23662 * @param {Object} arg The callback argument object passed to the load function.
23666 * @event loadexception
23667 * Fires if an Exception occurs during data retrieval.
23668 * @param {Object} This DataProxy object.
23669 * @param {Object} o The data object.
23670 * @param {Object} arg The callback argument object passed to the load function.
23671 * @param {Object} e The Exception.
23673 loadexception : true
23675 Roo.data.DataProxy.superclass.constructor.call(this);
23678 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
23681 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
23685 * Ext JS Library 1.1.1
23686 * Copyright(c) 2006-2007, Ext JS, LLC.
23688 * Originally Released Under LGPL - original licence link has changed is not relivant.
23691 * <script type="text/javascript">
23694 * @class Roo.data.MemoryProxy
23695 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
23696 * to the Reader when its load method is called.
23698 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
23700 Roo.data.MemoryProxy = function(data){
23704 Roo.data.MemoryProxy.superclass.constructor.call(this);
23708 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
23711 * Load data from the requested source (in this case an in-memory
23712 * data object passed to the constructor), read the data object into
23713 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23714 * process that block using the passed callback.
23715 * @param {Object} params This parameter is not used by the MemoryProxy class.
23716 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23717 * object into a block of Roo.data.Records.
23718 * @param {Function} callback The function into which to pass the block of Roo.data.records.
23719 * The function must be passed <ul>
23720 * <li>The Record block object</li>
23721 * <li>The "arg" argument from the load function</li>
23722 * <li>A boolean success indicator</li>
23724 * @param {Object} scope The scope in which to call the callback
23725 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23727 load : function(params, reader, callback, scope, arg){
23728 params = params || {};
23731 result = reader.readRecords(this.data);
23733 this.fireEvent("loadexception", this, arg, null, e);
23734 callback.call(scope, null, arg, false);
23737 callback.call(scope, result, arg, true);
23741 update : function(params, records){
23746 * Ext JS Library 1.1.1
23747 * Copyright(c) 2006-2007, Ext JS, LLC.
23749 * Originally Released Under LGPL - original licence link has changed is not relivant.
23752 * <script type="text/javascript">
23755 * @class Roo.data.HttpProxy
23756 * @extends Roo.data.DataProxy
23757 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
23758 * configured to reference a certain URL.<br><br>
23760 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
23761 * from which the running page was served.<br><br>
23763 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
23765 * Be aware that to enable the browser to parse an XML document, the server must set
23766 * the Content-Type header in the HTTP response to "text/xml".
23768 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
23769 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
23770 * will be used to make the request.
23772 Roo.data.HttpProxy = function(conn){
23773 Roo.data.HttpProxy.superclass.constructor.call(this);
23774 // is conn a conn config or a real conn?
23776 this.useAjax = !conn || !conn.events;
23780 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
23781 // thse are take from connection...
23784 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
23787 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
23788 * extra parameters to each request made by this object. (defaults to undefined)
23791 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
23792 * to each request made by this object. (defaults to undefined)
23795 * @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)
23798 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
23801 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
23807 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
23811 * Return the {@link Roo.data.Connection} object being used by this Proxy.
23812 * @return {Connection} The Connection object. This object may be used to subscribe to events on
23813 * a finer-grained basis than the DataProxy events.
23815 getConnection : function(){
23816 return this.useAjax ? Roo.Ajax : this.conn;
23820 * Load data from the configured {@link Roo.data.Connection}, read the data object into
23821 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
23822 * process that block using the passed callback.
23823 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23824 * for the request to the remote server.
23825 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23826 * object into a block of Roo.data.Records.
23827 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23828 * The function must be passed <ul>
23829 * <li>The Record block object</li>
23830 * <li>The "arg" argument from the load function</li>
23831 * <li>A boolean success indicator</li>
23833 * @param {Object} scope The scope in which to call the callback
23834 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23836 load : function(params, reader, callback, scope, arg){
23837 if(this.fireEvent("beforeload", this, params) !== false){
23839 params : params || {},
23841 callback : callback,
23846 callback : this.loadResponse,
23850 Roo.applyIf(o, this.conn);
23851 if(this.activeRequest){
23852 Roo.Ajax.abort(this.activeRequest);
23854 this.activeRequest = Roo.Ajax.request(o);
23856 this.conn.request(o);
23859 callback.call(scope||this, null, arg, false);
23864 loadResponse : function(o, success, response){
23865 delete this.activeRequest;
23867 this.fireEvent("loadexception", this, o, response);
23868 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23873 result = o.reader.read(response);
23875 this.fireEvent("loadexception", this, o, response, e);
23876 o.request.callback.call(o.request.scope, null, o.request.arg, false);
23880 this.fireEvent("load", this, o, o.request.arg);
23881 o.request.callback.call(o.request.scope, result, o.request.arg, true);
23885 update : function(dataSet){
23890 updateResponse : function(dataSet){
23895 * Ext JS Library 1.1.1
23896 * Copyright(c) 2006-2007, Ext JS, LLC.
23898 * Originally Released Under LGPL - original licence link has changed is not relivant.
23901 * <script type="text/javascript">
23905 * @class Roo.data.ScriptTagProxy
23906 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
23907 * other than the originating domain of the running page.<br><br>
23909 * <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
23910 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
23912 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
23913 * source code that is used as the source inside a <script> tag.<br><br>
23915 * In order for the browser to process the returned data, the server must wrap the data object
23916 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
23917 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
23918 * depending on whether the callback name was passed:
23921 boolean scriptTag = false;
23922 String cb = request.getParameter("callback");
23925 response.setContentType("text/javascript");
23927 response.setContentType("application/x-json");
23929 Writer out = response.getWriter();
23931 out.write(cb + "(");
23933 out.print(dataBlock.toJsonString());
23940 * @param {Object} config A configuration object.
23942 Roo.data.ScriptTagProxy = function(config){
23943 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
23944 Roo.apply(this, config);
23945 this.head = document.getElementsByTagName("head")[0];
23948 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
23950 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
23952 * @cfg {String} url The URL from which to request the data object.
23955 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
23959 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
23960 * the server the name of the callback function set up by the load call to process the returned data object.
23961 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
23962 * javascript output which calls this named function passing the data object as its only parameter.
23964 callbackParam : "callback",
23966 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
23967 * name to the request.
23972 * Load data from the configured URL, read the data object into
23973 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
23974 * process that block using the passed callback.
23975 * @param {Object} params An object containing properties which are to be used as HTTP parameters
23976 * for the request to the remote server.
23977 * @param {Roo.data.DataReader} reader The Reader object which converts the data
23978 * object into a block of Roo.data.Records.
23979 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
23980 * The function must be passed <ul>
23981 * <li>The Record block object</li>
23982 * <li>The "arg" argument from the load function</li>
23983 * <li>A boolean success indicator</li>
23985 * @param {Object} scope The scope in which to call the callback
23986 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
23988 load : function(params, reader, callback, scope, arg){
23989 if(this.fireEvent("beforeload", this, params) !== false){
23991 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
23993 var url = this.url;
23994 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
23996 url += "&_dc=" + (new Date().getTime());
23998 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24001 cb : "stcCallback"+transId,
24002 scriptId : "stcScript"+transId,
24006 callback : callback,
24012 window[trans.cb] = function(o){
24013 conn.handleResponse(o, trans);
24016 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24018 if(this.autoAbort !== false){
24022 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24024 var script = document.createElement("script");
24025 script.setAttribute("src", url);
24026 script.setAttribute("type", "text/javascript");
24027 script.setAttribute("id", trans.scriptId);
24028 this.head.appendChild(script);
24030 this.trans = trans;
24032 callback.call(scope||this, null, arg, false);
24037 isLoading : function(){
24038 return this.trans ? true : false;
24042 * Abort the current server request.
24044 abort : function(){
24045 if(this.isLoading()){
24046 this.destroyTrans(this.trans);
24051 destroyTrans : function(trans, isLoaded){
24052 this.head.removeChild(document.getElementById(trans.scriptId));
24053 clearTimeout(trans.timeoutId);
24055 window[trans.cb] = undefined;
24057 delete window[trans.cb];
24060 // if hasn't been loaded, wait for load to remove it to prevent script error
24061 window[trans.cb] = function(){
24062 window[trans.cb] = undefined;
24064 delete window[trans.cb];
24071 handleResponse : function(o, trans){
24072 this.trans = false;
24073 this.destroyTrans(trans, true);
24076 result = trans.reader.readRecords(o);
24078 this.fireEvent("loadexception", this, o, trans.arg, e);
24079 trans.callback.call(trans.scope||window, null, trans.arg, false);
24082 this.fireEvent("load", this, o, trans.arg);
24083 trans.callback.call(trans.scope||window, result, trans.arg, true);
24087 handleFailure : function(trans){
24088 this.trans = false;
24089 this.destroyTrans(trans, false);
24090 this.fireEvent("loadexception", this, null, trans.arg);
24091 trans.callback.call(trans.scope||window, null, trans.arg, false);
24095 * Ext JS Library 1.1.1
24096 * Copyright(c) 2006-2007, Ext JS, LLC.
24098 * Originally Released Under LGPL - original licence link has changed is not relivant.
24101 * <script type="text/javascript">
24105 * @class Roo.data.JsonReader
24106 * @extends Roo.data.DataReader
24107 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24108 * based on mappings in a provided Roo.data.Record constructor.
24110 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24111 * in the reply previously.
24116 var RecordDef = Roo.data.Record.create([
24117 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24118 {name: 'occupation'} // This field will use "occupation" as the mapping.
24120 var myReader = new Roo.data.JsonReader({
24121 totalProperty: "results", // The property which contains the total dataset size (optional)
24122 root: "rows", // The property which contains an Array of row objects
24123 id: "id" // The property within each row object that provides an ID for the record (optional)
24127 * This would consume a JSON file like this:
24129 { 'results': 2, 'rows': [
24130 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24131 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24134 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24135 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24136 * paged from the remote server.
24137 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24138 * @cfg {String} root name of the property which contains the Array of row objects.
24139 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24140 * @cfg {Array} fields Array of field definition objects
24142 * Create a new JsonReader
24143 * @param {Object} meta Metadata configuration options
24144 * @param {Object} recordType Either an Array of field definition objects,
24145 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24147 Roo.data.JsonReader = function(meta, recordType){
24150 // set some defaults:
24151 Roo.applyIf(meta, {
24152 totalProperty: 'total',
24153 successProperty : 'success',
24158 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24160 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24163 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
24164 * Used by Store query builder to append _requestMeta to params.
24167 metaFromRemote : false,
24169 * This method is only used by a DataProxy which has retrieved data from a remote server.
24170 * @param {Object} response The XHR object which contains the JSON data in its responseText.
24171 * @return {Object} data A data block which is used by an Roo.data.Store object as
24172 * a cache of Roo.data.Records.
24174 read : function(response){
24175 var json = response.responseText;
24177 var o = /* eval:var:o */ eval("("+json+")");
24179 throw {message: "JsonReader.read: Json object not found"};
24185 this.metaFromRemote = true;
24186 this.meta = o.metaData;
24187 this.recordType = Roo.data.Record.create(o.metaData.fields);
24188 this.onMetaChange(this.meta, this.recordType, o);
24190 return this.readRecords(o);
24193 // private function a store will implement
24194 onMetaChange : function(meta, recordType, o){
24201 simpleAccess: function(obj, subsc) {
24208 getJsonAccessor: function(){
24210 return function(expr) {
24212 return(re.test(expr))
24213 ? new Function("obj", "return obj." + expr)
24218 return Roo.emptyFn;
24223 * Create a data block containing Roo.data.Records from an XML document.
24224 * @param {Object} o An object which contains an Array of row objects in the property specified
24225 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
24226 * which contains the total size of the dataset.
24227 * @return {Object} data A data block which is used by an Roo.data.Store object as
24228 * a cache of Roo.data.Records.
24230 readRecords : function(o){
24232 * After any data loads, the raw JSON data is available for further custom processing.
24236 var s = this.meta, Record = this.recordType,
24237 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
24239 // Generate extraction functions for the totalProperty, the root, the id, and for each field
24241 if(s.totalProperty) {
24242 this.getTotal = this.getJsonAccessor(s.totalProperty);
24244 if(s.successProperty) {
24245 this.getSuccess = this.getJsonAccessor(s.successProperty);
24247 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
24249 var g = this.getJsonAccessor(s.id);
24250 this.getId = function(rec) {
24252 return (r === undefined || r === "") ? null : r;
24255 this.getId = function(){return null;};
24258 for(var jj = 0; jj < fl; jj++){
24260 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
24261 this.ef[jj] = this.getJsonAccessor(map);
24265 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
24266 if(s.totalProperty){
24267 var vt = parseInt(this.getTotal(o), 10);
24272 if(s.successProperty){
24273 var vs = this.getSuccess(o);
24274 if(vs === false || vs === 'false'){
24279 for(var i = 0; i < c; i++){
24282 var id = this.getId(n);
24283 for(var j = 0; j < fl; j++){
24285 var v = this.ef[j](n);
24287 Roo.log('missing convert for ' + f.name);
24291 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
24293 var record = new Record(values, id);
24295 records[i] = record;
24301 totalRecords : totalRecords
24306 * Ext JS Library 1.1.1
24307 * Copyright(c) 2006-2007, Ext JS, LLC.
24309 * Originally Released Under LGPL - original licence link has changed is not relivant.
24312 * <script type="text/javascript">
24316 * @class Roo.data.XmlReader
24317 * @extends Roo.data.DataReader
24318 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
24319 * based on mappings in a provided Roo.data.Record constructor.<br><br>
24321 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
24322 * header in the HTTP response must be set to "text/xml".</em>
24326 var RecordDef = Roo.data.Record.create([
24327 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24328 {name: 'occupation'} // This field will use "occupation" as the mapping.
24330 var myReader = new Roo.data.XmlReader({
24331 totalRecords: "results", // The element which contains the total dataset size (optional)
24332 record: "row", // The repeated element which contains row information
24333 id: "id" // The element within the row that provides an ID for the record (optional)
24337 * This would consume an XML file like this:
24341 <results>2</results>
24344 <name>Bill</name>
24345 <occupation>Gardener</occupation>
24349 <name>Ben</name>
24350 <occupation>Horticulturalist</occupation>
24354 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
24355 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24356 * paged from the remote server.
24357 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
24358 * @cfg {String} success The DomQuery path to the success attribute used by forms.
24359 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
24360 * a record identifier value.
24362 * Create a new XmlReader
24363 * @param {Object} meta Metadata configuration options
24364 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
24365 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
24366 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
24368 Roo.data.XmlReader = function(meta, recordType){
24370 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24372 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
24374 * This method is only used by a DataProxy which has retrieved data from a remote server.
24375 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
24376 * to contain a method called 'responseXML' that returns an XML document object.
24377 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24378 * a cache of Roo.data.Records.
24380 read : function(response){
24381 var doc = response.responseXML;
24383 throw {message: "XmlReader.read: XML Document not available"};
24385 return this.readRecords(doc);
24389 * Create a data block containing Roo.data.Records from an XML document.
24390 * @param {Object} doc A parsed XML document.
24391 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
24392 * a cache of Roo.data.Records.
24394 readRecords : function(doc){
24396 * After any data loads/reads, the raw XML Document is available for further custom processing.
24397 * @type XMLDocument
24399 this.xmlData = doc;
24400 var root = doc.documentElement || doc;
24401 var q = Roo.DomQuery;
24402 var recordType = this.recordType, fields = recordType.prototype.fields;
24403 var sid = this.meta.id;
24404 var totalRecords = 0, success = true;
24405 if(this.meta.totalRecords){
24406 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
24409 if(this.meta.success){
24410 var sv = q.selectValue(this.meta.success, root, true);
24411 success = sv !== false && sv !== 'false';
24414 var ns = q.select(this.meta.record, root);
24415 for(var i = 0, len = ns.length; i < len; i++) {
24418 var id = sid ? q.selectValue(sid, n) : undefined;
24419 for(var j = 0, jlen = fields.length; j < jlen; j++){
24420 var f = fields.items[j];
24421 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
24423 values[f.name] = v;
24425 var record = new recordType(values, id);
24427 records[records.length] = record;
24433 totalRecords : totalRecords || records.length
24438 * Ext JS Library 1.1.1
24439 * Copyright(c) 2006-2007, Ext JS, LLC.
24441 * Originally Released Under LGPL - original licence link has changed is not relivant.
24444 * <script type="text/javascript">
24448 * @class Roo.data.ArrayReader
24449 * @extends Roo.data.DataReader
24450 * Data reader class to create an Array of Roo.data.Record objects from an Array.
24451 * Each element of that Array represents a row of data fields. The
24452 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
24453 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
24457 var RecordDef = Roo.data.Record.create([
24458 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
24459 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
24461 var myReader = new Roo.data.ArrayReader({
24462 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
24466 * This would consume an Array like this:
24468 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
24470 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
24472 * Create a new JsonReader
24473 * @param {Object} meta Metadata configuration options.
24474 * @param {Object} recordType Either an Array of field definition objects
24475 * as specified to {@link Roo.data.Record#create},
24476 * or an {@link Roo.data.Record} object
24477 * created using {@link Roo.data.Record#create}.
24479 Roo.data.ArrayReader = function(meta, recordType){
24480 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
24483 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
24485 * Create a data block containing Roo.data.Records from an XML document.
24486 * @param {Object} o An Array of row objects which represents the dataset.
24487 * @return {Object} data A data block which is used by an Roo.data.Store object as
24488 * a cache of Roo.data.Records.
24490 readRecords : function(o){
24491 var sid = this.meta ? this.meta.id : null;
24492 var recordType = this.recordType, fields = recordType.prototype.fields;
24495 for(var i = 0; i < root.length; i++){
24498 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
24499 for(var j = 0, jlen = fields.length; j < jlen; j++){
24500 var f = fields.items[j];
24501 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
24502 var v = n[k] !== undefined ? n[k] : f.defaultValue;
24504 values[f.name] = v;
24506 var record = new recordType(values, id);
24508 records[records.length] = record;
24512 totalRecords : records.length
24517 * Ext JS Library 1.1.1
24518 * Copyright(c) 2006-2007, Ext JS, LLC.
24520 * Originally Released Under LGPL - original licence link has changed is not relivant.
24523 * <script type="text/javascript">
24528 * @class Roo.data.Tree
24529 * @extends Roo.util.Observable
24530 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
24531 * in the tree have most standard DOM functionality.
24533 * @param {Node} root (optional) The root node
24535 Roo.data.Tree = function(root){
24536 this.nodeHash = {};
24538 * The root node for this tree
24543 this.setRootNode(root);
24548 * Fires when a new child node is appended to a node in this tree.
24549 * @param {Tree} tree The owner tree
24550 * @param {Node} parent The parent node
24551 * @param {Node} node The newly appended node
24552 * @param {Number} index The index of the newly appended node
24557 * Fires when a child node is removed from a node in this tree.
24558 * @param {Tree} tree The owner tree
24559 * @param {Node} parent The parent node
24560 * @param {Node} node The child node removed
24565 * Fires when a node is moved to a new location in the tree
24566 * @param {Tree} tree The owner tree
24567 * @param {Node} node The node moved
24568 * @param {Node} oldParent The old parent of this node
24569 * @param {Node} newParent The new parent of this node
24570 * @param {Number} index The index it was moved to
24575 * Fires when a new child node is inserted in a node in this tree.
24576 * @param {Tree} tree The owner tree
24577 * @param {Node} parent The parent node
24578 * @param {Node} node The child node inserted
24579 * @param {Node} refNode The child node the node was inserted before
24583 * @event beforeappend
24584 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
24585 * @param {Tree} tree The owner tree
24586 * @param {Node} parent The parent node
24587 * @param {Node} node The child node to be appended
24589 "beforeappend" : true,
24591 * @event beforeremove
24592 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
24593 * @param {Tree} tree The owner tree
24594 * @param {Node} parent The parent node
24595 * @param {Node} node The child node to be removed
24597 "beforeremove" : true,
24599 * @event beforemove
24600 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
24601 * @param {Tree} tree The owner tree
24602 * @param {Node} node The node being moved
24603 * @param {Node} oldParent The parent of the node
24604 * @param {Node} newParent The new parent the node is moving to
24605 * @param {Number} index The index it is being moved to
24607 "beforemove" : true,
24609 * @event beforeinsert
24610 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
24611 * @param {Tree} tree The owner tree
24612 * @param {Node} parent The parent node
24613 * @param {Node} node The child node to be inserted
24614 * @param {Node} refNode The child node the node is being inserted before
24616 "beforeinsert" : true
24619 Roo.data.Tree.superclass.constructor.call(this);
24622 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
24623 pathSeparator: "/",
24625 proxyNodeEvent : function(){
24626 return this.fireEvent.apply(this, arguments);
24630 * Returns the root node for this tree.
24633 getRootNode : function(){
24638 * Sets the root node for this tree.
24639 * @param {Node} node
24642 setRootNode : function(node){
24644 node.ownerTree = this;
24645 node.isRoot = true;
24646 this.registerNode(node);
24651 * Gets a node in this tree by its id.
24652 * @param {String} id
24655 getNodeById : function(id){
24656 return this.nodeHash[id];
24659 registerNode : function(node){
24660 this.nodeHash[node.id] = node;
24663 unregisterNode : function(node){
24664 delete this.nodeHash[node.id];
24667 toString : function(){
24668 return "[Tree"+(this.id?" "+this.id:"")+"]";
24673 * @class Roo.data.Node
24674 * @extends Roo.util.Observable
24675 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
24676 * @cfg {String} id The id for this node. If one is not specified, one is generated.
24678 * @param {Object} attributes The attributes/config for the node
24680 Roo.data.Node = function(attributes){
24682 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
24685 this.attributes = attributes || {};
24686 this.leaf = this.attributes.leaf;
24688 * The node id. @type String
24690 this.id = this.attributes.id;
24692 this.id = Roo.id(null, "ynode-");
24693 this.attributes.id = this.id;
24698 * All child nodes of this node. @type Array
24700 this.childNodes = [];
24701 if(!this.childNodes.indexOf){ // indexOf is a must
24702 this.childNodes.indexOf = function(o){
24703 for(var i = 0, len = this.length; i < len; i++){
24712 * The parent node for this node. @type Node
24714 this.parentNode = null;
24716 * The first direct child node of this node, or null if this node has no child nodes. @type Node
24718 this.firstChild = null;
24720 * The last direct child node of this node, or null if this node has no child nodes. @type Node
24722 this.lastChild = null;
24724 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
24726 this.previousSibling = null;
24728 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
24730 this.nextSibling = null;
24735 * Fires when a new child node is appended
24736 * @param {Tree} tree The owner tree
24737 * @param {Node} this This node
24738 * @param {Node} node The newly appended node
24739 * @param {Number} index The index of the newly appended node
24744 * Fires when a child node is removed
24745 * @param {Tree} tree The owner tree
24746 * @param {Node} this This node
24747 * @param {Node} node The removed node
24752 * Fires when this node is moved to a new location in the tree
24753 * @param {Tree} tree The owner tree
24754 * @param {Node} this This node
24755 * @param {Node} oldParent The old parent of this node
24756 * @param {Node} newParent The new parent of this node
24757 * @param {Number} index The index it was moved to
24762 * Fires when a new child node is inserted.
24763 * @param {Tree} tree The owner tree
24764 * @param {Node} this This node
24765 * @param {Node} node The child node inserted
24766 * @param {Node} refNode The child node the node was inserted before
24770 * @event beforeappend
24771 * Fires before a new child is appended, return false to cancel the append.
24772 * @param {Tree} tree The owner tree
24773 * @param {Node} this This node
24774 * @param {Node} node The child node to be appended
24776 "beforeappend" : true,
24778 * @event beforeremove
24779 * Fires before a child is removed, return false to cancel the remove.
24780 * @param {Tree} tree The owner tree
24781 * @param {Node} this This node
24782 * @param {Node} node The child node to be removed
24784 "beforeremove" : true,
24786 * @event beforemove
24787 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
24788 * @param {Tree} tree The owner tree
24789 * @param {Node} this This node
24790 * @param {Node} oldParent The parent of this node
24791 * @param {Node} newParent The new parent this node is moving to
24792 * @param {Number} index The index it is being moved to
24794 "beforemove" : true,
24796 * @event beforeinsert
24797 * Fires before a new child is inserted, return false to cancel the insert.
24798 * @param {Tree} tree The owner tree
24799 * @param {Node} this This node
24800 * @param {Node} node The child node to be inserted
24801 * @param {Node} refNode The child node the node is being inserted before
24803 "beforeinsert" : true
24805 this.listeners = this.attributes.listeners;
24806 Roo.data.Node.superclass.constructor.call(this);
24809 Roo.extend(Roo.data.Node, Roo.util.Observable, {
24810 fireEvent : function(evtName){
24811 // first do standard event for this node
24812 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
24815 // then bubble it up to the tree if the event wasn't cancelled
24816 var ot = this.getOwnerTree();
24818 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
24826 * Returns true if this node is a leaf
24827 * @return {Boolean}
24829 isLeaf : function(){
24830 return this.leaf === true;
24834 setFirstChild : function(node){
24835 this.firstChild = node;
24839 setLastChild : function(node){
24840 this.lastChild = node;
24845 * Returns true if this node is the last child of its parent
24846 * @return {Boolean}
24848 isLast : function(){
24849 return (!this.parentNode ? true : this.parentNode.lastChild == this);
24853 * Returns true if this node is the first child of its parent
24854 * @return {Boolean}
24856 isFirst : function(){
24857 return (!this.parentNode ? true : this.parentNode.firstChild == this);
24860 hasChildNodes : function(){
24861 return !this.isLeaf() && this.childNodes.length > 0;
24865 * Insert node(s) as the last child node of this node.
24866 * @param {Node/Array} node The node or Array of nodes to append
24867 * @return {Node} The appended node if single append, or null if an array was passed
24869 appendChild : function(node){
24871 if(node instanceof Array){
24873 }else if(arguments.length > 1){
24876 // if passed an array or multiple args do them one by one
24878 for(var i = 0, len = multi.length; i < len; i++) {
24879 this.appendChild(multi[i]);
24882 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
24885 var index = this.childNodes.length;
24886 var oldParent = node.parentNode;
24887 // it's a move, make sure we move it cleanly
24889 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
24892 oldParent.removeChild(node);
24894 index = this.childNodes.length;
24896 this.setFirstChild(node);
24898 this.childNodes.push(node);
24899 node.parentNode = this;
24900 var ps = this.childNodes[index-1];
24902 node.previousSibling = ps;
24903 ps.nextSibling = node;
24905 node.previousSibling = null;
24907 node.nextSibling = null;
24908 this.setLastChild(node);
24909 node.setOwnerTree(this.getOwnerTree());
24910 this.fireEvent("append", this.ownerTree, this, node, index);
24912 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
24919 * Removes a child node from this node.
24920 * @param {Node} node The node to remove
24921 * @return {Node} The removed node
24923 removeChild : function(node){
24924 var index = this.childNodes.indexOf(node);
24928 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
24932 // remove it from childNodes collection
24933 this.childNodes.splice(index, 1);
24936 if(node.previousSibling){
24937 node.previousSibling.nextSibling = node.nextSibling;
24939 if(node.nextSibling){
24940 node.nextSibling.previousSibling = node.previousSibling;
24943 // update child refs
24944 if(this.firstChild == node){
24945 this.setFirstChild(node.nextSibling);
24947 if(this.lastChild == node){
24948 this.setLastChild(node.previousSibling);
24951 node.setOwnerTree(null);
24952 // clear any references from the node
24953 node.parentNode = null;
24954 node.previousSibling = null;
24955 node.nextSibling = null;
24956 this.fireEvent("remove", this.ownerTree, this, node);
24961 * Inserts the first node before the second node in this nodes childNodes collection.
24962 * @param {Node} node The node to insert
24963 * @param {Node} refNode The node to insert before (if null the node is appended)
24964 * @return {Node} The inserted node
24966 insertBefore : function(node, refNode){
24967 if(!refNode){ // like standard Dom, refNode can be null for append
24968 return this.appendChild(node);
24971 if(node == refNode){
24975 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
24978 var index = this.childNodes.indexOf(refNode);
24979 var oldParent = node.parentNode;
24980 var refIndex = index;
24982 // when moving internally, indexes will change after remove
24983 if(oldParent == this && this.childNodes.indexOf(node) < index){
24987 // it's a move, make sure we move it cleanly
24989 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
24992 oldParent.removeChild(node);
24995 this.setFirstChild(node);
24997 this.childNodes.splice(refIndex, 0, node);
24998 node.parentNode = this;
24999 var ps = this.childNodes[refIndex-1];
25001 node.previousSibling = ps;
25002 ps.nextSibling = node;
25004 node.previousSibling = null;
25006 node.nextSibling = refNode;
25007 refNode.previousSibling = node;
25008 node.setOwnerTree(this.getOwnerTree());
25009 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25011 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25017 * Returns the child node at the specified index.
25018 * @param {Number} index
25021 item : function(index){
25022 return this.childNodes[index];
25026 * Replaces one child node in this node with another.
25027 * @param {Node} newChild The replacement node
25028 * @param {Node} oldChild The node to replace
25029 * @return {Node} The replaced node
25031 replaceChild : function(newChild, oldChild){
25032 this.insertBefore(newChild, oldChild);
25033 this.removeChild(oldChild);
25038 * Returns the index of a child node
25039 * @param {Node} node
25040 * @return {Number} The index of the node or -1 if it was not found
25042 indexOf : function(child){
25043 return this.childNodes.indexOf(child);
25047 * Returns the tree this node is in.
25050 getOwnerTree : function(){
25051 // if it doesn't have one, look for one
25052 if(!this.ownerTree){
25056 this.ownerTree = p.ownerTree;
25062 return this.ownerTree;
25066 * Returns depth of this node (the root node has a depth of 0)
25069 getDepth : function(){
25072 while(p.parentNode){
25080 setOwnerTree : function(tree){
25081 // if it's move, we need to update everyone
25082 if(tree != this.ownerTree){
25083 if(this.ownerTree){
25084 this.ownerTree.unregisterNode(this);
25086 this.ownerTree = tree;
25087 var cs = this.childNodes;
25088 for(var i = 0, len = cs.length; i < len; i++) {
25089 cs[i].setOwnerTree(tree);
25092 tree.registerNode(this);
25098 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25099 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25100 * @return {String} The path
25102 getPath : function(attr){
25103 attr = attr || "id";
25104 var p = this.parentNode;
25105 var b = [this.attributes[attr]];
25107 b.unshift(p.attributes[attr]);
25110 var sep = this.getOwnerTree().pathSeparator;
25111 return sep + b.join(sep);
25115 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25116 * function call will be the scope provided or the current node. The arguments to the function
25117 * will be the args provided or the current node. If the function returns false at any point,
25118 * the bubble is stopped.
25119 * @param {Function} fn The function to call
25120 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25121 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25123 bubble : function(fn, scope, args){
25126 if(fn.call(scope || p, args || p) === false){
25134 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25135 * function call will be the scope provided or the current node. The arguments to the function
25136 * will be the args provided or the current node. If the function returns false at any point,
25137 * the cascade is stopped on that branch.
25138 * @param {Function} fn The function to call
25139 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25140 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25142 cascade : function(fn, scope, args){
25143 if(fn.call(scope || this, args || this) !== false){
25144 var cs = this.childNodes;
25145 for(var i = 0, len = cs.length; i < len; i++) {
25146 cs[i].cascade(fn, scope, args);
25152 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
25153 * function call will be the scope provided or the current node. The arguments to the function
25154 * will be the args provided or the current node. If the function returns false at any point,
25155 * the iteration stops.
25156 * @param {Function} fn The function to call
25157 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25158 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25160 eachChild : function(fn, scope, args){
25161 var cs = this.childNodes;
25162 for(var i = 0, len = cs.length; i < len; i++) {
25163 if(fn.call(scope || this, args || cs[i]) === false){
25170 * Finds the first child that has the attribute with the specified value.
25171 * @param {String} attribute The attribute name
25172 * @param {Mixed} value The value to search for
25173 * @return {Node} The found child or null if none was found
25175 findChild : function(attribute, value){
25176 var cs = this.childNodes;
25177 for(var i = 0, len = cs.length; i < len; i++) {
25178 if(cs[i].attributes[attribute] == value){
25186 * Finds the first child by a custom function. The child matches if the function passed
25188 * @param {Function} fn
25189 * @param {Object} scope (optional)
25190 * @return {Node} The found child or null if none was found
25192 findChildBy : function(fn, scope){
25193 var cs = this.childNodes;
25194 for(var i = 0, len = cs.length; i < len; i++) {
25195 if(fn.call(scope||cs[i], cs[i]) === true){
25203 * Sorts this nodes children using the supplied sort function
25204 * @param {Function} fn
25205 * @param {Object} scope (optional)
25207 sort : function(fn, scope){
25208 var cs = this.childNodes;
25209 var len = cs.length;
25211 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
25213 for(var i = 0; i < len; i++){
25215 n.previousSibling = cs[i-1];
25216 n.nextSibling = cs[i+1];
25218 this.setFirstChild(n);
25221 this.setLastChild(n);
25228 * Returns true if this node is an ancestor (at any point) of the passed node.
25229 * @param {Node} node
25230 * @return {Boolean}
25232 contains : function(node){
25233 return node.isAncestor(this);
25237 * Returns true if the passed node is an ancestor (at any point) of this node.
25238 * @param {Node} node
25239 * @return {Boolean}
25241 isAncestor : function(node){
25242 var p = this.parentNode;
25252 toString : function(){
25253 return "[Node"+(this.id?" "+this.id:"")+"]";
25257 * Ext JS Library 1.1.1
25258 * Copyright(c) 2006-2007, Ext JS, LLC.
25260 * Originally Released Under LGPL - original licence link has changed is not relivant.
25263 * <script type="text/javascript">
25268 * @extends Roo.Element
25269 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
25270 * automatic maintaining of shadow/shim positions.
25271 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
25272 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
25273 * you can pass a string with a CSS class name. False turns off the shadow.
25274 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
25275 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
25276 * @cfg {String} cls CSS class to add to the element
25277 * @cfg {Number} zindex Starting z-index (defaults to 11000)
25278 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
25280 * @param {Object} config An object with config options.
25281 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
25284 Roo.Layer = function(config, existingEl){
25285 config = config || {};
25286 var dh = Roo.DomHelper;
25287 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
25289 this.dom = Roo.getDom(existingEl);
25292 var o = config.dh || {tag: "div", cls: "x-layer"};
25293 this.dom = dh.append(pel, o);
25296 this.addClass(config.cls);
25298 this.constrain = config.constrain !== false;
25299 this.visibilityMode = Roo.Element.VISIBILITY;
25301 this.id = this.dom.id = config.id;
25303 this.id = Roo.id(this.dom);
25305 this.zindex = config.zindex || this.getZIndex();
25306 this.position("absolute", this.zindex);
25308 this.shadowOffset = config.shadowOffset || 4;
25309 this.shadow = new Roo.Shadow({
25310 offset : this.shadowOffset,
25311 mode : config.shadow
25314 this.shadowOffset = 0;
25316 this.useShim = config.shim !== false && Roo.useShims;
25317 this.useDisplay = config.useDisplay;
25321 var supr = Roo.Element.prototype;
25323 // shims are shared among layer to keep from having 100 iframes
25326 Roo.extend(Roo.Layer, Roo.Element, {
25328 getZIndex : function(){
25329 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
25332 getShim : function(){
25339 var shim = shims.shift();
25341 shim = this.createShim();
25342 shim.enableDisplayMode('block');
25343 shim.dom.style.display = 'none';
25344 shim.dom.style.visibility = 'visible';
25346 var pn = this.dom.parentNode;
25347 if(shim.dom.parentNode != pn){
25348 pn.insertBefore(shim.dom, this.dom);
25350 shim.setStyle('z-index', this.getZIndex()-2);
25355 hideShim : function(){
25357 this.shim.setDisplayed(false);
25358 shims.push(this.shim);
25363 disableShadow : function(){
25365 this.shadowDisabled = true;
25366 this.shadow.hide();
25367 this.lastShadowOffset = this.shadowOffset;
25368 this.shadowOffset = 0;
25372 enableShadow : function(show){
25374 this.shadowDisabled = false;
25375 this.shadowOffset = this.lastShadowOffset;
25376 delete this.lastShadowOffset;
25384 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
25385 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
25386 sync : function(doShow){
25387 var sw = this.shadow;
25388 if(!this.updating && this.isVisible() && (sw || this.useShim)){
25389 var sh = this.getShim();
25391 var w = this.getWidth(),
25392 h = this.getHeight();
25394 var l = this.getLeft(true),
25395 t = this.getTop(true);
25397 if(sw && !this.shadowDisabled){
25398 if(doShow && !sw.isVisible()){
25401 sw.realign(l, t, w, h);
25407 // fit the shim behind the shadow, so it is shimmed too
25408 var a = sw.adjusts, s = sh.dom.style;
25409 s.left = (Math.min(l, l+a.l))+"px";
25410 s.top = (Math.min(t, t+a.t))+"px";
25411 s.width = (w+a.w)+"px";
25412 s.height = (h+a.h)+"px";
25419 sh.setLeftTop(l, t);
25426 destroy : function(){
25429 this.shadow.hide();
25431 this.removeAllListeners();
25432 var pn = this.dom.parentNode;
25434 pn.removeChild(this.dom);
25436 Roo.Element.uncache(this.id);
25439 remove : function(){
25444 beginUpdate : function(){
25445 this.updating = true;
25449 endUpdate : function(){
25450 this.updating = false;
25455 hideUnders : function(negOffset){
25457 this.shadow.hide();
25463 constrainXY : function(){
25464 if(this.constrain){
25465 var vw = Roo.lib.Dom.getViewWidth(),
25466 vh = Roo.lib.Dom.getViewHeight();
25467 var s = Roo.get(document).getScroll();
25469 var xy = this.getXY();
25470 var x = xy[0], y = xy[1];
25471 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
25472 // only move it if it needs it
25474 // first validate right/bottom
25475 if((x + w) > vw+s.left){
25476 x = vw - w - this.shadowOffset;
25479 if((y + h) > vh+s.top){
25480 y = vh - h - this.shadowOffset;
25483 // then make sure top/left isn't negative
25494 var ay = this.avoidY;
25495 if(y <= ay && (y+h) >= ay){
25501 supr.setXY.call(this, xy);
25507 isVisible : function(){
25508 return this.visible;
25512 showAction : function(){
25513 this.visible = true; // track visibility to prevent getStyle calls
25514 if(this.useDisplay === true){
25515 this.setDisplayed("");
25516 }else if(this.lastXY){
25517 supr.setXY.call(this, this.lastXY);
25518 }else if(this.lastLT){
25519 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
25524 hideAction : function(){
25525 this.visible = false;
25526 if(this.useDisplay === true){
25527 this.setDisplayed(false);
25529 this.setLeftTop(-10000,-10000);
25533 // overridden Element method
25534 setVisible : function(v, a, d, c, e){
25539 var cb = function(){
25544 }.createDelegate(this);
25545 supr.setVisible.call(this, true, true, d, cb, e);
25548 this.hideUnders(true);
25557 }.createDelegate(this);
25559 supr.setVisible.call(this, v, a, d, cb, e);
25568 storeXY : function(xy){
25569 delete this.lastLT;
25573 storeLeftTop : function(left, top){
25574 delete this.lastXY;
25575 this.lastLT = [left, top];
25579 beforeFx : function(){
25580 this.beforeAction();
25581 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
25585 afterFx : function(){
25586 Roo.Layer.superclass.afterFx.apply(this, arguments);
25587 this.sync(this.isVisible());
25591 beforeAction : function(){
25592 if(!this.updating && this.shadow){
25593 this.shadow.hide();
25597 // overridden Element method
25598 setLeft : function(left){
25599 this.storeLeftTop(left, this.getTop(true));
25600 supr.setLeft.apply(this, arguments);
25604 setTop : function(top){
25605 this.storeLeftTop(this.getLeft(true), top);
25606 supr.setTop.apply(this, arguments);
25610 setLeftTop : function(left, top){
25611 this.storeLeftTop(left, top);
25612 supr.setLeftTop.apply(this, arguments);
25616 setXY : function(xy, a, d, c, e){
25618 this.beforeAction();
25620 var cb = this.createCB(c);
25621 supr.setXY.call(this, xy, a, d, cb, e);
25628 createCB : function(c){
25639 // overridden Element method
25640 setX : function(x, a, d, c, e){
25641 this.setXY([x, this.getY()], a, d, c, e);
25644 // overridden Element method
25645 setY : function(y, a, d, c, e){
25646 this.setXY([this.getX(), y], a, d, c, e);
25649 // overridden Element method
25650 setSize : function(w, h, a, d, c, e){
25651 this.beforeAction();
25652 var cb = this.createCB(c);
25653 supr.setSize.call(this, w, h, a, d, cb, e);
25659 // overridden Element method
25660 setWidth : function(w, a, d, c, e){
25661 this.beforeAction();
25662 var cb = this.createCB(c);
25663 supr.setWidth.call(this, w, a, d, cb, e);
25669 // overridden Element method
25670 setHeight : function(h, a, d, c, e){
25671 this.beforeAction();
25672 var cb = this.createCB(c);
25673 supr.setHeight.call(this, h, a, d, cb, e);
25679 // overridden Element method
25680 setBounds : function(x, y, w, h, a, d, c, e){
25681 this.beforeAction();
25682 var cb = this.createCB(c);
25684 this.storeXY([x, y]);
25685 supr.setXY.call(this, [x, y]);
25686 supr.setSize.call(this, w, h, a, d, cb, e);
25689 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
25695 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
25696 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
25697 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
25698 * @param {Number} zindex The new z-index to set
25699 * @return {this} The Layer
25701 setZIndex : function(zindex){
25702 this.zindex = zindex;
25703 this.setStyle("z-index", zindex + 2);
25705 this.shadow.setZIndex(zindex + 1);
25708 this.shim.setStyle("z-index", zindex);
25714 * Ext JS Library 1.1.1
25715 * Copyright(c) 2006-2007, Ext JS, LLC.
25717 * Originally Released Under LGPL - original licence link has changed is not relivant.
25720 * <script type="text/javascript">
25725 * @class Roo.Shadow
25726 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
25727 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
25728 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
25730 * Create a new Shadow
25731 * @param {Object} config The config object
25733 Roo.Shadow = function(config){
25734 Roo.apply(this, config);
25735 if(typeof this.mode != "string"){
25736 this.mode = this.defaultMode;
25738 var o = this.offset, a = {h: 0};
25739 var rad = Math.floor(this.offset/2);
25740 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
25746 a.l -= this.offset + rad;
25747 a.t -= this.offset + rad;
25758 a.l -= (this.offset - rad);
25759 a.t -= this.offset + rad;
25761 a.w -= (this.offset - rad)*2;
25772 a.l -= (this.offset - rad);
25773 a.t -= (this.offset - rad);
25775 a.w -= (this.offset + rad + 1);
25776 a.h -= (this.offset + rad);
25785 Roo.Shadow.prototype = {
25787 * @cfg {String} mode
25788 * The shadow display mode. Supports the following options:<br />
25789 * sides: Shadow displays on both sides and bottom only<br />
25790 * frame: Shadow displays equally on all four sides<br />
25791 * drop: Traditional bottom-right drop shadow (default)
25794 * @cfg {String} offset
25795 * The number of pixels to offset the shadow from the element (defaults to 4)
25800 defaultMode: "drop",
25803 * Displays the shadow under the target element
25804 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
25806 show : function(target){
25807 target = Roo.get(target);
25809 this.el = Roo.Shadow.Pool.pull();
25810 if(this.el.dom.nextSibling != target.dom){
25811 this.el.insertBefore(target);
25814 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
25816 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
25819 target.getLeft(true),
25820 target.getTop(true),
25824 this.el.dom.style.display = "block";
25828 * Returns true if the shadow is visible, else false
25830 isVisible : function(){
25831 return this.el ? true : false;
25835 * Direct alignment when values are already available. Show must be called at least once before
25836 * calling this method to ensure it is initialized.
25837 * @param {Number} left The target element left position
25838 * @param {Number} top The target element top position
25839 * @param {Number} width The target element width
25840 * @param {Number} height The target element height
25842 realign : function(l, t, w, h){
25846 var a = this.adjusts, d = this.el.dom, s = d.style;
25848 s.left = (l+a.l)+"px";
25849 s.top = (t+a.t)+"px";
25850 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
25852 if(s.width != sws || s.height != shs){
25856 var cn = d.childNodes;
25857 var sww = Math.max(0, (sw-12))+"px";
25858 cn[0].childNodes[1].style.width = sww;
25859 cn[1].childNodes[1].style.width = sww;
25860 cn[2].childNodes[1].style.width = sww;
25861 cn[1].style.height = Math.max(0, (sh-12))+"px";
25867 * Hides this shadow
25871 this.el.dom.style.display = "none";
25872 Roo.Shadow.Pool.push(this.el);
25878 * Adjust the z-index of this shadow
25879 * @param {Number} zindex The new z-index
25881 setZIndex : function(z){
25884 this.el.setStyle("z-index", z);
25889 // Private utility class that manages the internal Shadow cache
25890 Roo.Shadow.Pool = function(){
25892 var markup = Roo.isIE ?
25893 '<div class="x-ie-shadow"></div>' :
25894 '<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>';
25897 var sh = p.shift();
25899 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
25900 sh.autoBoxAdjust = false;
25905 push : function(sh){
25911 * Ext JS Library 1.1.1
25912 * Copyright(c) 2006-2007, Ext JS, LLC.
25914 * Originally Released Under LGPL - original licence link has changed is not relivant.
25917 * <script type="text/javascript">
25922 * @class Roo.SplitBar
25923 * @extends Roo.util.Observable
25924 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
25928 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
25929 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
25930 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
25931 split.minSize = 100;
25932 split.maxSize = 600;
25933 split.animate = true;
25934 split.on('moved', splitterMoved);
25937 * Create a new SplitBar
25938 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
25939 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
25940 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25941 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
25942 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
25943 position of the SplitBar).
25945 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
25948 this.el = Roo.get(dragElement, true);
25949 this.el.dom.unselectable = "on";
25951 this.resizingEl = Roo.get(resizingElement, true);
25955 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
25956 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
25959 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
25962 * The minimum size of the resizing element. (Defaults to 0)
25968 * The maximum size of the resizing element. (Defaults to 2000)
25971 this.maxSize = 2000;
25974 * Whether to animate the transition to the new size
25977 this.animate = false;
25980 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
25983 this.useShim = false;
25988 if(!existingProxy){
25990 this.proxy = Roo.SplitBar.createProxy(this.orientation);
25992 this.proxy = Roo.get(existingProxy).dom;
25995 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
25998 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26001 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26004 this.dragSpecs = {};
26007 * @private The adapter to use to positon and resize elements
26009 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26010 this.adapter.init(this);
26012 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26014 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26015 this.el.addClass("x-splitbar-h");
26018 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26019 this.el.addClass("x-splitbar-v");
26025 * Fires when the splitter is moved (alias for {@link #event-moved})
26026 * @param {Roo.SplitBar} this
26027 * @param {Number} newSize the new width or height
26032 * Fires when the splitter is moved
26033 * @param {Roo.SplitBar} this
26034 * @param {Number} newSize the new width or height
26038 * @event beforeresize
26039 * Fires before the splitter is dragged
26040 * @param {Roo.SplitBar} this
26042 "beforeresize" : true,
26044 "beforeapply" : true
26047 Roo.util.Observable.call(this);
26050 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26051 onStartProxyDrag : function(x, y){
26052 this.fireEvent("beforeresize", this);
26054 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26056 o.enableDisplayMode("block");
26057 // all splitbars share the same overlay
26058 Roo.SplitBar.prototype.overlay = o;
26060 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26061 this.overlay.show();
26062 Roo.get(this.proxy).setDisplayed("block");
26063 var size = this.adapter.getElementSize(this);
26064 this.activeMinSize = this.getMinimumSize();;
26065 this.activeMaxSize = this.getMaximumSize();;
26066 var c1 = size - this.activeMinSize;
26067 var c2 = Math.max(this.activeMaxSize - size, 0);
26068 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26069 this.dd.resetConstraints();
26070 this.dd.setXConstraint(
26071 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26072 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26074 this.dd.setYConstraint(0, 0);
26076 this.dd.resetConstraints();
26077 this.dd.setXConstraint(0, 0);
26078 this.dd.setYConstraint(
26079 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26080 this.placement == Roo.SplitBar.TOP ? c2 : c1
26083 this.dragSpecs.startSize = size;
26084 this.dragSpecs.startPoint = [x, y];
26085 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26089 * @private Called after the drag operation by the DDProxy
26091 onEndProxyDrag : function(e){
26092 Roo.get(this.proxy).setDisplayed(false);
26093 var endPoint = Roo.lib.Event.getXY(e);
26095 this.overlay.hide();
26098 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26099 newSize = this.dragSpecs.startSize +
26100 (this.placement == Roo.SplitBar.LEFT ?
26101 endPoint[0] - this.dragSpecs.startPoint[0] :
26102 this.dragSpecs.startPoint[0] - endPoint[0]
26105 newSize = this.dragSpecs.startSize +
26106 (this.placement == Roo.SplitBar.TOP ?
26107 endPoint[1] - this.dragSpecs.startPoint[1] :
26108 this.dragSpecs.startPoint[1] - endPoint[1]
26111 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26112 if(newSize != this.dragSpecs.startSize){
26113 if(this.fireEvent('beforeapply', this, newSize) !== false){
26114 this.adapter.setElementSize(this, newSize);
26115 this.fireEvent("moved", this, newSize);
26116 this.fireEvent("resize", this, newSize);
26122 * Get the adapter this SplitBar uses
26123 * @return The adapter object
26125 getAdapter : function(){
26126 return this.adapter;
26130 * Set the adapter this SplitBar uses
26131 * @param {Object} adapter A SplitBar adapter object
26133 setAdapter : function(adapter){
26134 this.adapter = adapter;
26135 this.adapter.init(this);
26139 * Gets the minimum size for the resizing element
26140 * @return {Number} The minimum size
26142 getMinimumSize : function(){
26143 return this.minSize;
26147 * Sets the minimum size for the resizing element
26148 * @param {Number} minSize The minimum size
26150 setMinimumSize : function(minSize){
26151 this.minSize = minSize;
26155 * Gets the maximum size for the resizing element
26156 * @return {Number} The maximum size
26158 getMaximumSize : function(){
26159 return this.maxSize;
26163 * Sets the maximum size for the resizing element
26164 * @param {Number} maxSize The maximum size
26166 setMaximumSize : function(maxSize){
26167 this.maxSize = maxSize;
26171 * Sets the initialize size for the resizing element
26172 * @param {Number} size The initial size
26174 setCurrentSize : function(size){
26175 var oldAnimate = this.animate;
26176 this.animate = false;
26177 this.adapter.setElementSize(this, size);
26178 this.animate = oldAnimate;
26182 * Destroy this splitbar.
26183 * @param {Boolean} removeEl True to remove the element
26185 destroy : function(removeEl){
26187 this.shim.remove();
26190 this.proxy.parentNode.removeChild(this.proxy);
26198 * @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.
26200 Roo.SplitBar.createProxy = function(dir){
26201 var proxy = new Roo.Element(document.createElement("div"));
26202 proxy.unselectable();
26203 var cls = 'x-splitbar-proxy';
26204 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26205 document.body.appendChild(proxy.dom);
26210 * @class Roo.SplitBar.BasicLayoutAdapter
26211 * Default Adapter. It assumes the splitter and resizing element are not positioned
26212 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26214 Roo.SplitBar.BasicLayoutAdapter = function(){
26217 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26218 // do nothing for now
26219 init : function(s){
26223 * Called before drag operations to get the current size of the resizing element.
26224 * @param {Roo.SplitBar} s The SplitBar using this adapter
26226 getElementSize : function(s){
26227 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26228 return s.resizingEl.getWidth();
26230 return s.resizingEl.getHeight();
26235 * Called after drag operations to set the size of the resizing element.
26236 * @param {Roo.SplitBar} s The SplitBar using this adapter
26237 * @param {Number} newSize The new size to set
26238 * @param {Function} onComplete A function to be invoked when resizing is complete
26240 setElementSize : function(s, newSize, onComplete){
26241 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26243 s.resizingEl.setWidth(newSize);
26245 onComplete(s, newSize);
26248 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26253 s.resizingEl.setHeight(newSize);
26255 onComplete(s, newSize);
26258 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26265 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26266 * @extends Roo.SplitBar.BasicLayoutAdapter
26267 * Adapter that moves the splitter element to align with the resized sizing element.
26268 * Used with an absolute positioned SplitBar.
26269 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26270 * document.body, make sure you assign an id to the body element.
26272 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26273 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26274 this.container = Roo.get(container);
26277 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26278 init : function(s){
26279 this.basic.init(s);
26282 getElementSize : function(s){
26283 return this.basic.getElementSize(s);
26286 setElementSize : function(s, newSize, onComplete){
26287 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26290 moveSplitter : function(s){
26291 var yes = Roo.SplitBar;
26292 switch(s.placement){
26294 s.el.setX(s.resizingEl.getRight());
26297 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26300 s.el.setY(s.resizingEl.getBottom());
26303 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26310 * Orientation constant - Create a vertical SplitBar
26314 Roo.SplitBar.VERTICAL = 1;
26317 * Orientation constant - Create a horizontal SplitBar
26321 Roo.SplitBar.HORIZONTAL = 2;
26324 * Placement constant - The resizing element is to the left of the splitter element
26328 Roo.SplitBar.LEFT = 1;
26331 * Placement constant - The resizing element is to the right of the splitter element
26335 Roo.SplitBar.RIGHT = 2;
26338 * Placement constant - The resizing element is positioned above the splitter element
26342 Roo.SplitBar.TOP = 3;
26345 * Placement constant - The resizing element is positioned under splitter element
26349 Roo.SplitBar.BOTTOM = 4;
26352 * Ext JS Library 1.1.1
26353 * Copyright(c) 2006-2007, Ext JS, LLC.
26355 * Originally Released Under LGPL - original licence link has changed is not relivant.
26358 * <script type="text/javascript">
26363 * @extends Roo.util.Observable
26364 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26365 * This class also supports single and multi selection modes. <br>
26366 * Create a data model bound view:
26368 var store = new Roo.data.Store(...);
26370 var view = new Roo.View({
26372 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26374 singleSelect: true,
26375 selectedClass: "ydataview-selected",
26379 // listen for node click?
26380 view.on("click", function(vw, index, node, e){
26381 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26385 dataModel.load("foobar.xml");
26387 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26389 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26390 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26392 * Note: old style constructor is still suported (container, template, config)
26395 * Create a new View
26396 * @param {Object} config The config object
26399 Roo.View = function(config, depreciated_tpl, depreciated_config){
26401 this.parent = false;
26403 if (typeof(depreciated_tpl) == 'undefined') {
26404 // new way.. - universal constructor.
26405 Roo.apply(this, config);
26406 this.el = Roo.get(this.el);
26409 this.el = Roo.get(config);
26410 this.tpl = depreciated_tpl;
26411 Roo.apply(this, depreciated_config);
26413 this.wrapEl = this.el.wrap().wrap();
26414 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26417 if(typeof(this.tpl) == "string"){
26418 this.tpl = new Roo.Template(this.tpl);
26420 // support xtype ctors..
26421 this.tpl = new Roo.factory(this.tpl, Roo);
26425 this.tpl.compile();
26430 * @event beforeclick
26431 * Fires before a click is processed. Returns false to cancel the default action.
26432 * @param {Roo.View} this
26433 * @param {Number} index The index of the target node
26434 * @param {HTMLElement} node The target node
26435 * @param {Roo.EventObject} e The raw event object
26437 "beforeclick" : true,
26440 * Fires when a template node is clicked.
26441 * @param {Roo.View} this
26442 * @param {Number} index The index of the target node
26443 * @param {HTMLElement} node The target node
26444 * @param {Roo.EventObject} e The raw event object
26449 * Fires when a template node is double clicked.
26450 * @param {Roo.View} this
26451 * @param {Number} index The index of the target node
26452 * @param {HTMLElement} node The target node
26453 * @param {Roo.EventObject} e The raw event object
26457 * @event contextmenu
26458 * Fires when a template node is right clicked.
26459 * @param {Roo.View} this
26460 * @param {Number} index The index of the target node
26461 * @param {HTMLElement} node The target node
26462 * @param {Roo.EventObject} e The raw event object
26464 "contextmenu" : true,
26466 * @event selectionchange
26467 * Fires when the selected nodes change.
26468 * @param {Roo.View} this
26469 * @param {Array} selections Array of the selected nodes
26471 "selectionchange" : true,
26474 * @event beforeselect
26475 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26476 * @param {Roo.View} this
26477 * @param {HTMLElement} node The node to be selected
26478 * @param {Array} selections Array of currently selected nodes
26480 "beforeselect" : true,
26482 * @event preparedata
26483 * Fires on every row to render, to allow you to change the data.
26484 * @param {Roo.View} this
26485 * @param {Object} data to be rendered (change this)
26487 "preparedata" : true
26495 "click": this.onClick,
26496 "dblclick": this.onDblClick,
26497 "contextmenu": this.onContextMenu,
26501 this.selections = [];
26503 this.cmp = new Roo.CompositeElementLite([]);
26505 this.store = Roo.factory(this.store, Roo.data);
26506 this.setStore(this.store, true);
26509 if ( this.footer && this.footer.xtype) {
26511 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26513 this.footer.dataSource = this.store;
26514 this.footer.container = fctr;
26515 this.footer = Roo.factory(this.footer, Roo);
26516 fctr.insertFirst(this.el);
26518 // this is a bit insane - as the paging toolbar seems to detach the el..
26519 // dom.parentNode.parentNode.parentNode
26520 // they get detached?
26524 Roo.View.superclass.constructor.call(this);
26529 Roo.extend(Roo.View, Roo.util.Observable, {
26532 * @cfg {Roo.data.Store} store Data store to load data from.
26537 * @cfg {String|Roo.Element} el The container element.
26542 * @cfg {String|Roo.Template} tpl The template used by this View
26546 * @cfg {String} dataName the named area of the template to use as the data area
26547 * Works with domtemplates roo-name="name"
26551 * @cfg {String} selectedClass The css class to add to selected nodes
26553 selectedClass : "x-view-selected",
26555 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26560 * @cfg {String} text to display on mask (default Loading)
26564 * @cfg {Boolean} multiSelect Allow multiple selection
26566 multiSelect : false,
26568 * @cfg {Boolean} singleSelect Allow single selection
26570 singleSelect: false,
26573 * @cfg {Boolean} toggleSelect - selecting
26575 toggleSelect : false,
26578 * @cfg {Boolean} tickable - selecting
26583 * Returns the element this view is bound to.
26584 * @return {Roo.Element}
26586 getEl : function(){
26587 return this.wrapEl;
26593 * Refreshes the view. - called by datachanged on the store. - do not call directly.
26595 refresh : function(){
26596 //Roo.log('refresh');
26599 // if we are using something like 'domtemplate', then
26600 // the what gets used is:
26601 // t.applySubtemplate(NAME, data, wrapping data..)
26602 // the outer template then get' applied with
26603 // the store 'extra data'
26604 // and the body get's added to the
26605 // roo-name="data" node?
26606 // <span class='roo-tpl-{name}'></span> ?????
26610 this.clearSelections();
26611 this.el.update("");
26613 var records = this.store.getRange();
26614 if(records.length < 1) {
26616 // is this valid?? = should it render a template??
26618 this.el.update(this.emptyText);
26622 if (this.dataName) {
26623 this.el.update(t.apply(this.store.meta)); //????
26624 el = this.el.child('.roo-tpl-' + this.dataName);
26627 for(var i = 0, len = records.length; i < len; i++){
26628 var data = this.prepareData(records[i].data, i, records[i]);
26629 this.fireEvent("preparedata", this, data, i, records[i]);
26631 var d = Roo.apply({}, data);
26634 Roo.apply(d, {'roo-id' : Roo.id()});
26638 Roo.each(this.parent.item, function(item){
26639 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
26642 Roo.apply(d, {'roo-data-checked' : 'checked'});
26646 html[html.length] = Roo.util.Format.trim(
26648 t.applySubtemplate(this.dataName, d, this.store.meta) :
26655 el.update(html.join(""));
26656 this.nodes = el.dom.childNodes;
26657 this.updateIndexes(0);
26662 * Function to override to reformat the data that is sent to
26663 * the template for each node.
26664 * DEPRICATED - use the preparedata event handler.
26665 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
26666 * a JSON object for an UpdateManager bound view).
26668 prepareData : function(data, index, record)
26670 this.fireEvent("preparedata", this, data, index, record);
26674 onUpdate : function(ds, record){
26675 // Roo.log('on update');
26676 this.clearSelections();
26677 var index = this.store.indexOf(record);
26678 var n = this.nodes[index];
26679 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
26680 n.parentNode.removeChild(n);
26681 this.updateIndexes(index, index);
26687 onAdd : function(ds, records, index)
26689 //Roo.log(['on Add', ds, records, index] );
26690 this.clearSelections();
26691 if(this.nodes.length == 0){
26695 var n = this.nodes[index];
26696 for(var i = 0, len = records.length; i < len; i++){
26697 var d = this.prepareData(records[i].data, i, records[i]);
26699 this.tpl.insertBefore(n, d);
26702 this.tpl.append(this.el, d);
26705 this.updateIndexes(index);
26708 onRemove : function(ds, record, index){
26709 // Roo.log('onRemove');
26710 this.clearSelections();
26711 var el = this.dataName ?
26712 this.el.child('.roo-tpl-' + this.dataName) :
26715 el.dom.removeChild(this.nodes[index]);
26716 this.updateIndexes(index);
26720 * Refresh an individual node.
26721 * @param {Number} index
26723 refreshNode : function(index){
26724 this.onUpdate(this.store, this.store.getAt(index));
26727 updateIndexes : function(startIndex, endIndex){
26728 var ns = this.nodes;
26729 startIndex = startIndex || 0;
26730 endIndex = endIndex || ns.length - 1;
26731 for(var i = startIndex; i <= endIndex; i++){
26732 ns[i].nodeIndex = i;
26737 * Changes the data store this view uses and refresh the view.
26738 * @param {Store} store
26740 setStore : function(store, initial){
26741 if(!initial && this.store){
26742 this.store.un("datachanged", this.refresh);
26743 this.store.un("add", this.onAdd);
26744 this.store.un("remove", this.onRemove);
26745 this.store.un("update", this.onUpdate);
26746 this.store.un("clear", this.refresh);
26747 this.store.un("beforeload", this.onBeforeLoad);
26748 this.store.un("load", this.onLoad);
26749 this.store.un("loadexception", this.onLoad);
26753 store.on("datachanged", this.refresh, this);
26754 store.on("add", this.onAdd, this);
26755 store.on("remove", this.onRemove, this);
26756 store.on("update", this.onUpdate, this);
26757 store.on("clear", this.refresh, this);
26758 store.on("beforeload", this.onBeforeLoad, this);
26759 store.on("load", this.onLoad, this);
26760 store.on("loadexception", this.onLoad, this);
26768 * onbeforeLoad - masks the loading area.
26771 onBeforeLoad : function(store,opts)
26773 //Roo.log('onBeforeLoad');
26775 this.el.update("");
26777 this.el.mask(this.mask ? this.mask : "Loading" );
26779 onLoad : function ()
26786 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
26787 * @param {HTMLElement} node
26788 * @return {HTMLElement} The template node
26790 findItemFromChild : function(node){
26791 var el = this.dataName ?
26792 this.el.child('.roo-tpl-' + this.dataName,true) :
26795 if(!node || node.parentNode == el){
26798 var p = node.parentNode;
26799 while(p && p != el){
26800 if(p.parentNode == el){
26809 onClick : function(e){
26810 var item = this.findItemFromChild(e.getTarget());
26812 var index = this.indexOf(item);
26813 if(this.onItemClick(item, index, e) !== false){
26814 this.fireEvent("click", this, index, item, e);
26817 this.clearSelections();
26822 onContextMenu : function(e){
26823 var item = this.findItemFromChild(e.getTarget());
26825 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
26830 onDblClick : function(e){
26831 var item = this.findItemFromChild(e.getTarget());
26833 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
26837 onItemClick : function(item, index, e)
26839 if(this.fireEvent("beforeclick", this, index, item, e) === false){
26842 if (this.toggleSelect) {
26843 var m = this.isSelected(item) ? 'unselect' : 'select';
26846 _t[m](item, true, false);
26849 if(this.multiSelect || this.singleSelect){
26850 if(this.multiSelect && e.shiftKey && this.lastSelection){
26851 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
26853 this.select(item, this.multiSelect && e.ctrlKey);
26854 this.lastSelection = item;
26857 if(!this.tickable){
26858 e.preventDefault();
26866 * Get the number of selected nodes.
26869 getSelectionCount : function(){
26870 return this.selections.length;
26874 * Get the currently selected nodes.
26875 * @return {Array} An array of HTMLElements
26877 getSelectedNodes : function(){
26878 return this.selections;
26882 * Get the indexes of the selected nodes.
26885 getSelectedIndexes : function(){
26886 var indexes = [], s = this.selections;
26887 for(var i = 0, len = s.length; i < len; i++){
26888 indexes.push(s[i].nodeIndex);
26894 * Clear all selections
26895 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
26897 clearSelections : function(suppressEvent){
26898 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
26899 this.cmp.elements = this.selections;
26900 this.cmp.removeClass(this.selectedClass);
26901 this.selections = [];
26902 if(!suppressEvent){
26903 this.fireEvent("selectionchange", this, this.selections);
26909 * Returns true if the passed node is selected
26910 * @param {HTMLElement/Number} node The node or node index
26911 * @return {Boolean}
26913 isSelected : function(node){
26914 var s = this.selections;
26918 node = this.getNode(node);
26919 return s.indexOf(node) !== -1;
26924 * @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
26925 * @param {Boolean} keepExisting (optional) true to keep existing selections
26926 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26928 select : function(nodeInfo, keepExisting, suppressEvent){
26929 if(nodeInfo instanceof Array){
26931 this.clearSelections(true);
26933 for(var i = 0, len = nodeInfo.length; i < len; i++){
26934 this.select(nodeInfo[i], true, true);
26938 var node = this.getNode(nodeInfo);
26939 if(!node || this.isSelected(node)){
26940 return; // already selected.
26943 this.clearSelections(true);
26946 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
26947 Roo.fly(node).addClass(this.selectedClass);
26948 this.selections.push(node);
26949 if(!suppressEvent){
26950 this.fireEvent("selectionchange", this, this.selections);
26958 * @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
26959 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
26960 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
26962 unselect : function(nodeInfo, keepExisting, suppressEvent)
26964 if(nodeInfo instanceof Array){
26965 Roo.each(this.selections, function(s) {
26966 this.unselect(s, nodeInfo);
26970 var node = this.getNode(nodeInfo);
26971 if(!node || !this.isSelected(node)){
26972 //Roo.log("not selected");
26973 return; // not selected.
26977 Roo.each(this.selections, function(s) {
26979 Roo.fly(node).removeClass(this.selectedClass);
26986 this.selections= ns;
26987 this.fireEvent("selectionchange", this, this.selections);
26991 * Gets a template node.
26992 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
26993 * @return {HTMLElement} The node or null if it wasn't found
26995 getNode : function(nodeInfo){
26996 if(typeof nodeInfo == "string"){
26997 return document.getElementById(nodeInfo);
26998 }else if(typeof nodeInfo == "number"){
26999 return this.nodes[nodeInfo];
27005 * Gets a range template nodes.
27006 * @param {Number} startIndex
27007 * @param {Number} endIndex
27008 * @return {Array} An array of nodes
27010 getNodes : function(start, end){
27011 var ns = this.nodes;
27012 start = start || 0;
27013 end = typeof end == "undefined" ? ns.length - 1 : end;
27016 for(var i = start; i <= end; i++){
27020 for(var i = start; i >= end; i--){
27028 * Finds the index of the passed node
27029 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27030 * @return {Number} The index of the node or -1
27032 indexOf : function(node){
27033 node = this.getNode(node);
27034 if(typeof node.nodeIndex == "number"){
27035 return node.nodeIndex;
27037 var ns = this.nodes;
27038 for(var i = 0, len = ns.length; i < len; i++){
27048 * Ext JS Library 1.1.1
27049 * Copyright(c) 2006-2007, Ext JS, LLC.
27051 * Originally Released Under LGPL - original licence link has changed is not relivant.
27054 * <script type="text/javascript">
27058 * @class Roo.JsonView
27059 * @extends Roo.View
27060 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27062 var view = new Roo.JsonView({
27063 container: "my-element",
27064 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27069 // listen for node click?
27070 view.on("click", function(vw, index, node, e){
27071 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27074 // direct load of JSON data
27075 view.load("foobar.php");
27077 // Example from my blog list
27078 var tpl = new Roo.Template(
27079 '<div class="entry">' +
27080 '<a class="entry-title" href="{link}">{title}</a>' +
27081 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27082 "</div><hr />"
27085 var moreView = new Roo.JsonView({
27086 container : "entry-list",
27090 moreView.on("beforerender", this.sortEntries, this);
27092 url: "/blog/get-posts.php",
27093 params: "allposts=true",
27094 text: "Loading Blog Entries..."
27098 * Note: old code is supported with arguments : (container, template, config)
27102 * Create a new JsonView
27104 * @param {Object} config The config object
27107 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27110 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27112 var um = this.el.getUpdateManager();
27113 um.setRenderer(this);
27114 um.on("update", this.onLoad, this);
27115 um.on("failure", this.onLoadException, this);
27118 * @event beforerender
27119 * Fires before rendering of the downloaded JSON data.
27120 * @param {Roo.JsonView} this
27121 * @param {Object} data The JSON data loaded
27125 * Fires when data is loaded.
27126 * @param {Roo.JsonView} this
27127 * @param {Object} data The JSON data loaded
27128 * @param {Object} response The raw Connect response object
27131 * @event loadexception
27132 * Fires when loading fails.
27133 * @param {Roo.JsonView} this
27134 * @param {Object} response The raw Connect response object
27137 'beforerender' : true,
27139 'loadexception' : true
27142 Roo.extend(Roo.JsonView, Roo.View, {
27144 * @type {String} The root property in the loaded JSON object that contains the data
27149 * Refreshes the view.
27151 refresh : function(){
27152 this.clearSelections();
27153 this.el.update("");
27155 var o = this.jsonData;
27156 if(o && o.length > 0){
27157 for(var i = 0, len = o.length; i < len; i++){
27158 var data = this.prepareData(o[i], i, o);
27159 html[html.length] = this.tpl.apply(data);
27162 html.push(this.emptyText);
27164 this.el.update(html.join(""));
27165 this.nodes = this.el.dom.childNodes;
27166 this.updateIndexes(0);
27170 * 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.
27171 * @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:
27174 url: "your-url.php",
27175 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27176 callback: yourFunction,
27177 scope: yourObject, //(optional scope)
27180 text: "Loading...",
27185 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27186 * 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.
27187 * @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}
27188 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27189 * @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.
27192 var um = this.el.getUpdateManager();
27193 um.update.apply(um, arguments);
27196 // note - render is a standard framework call...
27197 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27198 render : function(el, response){
27200 this.clearSelections();
27201 this.el.update("");
27204 if (response != '') {
27205 o = Roo.util.JSON.decode(response.responseText);
27208 o = o[this.jsonRoot];
27214 * The current JSON data or null
27217 this.beforeRender();
27222 * Get the number of records in the current JSON dataset
27225 getCount : function(){
27226 return this.jsonData ? this.jsonData.length : 0;
27230 * Returns the JSON object for the specified node(s)
27231 * @param {HTMLElement/Array} node The node or an array of nodes
27232 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27233 * you get the JSON object for the node
27235 getNodeData : function(node){
27236 if(node instanceof Array){
27238 for(var i = 0, len = node.length; i < len; i++){
27239 data.push(this.getNodeData(node[i]));
27243 return this.jsonData[this.indexOf(node)] || null;
27246 beforeRender : function(){
27247 this.snapshot = this.jsonData;
27249 this.sort.apply(this, this.sortInfo);
27251 this.fireEvent("beforerender", this, this.jsonData);
27254 onLoad : function(el, o){
27255 this.fireEvent("load", this, this.jsonData, o);
27258 onLoadException : function(el, o){
27259 this.fireEvent("loadexception", this, o);
27263 * Filter the data by a specific property.
27264 * @param {String} property A property on your JSON objects
27265 * @param {String/RegExp} value Either string that the property values
27266 * should start with, or a RegExp to test against the property
27268 filter : function(property, value){
27271 var ss = this.snapshot;
27272 if(typeof value == "string"){
27273 var vlen = value.length;
27275 this.clearFilter();
27278 value = value.toLowerCase();
27279 for(var i = 0, len = ss.length; i < len; i++){
27281 if(o[property].substr(0, vlen).toLowerCase() == value){
27285 } else if(value.exec){ // regex?
27286 for(var i = 0, len = ss.length; i < len; i++){
27288 if(value.test(o[property])){
27295 this.jsonData = data;
27301 * Filter by a function. The passed function will be called with each
27302 * object in the current dataset. If the function returns true the value is kept,
27303 * otherwise it is filtered.
27304 * @param {Function} fn
27305 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27307 filterBy : function(fn, scope){
27310 var ss = this.snapshot;
27311 for(var i = 0, len = ss.length; i < len; i++){
27313 if(fn.call(scope || this, o)){
27317 this.jsonData = data;
27323 * Clears the current filter.
27325 clearFilter : function(){
27326 if(this.snapshot && this.jsonData != this.snapshot){
27327 this.jsonData = this.snapshot;
27334 * Sorts the data for this view and refreshes it.
27335 * @param {String} property A property on your JSON objects to sort on
27336 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27337 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27339 sort : function(property, dir, sortType){
27340 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27343 var dsc = dir && dir.toLowerCase() == "desc";
27344 var f = function(o1, o2){
27345 var v1 = sortType ? sortType(o1[p]) : o1[p];
27346 var v2 = sortType ? sortType(o2[p]) : o2[p];
27349 return dsc ? +1 : -1;
27350 } else if(v1 > v2){
27351 return dsc ? -1 : +1;
27356 this.jsonData.sort(f);
27358 if(this.jsonData != this.snapshot){
27359 this.snapshot.sort(f);
27365 * Ext JS Library 1.1.1
27366 * Copyright(c) 2006-2007, Ext JS, LLC.
27368 * Originally Released Under LGPL - original licence link has changed is not relivant.
27371 * <script type="text/javascript">
27376 * @class Roo.ColorPalette
27377 * @extends Roo.Component
27378 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27379 * Here's an example of typical usage:
27381 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27382 cp.render('my-div');
27384 cp.on('select', function(palette, selColor){
27385 // do something with selColor
27389 * Create a new ColorPalette
27390 * @param {Object} config The config object
27392 Roo.ColorPalette = function(config){
27393 Roo.ColorPalette.superclass.constructor.call(this, config);
27397 * Fires when a color is selected
27398 * @param {ColorPalette} this
27399 * @param {String} color The 6-digit color hex code (without the # symbol)
27405 this.on("select", this.handler, this.scope, true);
27408 Roo.extend(Roo.ColorPalette, Roo.Component, {
27410 * @cfg {String} itemCls
27411 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27413 itemCls : "x-color-palette",
27415 * @cfg {String} value
27416 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27417 * the hex codes are case-sensitive.
27420 clickEvent:'click',
27422 ctype: "Roo.ColorPalette",
27425 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27427 allowReselect : false,
27430 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27431 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27432 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27433 * of colors with the width setting until the box is symmetrical.</p>
27434 * <p>You can override individual colors if needed:</p>
27436 var cp = new Roo.ColorPalette();
27437 cp.colors[0] = "FF0000"; // change the first box to red
27440 Or you can provide a custom array of your own for complete control:
27442 var cp = new Roo.ColorPalette();
27443 cp.colors = ["000000", "993300", "333300"];
27448 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27449 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27450 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27451 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27452 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27456 onRender : function(container, position){
27457 var t = new Roo.MasterTemplate(
27458 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27460 var c = this.colors;
27461 for(var i = 0, len = c.length; i < len; i++){
27464 var el = document.createElement("div");
27465 el.className = this.itemCls;
27467 container.dom.insertBefore(el, position);
27468 this.el = Roo.get(el);
27469 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27470 if(this.clickEvent != 'click'){
27471 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27476 afterRender : function(){
27477 Roo.ColorPalette.superclass.afterRender.call(this);
27479 var s = this.value;
27486 handleClick : function(e, t){
27487 e.preventDefault();
27488 if(!this.disabled){
27489 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27490 this.select(c.toUpperCase());
27495 * Selects the specified color in the palette (fires the select event)
27496 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27498 select : function(color){
27499 color = color.replace("#", "");
27500 if(color != this.value || this.allowReselect){
27503 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27505 el.child("a.color-"+color).addClass("x-color-palette-sel");
27506 this.value = color;
27507 this.fireEvent("select", this, color);
27512 * Ext JS Library 1.1.1
27513 * Copyright(c) 2006-2007, Ext JS, LLC.
27515 * Originally Released Under LGPL - original licence link has changed is not relivant.
27518 * <script type="text/javascript">
27522 * @class Roo.DatePicker
27523 * @extends Roo.Component
27524 * Simple date picker class.
27526 * Create a new DatePicker
27527 * @param {Object} config The config object
27529 Roo.DatePicker = function(config){
27530 Roo.DatePicker.superclass.constructor.call(this, config);
27532 this.value = config && config.value ?
27533 config.value.clearTime() : new Date().clearTime();
27538 * Fires when a date is selected
27539 * @param {DatePicker} this
27540 * @param {Date} date The selected date
27544 * @event monthchange
27545 * Fires when the displayed month changes
27546 * @param {DatePicker} this
27547 * @param {Date} date The selected month
27549 'monthchange': true
27553 this.on("select", this.handler, this.scope || this);
27555 // build the disabledDatesRE
27556 if(!this.disabledDatesRE && this.disabledDates){
27557 var dd = this.disabledDates;
27559 for(var i = 0; i < dd.length; i++){
27561 if(i != dd.length-1) {
27565 this.disabledDatesRE = new RegExp(re + ")");
27569 Roo.extend(Roo.DatePicker, Roo.Component, {
27571 * @cfg {String} todayText
27572 * The text to display on the button that selects the current date (defaults to "Today")
27574 todayText : "Today",
27576 * @cfg {String} okText
27577 * The text to display on the ok button
27579 okText : " OK ", //   to give the user extra clicking room
27581 * @cfg {String} cancelText
27582 * The text to display on the cancel button
27584 cancelText : "Cancel",
27586 * @cfg {String} todayTip
27587 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
27589 todayTip : "{0} (Spacebar)",
27591 * @cfg {Date} minDate
27592 * Minimum allowable date (JavaScript date object, defaults to null)
27596 * @cfg {Date} maxDate
27597 * Maximum allowable date (JavaScript date object, defaults to null)
27601 * @cfg {String} minText
27602 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
27604 minText : "This date is before the minimum date",
27606 * @cfg {String} maxText
27607 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
27609 maxText : "This date is after the maximum date",
27611 * @cfg {String} format
27612 * The default date format string which can be overriden for localization support. The format must be
27613 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
27617 * @cfg {Array} disabledDays
27618 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
27620 disabledDays : null,
27622 * @cfg {String} disabledDaysText
27623 * The tooltip to display when the date falls on a disabled day (defaults to "")
27625 disabledDaysText : "",
27627 * @cfg {RegExp} disabledDatesRE
27628 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
27630 disabledDatesRE : null,
27632 * @cfg {String} disabledDatesText
27633 * The tooltip text to display when the date falls on a disabled date (defaults to "")
27635 disabledDatesText : "",
27637 * @cfg {Boolean} constrainToViewport
27638 * True to constrain the date picker to the viewport (defaults to true)
27640 constrainToViewport : true,
27642 * @cfg {Array} monthNames
27643 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
27645 monthNames : Date.monthNames,
27647 * @cfg {Array} dayNames
27648 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
27650 dayNames : Date.dayNames,
27652 * @cfg {String} nextText
27653 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
27655 nextText: 'Next Month (Control+Right)',
27657 * @cfg {String} prevText
27658 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
27660 prevText: 'Previous Month (Control+Left)',
27662 * @cfg {String} monthYearText
27663 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
27665 monthYearText: 'Choose a month (Control+Up/Down to move years)',
27667 * @cfg {Number} startDay
27668 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
27672 * @cfg {Bool} showClear
27673 * Show a clear button (usefull for date form elements that can be blank.)
27679 * Sets the value of the date field
27680 * @param {Date} value The date to set
27682 setValue : function(value){
27683 var old = this.value;
27685 if (typeof(value) == 'string') {
27687 value = Date.parseDate(value, this.format);
27690 value = new Date();
27693 this.value = value.clearTime(true);
27695 this.update(this.value);
27700 * Gets the current selected value of the date field
27701 * @return {Date} The selected date
27703 getValue : function(){
27708 focus : function(){
27710 this.update(this.activeDate);
27715 onRender : function(container, position){
27718 '<table cellspacing="0">',
27719 '<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>',
27720 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
27721 var dn = this.dayNames;
27722 for(var i = 0; i < 7; i++){
27723 var d = this.startDay+i;
27727 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
27729 m[m.length] = "</tr></thead><tbody><tr>";
27730 for(var i = 0; i < 42; i++) {
27731 if(i % 7 == 0 && i != 0){
27732 m[m.length] = "</tr><tr>";
27734 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
27736 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
27737 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
27739 var el = document.createElement("div");
27740 el.className = "x-date-picker";
27741 el.innerHTML = m.join("");
27743 container.dom.insertBefore(el, position);
27745 this.el = Roo.get(el);
27746 this.eventEl = Roo.get(el.firstChild);
27748 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
27749 handler: this.showPrevMonth,
27751 preventDefault:true,
27755 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
27756 handler: this.showNextMonth,
27758 preventDefault:true,
27762 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
27764 this.monthPicker = this.el.down('div.x-date-mp');
27765 this.monthPicker.enableDisplayMode('block');
27767 var kn = new Roo.KeyNav(this.eventEl, {
27768 "left" : function(e){
27770 this.showPrevMonth() :
27771 this.update(this.activeDate.add("d", -1));
27774 "right" : function(e){
27776 this.showNextMonth() :
27777 this.update(this.activeDate.add("d", 1));
27780 "up" : function(e){
27782 this.showNextYear() :
27783 this.update(this.activeDate.add("d", -7));
27786 "down" : function(e){
27788 this.showPrevYear() :
27789 this.update(this.activeDate.add("d", 7));
27792 "pageUp" : function(e){
27793 this.showNextMonth();
27796 "pageDown" : function(e){
27797 this.showPrevMonth();
27800 "enter" : function(e){
27801 e.stopPropagation();
27808 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
27810 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
27812 this.el.unselectable();
27814 this.cells = this.el.select("table.x-date-inner tbody td");
27815 this.textNodes = this.el.query("table.x-date-inner tbody span");
27817 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
27819 tooltip: this.monthYearText
27822 this.mbtn.on('click', this.showMonthPicker, this);
27823 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
27826 var today = (new Date()).dateFormat(this.format);
27828 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
27829 if (this.showClear) {
27830 baseTb.add( new Roo.Toolbar.Fill());
27833 text: String.format(this.todayText, today),
27834 tooltip: String.format(this.todayTip, today),
27835 handler: this.selectToday,
27839 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
27842 if (this.showClear) {
27844 baseTb.add( new Roo.Toolbar.Fill());
27847 cls: 'x-btn-icon x-btn-clear',
27848 handler: function() {
27850 this.fireEvent("select", this, '');
27860 this.update(this.value);
27863 createMonthPicker : function(){
27864 if(!this.monthPicker.dom.firstChild){
27865 var buf = ['<table border="0" cellspacing="0">'];
27866 for(var i = 0; i < 6; i++){
27868 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
27869 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
27871 '<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>' :
27872 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
27876 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
27878 '</button><button type="button" class="x-date-mp-cancel">',
27880 '</button></td></tr>',
27883 this.monthPicker.update(buf.join(''));
27884 this.monthPicker.on('click', this.onMonthClick, this);
27885 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
27887 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
27888 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
27890 this.mpMonths.each(function(m, a, i){
27893 m.dom.xmonth = 5 + Math.round(i * .5);
27895 m.dom.xmonth = Math.round((i-1) * .5);
27901 showMonthPicker : function(){
27902 this.createMonthPicker();
27903 var size = this.el.getSize();
27904 this.monthPicker.setSize(size);
27905 this.monthPicker.child('table').setSize(size);
27907 this.mpSelMonth = (this.activeDate || this.value).getMonth();
27908 this.updateMPMonth(this.mpSelMonth);
27909 this.mpSelYear = (this.activeDate || this.value).getFullYear();
27910 this.updateMPYear(this.mpSelYear);
27912 this.monthPicker.slideIn('t', {duration:.2});
27915 updateMPYear : function(y){
27917 var ys = this.mpYears.elements;
27918 for(var i = 1; i <= 10; i++){
27919 var td = ys[i-1], y2;
27921 y2 = y + Math.round(i * .5);
27922 td.firstChild.innerHTML = y2;
27925 y2 = y - (5-Math.round(i * .5));
27926 td.firstChild.innerHTML = y2;
27929 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
27933 updateMPMonth : function(sm){
27934 this.mpMonths.each(function(m, a, i){
27935 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
27939 selectMPMonth: function(m){
27943 onMonthClick : function(e, t){
27945 var el = new Roo.Element(t), pn;
27946 if(el.is('button.x-date-mp-cancel')){
27947 this.hideMonthPicker();
27949 else if(el.is('button.x-date-mp-ok')){
27950 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27951 this.hideMonthPicker();
27953 else if(pn = el.up('td.x-date-mp-month', 2)){
27954 this.mpMonths.removeClass('x-date-mp-sel');
27955 pn.addClass('x-date-mp-sel');
27956 this.mpSelMonth = pn.dom.xmonth;
27958 else if(pn = el.up('td.x-date-mp-year', 2)){
27959 this.mpYears.removeClass('x-date-mp-sel');
27960 pn.addClass('x-date-mp-sel');
27961 this.mpSelYear = pn.dom.xyear;
27963 else if(el.is('a.x-date-mp-prev')){
27964 this.updateMPYear(this.mpyear-10);
27966 else if(el.is('a.x-date-mp-next')){
27967 this.updateMPYear(this.mpyear+10);
27971 onMonthDblClick : function(e, t){
27973 var el = new Roo.Element(t), pn;
27974 if(pn = el.up('td.x-date-mp-month', 2)){
27975 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
27976 this.hideMonthPicker();
27978 else if(pn = el.up('td.x-date-mp-year', 2)){
27979 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
27980 this.hideMonthPicker();
27984 hideMonthPicker : function(disableAnim){
27985 if(this.monthPicker){
27986 if(disableAnim === true){
27987 this.monthPicker.hide();
27989 this.monthPicker.slideOut('t', {duration:.2});
27995 showPrevMonth : function(e){
27996 this.update(this.activeDate.add("mo", -1));
28000 showNextMonth : function(e){
28001 this.update(this.activeDate.add("mo", 1));
28005 showPrevYear : function(){
28006 this.update(this.activeDate.add("y", -1));
28010 showNextYear : function(){
28011 this.update(this.activeDate.add("y", 1));
28015 handleMouseWheel : function(e){
28016 var delta = e.getWheelDelta();
28018 this.showPrevMonth();
28020 } else if(delta < 0){
28021 this.showNextMonth();
28027 handleDateClick : function(e, t){
28029 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28030 this.setValue(new Date(t.dateValue));
28031 this.fireEvent("select", this, this.value);
28036 selectToday : function(){
28037 this.setValue(new Date().clearTime());
28038 this.fireEvent("select", this, this.value);
28042 update : function(date)
28044 var vd = this.activeDate;
28045 this.activeDate = date;
28047 var t = date.getTime();
28048 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28049 this.cells.removeClass("x-date-selected");
28050 this.cells.each(function(c){
28051 if(c.dom.firstChild.dateValue == t){
28052 c.addClass("x-date-selected");
28053 setTimeout(function(){
28054 try{c.dom.firstChild.focus();}catch(e){}
28063 var days = date.getDaysInMonth();
28064 var firstOfMonth = date.getFirstDateOfMonth();
28065 var startingPos = firstOfMonth.getDay()-this.startDay;
28067 if(startingPos <= this.startDay){
28071 var pm = date.add("mo", -1);
28072 var prevStart = pm.getDaysInMonth()-startingPos;
28074 var cells = this.cells.elements;
28075 var textEls = this.textNodes;
28076 days += startingPos;
28078 // convert everything to numbers so it's fast
28079 var day = 86400000;
28080 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28081 var today = new Date().clearTime().getTime();
28082 var sel = date.clearTime().getTime();
28083 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28084 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28085 var ddMatch = this.disabledDatesRE;
28086 var ddText = this.disabledDatesText;
28087 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28088 var ddaysText = this.disabledDaysText;
28089 var format = this.format;
28091 var setCellClass = function(cal, cell){
28093 var t = d.getTime();
28094 cell.firstChild.dateValue = t;
28096 cell.className += " x-date-today";
28097 cell.title = cal.todayText;
28100 cell.className += " x-date-selected";
28101 setTimeout(function(){
28102 try{cell.firstChild.focus();}catch(e){}
28107 cell.className = " x-date-disabled";
28108 cell.title = cal.minText;
28112 cell.className = " x-date-disabled";
28113 cell.title = cal.maxText;
28117 if(ddays.indexOf(d.getDay()) != -1){
28118 cell.title = ddaysText;
28119 cell.className = " x-date-disabled";
28122 if(ddMatch && format){
28123 var fvalue = d.dateFormat(format);
28124 if(ddMatch.test(fvalue)){
28125 cell.title = ddText.replace("%0", fvalue);
28126 cell.className = " x-date-disabled";
28132 for(; i < startingPos; i++) {
28133 textEls[i].innerHTML = (++prevStart);
28134 d.setDate(d.getDate()+1);
28135 cells[i].className = "x-date-prevday";
28136 setCellClass(this, cells[i]);
28138 for(; i < days; i++){
28139 intDay = i - startingPos + 1;
28140 textEls[i].innerHTML = (intDay);
28141 d.setDate(d.getDate()+1);
28142 cells[i].className = "x-date-active";
28143 setCellClass(this, cells[i]);
28146 for(; i < 42; i++) {
28147 textEls[i].innerHTML = (++extraDays);
28148 d.setDate(d.getDate()+1);
28149 cells[i].className = "x-date-nextday";
28150 setCellClass(this, cells[i]);
28153 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28154 this.fireEvent('monthchange', this, date);
28156 if(!this.internalRender){
28157 var main = this.el.dom.firstChild;
28158 var w = main.offsetWidth;
28159 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28160 Roo.fly(main).setWidth(w);
28161 this.internalRender = true;
28162 // opera does not respect the auto grow header center column
28163 // then, after it gets a width opera refuses to recalculate
28164 // without a second pass
28165 if(Roo.isOpera && !this.secondPass){
28166 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28167 this.secondPass = true;
28168 this.update.defer(10, this, [date]);
28176 * Ext JS Library 1.1.1
28177 * Copyright(c) 2006-2007, Ext JS, LLC.
28179 * Originally Released Under LGPL - original licence link has changed is not relivant.
28182 * <script type="text/javascript">
28185 * @class Roo.TabPanel
28186 * @extends Roo.util.Observable
28187 * A lightweight tab container.
28191 // basic tabs 1, built from existing content
28192 var tabs = new Roo.TabPanel("tabs1");
28193 tabs.addTab("script", "View Script");
28194 tabs.addTab("markup", "View Markup");
28195 tabs.activate("script");
28197 // more advanced tabs, built from javascript
28198 var jtabs = new Roo.TabPanel("jtabs");
28199 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28201 // set up the UpdateManager
28202 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28203 var updater = tab2.getUpdateManager();
28204 updater.setDefaultUrl("ajax1.htm");
28205 tab2.on('activate', updater.refresh, updater, true);
28207 // Use setUrl for Ajax loading
28208 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28209 tab3.setUrl("ajax2.htm", null, true);
28212 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28215 jtabs.activate("jtabs-1");
28218 * Create a new TabPanel.
28219 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28220 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28222 Roo.TabPanel = function(container, config){
28224 * The container element for this TabPanel.
28225 * @type Roo.Element
28227 this.el = Roo.get(container, true);
28229 if(typeof config == "boolean"){
28230 this.tabPosition = config ? "bottom" : "top";
28232 Roo.apply(this, config);
28235 if(this.tabPosition == "bottom"){
28236 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28237 this.el.addClass("x-tabs-bottom");
28239 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28240 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28241 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28243 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28245 if(this.tabPosition != "bottom"){
28246 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28247 * @type Roo.Element
28249 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28250 this.el.addClass("x-tabs-top");
28254 this.bodyEl.setStyle("position", "relative");
28256 this.active = null;
28257 this.activateDelegate = this.activate.createDelegate(this);
28262 * Fires when the active tab changes
28263 * @param {Roo.TabPanel} this
28264 * @param {Roo.TabPanelItem} activePanel The new active tab
28268 * @event beforetabchange
28269 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28270 * @param {Roo.TabPanel} this
28271 * @param {Object} e Set cancel to true on this object to cancel the tab change
28272 * @param {Roo.TabPanelItem} tab The tab being changed to
28274 "beforetabchange" : true
28277 Roo.EventManager.onWindowResize(this.onResize, this);
28278 this.cpad = this.el.getPadding("lr");
28279 this.hiddenCount = 0;
28282 // toolbar on the tabbar support...
28283 if (this.toolbar) {
28284 var tcfg = this.toolbar;
28285 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28286 this.toolbar = new Roo.Toolbar(tcfg);
28287 if (Roo.isSafari) {
28288 var tbl = tcfg.container.child('table', true);
28289 tbl.setAttribute('width', '100%');
28296 Roo.TabPanel.superclass.constructor.call(this);
28299 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28301 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28303 tabPosition : "top",
28305 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28307 currentTabWidth : 0,
28309 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28313 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28317 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28319 preferredTabWidth : 175,
28321 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28323 resizeTabs : false,
28325 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28327 monitorResize : true,
28329 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28334 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28335 * @param {String} id The id of the div to use <b>or create</b>
28336 * @param {String} text The text for the tab
28337 * @param {String} content (optional) Content to put in the TabPanelItem body
28338 * @param {Boolean} closable (optional) True to create a close icon on the tab
28339 * @return {Roo.TabPanelItem} The created TabPanelItem
28341 addTab : function(id, text, content, closable){
28342 var item = new Roo.TabPanelItem(this, id, text, closable);
28343 this.addTabItem(item);
28345 item.setContent(content);
28351 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28352 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28353 * @return {Roo.TabPanelItem}
28355 getTab : function(id){
28356 return this.items[id];
28360 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28361 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28363 hideTab : function(id){
28364 var t = this.items[id];
28367 this.hiddenCount++;
28368 this.autoSizeTabs();
28373 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28374 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28376 unhideTab : function(id){
28377 var t = this.items[id];
28379 t.setHidden(false);
28380 this.hiddenCount--;
28381 this.autoSizeTabs();
28386 * Adds an existing {@link Roo.TabPanelItem}.
28387 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28389 addTabItem : function(item){
28390 this.items[item.id] = item;
28391 this.items.push(item);
28392 if(this.resizeTabs){
28393 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28394 this.autoSizeTabs();
28401 * Removes a {@link Roo.TabPanelItem}.
28402 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28404 removeTab : function(id){
28405 var items = this.items;
28406 var tab = items[id];
28407 if(!tab) { return; }
28408 var index = items.indexOf(tab);
28409 if(this.active == tab && items.length > 1){
28410 var newTab = this.getNextAvailable(index);
28415 this.stripEl.dom.removeChild(tab.pnode.dom);
28416 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28417 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28419 items.splice(index, 1);
28420 delete this.items[tab.id];
28421 tab.fireEvent("close", tab);
28422 tab.purgeListeners();
28423 this.autoSizeTabs();
28426 getNextAvailable : function(start){
28427 var items = this.items;
28429 // look for a next tab that will slide over to
28430 // replace the one being removed
28431 while(index < items.length){
28432 var item = items[++index];
28433 if(item && !item.isHidden()){
28437 // if one isn't found select the previous tab (on the left)
28440 var item = items[--index];
28441 if(item && !item.isHidden()){
28449 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28450 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28452 disableTab : function(id){
28453 var tab = this.items[id];
28454 if(tab && this.active != tab){
28460 * Enables a {@link Roo.TabPanelItem} that is disabled.
28461 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28463 enableTab : function(id){
28464 var tab = this.items[id];
28469 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28470 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28471 * @return {Roo.TabPanelItem} The TabPanelItem.
28473 activate : function(id){
28474 var tab = this.items[id];
28478 if(tab == this.active || tab.disabled){
28482 this.fireEvent("beforetabchange", this, e, tab);
28483 if(e.cancel !== true && !tab.disabled){
28485 this.active.hide();
28487 this.active = this.items[id];
28488 this.active.show();
28489 this.fireEvent("tabchange", this, this.active);
28495 * Gets the active {@link Roo.TabPanelItem}.
28496 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28498 getActiveTab : function(){
28499 return this.active;
28503 * Updates the tab body element to fit the height of the container element
28504 * for overflow scrolling
28505 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28507 syncHeight : function(targetHeight){
28508 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28509 var bm = this.bodyEl.getMargins();
28510 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28511 this.bodyEl.setHeight(newHeight);
28515 onResize : function(){
28516 if(this.monitorResize){
28517 this.autoSizeTabs();
28522 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28524 beginUpdate : function(){
28525 this.updating = true;
28529 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28531 endUpdate : function(){
28532 this.updating = false;
28533 this.autoSizeTabs();
28537 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28539 autoSizeTabs : function(){
28540 var count = this.items.length;
28541 var vcount = count - this.hiddenCount;
28542 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28545 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28546 var availWidth = Math.floor(w / vcount);
28547 var b = this.stripBody;
28548 if(b.getWidth() > w){
28549 var tabs = this.items;
28550 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28551 if(availWidth < this.minTabWidth){
28552 /*if(!this.sleft){ // incomplete scrolling code
28553 this.createScrollButtons();
28556 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28559 if(this.currentTabWidth < this.preferredTabWidth){
28560 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28566 * Returns the number of tabs in this TabPanel.
28569 getCount : function(){
28570 return this.items.length;
28574 * Resizes all the tabs to the passed width
28575 * @param {Number} The new width
28577 setTabWidth : function(width){
28578 this.currentTabWidth = width;
28579 for(var i = 0, len = this.items.length; i < len; i++) {
28580 if(!this.items[i].isHidden()) {
28581 this.items[i].setWidth(width);
28587 * Destroys this TabPanel
28588 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
28590 destroy : function(removeEl){
28591 Roo.EventManager.removeResizeListener(this.onResize, this);
28592 for(var i = 0, len = this.items.length; i < len; i++){
28593 this.items[i].purgeListeners();
28595 if(removeEl === true){
28596 this.el.update("");
28603 * @class Roo.TabPanelItem
28604 * @extends Roo.util.Observable
28605 * Represents an individual item (tab plus body) in a TabPanel.
28606 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
28607 * @param {String} id The id of this TabPanelItem
28608 * @param {String} text The text for the tab of this TabPanelItem
28609 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
28611 Roo.TabPanelItem = function(tabPanel, id, text, closable){
28613 * The {@link Roo.TabPanel} this TabPanelItem belongs to
28614 * @type Roo.TabPanel
28616 this.tabPanel = tabPanel;
28618 * The id for this TabPanelItem
28623 this.disabled = false;
28627 this.loaded = false;
28628 this.closable = closable;
28631 * The body element for this TabPanelItem.
28632 * @type Roo.Element
28634 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
28635 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
28636 this.bodyEl.setStyle("display", "block");
28637 this.bodyEl.setStyle("zoom", "1");
28640 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
28642 this.el = Roo.get(els.el, true);
28643 this.inner = Roo.get(els.inner, true);
28644 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
28645 this.pnode = Roo.get(els.el.parentNode, true);
28646 this.el.on("mousedown", this.onTabMouseDown, this);
28647 this.el.on("click", this.onTabClick, this);
28650 var c = Roo.get(els.close, true);
28651 c.dom.title = this.closeText;
28652 c.addClassOnOver("close-over");
28653 c.on("click", this.closeClick, this);
28659 * Fires when this tab becomes the active tab.
28660 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28661 * @param {Roo.TabPanelItem} this
28665 * @event beforeclose
28666 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
28667 * @param {Roo.TabPanelItem} this
28668 * @param {Object} e Set cancel to true on this object to cancel the close.
28670 "beforeclose": true,
28673 * Fires when this tab is closed.
28674 * @param {Roo.TabPanelItem} this
28678 * @event deactivate
28679 * Fires when this tab is no longer the active tab.
28680 * @param {Roo.TabPanel} tabPanel The parent TabPanel
28681 * @param {Roo.TabPanelItem} this
28683 "deactivate" : true
28685 this.hidden = false;
28687 Roo.TabPanelItem.superclass.constructor.call(this);
28690 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
28691 purgeListeners : function(){
28692 Roo.util.Observable.prototype.purgeListeners.call(this);
28693 this.el.removeAllListeners();
28696 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
28699 this.pnode.addClass("on");
28702 this.tabPanel.stripWrap.repaint();
28704 this.fireEvent("activate", this.tabPanel, this);
28708 * Returns true if this tab is the active tab.
28709 * @return {Boolean}
28711 isActive : function(){
28712 return this.tabPanel.getActiveTab() == this;
28716 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
28719 this.pnode.removeClass("on");
28721 this.fireEvent("deactivate", this.tabPanel, this);
28724 hideAction : function(){
28725 this.bodyEl.hide();
28726 this.bodyEl.setStyle("position", "absolute");
28727 this.bodyEl.setLeft("-20000px");
28728 this.bodyEl.setTop("-20000px");
28731 showAction : function(){
28732 this.bodyEl.setStyle("position", "relative");
28733 this.bodyEl.setTop("");
28734 this.bodyEl.setLeft("");
28735 this.bodyEl.show();
28739 * Set the tooltip for the tab.
28740 * @param {String} tooltip The tab's tooltip
28742 setTooltip : function(text){
28743 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
28744 this.textEl.dom.qtip = text;
28745 this.textEl.dom.removeAttribute('title');
28747 this.textEl.dom.title = text;
28751 onTabClick : function(e){
28752 e.preventDefault();
28753 this.tabPanel.activate(this.id);
28756 onTabMouseDown : function(e){
28757 e.preventDefault();
28758 this.tabPanel.activate(this.id);
28761 getWidth : function(){
28762 return this.inner.getWidth();
28765 setWidth : function(width){
28766 var iwidth = width - this.pnode.getPadding("lr");
28767 this.inner.setWidth(iwidth);
28768 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
28769 this.pnode.setWidth(width);
28773 * Show or hide the tab
28774 * @param {Boolean} hidden True to hide or false to show.
28776 setHidden : function(hidden){
28777 this.hidden = hidden;
28778 this.pnode.setStyle("display", hidden ? "none" : "");
28782 * Returns true if this tab is "hidden"
28783 * @return {Boolean}
28785 isHidden : function(){
28786 return this.hidden;
28790 * Returns the text for this tab
28793 getText : function(){
28797 autoSize : function(){
28798 //this.el.beginMeasure();
28799 this.textEl.setWidth(1);
28801 * #2804 [new] Tabs in Roojs
28802 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
28804 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
28805 //this.el.endMeasure();
28809 * Sets the text for the tab (Note: this also sets the tooltip text)
28810 * @param {String} text The tab's text and tooltip
28812 setText : function(text){
28814 this.textEl.update(text);
28815 this.setTooltip(text);
28816 if(!this.tabPanel.resizeTabs){
28821 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
28823 activate : function(){
28824 this.tabPanel.activate(this.id);
28828 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
28830 disable : function(){
28831 if(this.tabPanel.active != this){
28832 this.disabled = true;
28833 this.pnode.addClass("disabled");
28838 * Enables this TabPanelItem if it was previously disabled.
28840 enable : function(){
28841 this.disabled = false;
28842 this.pnode.removeClass("disabled");
28846 * Sets the content for this TabPanelItem.
28847 * @param {String} content The content
28848 * @param {Boolean} loadScripts true to look for and load scripts
28850 setContent : function(content, loadScripts){
28851 this.bodyEl.update(content, loadScripts);
28855 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
28856 * @return {Roo.UpdateManager} The UpdateManager
28858 getUpdateManager : function(){
28859 return this.bodyEl.getUpdateManager();
28863 * Set a URL to be used to load the content for this TabPanelItem.
28864 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
28865 * @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)
28866 * @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)
28867 * @return {Roo.UpdateManager} The UpdateManager
28869 setUrl : function(url, params, loadOnce){
28870 if(this.refreshDelegate){
28871 this.un('activate', this.refreshDelegate);
28873 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
28874 this.on("activate", this.refreshDelegate);
28875 return this.bodyEl.getUpdateManager();
28879 _handleRefresh : function(url, params, loadOnce){
28880 if(!loadOnce || !this.loaded){
28881 var updater = this.bodyEl.getUpdateManager();
28882 updater.update(url, params, this._setLoaded.createDelegate(this));
28887 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
28888 * Will fail silently if the setUrl method has not been called.
28889 * This does not activate the panel, just updates its content.
28891 refresh : function(){
28892 if(this.refreshDelegate){
28893 this.loaded = false;
28894 this.refreshDelegate();
28899 _setLoaded : function(){
28900 this.loaded = true;
28904 closeClick : function(e){
28907 this.fireEvent("beforeclose", this, o);
28908 if(o.cancel !== true){
28909 this.tabPanel.removeTab(this.id);
28913 * The text displayed in the tooltip for the close icon.
28916 closeText : "Close this tab"
28920 Roo.TabPanel.prototype.createStrip = function(container){
28921 var strip = document.createElement("div");
28922 strip.className = "x-tabs-wrap";
28923 container.appendChild(strip);
28927 Roo.TabPanel.prototype.createStripList = function(strip){
28928 // div wrapper for retard IE
28929 // returns the "tr" element.
28930 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
28931 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
28932 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
28933 return strip.firstChild.firstChild.firstChild.firstChild;
28936 Roo.TabPanel.prototype.createBody = function(container){
28937 var body = document.createElement("div");
28938 Roo.id(body, "tab-body");
28939 Roo.fly(body).addClass("x-tabs-body");
28940 container.appendChild(body);
28944 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
28945 var body = Roo.getDom(id);
28947 body = document.createElement("div");
28950 Roo.fly(body).addClass("x-tabs-item-body");
28951 bodyEl.insertBefore(body, bodyEl.firstChild);
28955 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
28956 var td = document.createElement("td");
28957 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
28958 //stripEl.appendChild(td);
28960 td.className = "x-tabs-closable";
28961 if(!this.closeTpl){
28962 this.closeTpl = new Roo.Template(
28963 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28964 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
28965 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
28968 var el = this.closeTpl.overwrite(td, {"text": text});
28969 var close = el.getElementsByTagName("div")[0];
28970 var inner = el.getElementsByTagName("em")[0];
28971 return {"el": el, "close": close, "inner": inner};
28974 this.tabTpl = new Roo.Template(
28975 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
28976 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
28979 var el = this.tabTpl.overwrite(td, {"text": text});
28980 var inner = el.getElementsByTagName("em")[0];
28981 return {"el": el, "inner": inner};
28985 * Ext JS Library 1.1.1
28986 * Copyright(c) 2006-2007, Ext JS, LLC.
28988 * Originally Released Under LGPL - original licence link has changed is not relivant.
28991 * <script type="text/javascript">
28995 * @class Roo.Button
28996 * @extends Roo.util.Observable
28997 * Simple Button class
28998 * @cfg {String} text The button text
28999 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29000 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29001 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29002 * @cfg {Object} scope The scope of the handler
29003 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29004 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29005 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29006 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29007 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29008 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29009 applies if enableToggle = true)
29010 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29011 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29012 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29014 * Create a new button
29015 * @param {Object} config The config object
29017 Roo.Button = function(renderTo, config)
29021 renderTo = config.renderTo || false;
29024 Roo.apply(this, config);
29028 * Fires when this button is clicked
29029 * @param {Button} this
29030 * @param {EventObject} e The click event
29035 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29036 * @param {Button} this
29037 * @param {Boolean} pressed
29042 * Fires when the mouse hovers over the button
29043 * @param {Button} this
29044 * @param {Event} e The event object
29046 'mouseover' : true,
29049 * Fires when the mouse exits the button
29050 * @param {Button} this
29051 * @param {Event} e The event object
29056 * Fires when the button is rendered
29057 * @param {Button} this
29062 this.menu = Roo.menu.MenuMgr.get(this.menu);
29064 // register listeners first!! - so render can be captured..
29065 Roo.util.Observable.call(this);
29067 this.render(renderTo);
29073 Roo.extend(Roo.Button, Roo.util.Observable, {
29079 * Read-only. True if this button is hidden
29084 * Read-only. True if this button is disabled
29089 * Read-only. True if this button is pressed (only if enableToggle = true)
29095 * @cfg {Number} tabIndex
29096 * The DOM tabIndex for this button (defaults to undefined)
29098 tabIndex : undefined,
29101 * @cfg {Boolean} enableToggle
29102 * True to enable pressed/not pressed toggling (defaults to false)
29104 enableToggle: false,
29106 * @cfg {Mixed} menu
29107 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29111 * @cfg {String} menuAlign
29112 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29114 menuAlign : "tl-bl?",
29117 * @cfg {String} iconCls
29118 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29120 iconCls : undefined,
29122 * @cfg {String} type
29123 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29128 menuClassTarget: 'tr',
29131 * @cfg {String} clickEvent
29132 * The type of event to map to the button's event handler (defaults to 'click')
29134 clickEvent : 'click',
29137 * @cfg {Boolean} handleMouseEvents
29138 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29140 handleMouseEvents : true,
29143 * @cfg {String} tooltipType
29144 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29146 tooltipType : 'qtip',
29149 * @cfg {String} cls
29150 * A CSS class to apply to the button's main element.
29154 * @cfg {Roo.Template} template (Optional)
29155 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29156 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29157 * require code modifications if required elements (e.g. a button) aren't present.
29161 render : function(renderTo){
29163 if(this.hideParent){
29164 this.parentEl = Roo.get(renderTo);
29166 if(!this.dhconfig){
29167 if(!this.template){
29168 if(!Roo.Button.buttonTemplate){
29169 // hideous table template
29170 Roo.Button.buttonTemplate = new Roo.Template(
29171 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29172 '<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>',
29173 "</tr></tbody></table>");
29175 this.template = Roo.Button.buttonTemplate;
29177 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29178 var btnEl = btn.child("button:first");
29179 btnEl.on('focus', this.onFocus, this);
29180 btnEl.on('blur', this.onBlur, this);
29182 btn.addClass(this.cls);
29185 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29188 btnEl.addClass(this.iconCls);
29190 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29193 if(this.tabIndex !== undefined){
29194 btnEl.dom.tabIndex = this.tabIndex;
29197 if(typeof this.tooltip == 'object'){
29198 Roo.QuickTips.tips(Roo.apply({
29202 btnEl.dom[this.tooltipType] = this.tooltip;
29206 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29210 this.el.dom.id = this.el.id = this.id;
29213 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29214 this.menu.on("show", this.onMenuShow, this);
29215 this.menu.on("hide", this.onMenuHide, this);
29217 btn.addClass("x-btn");
29218 if(Roo.isIE && !Roo.isIE7){
29219 this.autoWidth.defer(1, this);
29223 if(this.handleMouseEvents){
29224 btn.on("mouseover", this.onMouseOver, this);
29225 btn.on("mouseout", this.onMouseOut, this);
29226 btn.on("mousedown", this.onMouseDown, this);
29228 btn.on(this.clickEvent, this.onClick, this);
29229 //btn.on("mouseup", this.onMouseUp, this);
29236 Roo.ButtonToggleMgr.register(this);
29238 this.el.addClass("x-btn-pressed");
29241 var repeater = new Roo.util.ClickRepeater(btn,
29242 typeof this.repeat == "object" ? this.repeat : {}
29244 repeater.on("click", this.onClick, this);
29247 this.fireEvent('render', this);
29251 * Returns the button's underlying element
29252 * @return {Roo.Element} The element
29254 getEl : function(){
29259 * Destroys this Button and removes any listeners.
29261 destroy : function(){
29262 Roo.ButtonToggleMgr.unregister(this);
29263 this.el.removeAllListeners();
29264 this.purgeListeners();
29269 autoWidth : function(){
29271 this.el.setWidth("auto");
29272 if(Roo.isIE7 && Roo.isStrict){
29273 var ib = this.el.child('button');
29274 if(ib && ib.getWidth() > 20){
29276 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29281 this.el.beginMeasure();
29283 if(this.el.getWidth() < this.minWidth){
29284 this.el.setWidth(this.minWidth);
29287 this.el.endMeasure();
29294 * Assigns this button's click handler
29295 * @param {Function} handler The function to call when the button is clicked
29296 * @param {Object} scope (optional) Scope for the function passed in
29298 setHandler : function(handler, scope){
29299 this.handler = handler;
29300 this.scope = scope;
29304 * Sets this button's text
29305 * @param {String} text The button text
29307 setText : function(text){
29310 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29316 * Gets the text for this button
29317 * @return {String} The button text
29319 getText : function(){
29327 this.hidden = false;
29329 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29337 this.hidden = true;
29339 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29344 * Convenience function for boolean show/hide
29345 * @param {Boolean} visible True to show, false to hide
29347 setVisible: function(visible){
29356 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29357 * @param {Boolean} state (optional) Force a particular state
29359 toggle : function(state){
29360 state = state === undefined ? !this.pressed : state;
29361 if(state != this.pressed){
29363 this.el.addClass("x-btn-pressed");
29364 this.pressed = true;
29365 this.fireEvent("toggle", this, true);
29367 this.el.removeClass("x-btn-pressed");
29368 this.pressed = false;
29369 this.fireEvent("toggle", this, false);
29371 if(this.toggleHandler){
29372 this.toggleHandler.call(this.scope || this, this, state);
29380 focus : function(){
29381 this.el.child('button:first').focus();
29385 * Disable this button
29387 disable : function(){
29389 this.el.addClass("x-btn-disabled");
29391 this.disabled = true;
29395 * Enable this button
29397 enable : function(){
29399 this.el.removeClass("x-btn-disabled");
29401 this.disabled = false;
29405 * Convenience function for boolean enable/disable
29406 * @param {Boolean} enabled True to enable, false to disable
29408 setDisabled : function(v){
29409 this[v !== true ? "enable" : "disable"]();
29413 onClick : function(e)
29416 e.preventDefault();
29421 if(!this.disabled){
29422 if(this.enableToggle){
29425 if(this.menu && !this.menu.isVisible()){
29426 this.menu.show(this.el, this.menuAlign);
29428 this.fireEvent("click", this, e);
29430 this.el.removeClass("x-btn-over");
29431 this.handler.call(this.scope || this, this, e);
29436 onMouseOver : function(e){
29437 if(!this.disabled){
29438 this.el.addClass("x-btn-over");
29439 this.fireEvent('mouseover', this, e);
29443 onMouseOut : function(e){
29444 if(!e.within(this.el, true)){
29445 this.el.removeClass("x-btn-over");
29446 this.fireEvent('mouseout', this, e);
29450 onFocus : function(e){
29451 if(!this.disabled){
29452 this.el.addClass("x-btn-focus");
29456 onBlur : function(e){
29457 this.el.removeClass("x-btn-focus");
29460 onMouseDown : function(e){
29461 if(!this.disabled && e.button == 0){
29462 this.el.addClass("x-btn-click");
29463 Roo.get(document).on('mouseup', this.onMouseUp, this);
29467 onMouseUp : function(e){
29469 this.el.removeClass("x-btn-click");
29470 Roo.get(document).un('mouseup', this.onMouseUp, this);
29474 onMenuShow : function(e){
29475 this.el.addClass("x-btn-menu-active");
29478 onMenuHide : function(e){
29479 this.el.removeClass("x-btn-menu-active");
29483 // Private utility class used by Button
29484 Roo.ButtonToggleMgr = function(){
29487 function toggleGroup(btn, state){
29489 var g = groups[btn.toggleGroup];
29490 for(var i = 0, l = g.length; i < l; i++){
29492 g[i].toggle(false);
29499 register : function(btn){
29500 if(!btn.toggleGroup){
29503 var g = groups[btn.toggleGroup];
29505 g = groups[btn.toggleGroup] = [];
29508 btn.on("toggle", toggleGroup);
29511 unregister : function(btn){
29512 if(!btn.toggleGroup){
29515 var g = groups[btn.toggleGroup];
29518 btn.un("toggle", toggleGroup);
29524 * Ext JS Library 1.1.1
29525 * Copyright(c) 2006-2007, Ext JS, LLC.
29527 * Originally Released Under LGPL - original licence link has changed is not relivant.
29530 * <script type="text/javascript">
29534 * @class Roo.SplitButton
29535 * @extends Roo.Button
29536 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29537 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29538 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29539 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29540 * @cfg {String} arrowTooltip The title attribute of the arrow
29542 * Create a new menu button
29543 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29544 * @param {Object} config The config object
29546 Roo.SplitButton = function(renderTo, config){
29547 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29549 * @event arrowclick
29550 * Fires when this button's arrow is clicked
29551 * @param {SplitButton} this
29552 * @param {EventObject} e The click event
29554 this.addEvents({"arrowclick":true});
29557 Roo.extend(Roo.SplitButton, Roo.Button, {
29558 render : function(renderTo){
29559 // this is one sweet looking template!
29560 var tpl = new Roo.Template(
29561 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29562 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29563 '<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>',
29564 "</tbody></table></td><td>",
29565 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29566 '<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>',
29567 "</tbody></table></td></tr></table>"
29569 var btn = tpl.append(renderTo, [this.text, this.type], true);
29570 var btnEl = btn.child("button");
29572 btn.addClass(this.cls);
29575 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29578 btnEl.addClass(this.iconCls);
29580 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29584 if(this.handleMouseEvents){
29585 btn.on("mouseover", this.onMouseOver, this);
29586 btn.on("mouseout", this.onMouseOut, this);
29587 btn.on("mousedown", this.onMouseDown, this);
29588 btn.on("mouseup", this.onMouseUp, this);
29590 btn.on(this.clickEvent, this.onClick, this);
29592 if(typeof this.tooltip == 'object'){
29593 Roo.QuickTips.tips(Roo.apply({
29597 btnEl.dom[this.tooltipType] = this.tooltip;
29600 if(this.arrowTooltip){
29601 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
29610 this.el.addClass("x-btn-pressed");
29612 if(Roo.isIE && !Roo.isIE7){
29613 this.autoWidth.defer(1, this);
29618 this.menu.on("show", this.onMenuShow, this);
29619 this.menu.on("hide", this.onMenuHide, this);
29621 this.fireEvent('render', this);
29625 autoWidth : function(){
29627 var tbl = this.el.child("table:first");
29628 var tbl2 = this.el.child("table:last");
29629 this.el.setWidth("auto");
29630 tbl.setWidth("auto");
29631 if(Roo.isIE7 && Roo.isStrict){
29632 var ib = this.el.child('button:first');
29633 if(ib && ib.getWidth() > 20){
29635 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29640 this.el.beginMeasure();
29642 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
29643 tbl.setWidth(this.minWidth-tbl2.getWidth());
29646 this.el.endMeasure();
29649 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
29653 * Sets this button's click handler
29654 * @param {Function} handler The function to call when the button is clicked
29655 * @param {Object} scope (optional) Scope for the function passed above
29657 setHandler : function(handler, scope){
29658 this.handler = handler;
29659 this.scope = scope;
29663 * Sets this button's arrow click handler
29664 * @param {Function} handler The function to call when the arrow is clicked
29665 * @param {Object} scope (optional) Scope for the function passed above
29667 setArrowHandler : function(handler, scope){
29668 this.arrowHandler = handler;
29669 this.scope = scope;
29675 focus : function(){
29677 this.el.child("button:first").focus();
29682 onClick : function(e){
29683 e.preventDefault();
29684 if(!this.disabled){
29685 if(e.getTarget(".x-btn-menu-arrow-wrap")){
29686 if(this.menu && !this.menu.isVisible()){
29687 this.menu.show(this.el, this.menuAlign);
29689 this.fireEvent("arrowclick", this, e);
29690 if(this.arrowHandler){
29691 this.arrowHandler.call(this.scope || this, this, e);
29694 this.fireEvent("click", this, e);
29696 this.handler.call(this.scope || this, this, e);
29702 onMouseDown : function(e){
29703 if(!this.disabled){
29704 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
29708 onMouseUp : function(e){
29709 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
29714 // backwards compat
29715 Roo.MenuButton = Roo.SplitButton;/*
29717 * Ext JS Library 1.1.1
29718 * Copyright(c) 2006-2007, Ext JS, LLC.
29720 * Originally Released Under LGPL - original licence link has changed is not relivant.
29723 * <script type="text/javascript">
29727 * @class Roo.Toolbar
29728 * Basic Toolbar class.
29730 * Creates a new Toolbar
29731 * @param {Object} container The config object
29733 Roo.Toolbar = function(container, buttons, config)
29735 /// old consturctor format still supported..
29736 if(container instanceof Array){ // omit the container for later rendering
29737 buttons = container;
29741 if (typeof(container) == 'object' && container.xtype) {
29742 config = container;
29743 container = config.container;
29744 buttons = config.buttons || []; // not really - use items!!
29747 if (config && config.items) {
29748 xitems = config.items;
29749 delete config.items;
29751 Roo.apply(this, config);
29752 this.buttons = buttons;
29755 this.render(container);
29757 this.xitems = xitems;
29758 Roo.each(xitems, function(b) {
29764 Roo.Toolbar.prototype = {
29766 * @cfg {Array} items
29767 * array of button configs or elements to add (will be converted to a MixedCollection)
29771 * @cfg {String/HTMLElement/Element} container
29772 * The id or element that will contain the toolbar
29775 render : function(ct){
29776 this.el = Roo.get(ct);
29778 this.el.addClass(this.cls);
29780 // using a table allows for vertical alignment
29781 // 100% width is needed by Safari...
29782 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
29783 this.tr = this.el.child("tr", true);
29785 this.items = new Roo.util.MixedCollection(false, function(o){
29786 return o.id || ("item" + (++autoId));
29789 this.add.apply(this, this.buttons);
29790 delete this.buttons;
29795 * Adds element(s) to the toolbar -- this function takes a variable number of
29796 * arguments of mixed type and adds them to the toolbar.
29797 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
29799 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
29800 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
29801 * <li>Field: Any form field (equivalent to {@link #addField})</li>
29802 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
29803 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
29804 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
29805 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
29806 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
29807 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
29809 * @param {Mixed} arg2
29810 * @param {Mixed} etc.
29813 var a = arguments, l = a.length;
29814 for(var i = 0; i < l; i++){
29819 _add : function(el) {
29822 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
29825 if (el.applyTo){ // some kind of form field
29826 return this.addField(el);
29828 if (el.render){ // some kind of Toolbar.Item
29829 return this.addItem(el);
29831 if (typeof el == "string"){ // string
29832 if(el == "separator" || el == "-"){
29833 return this.addSeparator();
29836 return this.addSpacer();
29839 return this.addFill();
29841 return this.addText(el);
29844 if(el.tagName){ // element
29845 return this.addElement(el);
29847 if(typeof el == "object"){ // must be button config?
29848 return this.addButton(el);
29850 // and now what?!?!
29856 * Add an Xtype element
29857 * @param {Object} xtype Xtype Object
29858 * @return {Object} created Object
29860 addxtype : function(e){
29861 return this.add(e);
29865 * Returns the Element for this toolbar.
29866 * @return {Roo.Element}
29868 getEl : function(){
29874 * @return {Roo.Toolbar.Item} The separator item
29876 addSeparator : function(){
29877 return this.addItem(new Roo.Toolbar.Separator());
29881 * Adds a spacer element
29882 * @return {Roo.Toolbar.Spacer} The spacer item
29884 addSpacer : function(){
29885 return this.addItem(new Roo.Toolbar.Spacer());
29889 * Adds a fill element that forces subsequent additions to the right side of the toolbar
29890 * @return {Roo.Toolbar.Fill} The fill item
29892 addFill : function(){
29893 return this.addItem(new Roo.Toolbar.Fill());
29897 * Adds any standard HTML element to the toolbar
29898 * @param {String/HTMLElement/Element} el The element or id of the element to add
29899 * @return {Roo.Toolbar.Item} The element's item
29901 addElement : function(el){
29902 return this.addItem(new Roo.Toolbar.Item(el));
29905 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
29906 * @type Roo.util.MixedCollection
29911 * Adds any Toolbar.Item or subclass
29912 * @param {Roo.Toolbar.Item} item
29913 * @return {Roo.Toolbar.Item} The item
29915 addItem : function(item){
29916 var td = this.nextBlock();
29918 this.items.add(item);
29923 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
29924 * @param {Object/Array} config A button config or array of configs
29925 * @return {Roo.Toolbar.Button/Array}
29927 addButton : function(config){
29928 if(config instanceof Array){
29930 for(var i = 0, len = config.length; i < len; i++) {
29931 buttons.push(this.addButton(config[i]));
29936 if(!(config instanceof Roo.Toolbar.Button)){
29938 new Roo.Toolbar.SplitButton(config) :
29939 new Roo.Toolbar.Button(config);
29941 var td = this.nextBlock();
29948 * Adds text to the toolbar
29949 * @param {String} text The text to add
29950 * @return {Roo.Toolbar.Item} The element's item
29952 addText : function(text){
29953 return this.addItem(new Roo.Toolbar.TextItem(text));
29957 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
29958 * @param {Number} index The index where the item is to be inserted
29959 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
29960 * @return {Roo.Toolbar.Button/Item}
29962 insertButton : function(index, item){
29963 if(item instanceof Array){
29965 for(var i = 0, len = item.length; i < len; i++) {
29966 buttons.push(this.insertButton(index + i, item[i]));
29970 if (!(item instanceof Roo.Toolbar.Button)){
29971 item = new Roo.Toolbar.Button(item);
29973 var td = document.createElement("td");
29974 this.tr.insertBefore(td, this.tr.childNodes[index]);
29976 this.items.insert(index, item);
29981 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
29982 * @param {Object} config
29983 * @return {Roo.Toolbar.Item} The element's item
29985 addDom : function(config, returnEl){
29986 var td = this.nextBlock();
29987 Roo.DomHelper.overwrite(td, config);
29988 var ti = new Roo.Toolbar.Item(td.firstChild);
29990 this.items.add(ti);
29995 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
29996 * @type Roo.util.MixedCollection
30001 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30002 * Note: the field should not have been rendered yet. For a field that has already been
30003 * rendered, use {@link #addElement}.
30004 * @param {Roo.form.Field} field
30005 * @return {Roo.ToolbarItem}
30009 addField : function(field) {
30010 if (!this.fields) {
30012 this.fields = new Roo.util.MixedCollection(false, function(o){
30013 return o.id || ("item" + (++autoId));
30018 var td = this.nextBlock();
30020 var ti = new Roo.Toolbar.Item(td.firstChild);
30022 this.items.add(ti);
30023 this.fields.add(field);
30034 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30035 this.el.child('div').hide();
30043 this.el.child('div').show();
30047 nextBlock : function(){
30048 var td = document.createElement("td");
30049 this.tr.appendChild(td);
30054 destroy : function(){
30055 if(this.items){ // rendered?
30056 Roo.destroy.apply(Roo, this.items.items);
30058 if(this.fields){ // rendered?
30059 Roo.destroy.apply(Roo, this.fields.items);
30061 Roo.Element.uncache(this.el, this.tr);
30066 * @class Roo.Toolbar.Item
30067 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30069 * Creates a new Item
30070 * @param {HTMLElement} el
30072 Roo.Toolbar.Item = function(el){
30074 if (typeof (el.xtype) != 'undefined') {
30079 this.el = Roo.getDom(el);
30080 this.id = Roo.id(this.el);
30081 this.hidden = false;
30086 * Fires when the button is rendered
30087 * @param {Button} this
30091 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30093 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30094 //Roo.Toolbar.Item.prototype = {
30097 * Get this item's HTML Element
30098 * @return {HTMLElement}
30100 getEl : function(){
30105 render : function(td){
30108 td.appendChild(this.el);
30110 this.fireEvent('render', this);
30114 * Removes and destroys this item.
30116 destroy : function(){
30117 this.td.parentNode.removeChild(this.td);
30124 this.hidden = false;
30125 this.td.style.display = "";
30132 this.hidden = true;
30133 this.td.style.display = "none";
30137 * Convenience function for boolean show/hide.
30138 * @param {Boolean} visible true to show/false to hide
30140 setVisible: function(visible){
30149 * Try to focus this item.
30151 focus : function(){
30152 Roo.fly(this.el).focus();
30156 * Disables this item.
30158 disable : function(){
30159 Roo.fly(this.td).addClass("x-item-disabled");
30160 this.disabled = true;
30161 this.el.disabled = true;
30165 * Enables this item.
30167 enable : function(){
30168 Roo.fly(this.td).removeClass("x-item-disabled");
30169 this.disabled = false;
30170 this.el.disabled = false;
30176 * @class Roo.Toolbar.Separator
30177 * @extends Roo.Toolbar.Item
30178 * A simple toolbar separator class
30180 * Creates a new Separator
30182 Roo.Toolbar.Separator = function(cfg){
30184 var s = document.createElement("span");
30185 s.className = "ytb-sep";
30190 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30192 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30193 enable:Roo.emptyFn,
30194 disable:Roo.emptyFn,
30199 * @class Roo.Toolbar.Spacer
30200 * @extends Roo.Toolbar.Item
30201 * A simple element that adds extra horizontal space to a toolbar.
30203 * Creates a new Spacer
30205 Roo.Toolbar.Spacer = function(cfg){
30206 var s = document.createElement("div");
30207 s.className = "ytb-spacer";
30211 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30213 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30214 enable:Roo.emptyFn,
30215 disable:Roo.emptyFn,
30220 * @class Roo.Toolbar.Fill
30221 * @extends Roo.Toolbar.Spacer
30222 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30224 * Creates a new Spacer
30226 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30228 render : function(td){
30229 td.style.width = '100%';
30230 Roo.Toolbar.Fill.superclass.render.call(this, td);
30235 * @class Roo.Toolbar.TextItem
30236 * @extends Roo.Toolbar.Item
30237 * A simple class that renders text directly into a toolbar.
30239 * Creates a new TextItem
30240 * @param {String} text
30242 Roo.Toolbar.TextItem = function(cfg){
30243 var text = cfg || "";
30244 if (typeof(cfg) == 'object') {
30245 text = cfg.text || "";
30249 var s = document.createElement("span");
30250 s.className = "ytb-text";
30251 s.innerHTML = text;
30256 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30258 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30261 enable:Roo.emptyFn,
30262 disable:Roo.emptyFn,
30267 * @class Roo.Toolbar.Button
30268 * @extends Roo.Button
30269 * A button that renders into a toolbar.
30271 * Creates a new Button
30272 * @param {Object} config A standard {@link Roo.Button} config object
30274 Roo.Toolbar.Button = function(config){
30275 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30277 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30278 render : function(td){
30280 Roo.Toolbar.Button.superclass.render.call(this, td);
30284 * Removes and destroys this button
30286 destroy : function(){
30287 Roo.Toolbar.Button.superclass.destroy.call(this);
30288 this.td.parentNode.removeChild(this.td);
30292 * Shows this button
30295 this.hidden = false;
30296 this.td.style.display = "";
30300 * Hides this button
30303 this.hidden = true;
30304 this.td.style.display = "none";
30308 * Disables this item
30310 disable : function(){
30311 Roo.fly(this.td).addClass("x-item-disabled");
30312 this.disabled = true;
30316 * Enables this item
30318 enable : function(){
30319 Roo.fly(this.td).removeClass("x-item-disabled");
30320 this.disabled = false;
30323 // backwards compat
30324 Roo.ToolbarButton = Roo.Toolbar.Button;
30327 * @class Roo.Toolbar.SplitButton
30328 * @extends Roo.SplitButton
30329 * A menu button that renders into a toolbar.
30331 * Creates a new SplitButton
30332 * @param {Object} config A standard {@link Roo.SplitButton} config object
30334 Roo.Toolbar.SplitButton = function(config){
30335 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30337 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30338 render : function(td){
30340 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30344 * Removes and destroys this button
30346 destroy : function(){
30347 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30348 this.td.parentNode.removeChild(this.td);
30352 * Shows this button
30355 this.hidden = false;
30356 this.td.style.display = "";
30360 * Hides this button
30363 this.hidden = true;
30364 this.td.style.display = "none";
30368 // backwards compat
30369 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30371 * Ext JS Library 1.1.1
30372 * Copyright(c) 2006-2007, Ext JS, LLC.
30374 * Originally Released Under LGPL - original licence link has changed is not relivant.
30377 * <script type="text/javascript">
30381 * @class Roo.PagingToolbar
30382 * @extends Roo.Toolbar
30383 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30385 * Create a new PagingToolbar
30386 * @param {Object} config The config object
30388 Roo.PagingToolbar = function(el, ds, config)
30390 // old args format still supported... - xtype is prefered..
30391 if (typeof(el) == 'object' && el.xtype) {
30392 // created from xtype...
30394 ds = el.dataSource;
30395 el = config.container;
30398 if (config.items) {
30399 items = config.items;
30403 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30406 this.renderButtons(this.el);
30409 // supprot items array.
30411 Roo.each(items, function(e) {
30412 this.add(Roo.factory(e));
30417 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30419 * @cfg {Roo.data.Store} dataSource
30420 * The underlying data store providing the paged data
30423 * @cfg {String/HTMLElement/Element} container
30424 * container The id or element that will contain the toolbar
30427 * @cfg {Boolean} displayInfo
30428 * True to display the displayMsg (defaults to false)
30431 * @cfg {Number} pageSize
30432 * The number of records to display per page (defaults to 20)
30436 * @cfg {String} displayMsg
30437 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30439 displayMsg : 'Displaying {0} - {1} of {2}',
30441 * @cfg {String} emptyMsg
30442 * The message to display when no records are found (defaults to "No data to display")
30444 emptyMsg : 'No data to display',
30446 * Customizable piece of the default paging text (defaults to "Page")
30449 beforePageText : "Page",
30451 * Customizable piece of the default paging text (defaults to "of %0")
30454 afterPageText : "of {0}",
30456 * Customizable piece of the default paging text (defaults to "First Page")
30459 firstText : "First Page",
30461 * Customizable piece of the default paging text (defaults to "Previous Page")
30464 prevText : "Previous Page",
30466 * Customizable piece of the default paging text (defaults to "Next Page")
30469 nextText : "Next Page",
30471 * Customizable piece of the default paging text (defaults to "Last Page")
30474 lastText : "Last Page",
30476 * Customizable piece of the default paging text (defaults to "Refresh")
30479 refreshText : "Refresh",
30482 renderButtons : function(el){
30483 Roo.PagingToolbar.superclass.render.call(this, el);
30484 this.first = this.addButton({
30485 tooltip: this.firstText,
30486 cls: "x-btn-icon x-grid-page-first",
30488 handler: this.onClick.createDelegate(this, ["first"])
30490 this.prev = this.addButton({
30491 tooltip: this.prevText,
30492 cls: "x-btn-icon x-grid-page-prev",
30494 handler: this.onClick.createDelegate(this, ["prev"])
30496 //this.addSeparator();
30497 this.add(this.beforePageText);
30498 this.field = Roo.get(this.addDom({
30503 cls: "x-grid-page-number"
30505 this.field.on("keydown", this.onPagingKeydown, this);
30506 this.field.on("focus", function(){this.dom.select();});
30507 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30508 this.field.setHeight(18);
30509 //this.addSeparator();
30510 this.next = this.addButton({
30511 tooltip: this.nextText,
30512 cls: "x-btn-icon x-grid-page-next",
30514 handler: this.onClick.createDelegate(this, ["next"])
30516 this.last = this.addButton({
30517 tooltip: this.lastText,
30518 cls: "x-btn-icon x-grid-page-last",
30520 handler: this.onClick.createDelegate(this, ["last"])
30522 //this.addSeparator();
30523 this.loading = this.addButton({
30524 tooltip: this.refreshText,
30525 cls: "x-btn-icon x-grid-loading",
30526 handler: this.onClick.createDelegate(this, ["refresh"])
30529 if(this.displayInfo){
30530 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30535 updateInfo : function(){
30536 if(this.displayEl){
30537 var count = this.ds.getCount();
30538 var msg = count == 0 ?
30542 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30544 this.displayEl.update(msg);
30549 onLoad : function(ds, r, o){
30550 this.cursor = o.params ? o.params.start : 0;
30551 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30553 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30554 this.field.dom.value = ap;
30555 this.first.setDisabled(ap == 1);
30556 this.prev.setDisabled(ap == 1);
30557 this.next.setDisabled(ap == ps);
30558 this.last.setDisabled(ap == ps);
30559 this.loading.enable();
30564 getPageData : function(){
30565 var total = this.ds.getTotalCount();
30568 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30569 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30574 onLoadError : function(){
30575 this.loading.enable();
30579 onPagingKeydown : function(e){
30580 var k = e.getKey();
30581 var d = this.getPageData();
30583 var v = this.field.dom.value, pageNum;
30584 if(!v || isNaN(pageNum = parseInt(v, 10))){
30585 this.field.dom.value = d.activePage;
30588 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
30589 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30592 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))
30594 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
30595 this.field.dom.value = pageNum;
30596 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
30599 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
30601 var v = this.field.dom.value, pageNum;
30602 var increment = (e.shiftKey) ? 10 : 1;
30603 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
30606 if(!v || isNaN(pageNum = parseInt(v, 10))) {
30607 this.field.dom.value = d.activePage;
30610 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
30612 this.field.dom.value = parseInt(v, 10) + increment;
30613 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
30614 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
30621 beforeLoad : function(){
30623 this.loading.disable();
30628 onClick : function(which){
30632 ds.load({params:{start: 0, limit: this.pageSize}});
30635 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
30638 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
30641 var total = ds.getTotalCount();
30642 var extra = total % this.pageSize;
30643 var lastStart = extra ? (total - extra) : total-this.pageSize;
30644 ds.load({params:{start: lastStart, limit: this.pageSize}});
30647 ds.load({params:{start: this.cursor, limit: this.pageSize}});
30653 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
30654 * @param {Roo.data.Store} store The data store to unbind
30656 unbind : function(ds){
30657 ds.un("beforeload", this.beforeLoad, this);
30658 ds.un("load", this.onLoad, this);
30659 ds.un("loadexception", this.onLoadError, this);
30660 ds.un("remove", this.updateInfo, this);
30661 ds.un("add", this.updateInfo, this);
30662 this.ds = undefined;
30666 * Binds the paging toolbar to the specified {@link Roo.data.Store}
30667 * @param {Roo.data.Store} store The data store to bind
30669 bind : function(ds){
30670 ds.on("beforeload", this.beforeLoad, this);
30671 ds.on("load", this.onLoad, this);
30672 ds.on("loadexception", this.onLoadError, this);
30673 ds.on("remove", this.updateInfo, this);
30674 ds.on("add", this.updateInfo, this);
30679 * Ext JS Library 1.1.1
30680 * Copyright(c) 2006-2007, Ext JS, LLC.
30682 * Originally Released Under LGPL - original licence link has changed is not relivant.
30685 * <script type="text/javascript">
30689 * @class Roo.Resizable
30690 * @extends Roo.util.Observable
30691 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
30692 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
30693 * 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
30694 * the element will be wrapped for you automatically.</p>
30695 * <p>Here is the list of valid resize handles:</p>
30698 ------ -------------------
30707 'hd' horizontal drag
30710 * <p>Here's an example showing the creation of a typical Resizable:</p>
30712 var resizer = new Roo.Resizable("element-id", {
30720 resizer.on("resize", myHandler);
30722 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
30723 * resizer.east.setDisplayed(false);</p>
30724 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
30725 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
30726 * resize operation's new size (defaults to [0, 0])
30727 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
30728 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
30729 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
30730 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
30731 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
30732 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
30733 * @cfg {Number} width The width of the element in pixels (defaults to null)
30734 * @cfg {Number} height The height of the element in pixels (defaults to null)
30735 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
30736 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
30737 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
30738 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
30739 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
30740 * in favor of the handles config option (defaults to false)
30741 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
30742 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
30743 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
30744 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
30745 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
30746 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
30747 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
30748 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
30749 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
30750 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
30751 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
30753 * Create a new resizable component
30754 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
30755 * @param {Object} config configuration options
30757 Roo.Resizable = function(el, config)
30759 this.el = Roo.get(el);
30761 if(config && config.wrap){
30762 config.resizeChild = this.el;
30763 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
30764 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
30765 this.el.setStyle("overflow", "hidden");
30766 this.el.setPositioning(config.resizeChild.getPositioning());
30767 config.resizeChild.clearPositioning();
30768 if(!config.width || !config.height){
30769 var csize = config.resizeChild.getSize();
30770 this.el.setSize(csize.width, csize.height);
30772 if(config.pinned && !config.adjustments){
30773 config.adjustments = "auto";
30777 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
30778 this.proxy.unselectable();
30779 this.proxy.enableDisplayMode('block');
30781 Roo.apply(this, config);
30784 this.disableTrackOver = true;
30785 this.el.addClass("x-resizable-pinned");
30787 // if the element isn't positioned, make it relative
30788 var position = this.el.getStyle("position");
30789 if(position != "absolute" && position != "fixed"){
30790 this.el.setStyle("position", "relative");
30792 if(!this.handles){ // no handles passed, must be legacy style
30793 this.handles = 's,e,se';
30794 if(this.multiDirectional){
30795 this.handles += ',n,w';
30798 if(this.handles == "all"){
30799 this.handles = "n s e w ne nw se sw";
30801 var hs = this.handles.split(/\s*?[,;]\s*?| /);
30802 var ps = Roo.Resizable.positions;
30803 for(var i = 0, len = hs.length; i < len; i++){
30804 if(hs[i] && ps[hs[i]]){
30805 var pos = ps[hs[i]];
30806 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
30810 this.corner = this.southeast;
30812 // updateBox = the box can move..
30813 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
30814 this.updateBox = true;
30817 this.activeHandle = null;
30819 if(this.resizeChild){
30820 if(typeof this.resizeChild == "boolean"){
30821 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
30823 this.resizeChild = Roo.get(this.resizeChild, true);
30827 if(this.adjustments == "auto"){
30828 var rc = this.resizeChild;
30829 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
30830 if(rc && (hw || hn)){
30831 rc.position("relative");
30832 rc.setLeft(hw ? hw.el.getWidth() : 0);
30833 rc.setTop(hn ? hn.el.getHeight() : 0);
30835 this.adjustments = [
30836 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
30837 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
30841 if(this.draggable){
30842 this.dd = this.dynamic ?
30843 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
30844 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
30850 * @event beforeresize
30851 * Fired before resize is allowed. Set enabled to false to cancel resize.
30852 * @param {Roo.Resizable} this
30853 * @param {Roo.EventObject} e The mousedown event
30855 "beforeresize" : true,
30858 * Fired a resizing.
30859 * @param {Roo.Resizable} this
30860 * @param {Number} x The new x position
30861 * @param {Number} y The new y position
30862 * @param {Number} w The new w width
30863 * @param {Number} h The new h hight
30864 * @param {Roo.EventObject} e The mouseup event
30869 * Fired after a resize.
30870 * @param {Roo.Resizable} this
30871 * @param {Number} width The new width
30872 * @param {Number} height The new height
30873 * @param {Roo.EventObject} e The mouseup event
30878 if(this.width !== null && this.height !== null){
30879 this.resizeTo(this.width, this.height);
30881 this.updateChildSize();
30884 this.el.dom.style.zoom = 1;
30886 Roo.Resizable.superclass.constructor.call(this);
30889 Roo.extend(Roo.Resizable, Roo.util.Observable, {
30890 resizeChild : false,
30891 adjustments : [0, 0],
30901 multiDirectional : false,
30902 disableTrackOver : false,
30903 easing : 'easeOutStrong',
30904 widthIncrement : 0,
30905 heightIncrement : 0,
30909 preserveRatio : false,
30910 transparent: false,
30916 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
30918 constrainTo: undefined,
30920 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
30922 resizeRegion: undefined,
30926 * Perform a manual resize
30927 * @param {Number} width
30928 * @param {Number} height
30930 resizeTo : function(width, height){
30931 this.el.setSize(width, height);
30932 this.updateChildSize();
30933 this.fireEvent("resize", this, width, height, null);
30937 startSizing : function(e, handle){
30938 this.fireEvent("beforeresize", this, e);
30939 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
30942 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
30943 this.overlay.unselectable();
30944 this.overlay.enableDisplayMode("block");
30945 this.overlay.on("mousemove", this.onMouseMove, this);
30946 this.overlay.on("mouseup", this.onMouseUp, this);
30948 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
30950 this.resizing = true;
30951 this.startBox = this.el.getBox();
30952 this.startPoint = e.getXY();
30953 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
30954 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
30956 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
30957 this.overlay.show();
30959 if(this.constrainTo) {
30960 var ct = Roo.get(this.constrainTo);
30961 this.resizeRegion = ct.getRegion().adjust(
30962 ct.getFrameWidth('t'),
30963 ct.getFrameWidth('l'),
30964 -ct.getFrameWidth('b'),
30965 -ct.getFrameWidth('r')
30969 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
30971 this.proxy.setBox(this.startBox);
30973 this.proxy.setStyle('visibility', 'visible');
30979 onMouseDown : function(handle, e){
30982 this.activeHandle = handle;
30983 this.startSizing(e, handle);
30988 onMouseUp : function(e){
30989 var size = this.resizeElement();
30990 this.resizing = false;
30992 this.overlay.hide();
30994 this.fireEvent("resize", this, size.width, size.height, e);
30998 updateChildSize : function(){
31000 if(this.resizeChild){
31002 var child = this.resizeChild;
31003 var adj = this.adjustments;
31004 if(el.dom.offsetWidth){
31005 var b = el.getSize(true);
31006 child.setSize(b.width+adj[0], b.height+adj[1]);
31008 // Second call here for IE
31009 // The first call enables instant resizing and
31010 // the second call corrects scroll bars if they
31013 setTimeout(function(){
31014 if(el.dom.offsetWidth){
31015 var b = el.getSize(true);
31016 child.setSize(b.width+adj[0], b.height+adj[1]);
31024 snap : function(value, inc, min){
31025 if(!inc || !value) {
31028 var newValue = value;
31029 var m = value % inc;
31032 newValue = value + (inc-m);
31034 newValue = value - m;
31037 return Math.max(min, newValue);
31041 resizeElement : function(){
31042 var box = this.proxy.getBox();
31043 if(this.updateBox){
31044 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31046 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31048 this.updateChildSize();
31056 constrain : function(v, diff, m, mx){
31059 }else if(v - diff > mx){
31066 onMouseMove : function(e){
31069 try{// try catch so if something goes wrong the user doesn't get hung
31071 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31075 //var curXY = this.startPoint;
31076 var curSize = this.curSize || this.startBox;
31077 var x = this.startBox.x, y = this.startBox.y;
31078 var ox = x, oy = y;
31079 var w = curSize.width, h = curSize.height;
31080 var ow = w, oh = h;
31081 var mw = this.minWidth, mh = this.minHeight;
31082 var mxw = this.maxWidth, mxh = this.maxHeight;
31083 var wi = this.widthIncrement;
31084 var hi = this.heightIncrement;
31086 var eventXY = e.getXY();
31087 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31088 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31090 var pos = this.activeHandle.position;
31095 w = Math.min(Math.max(mw, w), mxw);
31100 h = Math.min(Math.max(mh, h), mxh);
31105 w = Math.min(Math.max(mw, w), mxw);
31106 h = Math.min(Math.max(mh, h), mxh);
31109 diffY = this.constrain(h, diffY, mh, mxh);
31116 var adiffX = Math.abs(diffX);
31117 var sub = (adiffX % wi); // how much
31118 if (sub > (wi/2)) { // far enough to snap
31119 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31121 // remove difference..
31122 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31126 x = Math.max(this.minX, x);
31129 diffX = this.constrain(w, diffX, mw, mxw);
31135 w = Math.min(Math.max(mw, w), mxw);
31136 diffY = this.constrain(h, diffY, mh, mxh);
31141 diffX = this.constrain(w, diffX, mw, mxw);
31142 diffY = this.constrain(h, diffY, mh, mxh);
31149 diffX = this.constrain(w, diffX, mw, mxw);
31151 h = Math.min(Math.max(mh, h), mxh);
31157 var sw = this.snap(w, wi, mw);
31158 var sh = this.snap(h, hi, mh);
31159 if(sw != w || sh != h){
31182 if(this.preserveRatio){
31187 h = Math.min(Math.max(mh, h), mxh);
31192 w = Math.min(Math.max(mw, w), mxw);
31197 w = Math.min(Math.max(mw, w), mxw);
31203 w = Math.min(Math.max(mw, w), mxw);
31209 h = Math.min(Math.max(mh, h), mxh);
31217 h = Math.min(Math.max(mh, h), mxh);
31227 h = Math.min(Math.max(mh, h), mxh);
31235 if (pos == 'hdrag') {
31238 this.proxy.setBounds(x, y, w, h);
31240 this.resizeElement();
31244 this.fireEvent("resizing", this, x, y, w, h, e);
31248 handleOver : function(){
31250 this.el.addClass("x-resizable-over");
31255 handleOut : function(){
31256 if(!this.resizing){
31257 this.el.removeClass("x-resizable-over");
31262 * Returns the element this component is bound to.
31263 * @return {Roo.Element}
31265 getEl : function(){
31270 * Returns the resizeChild element (or null).
31271 * @return {Roo.Element}
31273 getResizeChild : function(){
31274 return this.resizeChild;
31276 groupHandler : function()
31281 * Destroys this resizable. If the element was wrapped and
31282 * removeEl is not true then the element remains.
31283 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31285 destroy : function(removeEl){
31286 this.proxy.remove();
31288 this.overlay.removeAllListeners();
31289 this.overlay.remove();
31291 var ps = Roo.Resizable.positions;
31293 if(typeof ps[k] != "function" && this[ps[k]]){
31294 var h = this[ps[k]];
31295 h.el.removeAllListeners();
31300 this.el.update("");
31307 // hash to map config positions to true positions
31308 Roo.Resizable.positions = {
31309 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31314 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31316 // only initialize the template if resizable is used
31317 var tpl = Roo.DomHelper.createTemplate(
31318 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31321 Roo.Resizable.Handle.prototype.tpl = tpl;
31323 this.position = pos;
31325 // show north drag fro topdra
31326 var handlepos = pos == 'hdrag' ? 'north' : pos;
31328 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31329 if (pos == 'hdrag') {
31330 this.el.setStyle('cursor', 'pointer');
31332 this.el.unselectable();
31334 this.el.setOpacity(0);
31336 this.el.on("mousedown", this.onMouseDown, this);
31337 if(!disableTrackOver){
31338 this.el.on("mouseover", this.onMouseOver, this);
31339 this.el.on("mouseout", this.onMouseOut, this);
31344 Roo.Resizable.Handle.prototype = {
31345 afterResize : function(rz){
31350 onMouseDown : function(e){
31351 this.rz.onMouseDown(this, e);
31354 onMouseOver : function(e){
31355 this.rz.handleOver(this, e);
31358 onMouseOut : function(e){
31359 this.rz.handleOut(this, e);
31363 * Ext JS Library 1.1.1
31364 * Copyright(c) 2006-2007, Ext JS, LLC.
31366 * Originally Released Under LGPL - original licence link has changed is not relivant.
31369 * <script type="text/javascript">
31373 * @class Roo.Editor
31374 * @extends Roo.Component
31375 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31377 * Create a new Editor
31378 * @param {Roo.form.Field} field The Field object (or descendant)
31379 * @param {Object} config The config object
31381 Roo.Editor = function(field, config){
31382 Roo.Editor.superclass.constructor.call(this, config);
31383 this.field = field;
31386 * @event beforestartedit
31387 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31388 * false from the handler of this event.
31389 * @param {Editor} this
31390 * @param {Roo.Element} boundEl The underlying element bound to this editor
31391 * @param {Mixed} value The field value being set
31393 "beforestartedit" : true,
31396 * Fires when this editor is displayed
31397 * @param {Roo.Element} boundEl The underlying element bound to this editor
31398 * @param {Mixed} value The starting field value
31400 "startedit" : true,
31402 * @event beforecomplete
31403 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31404 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31405 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31406 * event will not fire since no edit actually occurred.
31407 * @param {Editor} this
31408 * @param {Mixed} value The current field value
31409 * @param {Mixed} startValue The original field value
31411 "beforecomplete" : true,
31414 * Fires after editing is complete and any changed value has been written to the underlying field.
31415 * @param {Editor} this
31416 * @param {Mixed} value The current field value
31417 * @param {Mixed} startValue The original field value
31421 * @event specialkey
31422 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31423 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31424 * @param {Roo.form.Field} this
31425 * @param {Roo.EventObject} e The event object
31427 "specialkey" : true
31431 Roo.extend(Roo.Editor, Roo.Component, {
31433 * @cfg {Boolean/String} autosize
31434 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31435 * or "height" to adopt the height only (defaults to false)
31438 * @cfg {Boolean} revertInvalid
31439 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31440 * validation fails (defaults to true)
31443 * @cfg {Boolean} ignoreNoChange
31444 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31445 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31446 * will never be ignored.
31449 * @cfg {Boolean} hideEl
31450 * False to keep the bound element visible while the editor is displayed (defaults to true)
31453 * @cfg {Mixed} value
31454 * The data value of the underlying field (defaults to "")
31458 * @cfg {String} alignment
31459 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31463 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31464 * for bottom-right shadow (defaults to "frame")
31468 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31472 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31474 completeOnEnter : false,
31476 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31478 cancelOnEsc : false,
31480 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31485 onRender : function(ct, position){
31486 this.el = new Roo.Layer({
31487 shadow: this.shadow,
31493 constrain: this.constrain
31495 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31496 if(this.field.msgTarget != 'title'){
31497 this.field.msgTarget = 'qtip';
31499 this.field.render(this.el);
31501 this.field.el.dom.setAttribute('autocomplete', 'off');
31503 this.field.on("specialkey", this.onSpecialKey, this);
31504 if(this.swallowKeys){
31505 this.field.el.swallowEvent(['keydown','keypress']);
31508 this.field.on("blur", this.onBlur, this);
31509 if(this.field.grow){
31510 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31514 onSpecialKey : function(field, e)
31516 //Roo.log('editor onSpecialKey');
31517 if(this.completeOnEnter && e.getKey() == e.ENTER){
31519 this.completeEdit();
31522 // do not fire special key otherwise it might hide close the editor...
31523 if(e.getKey() == e.ENTER){
31526 if(this.cancelOnEsc && e.getKey() == e.ESC){
31530 this.fireEvent('specialkey', field, e);
31535 * Starts the editing process and shows the editor.
31536 * @param {String/HTMLElement/Element} el The element to edit
31537 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31538 * to the innerHTML of el.
31540 startEdit : function(el, value){
31542 this.completeEdit();
31544 this.boundEl = Roo.get(el);
31545 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31546 if(!this.rendered){
31547 this.render(this.parentEl || document.body);
31549 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31552 this.startValue = v;
31553 this.field.setValue(v);
31555 var sz = this.boundEl.getSize();
31556 switch(this.autoSize){
31558 this.setSize(sz.width, "");
31561 this.setSize("", sz.height);
31564 this.setSize(sz.width, sz.height);
31567 this.el.alignTo(this.boundEl, this.alignment);
31568 this.editing = true;
31570 Roo.QuickTips.disable();
31576 * Sets the height and width of this editor.
31577 * @param {Number} width The new width
31578 * @param {Number} height The new height
31580 setSize : function(w, h){
31581 this.field.setSize(w, h);
31588 * Realigns the editor to the bound field based on the current alignment config value.
31590 realign : function(){
31591 this.el.alignTo(this.boundEl, this.alignment);
31595 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
31596 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
31598 completeEdit : function(remainVisible){
31602 var v = this.getValue();
31603 if(this.revertInvalid !== false && !this.field.isValid()){
31604 v = this.startValue;
31605 this.cancelEdit(true);
31607 if(String(v) === String(this.startValue) && this.ignoreNoChange){
31608 this.editing = false;
31612 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
31613 this.editing = false;
31614 if(this.updateEl && this.boundEl){
31615 this.boundEl.update(v);
31617 if(remainVisible !== true){
31620 this.fireEvent("complete", this, v, this.startValue);
31625 onShow : function(){
31627 if(this.hideEl !== false){
31628 this.boundEl.hide();
31631 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
31632 this.fixIEFocus = true;
31633 this.deferredFocus.defer(50, this);
31635 this.field.focus();
31637 this.fireEvent("startedit", this.boundEl, this.startValue);
31640 deferredFocus : function(){
31642 this.field.focus();
31647 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
31648 * reverted to the original starting value.
31649 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
31650 * cancel (defaults to false)
31652 cancelEdit : function(remainVisible){
31654 this.setValue(this.startValue);
31655 if(remainVisible !== true){
31662 onBlur : function(){
31663 if(this.allowBlur !== true && this.editing){
31664 this.completeEdit();
31669 onHide : function(){
31671 this.completeEdit();
31675 if(this.field.collapse){
31676 this.field.collapse();
31679 if(this.hideEl !== false){
31680 this.boundEl.show();
31683 Roo.QuickTips.enable();
31688 * Sets the data value of the editor
31689 * @param {Mixed} value Any valid value supported by the underlying field
31691 setValue : function(v){
31692 this.field.setValue(v);
31696 * Gets the data value of the editor
31697 * @return {Mixed} The data value
31699 getValue : function(){
31700 return this.field.getValue();
31704 * Ext JS Library 1.1.1
31705 * Copyright(c) 2006-2007, Ext JS, LLC.
31707 * Originally Released Under LGPL - original licence link has changed is not relivant.
31710 * <script type="text/javascript">
31714 * @class Roo.BasicDialog
31715 * @extends Roo.util.Observable
31716 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
31718 var dlg = new Roo.BasicDialog("my-dlg", {
31727 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
31728 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
31729 dlg.addButton('Cancel', dlg.hide, dlg);
31732 <b>A Dialog should always be a direct child of the body element.</b>
31733 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
31734 * @cfg {String} title Default text to display in the title bar (defaults to null)
31735 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31736 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
31737 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
31738 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
31739 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
31740 * (defaults to null with no animation)
31741 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
31742 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
31743 * property for valid values (defaults to 'all')
31744 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
31745 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
31746 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
31747 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
31748 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
31749 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
31750 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
31751 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
31752 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
31753 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
31754 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
31755 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
31756 * draggable = true (defaults to false)
31757 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
31758 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31759 * shadow (defaults to false)
31760 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
31761 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
31762 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
31763 * @cfg {Array} buttons Array of buttons
31764 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
31766 * Create a new BasicDialog.
31767 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
31768 * @param {Object} config Configuration options
31770 Roo.BasicDialog = function(el, config){
31771 this.el = Roo.get(el);
31772 var dh = Roo.DomHelper;
31773 if(!this.el && config && config.autoCreate){
31774 if(typeof config.autoCreate == "object"){
31775 if(!config.autoCreate.id){
31776 config.autoCreate.id = el;
31778 this.el = dh.append(document.body,
31779 config.autoCreate, true);
31781 this.el = dh.append(document.body,
31782 {tag: "div", id: el, style:'visibility:hidden;'}, true);
31786 el.setDisplayed(true);
31787 el.hide = this.hideAction;
31789 el.addClass("x-dlg");
31791 Roo.apply(this, config);
31793 this.proxy = el.createProxy("x-dlg-proxy");
31794 this.proxy.hide = this.hideAction;
31795 this.proxy.setOpacity(.5);
31799 el.setWidth(config.width);
31802 el.setHeight(config.height);
31804 this.size = el.getSize();
31805 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
31806 this.xy = [config.x,config.y];
31808 this.xy = el.getCenterXY(true);
31810 /** The header element @type Roo.Element */
31811 this.header = el.child("> .x-dlg-hd");
31812 /** The body element @type Roo.Element */
31813 this.body = el.child("> .x-dlg-bd");
31814 /** The footer element @type Roo.Element */
31815 this.footer = el.child("> .x-dlg-ft");
31818 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
31821 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
31824 this.header.unselectable();
31826 this.header.update(this.title);
31828 // this element allows the dialog to be focused for keyboard event
31829 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
31830 this.focusEl.swallowEvent("click", true);
31832 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
31834 // wrap the body and footer for special rendering
31835 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
31837 this.bwrap.dom.appendChild(this.footer.dom);
31840 this.bg = this.el.createChild({
31841 tag: "div", cls:"x-dlg-bg",
31842 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
31844 this.centerBg = this.bg.child("div.x-dlg-bg-center");
31847 if(this.autoScroll !== false && !this.autoTabs){
31848 this.body.setStyle("overflow", "auto");
31851 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
31853 if(this.closable !== false){
31854 this.el.addClass("x-dlg-closable");
31855 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
31856 this.close.on("click", this.closeClick, this);
31857 this.close.addClassOnOver("x-dlg-close-over");
31859 if(this.collapsible !== false){
31860 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
31861 this.collapseBtn.on("click", this.collapseClick, this);
31862 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
31863 this.header.on("dblclick", this.collapseClick, this);
31865 if(this.resizable !== false){
31866 this.el.addClass("x-dlg-resizable");
31867 this.resizer = new Roo.Resizable(el, {
31868 minWidth: this.minWidth || 80,
31869 minHeight:this.minHeight || 80,
31870 handles: this.resizeHandles || "all",
31873 this.resizer.on("beforeresize", this.beforeResize, this);
31874 this.resizer.on("resize", this.onResize, this);
31876 if(this.draggable !== false){
31877 el.addClass("x-dlg-draggable");
31878 if (!this.proxyDrag) {
31879 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
31882 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
31884 dd.setHandleElId(this.header.id);
31885 dd.endDrag = this.endMove.createDelegate(this);
31886 dd.startDrag = this.startMove.createDelegate(this);
31887 dd.onDrag = this.onDrag.createDelegate(this);
31892 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
31893 this.mask.enableDisplayMode("block");
31895 this.el.addClass("x-dlg-modal");
31898 this.shadow = new Roo.Shadow({
31899 mode : typeof this.shadow == "string" ? this.shadow : "sides",
31900 offset : this.shadowOffset
31903 this.shadowOffset = 0;
31905 if(Roo.useShims && this.shim !== false){
31906 this.shim = this.el.createShim();
31907 this.shim.hide = this.hideAction;
31915 if (this.buttons) {
31916 var bts= this.buttons;
31918 Roo.each(bts, function(b) {
31927 * Fires when a key is pressed
31928 * @param {Roo.BasicDialog} this
31929 * @param {Roo.EventObject} e
31934 * Fires when this dialog is moved by the user.
31935 * @param {Roo.BasicDialog} this
31936 * @param {Number} x The new page X
31937 * @param {Number} y The new page Y
31942 * Fires when this dialog is resized by the user.
31943 * @param {Roo.BasicDialog} this
31944 * @param {Number} width The new width
31945 * @param {Number} height The new height
31949 * @event beforehide
31950 * Fires before this dialog is hidden.
31951 * @param {Roo.BasicDialog} this
31953 "beforehide" : true,
31956 * Fires when this dialog is hidden.
31957 * @param {Roo.BasicDialog} this
31961 * @event beforeshow
31962 * Fires before this dialog is shown.
31963 * @param {Roo.BasicDialog} this
31965 "beforeshow" : true,
31968 * Fires when this dialog is shown.
31969 * @param {Roo.BasicDialog} this
31973 el.on("keydown", this.onKeyDown, this);
31974 el.on("mousedown", this.toFront, this);
31975 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
31977 Roo.DialogManager.register(this);
31978 Roo.BasicDialog.superclass.constructor.call(this);
31981 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
31982 shadowOffset: Roo.isIE ? 6 : 5,
31985 minButtonWidth: 75,
31986 defaultButton: null,
31987 buttonAlign: "right",
31992 * Sets the dialog title text
31993 * @param {String} text The title text to display
31994 * @return {Roo.BasicDialog} this
31996 setTitle : function(text){
31997 this.header.update(text);
32002 closeClick : function(){
32007 collapseClick : function(){
32008 this[this.collapsed ? "expand" : "collapse"]();
32012 * Collapses the dialog to its minimized state (only the title bar is visible).
32013 * Equivalent to the user clicking the collapse dialog button.
32015 collapse : function(){
32016 if(!this.collapsed){
32017 this.collapsed = true;
32018 this.el.addClass("x-dlg-collapsed");
32019 this.restoreHeight = this.el.getHeight();
32020 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32025 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32026 * clicking the expand dialog button.
32028 expand : function(){
32029 if(this.collapsed){
32030 this.collapsed = false;
32031 this.el.removeClass("x-dlg-collapsed");
32032 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32037 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32038 * @return {Roo.TabPanel} The tabs component
32040 initTabs : function(){
32041 var tabs = this.getTabs();
32042 while(tabs.getTab(0)){
32045 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32047 tabs.addTab(Roo.id(dom), dom.title);
32055 beforeResize : function(){
32056 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32060 onResize : function(){
32061 this.refreshSize();
32062 this.syncBodyHeight();
32063 this.adjustAssets();
32065 this.fireEvent("resize", this, this.size.width, this.size.height);
32069 onKeyDown : function(e){
32070 if(this.isVisible()){
32071 this.fireEvent("keydown", this, e);
32076 * Resizes the dialog.
32077 * @param {Number} width
32078 * @param {Number} height
32079 * @return {Roo.BasicDialog} this
32081 resizeTo : function(width, height){
32082 this.el.setSize(width, height);
32083 this.size = {width: width, height: height};
32084 this.syncBodyHeight();
32085 if(this.fixedcenter){
32088 if(this.isVisible()){
32089 this.constrainXY();
32090 this.adjustAssets();
32092 this.fireEvent("resize", this, width, height);
32098 * Resizes the dialog to fit the specified content size.
32099 * @param {Number} width
32100 * @param {Number} height
32101 * @return {Roo.BasicDialog} this
32103 setContentSize : function(w, h){
32104 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32105 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32106 //if(!this.el.isBorderBox()){
32107 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32108 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32111 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32112 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32114 this.resizeTo(w, h);
32119 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32120 * executed in response to a particular key being pressed while the dialog is active.
32121 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32122 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32123 * @param {Function} fn The function to call
32124 * @param {Object} scope (optional) The scope of the function
32125 * @return {Roo.BasicDialog} this
32127 addKeyListener : function(key, fn, scope){
32128 var keyCode, shift, ctrl, alt;
32129 if(typeof key == "object" && !(key instanceof Array)){
32130 keyCode = key["key"];
32131 shift = key["shift"];
32132 ctrl = key["ctrl"];
32137 var handler = function(dlg, e){
32138 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32139 var k = e.getKey();
32140 if(keyCode instanceof Array){
32141 for(var i = 0, len = keyCode.length; i < len; i++){
32142 if(keyCode[i] == k){
32143 fn.call(scope || window, dlg, k, e);
32149 fn.call(scope || window, dlg, k, e);
32154 this.on("keydown", handler);
32159 * Returns the TabPanel component (creates it if it doesn't exist).
32160 * Note: If you wish to simply check for the existence of tabs without creating them,
32161 * check for a null 'tabs' property.
32162 * @return {Roo.TabPanel} The tabs component
32164 getTabs : function(){
32166 this.el.addClass("x-dlg-auto-tabs");
32167 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32168 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32174 * Adds a button to the footer section of the dialog.
32175 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32176 * object or a valid Roo.DomHelper element config
32177 * @param {Function} handler The function called when the button is clicked
32178 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32179 * @return {Roo.Button} The new button
32181 addButton : function(config, handler, scope){
32182 var dh = Roo.DomHelper;
32184 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32186 if(!this.btnContainer){
32187 var tb = this.footer.createChild({
32189 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32190 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32192 this.btnContainer = tb.firstChild.firstChild.firstChild;
32197 minWidth: this.minButtonWidth,
32200 if(typeof config == "string"){
32201 bconfig.text = config;
32204 bconfig.dhconfig = config;
32206 Roo.apply(bconfig, config);
32210 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32211 bconfig.position = Math.max(0, bconfig.position);
32212 fc = this.btnContainer.childNodes[bconfig.position];
32215 var btn = new Roo.Button(
32217 this.btnContainer.insertBefore(document.createElement("td"),fc)
32218 : this.btnContainer.appendChild(document.createElement("td")),
32219 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32222 this.syncBodyHeight();
32225 * Array of all the buttons that have been added to this dialog via addButton
32230 this.buttons.push(btn);
32235 * Sets the default button to be focused when the dialog is displayed.
32236 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32237 * @return {Roo.BasicDialog} this
32239 setDefaultButton : function(btn){
32240 this.defaultButton = btn;
32245 getHeaderFooterHeight : function(safe){
32248 height += this.header.getHeight();
32251 var fm = this.footer.getMargins();
32252 height += (this.footer.getHeight()+fm.top+fm.bottom);
32254 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32255 height += this.centerBg.getPadding("tb");
32260 syncBodyHeight : function()
32262 var bd = this.body, // the text
32263 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32265 var height = this.size.height - this.getHeaderFooterHeight(false);
32266 bd.setHeight(height-bd.getMargins("tb"));
32267 var hh = this.header.getHeight();
32268 var h = this.size.height-hh;
32271 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32272 bw.setHeight(h-cb.getPadding("tb"));
32274 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32275 bd.setWidth(bw.getWidth(true));
32277 this.tabs.syncHeight();
32279 this.tabs.el.repaint();
32285 * Restores the previous state of the dialog if Roo.state is configured.
32286 * @return {Roo.BasicDialog} this
32288 restoreState : function(){
32289 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32290 if(box && box.width){
32291 this.xy = [box.x, box.y];
32292 this.resizeTo(box.width, box.height);
32298 beforeShow : function(){
32300 if(this.fixedcenter){
32301 this.xy = this.el.getCenterXY(true);
32304 Roo.get(document.body).addClass("x-body-masked");
32305 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32308 this.constrainXY();
32312 animShow : function(){
32313 var b = Roo.get(this.animateTarget).getBox();
32314 this.proxy.setSize(b.width, b.height);
32315 this.proxy.setLocation(b.x, b.y);
32317 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32318 true, .35, this.showEl.createDelegate(this));
32322 * Shows the dialog.
32323 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32324 * @return {Roo.BasicDialog} this
32326 show : function(animateTarget){
32327 if (this.fireEvent("beforeshow", this) === false){
32330 if(this.syncHeightBeforeShow){
32331 this.syncBodyHeight();
32332 }else if(this.firstShow){
32333 this.firstShow = false;
32334 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32336 this.animateTarget = animateTarget || this.animateTarget;
32337 if(!this.el.isVisible()){
32339 if(this.animateTarget && Roo.get(this.animateTarget)){
32349 showEl : function(){
32351 this.el.setXY(this.xy);
32353 this.adjustAssets(true);
32356 // IE peekaboo bug - fix found by Dave Fenwick
32360 this.fireEvent("show", this);
32364 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32365 * dialog itself will receive focus.
32367 focus : function(){
32368 if(this.defaultButton){
32369 this.defaultButton.focus();
32371 this.focusEl.focus();
32376 constrainXY : function(){
32377 if(this.constraintoviewport !== false){
32378 if(!this.viewSize){
32379 if(this.container){
32380 var s = this.container.getSize();
32381 this.viewSize = [s.width, s.height];
32383 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32386 var s = Roo.get(this.container||document).getScroll();
32388 var x = this.xy[0], y = this.xy[1];
32389 var w = this.size.width, h = this.size.height;
32390 var vw = this.viewSize[0], vh = this.viewSize[1];
32391 // only move it if it needs it
32393 // first validate right/bottom
32394 if(x + w > vw+s.left){
32398 if(y + h > vh+s.top){
32402 // then make sure top/left isn't negative
32414 if(this.isVisible()){
32415 this.el.setLocation(x, y);
32416 this.adjustAssets();
32423 onDrag : function(){
32424 if(!this.proxyDrag){
32425 this.xy = this.el.getXY();
32426 this.adjustAssets();
32431 adjustAssets : function(doShow){
32432 var x = this.xy[0], y = this.xy[1];
32433 var w = this.size.width, h = this.size.height;
32434 if(doShow === true){
32436 this.shadow.show(this.el);
32442 if(this.shadow && this.shadow.isVisible()){
32443 this.shadow.show(this.el);
32445 if(this.shim && this.shim.isVisible()){
32446 this.shim.setBounds(x, y, w, h);
32451 adjustViewport : function(w, h){
32453 w = Roo.lib.Dom.getViewWidth();
32454 h = Roo.lib.Dom.getViewHeight();
32457 this.viewSize = [w, h];
32458 if(this.modal && this.mask.isVisible()){
32459 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32460 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32462 if(this.isVisible()){
32463 this.constrainXY();
32468 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32469 * shadow, proxy, mask, etc.) Also removes all event listeners.
32470 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32472 destroy : function(removeEl){
32473 if(this.isVisible()){
32474 this.animateTarget = null;
32477 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32479 this.tabs.destroy(removeEl);
32492 for(var i = 0, len = this.buttons.length; i < len; i++){
32493 this.buttons[i].destroy();
32496 this.el.removeAllListeners();
32497 if(removeEl === true){
32498 this.el.update("");
32501 Roo.DialogManager.unregister(this);
32505 startMove : function(){
32506 if(this.proxyDrag){
32509 if(this.constraintoviewport !== false){
32510 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32515 endMove : function(){
32516 if(!this.proxyDrag){
32517 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32519 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32522 this.refreshSize();
32523 this.adjustAssets();
32525 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32529 * Brings this dialog to the front of any other visible dialogs
32530 * @return {Roo.BasicDialog} this
32532 toFront : function(){
32533 Roo.DialogManager.bringToFront(this);
32538 * Sends this dialog to the back (under) of any other visible dialogs
32539 * @return {Roo.BasicDialog} this
32541 toBack : function(){
32542 Roo.DialogManager.sendToBack(this);
32547 * Centers this dialog in the viewport
32548 * @return {Roo.BasicDialog} this
32550 center : function(){
32551 var xy = this.el.getCenterXY(true);
32552 this.moveTo(xy[0], xy[1]);
32557 * Moves the dialog's top-left corner to the specified point
32558 * @param {Number} x
32559 * @param {Number} y
32560 * @return {Roo.BasicDialog} this
32562 moveTo : function(x, y){
32564 if(this.isVisible()){
32565 this.el.setXY(this.xy);
32566 this.adjustAssets();
32572 * Aligns the dialog to the specified element
32573 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32574 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32575 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32576 * @return {Roo.BasicDialog} this
32578 alignTo : function(element, position, offsets){
32579 this.xy = this.el.getAlignToXY(element, position, offsets);
32580 if(this.isVisible()){
32581 this.el.setXY(this.xy);
32582 this.adjustAssets();
32588 * Anchors an element to another element and realigns it when the window is resized.
32589 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32590 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
32591 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32592 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
32593 * is a number, it is used as the buffer delay (defaults to 50ms).
32594 * @return {Roo.BasicDialog} this
32596 anchorTo : function(el, alignment, offsets, monitorScroll){
32597 var action = function(){
32598 this.alignTo(el, alignment, offsets);
32600 Roo.EventManager.onWindowResize(action, this);
32601 var tm = typeof monitorScroll;
32602 if(tm != 'undefined'){
32603 Roo.EventManager.on(window, 'scroll', action, this,
32604 {buffer: tm == 'number' ? monitorScroll : 50});
32611 * Returns true if the dialog is visible
32612 * @return {Boolean}
32614 isVisible : function(){
32615 return this.el.isVisible();
32619 animHide : function(callback){
32620 var b = Roo.get(this.animateTarget).getBox();
32622 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
32624 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
32625 this.hideEl.createDelegate(this, [callback]));
32629 * Hides the dialog.
32630 * @param {Function} callback (optional) Function to call when the dialog is hidden
32631 * @return {Roo.BasicDialog} this
32633 hide : function(callback){
32634 if (this.fireEvent("beforehide", this) === false){
32638 this.shadow.hide();
32643 // sometimes animateTarget seems to get set.. causing problems...
32644 // this just double checks..
32645 if(this.animateTarget && Roo.get(this.animateTarget)) {
32646 this.animHide(callback);
32649 this.hideEl(callback);
32655 hideEl : function(callback){
32659 Roo.get(document.body).removeClass("x-body-masked");
32661 this.fireEvent("hide", this);
32662 if(typeof callback == "function"){
32668 hideAction : function(){
32669 this.setLeft("-10000px");
32670 this.setTop("-10000px");
32671 this.setStyle("visibility", "hidden");
32675 refreshSize : function(){
32676 this.size = this.el.getSize();
32677 this.xy = this.el.getXY();
32678 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
32682 // z-index is managed by the DialogManager and may be overwritten at any time
32683 setZIndex : function(index){
32685 this.mask.setStyle("z-index", index);
32688 this.shim.setStyle("z-index", ++index);
32691 this.shadow.setZIndex(++index);
32693 this.el.setStyle("z-index", ++index);
32695 this.proxy.setStyle("z-index", ++index);
32698 this.resizer.proxy.setStyle("z-index", ++index);
32701 this.lastZIndex = index;
32705 * Returns the element for this dialog
32706 * @return {Roo.Element} The underlying dialog Element
32708 getEl : function(){
32714 * @class Roo.DialogManager
32715 * Provides global access to BasicDialogs that have been created and
32716 * support for z-indexing (layering) multiple open dialogs.
32718 Roo.DialogManager = function(){
32720 var accessList = [];
32724 var sortDialogs = function(d1, d2){
32725 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
32729 var orderDialogs = function(){
32730 accessList.sort(sortDialogs);
32731 var seed = Roo.DialogManager.zseed;
32732 for(var i = 0, len = accessList.length; i < len; i++){
32733 var dlg = accessList[i];
32735 dlg.setZIndex(seed + (i*10));
32742 * The starting z-index for BasicDialogs (defaults to 9000)
32743 * @type Number The z-index value
32748 register : function(dlg){
32749 list[dlg.id] = dlg;
32750 accessList.push(dlg);
32754 unregister : function(dlg){
32755 delete list[dlg.id];
32758 if(!accessList.indexOf){
32759 for( i = 0, len = accessList.length; i < len; i++){
32760 if(accessList[i] == dlg){
32761 accessList.splice(i, 1);
32766 i = accessList.indexOf(dlg);
32768 accessList.splice(i, 1);
32774 * Gets a registered dialog by id
32775 * @param {String/Object} id The id of the dialog or a dialog
32776 * @return {Roo.BasicDialog} this
32778 get : function(id){
32779 return typeof id == "object" ? id : list[id];
32783 * Brings the specified dialog to the front
32784 * @param {String/Object} dlg The id of the dialog or a dialog
32785 * @return {Roo.BasicDialog} this
32787 bringToFront : function(dlg){
32788 dlg = this.get(dlg);
32791 dlg._lastAccess = new Date().getTime();
32798 * Sends the specified dialog to the back
32799 * @param {String/Object} dlg The id of the dialog or a dialog
32800 * @return {Roo.BasicDialog} this
32802 sendToBack : function(dlg){
32803 dlg = this.get(dlg);
32804 dlg._lastAccess = -(new Date().getTime());
32810 * Hides all dialogs
32812 hideAll : function(){
32813 for(var id in list){
32814 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
32823 * @class Roo.LayoutDialog
32824 * @extends Roo.BasicDialog
32825 * Dialog which provides adjustments for working with a layout in a Dialog.
32826 * Add your necessary layout config options to the dialog's config.<br>
32827 * Example usage (including a nested layout):
32830 dialog = new Roo.LayoutDialog("download-dlg", {
32839 // layout config merges with the dialog config
32841 tabPosition: "top",
32842 alwaysShowTabs: true
32845 dialog.addKeyListener(27, dialog.hide, dialog);
32846 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
32847 dialog.addButton("Build It!", this.getDownload, this);
32849 // we can even add nested layouts
32850 var innerLayout = new Roo.BorderLayout("dl-inner", {
32860 innerLayout.beginUpdate();
32861 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
32862 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
32863 innerLayout.endUpdate(true);
32865 var layout = dialog.getLayout();
32866 layout.beginUpdate();
32867 layout.add("center", new Roo.ContentPanel("standard-panel",
32868 {title: "Download the Source", fitToFrame:true}));
32869 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
32870 {title: "Build your own roo.js"}));
32871 layout.getRegion("center").showPanel(sp);
32872 layout.endUpdate();
32876 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
32877 * @param {Object} config configuration options
32879 Roo.LayoutDialog = function(el, cfg){
32882 if (typeof(cfg) == 'undefined') {
32883 config = Roo.apply({}, el);
32884 // not sure why we use documentElement here.. - it should always be body.
32885 // IE7 borks horribly if we use documentElement.
32886 // webkit also does not like documentElement - it creates a body element...
32887 el = Roo.get( document.body || document.documentElement ).createChild();
32888 //config.autoCreate = true;
32892 config.autoTabs = false;
32893 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
32894 this.body.setStyle({overflow:"hidden", position:"relative"});
32895 this.layout = new Roo.BorderLayout(this.body.dom, config);
32896 this.layout.monitorWindowResize = false;
32897 this.el.addClass("x-dlg-auto-layout");
32898 // fix case when center region overwrites center function
32899 this.center = Roo.BasicDialog.prototype.center;
32900 this.on("show", this.layout.layout, this.layout, true);
32901 if (config.items) {
32902 var xitems = config.items;
32903 delete config.items;
32904 Roo.each(xitems, this.addxtype, this);
32909 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
32911 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
32914 endUpdate : function(){
32915 this.layout.endUpdate();
32919 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
32922 beginUpdate : function(){
32923 this.layout.beginUpdate();
32927 * Get the BorderLayout for this dialog
32928 * @return {Roo.BorderLayout}
32930 getLayout : function(){
32931 return this.layout;
32934 showEl : function(){
32935 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
32937 this.layout.layout();
32942 // Use the syncHeightBeforeShow config option to control this automatically
32943 syncBodyHeight : function(){
32944 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
32945 if(this.layout){this.layout.layout();}
32949 * Add an xtype element (actually adds to the layout.)
32950 * @return {Object} xdata xtype object data.
32953 addxtype : function(c) {
32954 return this.layout.addxtype(c);
32958 * Ext JS Library 1.1.1
32959 * Copyright(c) 2006-2007, Ext JS, LLC.
32961 * Originally Released Under LGPL - original licence link has changed is not relivant.
32964 * <script type="text/javascript">
32968 * @class Roo.MessageBox
32969 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
32973 Roo.Msg.alert('Status', 'Changes saved successfully.');
32975 // Prompt for user data:
32976 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
32978 // process text value...
32982 // Show a dialog using config options:
32984 title:'Save Changes?',
32985 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
32986 buttons: Roo.Msg.YESNOCANCEL,
32993 Roo.MessageBox = function(){
32994 var dlg, opt, mask, waitTimer;
32995 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
32996 var buttons, activeTextEl, bwidth;
32999 var handleButton = function(button){
33001 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33005 var handleHide = function(){
33006 if(opt && opt.cls){
33007 dlg.el.removeClass(opt.cls);
33010 Roo.TaskMgr.stop(waitTimer);
33016 var updateButtons = function(b){
33019 buttons["ok"].hide();
33020 buttons["cancel"].hide();
33021 buttons["yes"].hide();
33022 buttons["no"].hide();
33023 dlg.footer.dom.style.display = 'none';
33026 dlg.footer.dom.style.display = '';
33027 for(var k in buttons){
33028 if(typeof buttons[k] != "function"){
33031 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33032 width += buttons[k].el.getWidth()+15;
33042 var handleEsc = function(d, k, e){
33043 if(opt && opt.closable !== false){
33053 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33054 * @return {Roo.BasicDialog} The BasicDialog element
33056 getDialog : function(){
33058 dlg = new Roo.BasicDialog("x-msg-box", {
33063 constraintoviewport:false,
33065 collapsible : false,
33068 width:400, height:100,
33069 buttonAlign:"center",
33070 closeClick : function(){
33071 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33072 handleButton("no");
33074 handleButton("cancel");
33078 dlg.on("hide", handleHide);
33080 dlg.addKeyListener(27, handleEsc);
33082 var bt = this.buttonText;
33083 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33084 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33085 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33086 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33087 bodyEl = dlg.body.createChild({
33089 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>'
33091 msgEl = bodyEl.dom.firstChild;
33092 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33093 textboxEl.enableDisplayMode();
33094 textboxEl.addKeyListener([10,13], function(){
33095 if(dlg.isVisible() && opt && opt.buttons){
33096 if(opt.buttons.ok){
33097 handleButton("ok");
33098 }else if(opt.buttons.yes){
33099 handleButton("yes");
33103 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33104 textareaEl.enableDisplayMode();
33105 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33106 progressEl.enableDisplayMode();
33107 var pf = progressEl.dom.firstChild;
33109 pp = Roo.get(pf.firstChild);
33110 pp.setHeight(pf.offsetHeight);
33118 * Updates the message box body text
33119 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33120 * the XHTML-compliant non-breaking space character '&#160;')
33121 * @return {Roo.MessageBox} This message box
33123 updateText : function(text){
33124 if(!dlg.isVisible() && !opt.width){
33125 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33127 msgEl.innerHTML = text || ' ';
33129 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33130 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33132 Math.min(opt.width || cw , this.maxWidth),
33133 Math.max(opt.minWidth || this.minWidth, bwidth)
33136 activeTextEl.setWidth(w);
33138 if(dlg.isVisible()){
33139 dlg.fixedcenter = false;
33141 // to big, make it scroll. = But as usual stupid IE does not support
33144 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33145 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33146 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33148 bodyEl.dom.style.height = '';
33149 bodyEl.dom.style.overflowY = '';
33152 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33154 bodyEl.dom.style.overflowX = '';
33157 dlg.setContentSize(w, bodyEl.getHeight());
33158 if(dlg.isVisible()){
33159 dlg.fixedcenter = true;
33165 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33166 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33167 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33168 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33169 * @return {Roo.MessageBox} This message box
33171 updateProgress : function(value, text){
33173 this.updateText(text);
33175 if (pp) { // weird bug on my firefox - for some reason this is not defined
33176 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33182 * Returns true if the message box is currently displayed
33183 * @return {Boolean} True if the message box is visible, else false
33185 isVisible : function(){
33186 return dlg && dlg.isVisible();
33190 * Hides the message box if it is displayed
33193 if(this.isVisible()){
33199 * Displays a new message box, or reinitializes an existing message box, based on the config options
33200 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33201 * The following config object properties are supported:
33203 Property Type Description
33204 ---------- --------------- ------------------------------------------------------------------------------------
33205 animEl String/Element An id or Element from which the message box should animate as it opens and
33206 closes (defaults to undefined)
33207 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33208 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33209 closable Boolean False to hide the top-right close button (defaults to true). Note that
33210 progress and wait dialogs will ignore this property and always hide the
33211 close button as they can only be closed programmatically.
33212 cls String A custom CSS class to apply to the message box element
33213 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33214 displayed (defaults to 75)
33215 fn Function A callback function to execute after closing the dialog. The arguments to the
33216 function will be btn (the name of the button that was clicked, if applicable,
33217 e.g. "ok"), and text (the value of the active text field, if applicable).
33218 Progress and wait dialogs will ignore this option since they do not respond to
33219 user actions and can only be closed programmatically, so any required function
33220 should be called by the same code after it closes the dialog.
33221 icon String A CSS class that provides a background image to be used as an icon for
33222 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33223 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33224 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33225 modal Boolean False to allow user interaction with the page while the message box is
33226 displayed (defaults to true)
33227 msg String A string that will replace the existing message box body text (defaults
33228 to the XHTML-compliant non-breaking space character ' ')
33229 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33230 progress Boolean True to display a progress bar (defaults to false)
33231 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33232 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33233 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33234 title String The title text
33235 value String The string value to set into the active textbox element if displayed
33236 wait Boolean True to display a progress bar (defaults to false)
33237 width Number The width of the dialog in pixels
33244 msg: 'Please enter your address:',
33246 buttons: Roo.MessageBox.OKCANCEL,
33249 animEl: 'addAddressBtn'
33252 * @param {Object} config Configuration options
33253 * @return {Roo.MessageBox} This message box
33255 show : function(options)
33258 // this causes nightmares if you show one dialog after another
33259 // especially on callbacks..
33261 if(this.isVisible()){
33264 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33265 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33266 Roo.log("New Dialog Message:" + options.msg )
33267 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33268 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33271 var d = this.getDialog();
33273 d.setTitle(opt.title || " ");
33274 d.close.setDisplayed(opt.closable !== false);
33275 activeTextEl = textboxEl;
33276 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33281 textareaEl.setHeight(typeof opt.multiline == "number" ?
33282 opt.multiline : this.defaultTextHeight);
33283 activeTextEl = textareaEl;
33292 progressEl.setDisplayed(opt.progress === true);
33293 this.updateProgress(0);
33294 activeTextEl.dom.value = opt.value || "";
33296 dlg.setDefaultButton(activeTextEl);
33298 var bs = opt.buttons;
33301 db = buttons["ok"];
33302 }else if(bs && bs.yes){
33303 db = buttons["yes"];
33305 dlg.setDefaultButton(db);
33307 bwidth = updateButtons(opt.buttons);
33308 this.updateText(opt.msg);
33310 d.el.addClass(opt.cls);
33312 d.proxyDrag = opt.proxyDrag === true;
33313 d.modal = opt.modal !== false;
33314 d.mask = opt.modal !== false ? mask : false;
33315 if(!d.isVisible()){
33316 // force it to the end of the z-index stack so it gets a cursor in FF
33317 document.body.appendChild(dlg.el.dom);
33318 d.animateTarget = null;
33319 d.show(options.animEl);
33325 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33326 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33327 * and closing the message box when the process is complete.
33328 * @param {String} title The title bar text
33329 * @param {String} msg The message box body text
33330 * @return {Roo.MessageBox} This message box
33332 progress : function(title, msg){
33339 minWidth: this.minProgressWidth,
33346 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33347 * If a callback function is passed it will be called after the user clicks the button, and the
33348 * id of the button that was clicked will be passed as the only parameter to the callback
33349 * (could also be the top-right close button).
33350 * @param {String} title The title bar text
33351 * @param {String} msg The message box body text
33352 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33353 * @param {Object} scope (optional) The scope of the callback function
33354 * @return {Roo.MessageBox} This message box
33356 alert : function(title, msg, fn, scope){
33369 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33370 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33371 * You are responsible for closing the message box when the process is complete.
33372 * @param {String} msg The message box body text
33373 * @param {String} title (optional) The title bar text
33374 * @return {Roo.MessageBox} This message box
33376 wait : function(msg, title){
33387 waitTimer = Roo.TaskMgr.start({
33389 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33397 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33398 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33399 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33400 * @param {String} title The title bar text
33401 * @param {String} msg The message box body text
33402 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33403 * @param {Object} scope (optional) The scope of the callback function
33404 * @return {Roo.MessageBox} This message box
33406 confirm : function(title, msg, fn, scope){
33410 buttons: this.YESNO,
33419 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33420 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33421 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33422 * (could also be the top-right close button) and the text that was entered will be passed as the two
33423 * parameters to the callback.
33424 * @param {String} title The title bar text
33425 * @param {String} msg The message box body text
33426 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33427 * @param {Object} scope (optional) The scope of the callback function
33428 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33429 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33430 * @return {Roo.MessageBox} This message box
33432 prompt : function(title, msg, fn, scope, multiline){
33436 buttons: this.OKCANCEL,
33441 multiline: multiline,
33448 * Button config that displays a single OK button
33453 * Button config that displays Yes and No buttons
33456 YESNO : {yes:true, no:true},
33458 * Button config that displays OK and Cancel buttons
33461 OKCANCEL : {ok:true, cancel:true},
33463 * Button config that displays Yes, No and Cancel buttons
33466 YESNOCANCEL : {yes:true, no:true, cancel:true},
33469 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33472 defaultTextHeight : 75,
33474 * The maximum width in pixels of the message box (defaults to 600)
33479 * The minimum width in pixels of the message box (defaults to 100)
33484 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33485 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33488 minProgressWidth : 250,
33490 * An object containing the default button text strings that can be overriden for localized language support.
33491 * Supported properties are: ok, cancel, yes and no.
33492 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33505 * Shorthand for {@link Roo.MessageBox}
33507 Roo.Msg = Roo.MessageBox;/*
33509 * Ext JS Library 1.1.1
33510 * Copyright(c) 2006-2007, Ext JS, LLC.
33512 * Originally Released Under LGPL - original licence link has changed is not relivant.
33515 * <script type="text/javascript">
33518 * @class Roo.QuickTips
33519 * Provides attractive and customizable tooltips for any element.
33522 Roo.QuickTips = function(){
33523 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33524 var ce, bd, xy, dd;
33525 var visible = false, disabled = true, inited = false;
33526 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33528 var onOver = function(e){
33532 var t = e.getTarget();
33533 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33536 if(ce && t == ce.el){
33537 clearTimeout(hideProc);
33540 if(t && tagEls[t.id]){
33541 tagEls[t.id].el = t;
33542 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33545 var ttp, et = Roo.fly(t);
33546 var ns = cfg.namespace;
33547 if(tm.interceptTitles && t.title){
33550 t.removeAttribute("title");
33551 e.preventDefault();
33553 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33556 showProc = show.defer(tm.showDelay, tm, [{
33559 width: et.getAttributeNS(ns, cfg.width),
33560 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33561 title: et.getAttributeNS(ns, cfg.title),
33562 cls: et.getAttributeNS(ns, cfg.cls)
33567 var onOut = function(e){
33568 clearTimeout(showProc);
33569 var t = e.getTarget();
33570 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33571 hideProc = setTimeout(hide, tm.hideDelay);
33575 var onMove = function(e){
33581 if(tm.trackMouse && ce){
33586 var onDown = function(e){
33587 clearTimeout(showProc);
33588 clearTimeout(hideProc);
33590 if(tm.hideOnClick){
33593 tm.enable.defer(100, tm);
33598 var getPad = function(){
33599 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
33602 var show = function(o){
33606 clearTimeout(dismissProc);
33608 if(removeCls){ // in case manually hidden
33609 el.removeClass(removeCls);
33613 el.addClass(ce.cls);
33614 removeCls = ce.cls;
33617 tipTitle.update(ce.title);
33620 tipTitle.update('');
33623 el.dom.style.width = tm.maxWidth+'px';
33624 //tipBody.dom.style.width = '';
33625 tipBodyText.update(o.text);
33626 var p = getPad(), w = ce.width;
33628 var td = tipBodyText.dom;
33629 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
33630 if(aw > tm.maxWidth){
33632 }else if(aw < tm.minWidth){
33638 //tipBody.setWidth(w);
33639 el.setWidth(parseInt(w, 10) + p);
33640 if(ce.autoHide === false){
33641 close.setDisplayed(true);
33646 close.setDisplayed(false);
33652 el.avoidY = xy[1]-18;
33657 el.setStyle("visibility", "visible");
33658 el.fadeIn({callback: afterShow});
33664 var afterShow = function(){
33668 if(tm.autoDismiss && ce.autoHide !== false){
33669 dismissProc = setTimeout(hide, tm.autoDismissDelay);
33674 var hide = function(noanim){
33675 clearTimeout(dismissProc);
33676 clearTimeout(hideProc);
33678 if(el.isVisible()){
33680 if(noanim !== true && tm.animate){
33681 el.fadeOut({callback: afterHide});
33688 var afterHide = function(){
33691 el.removeClass(removeCls);
33698 * @cfg {Number} minWidth
33699 * The minimum width of the quick tip (defaults to 40)
33703 * @cfg {Number} maxWidth
33704 * The maximum width of the quick tip (defaults to 300)
33708 * @cfg {Boolean} interceptTitles
33709 * True to automatically use the element's DOM title value if available (defaults to false)
33711 interceptTitles : false,
33713 * @cfg {Boolean} trackMouse
33714 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
33716 trackMouse : false,
33718 * @cfg {Boolean} hideOnClick
33719 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
33721 hideOnClick : true,
33723 * @cfg {Number} showDelay
33724 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
33728 * @cfg {Number} hideDelay
33729 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
33733 * @cfg {Boolean} autoHide
33734 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
33735 * Used in conjunction with hideDelay.
33740 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
33741 * (defaults to true). Used in conjunction with autoDismissDelay.
33743 autoDismiss : true,
33746 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
33748 autoDismissDelay : 5000,
33750 * @cfg {Boolean} animate
33751 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
33756 * @cfg {String} title
33757 * Title text to display (defaults to ''). This can be any valid HTML markup.
33761 * @cfg {String} text
33762 * Body text to display (defaults to ''). This can be any valid HTML markup.
33766 * @cfg {String} cls
33767 * A CSS class to apply to the base quick tip element (defaults to '').
33771 * @cfg {Number} width
33772 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
33773 * minWidth or maxWidth.
33778 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
33779 * or display QuickTips in a page.
33782 tm = Roo.QuickTips;
33783 cfg = tm.tagConfig;
33785 if(!Roo.isReady){ // allow calling of init() before onReady
33786 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
33789 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
33790 el.fxDefaults = {stopFx: true};
33791 // maximum custom styling
33792 //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>');
33793 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>');
33794 tipTitle = el.child('h3');
33795 tipTitle.enableDisplayMode("block");
33796 tipBody = el.child('div.x-tip-bd');
33797 tipBodyText = el.child('div.x-tip-bd-inner');
33798 //bdLeft = el.child('div.x-tip-bd-left');
33799 //bdRight = el.child('div.x-tip-bd-right');
33800 close = el.child('div.x-tip-close');
33801 close.enableDisplayMode("block");
33802 close.on("click", hide);
33803 var d = Roo.get(document);
33804 d.on("mousedown", onDown);
33805 d.on("mouseover", onOver);
33806 d.on("mouseout", onOut);
33807 d.on("mousemove", onMove);
33808 esc = d.addKeyListener(27, hide);
33811 dd = el.initDD("default", null, {
33812 onDrag : function(){
33816 dd.setHandleElId(tipTitle.id);
33825 * Configures a new quick tip instance and assigns it to a target element. The following config options
33828 Property Type Description
33829 ---------- --------------------- ------------------------------------------------------------------------
33830 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
33832 * @param {Object} config The config object
33834 register : function(config){
33835 var cs = config instanceof Array ? config : arguments;
33836 for(var i = 0, len = cs.length; i < len; i++) {
33838 var target = c.target;
33840 if(target instanceof Array){
33841 for(var j = 0, jlen = target.length; j < jlen; j++){
33842 tagEls[target[j]] = c;
33845 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
33852 * Removes this quick tip from its element and destroys it.
33853 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
33855 unregister : function(el){
33856 delete tagEls[Roo.id(el)];
33860 * Enable this quick tip.
33862 enable : function(){
33863 if(inited && disabled){
33865 if(locks.length < 1){
33872 * Disable this quick tip.
33874 disable : function(){
33876 clearTimeout(showProc);
33877 clearTimeout(hideProc);
33878 clearTimeout(dismissProc);
33886 * Returns true if the quick tip is enabled, else false.
33888 isEnabled : function(){
33894 namespace : "roo", // was ext?? this may break..
33895 alt_namespace : "ext",
33896 attribute : "qtip",
33906 // backwards compat
33907 Roo.QuickTips.tips = Roo.QuickTips.register;/*
33909 * Ext JS Library 1.1.1
33910 * Copyright(c) 2006-2007, Ext JS, LLC.
33912 * Originally Released Under LGPL - original licence link has changed is not relivant.
33915 * <script type="text/javascript">
33920 * @class Roo.tree.TreePanel
33921 * @extends Roo.data.Tree
33923 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
33924 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
33925 * @cfg {Boolean} enableDD true to enable drag and drop
33926 * @cfg {Boolean} enableDrag true to enable just drag
33927 * @cfg {Boolean} enableDrop true to enable just drop
33928 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
33929 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
33930 * @cfg {String} ddGroup The DD group this TreePanel belongs to
33931 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
33932 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
33933 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
33934 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
33935 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
33936 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
33937 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
33938 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
33939 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
33940 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
33941 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
33942 * @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>
33943 * @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>
33946 * @param {String/HTMLElement/Element} el The container element
33947 * @param {Object} config
33949 Roo.tree.TreePanel = function(el, config){
33951 var loader = false;
33953 root = config.root;
33954 delete config.root;
33956 if (config.loader) {
33957 loader = config.loader;
33958 delete config.loader;
33961 Roo.apply(this, config);
33962 Roo.tree.TreePanel.superclass.constructor.call(this);
33963 this.el = Roo.get(el);
33964 this.el.addClass('x-tree');
33965 //console.log(root);
33967 this.setRootNode( Roo.factory(root, Roo.tree));
33970 this.loader = Roo.factory(loader, Roo.tree);
33973 * Read-only. The id of the container element becomes this TreePanel's id.
33975 this.id = this.el.id;
33978 * @event beforeload
33979 * Fires before a node is loaded, return false to cancel
33980 * @param {Node} node The node being loaded
33982 "beforeload" : true,
33985 * Fires when a node is loaded
33986 * @param {Node} node The node that was loaded
33990 * @event textchange
33991 * Fires when the text for a node is changed
33992 * @param {Node} node The node
33993 * @param {String} text The new text
33994 * @param {String} oldText The old text
33996 "textchange" : true,
33998 * @event beforeexpand
33999 * Fires before a node is expanded, return false to cancel.
34000 * @param {Node} node The node
34001 * @param {Boolean} deep
34002 * @param {Boolean} anim
34004 "beforeexpand" : true,
34006 * @event beforecollapse
34007 * Fires before a node is collapsed, return false to cancel.
34008 * @param {Node} node The node
34009 * @param {Boolean} deep
34010 * @param {Boolean} anim
34012 "beforecollapse" : true,
34015 * Fires when a node is expanded
34016 * @param {Node} node The node
34020 * @event disabledchange
34021 * Fires when the disabled status of a node changes
34022 * @param {Node} node The node
34023 * @param {Boolean} disabled
34025 "disabledchange" : true,
34028 * Fires when a node is collapsed
34029 * @param {Node} node The node
34033 * @event beforeclick
34034 * Fires before click processing on a node. Return false to cancel the default action.
34035 * @param {Node} node The node
34036 * @param {Roo.EventObject} e The event object
34038 "beforeclick":true,
34040 * @event checkchange
34041 * Fires when a node with a checkbox's checked property changes
34042 * @param {Node} this This node
34043 * @param {Boolean} checked
34045 "checkchange":true,
34048 * Fires when a node is clicked
34049 * @param {Node} node The node
34050 * @param {Roo.EventObject} e The event object
34055 * Fires when a node is double clicked
34056 * @param {Node} node The node
34057 * @param {Roo.EventObject} e The event object
34061 * @event contextmenu
34062 * Fires when a node is right clicked
34063 * @param {Node} node The node
34064 * @param {Roo.EventObject} e The event object
34066 "contextmenu":true,
34068 * @event beforechildrenrendered
34069 * Fires right before the child nodes for a node are rendered
34070 * @param {Node} node The node
34072 "beforechildrenrendered":true,
34075 * Fires when a node starts being dragged
34076 * @param {Roo.tree.TreePanel} this
34077 * @param {Roo.tree.TreeNode} node
34078 * @param {event} e The raw browser event
34080 "startdrag" : true,
34083 * Fires when a drag operation is complete
34084 * @param {Roo.tree.TreePanel} this
34085 * @param {Roo.tree.TreeNode} node
34086 * @param {event} e The raw browser event
34091 * Fires when a dragged node is dropped on a valid DD target
34092 * @param {Roo.tree.TreePanel} this
34093 * @param {Roo.tree.TreeNode} node
34094 * @param {DD} dd The dd it was dropped on
34095 * @param {event} e The raw browser event
34099 * @event beforenodedrop
34100 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34101 * passed to handlers has the following properties:<br />
34102 * <ul style="padding:5px;padding-left:16px;">
34103 * <li>tree - The TreePanel</li>
34104 * <li>target - The node being targeted for the drop</li>
34105 * <li>data - The drag data from the drag source</li>
34106 * <li>point - The point of the drop - append, above or below</li>
34107 * <li>source - The drag source</li>
34108 * <li>rawEvent - Raw mouse event</li>
34109 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34110 * to be inserted by setting them on this object.</li>
34111 * <li>cancel - Set this to true to cancel the drop.</li>
34113 * @param {Object} dropEvent
34115 "beforenodedrop" : true,
34118 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34119 * passed to handlers has the following properties:<br />
34120 * <ul style="padding:5px;padding-left:16px;">
34121 * <li>tree - The TreePanel</li>
34122 * <li>target - The node being targeted for the drop</li>
34123 * <li>data - The drag data from the drag source</li>
34124 * <li>point - The point of the drop - append, above or below</li>
34125 * <li>source - The drag source</li>
34126 * <li>rawEvent - Raw mouse event</li>
34127 * <li>dropNode - Dropped node(s).</li>
34129 * @param {Object} dropEvent
34133 * @event nodedragover
34134 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34135 * passed to handlers has the following properties:<br />
34136 * <ul style="padding:5px;padding-left:16px;">
34137 * <li>tree - The TreePanel</li>
34138 * <li>target - The node being targeted for the drop</li>
34139 * <li>data - The drag data from the drag source</li>
34140 * <li>point - The point of the drop - append, above or below</li>
34141 * <li>source - The drag source</li>
34142 * <li>rawEvent - Raw mouse event</li>
34143 * <li>dropNode - Drop node(s) provided by the source.</li>
34144 * <li>cancel - Set this to true to signal drop not allowed.</li>
34146 * @param {Object} dragOverEvent
34148 "nodedragover" : true
34151 if(this.singleExpand){
34152 this.on("beforeexpand", this.restrictExpand, this);
34155 this.editor.tree = this;
34156 this.editor = Roo.factory(this.editor, Roo.tree);
34159 if (this.selModel) {
34160 this.selModel = Roo.factory(this.selModel, Roo.tree);
34164 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34165 rootVisible : true,
34166 animate: Roo.enableFx,
34169 hlDrop : Roo.enableFx,
34173 rendererTip: false,
34175 restrictExpand : function(node){
34176 var p = node.parentNode;
34178 if(p.expandedChild && p.expandedChild.parentNode == p){
34179 p.expandedChild.collapse();
34181 p.expandedChild = node;
34185 // private override
34186 setRootNode : function(node){
34187 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34188 if(!this.rootVisible){
34189 node.ui = new Roo.tree.RootTreeNodeUI(node);
34195 * Returns the container element for this TreePanel
34197 getEl : function(){
34202 * Returns the default TreeLoader for this TreePanel
34204 getLoader : function(){
34205 return this.loader;
34211 expandAll : function(){
34212 this.root.expand(true);
34216 * Collapse all nodes
34218 collapseAll : function(){
34219 this.root.collapse(true);
34223 * Returns the selection model used by this TreePanel
34225 getSelectionModel : function(){
34226 if(!this.selModel){
34227 this.selModel = new Roo.tree.DefaultSelectionModel();
34229 return this.selModel;
34233 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34234 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34235 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34238 getChecked : function(a, startNode){
34239 startNode = startNode || this.root;
34241 var f = function(){
34242 if(this.attributes.checked){
34243 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34246 startNode.cascade(f);
34251 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34252 * @param {String} path
34253 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34254 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34255 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34257 expandPath : function(path, attr, callback){
34258 attr = attr || "id";
34259 var keys = path.split(this.pathSeparator);
34260 var curNode = this.root;
34261 if(curNode.attributes[attr] != keys[1]){ // invalid root
34263 callback(false, null);
34268 var f = function(){
34269 if(++index == keys.length){
34271 callback(true, curNode);
34275 var c = curNode.findChild(attr, keys[index]);
34278 callback(false, curNode);
34283 c.expand(false, false, f);
34285 curNode.expand(false, false, f);
34289 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34290 * @param {String} path
34291 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34292 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34293 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34295 selectPath : function(path, attr, callback){
34296 attr = attr || "id";
34297 var keys = path.split(this.pathSeparator);
34298 var v = keys.pop();
34299 if(keys.length > 0){
34300 var f = function(success, node){
34301 if(success && node){
34302 var n = node.findChild(attr, v);
34308 }else if(callback){
34309 callback(false, n);
34313 callback(false, n);
34317 this.expandPath(keys.join(this.pathSeparator), attr, f);
34319 this.root.select();
34321 callback(true, this.root);
34326 getTreeEl : function(){
34331 * Trigger rendering of this TreePanel
34333 render : function(){
34334 if (this.innerCt) {
34335 return this; // stop it rendering more than once!!
34338 this.innerCt = this.el.createChild({tag:"ul",
34339 cls:"x-tree-root-ct " +
34340 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34342 if(this.containerScroll){
34343 Roo.dd.ScrollManager.register(this.el);
34345 if((this.enableDD || this.enableDrop) && !this.dropZone){
34347 * The dropZone used by this tree if drop is enabled
34348 * @type Roo.tree.TreeDropZone
34350 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34351 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34354 if((this.enableDD || this.enableDrag) && !this.dragZone){
34356 * The dragZone used by this tree if drag is enabled
34357 * @type Roo.tree.TreeDragZone
34359 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34360 ddGroup: this.ddGroup || "TreeDD",
34361 scroll: this.ddScroll
34364 this.getSelectionModel().init(this);
34366 Roo.log("ROOT not set in tree");
34369 this.root.render();
34370 if(!this.rootVisible){
34371 this.root.renderChildren();
34377 * Ext JS Library 1.1.1
34378 * Copyright(c) 2006-2007, Ext JS, LLC.
34380 * Originally Released Under LGPL - original licence link has changed is not relivant.
34383 * <script type="text/javascript">
34388 * @class Roo.tree.DefaultSelectionModel
34389 * @extends Roo.util.Observable
34390 * The default single selection for a TreePanel.
34391 * @param {Object} cfg Configuration
34393 Roo.tree.DefaultSelectionModel = function(cfg){
34394 this.selNode = null;
34400 * @event selectionchange
34401 * Fires when the selected node changes
34402 * @param {DefaultSelectionModel} this
34403 * @param {TreeNode} node the new selection
34405 "selectionchange" : true,
34408 * @event beforeselect
34409 * Fires before the selected node changes, return false to cancel the change
34410 * @param {DefaultSelectionModel} this
34411 * @param {TreeNode} node the new selection
34412 * @param {TreeNode} node the old selection
34414 "beforeselect" : true
34417 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34420 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34421 init : function(tree){
34423 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34424 tree.on("click", this.onNodeClick, this);
34427 onNodeClick : function(node, e){
34428 if (e.ctrlKey && this.selNode == node) {
34429 this.unselect(node);
34437 * @param {TreeNode} node The node to select
34438 * @return {TreeNode} The selected node
34440 select : function(node){
34441 var last = this.selNode;
34442 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34444 last.ui.onSelectedChange(false);
34446 this.selNode = node;
34447 node.ui.onSelectedChange(true);
34448 this.fireEvent("selectionchange", this, node, last);
34455 * @param {TreeNode} node The node to unselect
34457 unselect : function(node){
34458 if(this.selNode == node){
34459 this.clearSelections();
34464 * Clear all selections
34466 clearSelections : function(){
34467 var n = this.selNode;
34469 n.ui.onSelectedChange(false);
34470 this.selNode = null;
34471 this.fireEvent("selectionchange", this, null);
34477 * Get the selected node
34478 * @return {TreeNode} The selected node
34480 getSelectedNode : function(){
34481 return this.selNode;
34485 * Returns true if the node is selected
34486 * @param {TreeNode} node The node to check
34487 * @return {Boolean}
34489 isSelected : function(node){
34490 return this.selNode == node;
34494 * Selects the node above the selected node in the tree, intelligently walking the nodes
34495 * @return TreeNode The new selection
34497 selectPrevious : function(){
34498 var s = this.selNode || this.lastSelNode;
34502 var ps = s.previousSibling;
34504 if(!ps.isExpanded() || ps.childNodes.length < 1){
34505 return this.select(ps);
34507 var lc = ps.lastChild;
34508 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34511 return this.select(lc);
34513 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34514 return this.select(s.parentNode);
34520 * Selects the node above the selected node in the tree, intelligently walking the nodes
34521 * @return TreeNode The new selection
34523 selectNext : function(){
34524 var s = this.selNode || this.lastSelNode;
34528 if(s.firstChild && s.isExpanded()){
34529 return this.select(s.firstChild);
34530 }else if(s.nextSibling){
34531 return this.select(s.nextSibling);
34532 }else if(s.parentNode){
34534 s.parentNode.bubble(function(){
34535 if(this.nextSibling){
34536 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34545 onKeyDown : function(e){
34546 var s = this.selNode || this.lastSelNode;
34547 // undesirable, but required
34552 var k = e.getKey();
34560 this.selectPrevious();
34563 e.preventDefault();
34564 if(s.hasChildNodes()){
34565 if(!s.isExpanded()){
34567 }else if(s.firstChild){
34568 this.select(s.firstChild, e);
34573 e.preventDefault();
34574 if(s.hasChildNodes() && s.isExpanded()){
34576 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
34577 this.select(s.parentNode, e);
34585 * @class Roo.tree.MultiSelectionModel
34586 * @extends Roo.util.Observable
34587 * Multi selection for a TreePanel.
34588 * @param {Object} cfg Configuration
34590 Roo.tree.MultiSelectionModel = function(){
34591 this.selNodes = [];
34595 * @event selectionchange
34596 * Fires when the selected nodes change
34597 * @param {MultiSelectionModel} this
34598 * @param {Array} nodes Array of the selected nodes
34600 "selectionchange" : true
34602 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
34606 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
34607 init : function(tree){
34609 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34610 tree.on("click", this.onNodeClick, this);
34613 onNodeClick : function(node, e){
34614 this.select(node, e, e.ctrlKey);
34619 * @param {TreeNode} node The node to select
34620 * @param {EventObject} e (optional) An event associated with the selection
34621 * @param {Boolean} keepExisting True to retain existing selections
34622 * @return {TreeNode} The selected node
34624 select : function(node, e, keepExisting){
34625 if(keepExisting !== true){
34626 this.clearSelections(true);
34628 if(this.isSelected(node)){
34629 this.lastSelNode = node;
34632 this.selNodes.push(node);
34633 this.selMap[node.id] = node;
34634 this.lastSelNode = node;
34635 node.ui.onSelectedChange(true);
34636 this.fireEvent("selectionchange", this, this.selNodes);
34642 * @param {TreeNode} node The node to unselect
34644 unselect : function(node){
34645 if(this.selMap[node.id]){
34646 node.ui.onSelectedChange(false);
34647 var sn = this.selNodes;
34650 index = sn.indexOf(node);
34652 for(var i = 0, len = sn.length; i < len; i++){
34660 this.selNodes.splice(index, 1);
34662 delete this.selMap[node.id];
34663 this.fireEvent("selectionchange", this, this.selNodes);
34668 * Clear all selections
34670 clearSelections : function(suppressEvent){
34671 var sn = this.selNodes;
34673 for(var i = 0, len = sn.length; i < len; i++){
34674 sn[i].ui.onSelectedChange(false);
34676 this.selNodes = [];
34678 if(suppressEvent !== true){
34679 this.fireEvent("selectionchange", this, this.selNodes);
34685 * Returns true if the node is selected
34686 * @param {TreeNode} node The node to check
34687 * @return {Boolean}
34689 isSelected : function(node){
34690 return this.selMap[node.id] ? true : false;
34694 * Returns an array of the selected nodes
34697 getSelectedNodes : function(){
34698 return this.selNodes;
34701 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
34703 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
34705 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
34708 * Ext JS Library 1.1.1
34709 * Copyright(c) 2006-2007, Ext JS, LLC.
34711 * Originally Released Under LGPL - original licence link has changed is not relivant.
34714 * <script type="text/javascript">
34718 * @class Roo.tree.TreeNode
34719 * @extends Roo.data.Node
34720 * @cfg {String} text The text for this node
34721 * @cfg {Boolean} expanded true to start the node expanded
34722 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
34723 * @cfg {Boolean} allowDrop false if this node cannot be drop on
34724 * @cfg {Boolean} disabled true to start the node disabled
34725 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
34726 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
34727 * @cfg {String} cls A css class to be added to the node
34728 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
34729 * @cfg {String} href URL of the link used for the node (defaults to #)
34730 * @cfg {String} hrefTarget target frame for the link
34731 * @cfg {String} qtip An Ext QuickTip for the node
34732 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
34733 * @cfg {Boolean} singleClickExpand True for single click expand on this node
34734 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
34735 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
34736 * (defaults to undefined with no checkbox rendered)
34738 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
34740 Roo.tree.TreeNode = function(attributes){
34741 attributes = attributes || {};
34742 if(typeof attributes == "string"){
34743 attributes = {text: attributes};
34745 this.childrenRendered = false;
34746 this.rendered = false;
34747 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
34748 this.expanded = attributes.expanded === true;
34749 this.isTarget = attributes.isTarget !== false;
34750 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
34751 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
34754 * Read-only. The text for this node. To change it use setText().
34757 this.text = attributes.text;
34759 * True if this node is disabled.
34762 this.disabled = attributes.disabled === true;
34766 * @event textchange
34767 * Fires when the text for this node is changed
34768 * @param {Node} this This node
34769 * @param {String} text The new text
34770 * @param {String} oldText The old text
34772 "textchange" : true,
34774 * @event beforeexpand
34775 * Fires before this node is expanded, return false to cancel.
34776 * @param {Node} this This node
34777 * @param {Boolean} deep
34778 * @param {Boolean} anim
34780 "beforeexpand" : true,
34782 * @event beforecollapse
34783 * Fires before this node is collapsed, return false to cancel.
34784 * @param {Node} this This node
34785 * @param {Boolean} deep
34786 * @param {Boolean} anim
34788 "beforecollapse" : true,
34791 * Fires when this node is expanded
34792 * @param {Node} this This node
34796 * @event disabledchange
34797 * Fires when the disabled status of this node changes
34798 * @param {Node} this This node
34799 * @param {Boolean} disabled
34801 "disabledchange" : true,
34804 * Fires when this node is collapsed
34805 * @param {Node} this This node
34809 * @event beforeclick
34810 * Fires before click processing. Return false to cancel the default action.
34811 * @param {Node} this This node
34812 * @param {Roo.EventObject} e The event object
34814 "beforeclick":true,
34816 * @event checkchange
34817 * Fires when a node with a checkbox's checked property changes
34818 * @param {Node} this This node
34819 * @param {Boolean} checked
34821 "checkchange":true,
34824 * Fires when this node is clicked
34825 * @param {Node} this This node
34826 * @param {Roo.EventObject} e The event object
34831 * Fires when this node is double clicked
34832 * @param {Node} this This node
34833 * @param {Roo.EventObject} e The event object
34837 * @event contextmenu
34838 * Fires when this node is right clicked
34839 * @param {Node} this This node
34840 * @param {Roo.EventObject} e The event object
34842 "contextmenu":true,
34844 * @event beforechildrenrendered
34845 * Fires right before the child nodes for this node are rendered
34846 * @param {Node} this This node
34848 "beforechildrenrendered":true
34851 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
34854 * Read-only. The UI for this node
34857 this.ui = new uiClass(this);
34859 // finally support items[]
34860 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
34865 Roo.each(this.attributes.items, function(c) {
34866 this.appendChild(Roo.factory(c,Roo.Tree));
34868 delete this.attributes.items;
34873 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
34874 preventHScroll: true,
34876 * Returns true if this node is expanded
34877 * @return {Boolean}
34879 isExpanded : function(){
34880 return this.expanded;
34884 * Returns the UI object for this node
34885 * @return {TreeNodeUI}
34887 getUI : function(){
34891 // private override
34892 setFirstChild : function(node){
34893 var of = this.firstChild;
34894 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
34895 if(this.childrenRendered && of && node != of){
34896 of.renderIndent(true, true);
34899 this.renderIndent(true, true);
34903 // private override
34904 setLastChild : function(node){
34905 var ol = this.lastChild;
34906 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
34907 if(this.childrenRendered && ol && node != ol){
34908 ol.renderIndent(true, true);
34911 this.renderIndent(true, true);
34915 // these methods are overridden to provide lazy rendering support
34916 // private override
34917 appendChild : function()
34919 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
34920 if(node && this.childrenRendered){
34923 this.ui.updateExpandIcon();
34927 // private override
34928 removeChild : function(node){
34929 this.ownerTree.getSelectionModel().unselect(node);
34930 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
34931 // if it's been rendered remove dom node
34932 if(this.childrenRendered){
34935 if(this.childNodes.length < 1){
34936 this.collapse(false, false);
34938 this.ui.updateExpandIcon();
34940 if(!this.firstChild) {
34941 this.childrenRendered = false;
34946 // private override
34947 insertBefore : function(node, refNode){
34948 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
34949 if(newNode && refNode && this.childrenRendered){
34952 this.ui.updateExpandIcon();
34957 * Sets the text for this node
34958 * @param {String} text
34960 setText : function(text){
34961 var oldText = this.text;
34963 this.attributes.text = text;
34964 if(this.rendered){ // event without subscribing
34965 this.ui.onTextChange(this, text, oldText);
34967 this.fireEvent("textchange", this, text, oldText);
34971 * Triggers selection of this node
34973 select : function(){
34974 this.getOwnerTree().getSelectionModel().select(this);
34978 * Triggers deselection of this node
34980 unselect : function(){
34981 this.getOwnerTree().getSelectionModel().unselect(this);
34985 * Returns true if this node is selected
34986 * @return {Boolean}
34988 isSelected : function(){
34989 return this.getOwnerTree().getSelectionModel().isSelected(this);
34993 * Expand this node.
34994 * @param {Boolean} deep (optional) True to expand all children as well
34995 * @param {Boolean} anim (optional) false to cancel the default animation
34996 * @param {Function} callback (optional) A callback to be called when
34997 * expanding this node completes (does not wait for deep expand to complete).
34998 * Called with 1 parameter, this node.
35000 expand : function(deep, anim, callback){
35001 if(!this.expanded){
35002 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35005 if(!this.childrenRendered){
35006 this.renderChildren();
35008 this.expanded = true;
35009 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
35010 this.ui.animExpand(function(){
35011 this.fireEvent("expand", this);
35012 if(typeof callback == "function"){
35016 this.expandChildNodes(true);
35018 }.createDelegate(this));
35022 this.fireEvent("expand", this);
35023 if(typeof callback == "function"){
35028 if(typeof callback == "function"){
35033 this.expandChildNodes(true);
35037 isHiddenRoot : function(){
35038 return this.isRoot && !this.getOwnerTree().rootVisible;
35042 * Collapse this node.
35043 * @param {Boolean} deep (optional) True to collapse all children as well
35044 * @param {Boolean} anim (optional) false to cancel the default animation
35046 collapse : function(deep, anim){
35047 if(this.expanded && !this.isHiddenRoot()){
35048 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35051 this.expanded = false;
35052 if((this.getOwnerTree().animate && anim !== false) || anim){
35053 this.ui.animCollapse(function(){
35054 this.fireEvent("collapse", this);
35056 this.collapseChildNodes(true);
35058 }.createDelegate(this));
35061 this.ui.collapse();
35062 this.fireEvent("collapse", this);
35066 var cs = this.childNodes;
35067 for(var i = 0, len = cs.length; i < len; i++) {
35068 cs[i].collapse(true, false);
35074 delayedExpand : function(delay){
35075 if(!this.expandProcId){
35076 this.expandProcId = this.expand.defer(delay, this);
35081 cancelExpand : function(){
35082 if(this.expandProcId){
35083 clearTimeout(this.expandProcId);
35085 this.expandProcId = false;
35089 * Toggles expanded/collapsed state of the node
35091 toggle : function(){
35100 * Ensures all parent nodes are expanded
35102 ensureVisible : function(callback){
35103 var tree = this.getOwnerTree();
35104 tree.expandPath(this.parentNode.getPath(), false, function(){
35105 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35106 Roo.callback(callback);
35107 }.createDelegate(this));
35111 * Expand all child nodes
35112 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35114 expandChildNodes : function(deep){
35115 var cs = this.childNodes;
35116 for(var i = 0, len = cs.length; i < len; i++) {
35117 cs[i].expand(deep);
35122 * Collapse all child nodes
35123 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35125 collapseChildNodes : function(deep){
35126 var cs = this.childNodes;
35127 for(var i = 0, len = cs.length; i < len; i++) {
35128 cs[i].collapse(deep);
35133 * Disables this node
35135 disable : function(){
35136 this.disabled = true;
35138 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35139 this.ui.onDisableChange(this, true);
35141 this.fireEvent("disabledchange", this, true);
35145 * Enables this node
35147 enable : function(){
35148 this.disabled = false;
35149 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35150 this.ui.onDisableChange(this, false);
35152 this.fireEvent("disabledchange", this, false);
35156 renderChildren : function(suppressEvent){
35157 if(suppressEvent !== false){
35158 this.fireEvent("beforechildrenrendered", this);
35160 var cs = this.childNodes;
35161 for(var i = 0, len = cs.length; i < len; i++){
35162 cs[i].render(true);
35164 this.childrenRendered = true;
35168 sort : function(fn, scope){
35169 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35170 if(this.childrenRendered){
35171 var cs = this.childNodes;
35172 for(var i = 0, len = cs.length; i < len; i++){
35173 cs[i].render(true);
35179 render : function(bulkRender){
35180 this.ui.render(bulkRender);
35181 if(!this.rendered){
35182 this.rendered = true;
35184 this.expanded = false;
35185 this.expand(false, false);
35191 renderIndent : function(deep, refresh){
35193 this.ui.childIndent = null;
35195 this.ui.renderIndent();
35196 if(deep === true && this.childrenRendered){
35197 var cs = this.childNodes;
35198 for(var i = 0, len = cs.length; i < len; i++){
35199 cs[i].renderIndent(true, refresh);
35205 * Ext JS Library 1.1.1
35206 * Copyright(c) 2006-2007, Ext JS, LLC.
35208 * Originally Released Under LGPL - original licence link has changed is not relivant.
35211 * <script type="text/javascript">
35215 * @class Roo.tree.AsyncTreeNode
35216 * @extends Roo.tree.TreeNode
35217 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35219 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35221 Roo.tree.AsyncTreeNode = function(config){
35222 this.loaded = false;
35223 this.loading = false;
35224 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35226 * @event beforeload
35227 * Fires before this node is loaded, return false to cancel
35228 * @param {Node} this This node
35230 this.addEvents({'beforeload':true, 'load': true});
35233 * Fires when this node is loaded
35234 * @param {Node} this This node
35237 * The loader used by this node (defaults to using the tree's defined loader)
35242 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35243 expand : function(deep, anim, callback){
35244 if(this.loading){ // if an async load is already running, waiting til it's done
35246 var f = function(){
35247 if(!this.loading){ // done loading
35248 clearInterval(timer);
35249 this.expand(deep, anim, callback);
35251 }.createDelegate(this);
35252 timer = setInterval(f, 200);
35256 if(this.fireEvent("beforeload", this) === false){
35259 this.loading = true;
35260 this.ui.beforeLoad(this);
35261 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35263 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35267 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35271 * Returns true if this node is currently loading
35272 * @return {Boolean}
35274 isLoading : function(){
35275 return this.loading;
35278 loadComplete : function(deep, anim, callback){
35279 this.loading = false;
35280 this.loaded = true;
35281 this.ui.afterLoad(this);
35282 this.fireEvent("load", this);
35283 this.expand(deep, anim, callback);
35287 * Returns true if this node has been loaded
35288 * @return {Boolean}
35290 isLoaded : function(){
35291 return this.loaded;
35294 hasChildNodes : function(){
35295 if(!this.isLeaf() && !this.loaded){
35298 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35303 * Trigger a reload for this node
35304 * @param {Function} callback
35306 reload : function(callback){
35307 this.collapse(false, false);
35308 while(this.firstChild){
35309 this.removeChild(this.firstChild);
35311 this.childrenRendered = false;
35312 this.loaded = false;
35313 if(this.isHiddenRoot()){
35314 this.expanded = false;
35316 this.expand(false, false, callback);
35320 * Ext JS Library 1.1.1
35321 * Copyright(c) 2006-2007, Ext JS, LLC.
35323 * Originally Released Under LGPL - original licence link has changed is not relivant.
35326 * <script type="text/javascript">
35330 * @class Roo.tree.TreeNodeUI
35332 * @param {Object} node The node to render
35333 * The TreeNode UI implementation is separate from the
35334 * tree implementation. Unless you are customizing the tree UI,
35335 * you should never have to use this directly.
35337 Roo.tree.TreeNodeUI = function(node){
35339 this.rendered = false;
35340 this.animating = false;
35341 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35344 Roo.tree.TreeNodeUI.prototype = {
35345 removeChild : function(node){
35347 this.ctNode.removeChild(node.ui.getEl());
35351 beforeLoad : function(){
35352 this.addClass("x-tree-node-loading");
35355 afterLoad : function(){
35356 this.removeClass("x-tree-node-loading");
35359 onTextChange : function(node, text, oldText){
35361 this.textNode.innerHTML = text;
35365 onDisableChange : function(node, state){
35366 this.disabled = state;
35368 this.addClass("x-tree-node-disabled");
35370 this.removeClass("x-tree-node-disabled");
35374 onSelectedChange : function(state){
35377 this.addClass("x-tree-selected");
35380 this.removeClass("x-tree-selected");
35384 onMove : function(tree, node, oldParent, newParent, index, refNode){
35385 this.childIndent = null;
35387 var targetNode = newParent.ui.getContainer();
35388 if(!targetNode){//target not rendered
35389 this.holder = document.createElement("div");
35390 this.holder.appendChild(this.wrap);
35393 var insertBefore = refNode ? refNode.ui.getEl() : null;
35395 targetNode.insertBefore(this.wrap, insertBefore);
35397 targetNode.appendChild(this.wrap);
35399 this.node.renderIndent(true);
35403 addClass : function(cls){
35405 Roo.fly(this.elNode).addClass(cls);
35409 removeClass : function(cls){
35411 Roo.fly(this.elNode).removeClass(cls);
35415 remove : function(){
35417 this.holder = document.createElement("div");
35418 this.holder.appendChild(this.wrap);
35422 fireEvent : function(){
35423 return this.node.fireEvent.apply(this.node, arguments);
35426 initEvents : function(){
35427 this.node.on("move", this.onMove, this);
35428 var E = Roo.EventManager;
35429 var a = this.anchor;
35431 var el = Roo.fly(a, '_treeui');
35433 if(Roo.isOpera){ // opera render bug ignores the CSS
35434 el.setStyle("text-decoration", "none");
35437 el.on("click", this.onClick, this);
35438 el.on("dblclick", this.onDblClick, this);
35441 Roo.EventManager.on(this.checkbox,
35442 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35445 el.on("contextmenu", this.onContextMenu, this);
35447 var icon = Roo.fly(this.iconNode);
35448 icon.on("click", this.onClick, this);
35449 icon.on("dblclick", this.onDblClick, this);
35450 icon.on("contextmenu", this.onContextMenu, this);
35451 E.on(this.ecNode, "click", this.ecClick, this, true);
35453 if(this.node.disabled){
35454 this.addClass("x-tree-node-disabled");
35456 if(this.node.hidden){
35457 this.addClass("x-tree-node-disabled");
35459 var ot = this.node.getOwnerTree();
35460 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
35461 if(dd && (!this.node.isRoot || ot.rootVisible)){
35462 Roo.dd.Registry.register(this.elNode, {
35464 handles: this.getDDHandles(),
35470 getDDHandles : function(){
35471 return [this.iconNode, this.textNode];
35476 this.wrap.style.display = "none";
35482 this.wrap.style.display = "";
35486 onContextMenu : function(e){
35487 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35488 e.preventDefault();
35490 this.fireEvent("contextmenu", this.node, e);
35494 onClick : function(e){
35499 if(this.fireEvent("beforeclick", this.node, e) !== false){
35500 if(!this.disabled && this.node.attributes.href){
35501 this.fireEvent("click", this.node, e);
35504 e.preventDefault();
35509 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35510 this.node.toggle();
35513 this.fireEvent("click", this.node, e);
35519 onDblClick : function(e){
35520 e.preventDefault();
35525 this.toggleCheck();
35527 if(!this.animating && this.node.hasChildNodes()){
35528 this.node.toggle();
35530 this.fireEvent("dblclick", this.node, e);
35533 onCheckChange : function(){
35534 var checked = this.checkbox.checked;
35535 this.node.attributes.checked = checked;
35536 this.fireEvent('checkchange', this.node, checked);
35539 ecClick : function(e){
35540 if(!this.animating && this.node.hasChildNodes()){
35541 this.node.toggle();
35545 startDrop : function(){
35546 this.dropping = true;
35549 // delayed drop so the click event doesn't get fired on a drop
35550 endDrop : function(){
35551 setTimeout(function(){
35552 this.dropping = false;
35553 }.createDelegate(this), 50);
35556 expand : function(){
35557 this.updateExpandIcon();
35558 this.ctNode.style.display = "";
35561 focus : function(){
35562 if(!this.node.preventHScroll){
35563 try{this.anchor.focus();
35565 }else if(!Roo.isIE){
35567 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35568 var l = noscroll.scrollLeft;
35569 this.anchor.focus();
35570 noscroll.scrollLeft = l;
35575 toggleCheck : function(value){
35576 var cb = this.checkbox;
35578 cb.checked = (value === undefined ? !cb.checked : value);
35584 this.anchor.blur();
35588 animExpand : function(callback){
35589 var ct = Roo.get(this.ctNode);
35591 if(!this.node.hasChildNodes()){
35592 this.updateExpandIcon();
35593 this.ctNode.style.display = "";
35594 Roo.callback(callback);
35597 this.animating = true;
35598 this.updateExpandIcon();
35601 callback : function(){
35602 this.animating = false;
35603 Roo.callback(callback);
35606 duration: this.node.ownerTree.duration || .25
35610 highlight : function(){
35611 var tree = this.node.getOwnerTree();
35612 Roo.fly(this.wrap).highlight(
35613 tree.hlColor || "C3DAF9",
35614 {endColor: tree.hlBaseColor}
35618 collapse : function(){
35619 this.updateExpandIcon();
35620 this.ctNode.style.display = "none";
35623 animCollapse : function(callback){
35624 var ct = Roo.get(this.ctNode);
35625 ct.enableDisplayMode('block');
35628 this.animating = true;
35629 this.updateExpandIcon();
35632 callback : function(){
35633 this.animating = false;
35634 Roo.callback(callback);
35637 duration: this.node.ownerTree.duration || .25
35641 getContainer : function(){
35642 return this.ctNode;
35645 getEl : function(){
35649 appendDDGhost : function(ghostNode){
35650 ghostNode.appendChild(this.elNode.cloneNode(true));
35653 getDDRepairXY : function(){
35654 return Roo.lib.Dom.getXY(this.iconNode);
35657 onRender : function(){
35661 render : function(bulkRender){
35662 var n = this.node, a = n.attributes;
35663 var targetNode = n.parentNode ?
35664 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
35666 if(!this.rendered){
35667 this.rendered = true;
35669 this.renderElements(n, a, targetNode, bulkRender);
35672 if(this.textNode.setAttributeNS){
35673 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
35675 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
35678 this.textNode.setAttribute("ext:qtip", a.qtip);
35680 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
35683 }else if(a.qtipCfg){
35684 a.qtipCfg.target = Roo.id(this.textNode);
35685 Roo.QuickTips.register(a.qtipCfg);
35688 if(!this.node.expanded){
35689 this.updateExpandIcon();
35692 if(bulkRender === true) {
35693 targetNode.appendChild(this.wrap);
35698 renderElements : function(n, a, targetNode, bulkRender)
35700 // add some indent caching, this helps performance when rendering a large tree
35701 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
35702 var t = n.getOwnerTree();
35703 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
35704 if (typeof(n.attributes.html) != 'undefined') {
35705 txt = n.attributes.html;
35707 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
35708 var cb = typeof a.checked == 'boolean';
35709 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
35710 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
35711 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
35712 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
35713 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
35714 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
35715 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
35716 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
35717 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
35718 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
35721 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
35722 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
35723 n.nextSibling.ui.getEl(), buf.join(""));
35725 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
35728 this.elNode = this.wrap.childNodes[0];
35729 this.ctNode = this.wrap.childNodes[1];
35730 var cs = this.elNode.childNodes;
35731 this.indentNode = cs[0];
35732 this.ecNode = cs[1];
35733 this.iconNode = cs[2];
35736 this.checkbox = cs[3];
35739 this.anchor = cs[index];
35740 this.textNode = cs[index].firstChild;
35743 getAnchor : function(){
35744 return this.anchor;
35747 getTextEl : function(){
35748 return this.textNode;
35751 getIconEl : function(){
35752 return this.iconNode;
35755 isChecked : function(){
35756 return this.checkbox ? this.checkbox.checked : false;
35759 updateExpandIcon : function(){
35761 var n = this.node, c1, c2;
35762 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
35763 var hasChild = n.hasChildNodes();
35767 c1 = "x-tree-node-collapsed";
35768 c2 = "x-tree-node-expanded";
35771 c1 = "x-tree-node-expanded";
35772 c2 = "x-tree-node-collapsed";
35775 this.removeClass("x-tree-node-leaf");
35776 this.wasLeaf = false;
35778 if(this.c1 != c1 || this.c2 != c2){
35779 Roo.fly(this.elNode).replaceClass(c1, c2);
35780 this.c1 = c1; this.c2 = c2;
35783 // this changes non-leafs into leafs if they have no children.
35784 // it's not very rational behaviour..
35786 if(!this.wasLeaf && this.node.leaf){
35787 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
35790 this.wasLeaf = true;
35793 var ecc = "x-tree-ec-icon "+cls;
35794 if(this.ecc != ecc){
35795 this.ecNode.className = ecc;
35801 getChildIndent : function(){
35802 if(!this.childIndent){
35806 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
35808 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
35810 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
35815 this.childIndent = buf.join("");
35817 return this.childIndent;
35820 renderIndent : function(){
35823 var p = this.node.parentNode;
35825 indent = p.ui.getChildIndent();
35827 if(this.indentMarkup != indent){ // don't rerender if not required
35828 this.indentNode.innerHTML = indent;
35829 this.indentMarkup = indent;
35831 this.updateExpandIcon();
35836 Roo.tree.RootTreeNodeUI = function(){
35837 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
35839 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
35840 render : function(){
35841 if(!this.rendered){
35842 var targetNode = this.node.ownerTree.innerCt.dom;
35843 this.node.expanded = true;
35844 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
35845 this.wrap = this.ctNode = targetNode.firstChild;
35848 collapse : function(){
35850 expand : function(){
35854 * Ext JS Library 1.1.1
35855 * Copyright(c) 2006-2007, Ext JS, LLC.
35857 * Originally Released Under LGPL - original licence link has changed is not relivant.
35860 * <script type="text/javascript">
35863 * @class Roo.tree.TreeLoader
35864 * @extends Roo.util.Observable
35865 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
35866 * nodes from a specified URL. The response must be a javascript Array definition
35867 * who's elements are node definition objects. eg:
35872 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
35873 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
35880 * The old style respose with just an array is still supported, but not recommended.
35883 * A server request is sent, and child nodes are loaded only when a node is expanded.
35884 * The loading node's id is passed to the server under the parameter name "node" to
35885 * enable the server to produce the correct child nodes.
35887 * To pass extra parameters, an event handler may be attached to the "beforeload"
35888 * event, and the parameters specified in the TreeLoader's baseParams property:
35890 myTreeLoader.on("beforeload", function(treeLoader, node) {
35891 this.baseParams.category = node.attributes.category;
35894 * This would pass an HTTP parameter called "category" to the server containing
35895 * the value of the Node's "category" attribute.
35897 * Creates a new Treeloader.
35898 * @param {Object} config A config object containing config properties.
35900 Roo.tree.TreeLoader = function(config){
35901 this.baseParams = {};
35902 this.requestMethod = "POST";
35903 Roo.apply(this, config);
35908 * @event beforeload
35909 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
35910 * @param {Object} This TreeLoader object.
35911 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35912 * @param {Object} callback The callback function specified in the {@link #load} call.
35917 * Fires when the node has been successfuly loaded.
35918 * @param {Object} This TreeLoader object.
35919 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35920 * @param {Object} response The response object containing the data from the server.
35924 * @event loadexception
35925 * Fires if the network request failed.
35926 * @param {Object} This TreeLoader object.
35927 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
35928 * @param {Object} response The response object containing the data from the server.
35930 loadexception : true,
35933 * Fires before a node is created, enabling you to return custom Node types
35934 * @param {Object} This TreeLoader object.
35935 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
35940 Roo.tree.TreeLoader.superclass.constructor.call(this);
35943 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
35945 * @cfg {String} dataUrl The URL from which to request a Json string which
35946 * specifies an array of node definition object representing the child nodes
35950 * @cfg {String} requestMethod either GET or POST
35951 * defaults to POST (due to BC)
35955 * @cfg {Object} baseParams (optional) An object containing properties which
35956 * specify HTTP parameters to be passed to each request for child nodes.
35959 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
35960 * created by this loader. If the attributes sent by the server have an attribute in this object,
35961 * they take priority.
35964 * @cfg {Object} uiProviders (optional) An object containing properties which
35966 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
35967 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
35968 * <i>uiProvider</i> attribute of a returned child node is a string rather
35969 * than a reference to a TreeNodeUI implementation, this that string value
35970 * is used as a property name in the uiProviders object. You can define the provider named
35971 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
35976 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
35977 * child nodes before loading.
35979 clearOnLoad : true,
35982 * @cfg {String} root (optional) Default to false. Use this to read data from an object
35983 * property on loading, rather than expecting an array. (eg. more compatible to a standard
35984 * Grid query { data : [ .....] }
35989 * @cfg {String} queryParam (optional)
35990 * Name of the query as it will be passed on the querystring (defaults to 'node')
35991 * eg. the request will be ?node=[id]
35998 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
35999 * This is called automatically when a node is expanded, but may be used to reload
36000 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36001 * @param {Roo.tree.TreeNode} node
36002 * @param {Function} callback
36004 load : function(node, callback){
36005 if(this.clearOnLoad){
36006 while(node.firstChild){
36007 node.removeChild(node.firstChild);
36010 if(node.attributes.children){ // preloaded json children
36011 var cs = node.attributes.children;
36012 for(var i = 0, len = cs.length; i < len; i++){
36013 node.appendChild(this.createNode(cs[i]));
36015 if(typeof callback == "function"){
36018 }else if(this.dataUrl){
36019 this.requestData(node, callback);
36023 getParams: function(node){
36024 var buf = [], bp = this.baseParams;
36025 for(var key in bp){
36026 if(typeof bp[key] != "function"){
36027 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36030 var n = this.queryParam === false ? 'node' : this.queryParam;
36031 buf.push(n + "=", encodeURIComponent(node.id));
36032 return buf.join("");
36035 requestData : function(node, callback){
36036 if(this.fireEvent("beforeload", this, node, callback) !== false){
36037 this.transId = Roo.Ajax.request({
36038 method:this.requestMethod,
36039 url: this.dataUrl||this.url,
36040 success: this.handleResponse,
36041 failure: this.handleFailure,
36043 argument: {callback: callback, node: node},
36044 params: this.getParams(node)
36047 // if the load is cancelled, make sure we notify
36048 // the node that we are done
36049 if(typeof callback == "function"){
36055 isLoading : function(){
36056 return this.transId ? true : false;
36059 abort : function(){
36060 if(this.isLoading()){
36061 Roo.Ajax.abort(this.transId);
36066 createNode : function(attr)
36068 // apply baseAttrs, nice idea Corey!
36069 if(this.baseAttrs){
36070 Roo.applyIf(attr, this.baseAttrs);
36072 if(this.applyLoader !== false){
36073 attr.loader = this;
36075 // uiProvider = depreciated..
36077 if(typeof(attr.uiProvider) == 'string'){
36078 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36079 /** eval:var:attr */ eval(attr.uiProvider);
36081 if(typeof(this.uiProviders['default']) != 'undefined') {
36082 attr.uiProvider = this.uiProviders['default'];
36085 this.fireEvent('create', this, attr);
36087 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36089 new Roo.tree.TreeNode(attr) :
36090 new Roo.tree.AsyncTreeNode(attr));
36093 processResponse : function(response, node, callback)
36095 var json = response.responseText;
36098 var o = Roo.decode(json);
36100 if (this.root === false && typeof(o.success) != undefined) {
36101 this.root = 'data'; // the default behaviour for list like data..
36104 if (this.root !== false && !o.success) {
36105 // it's a failure condition.
36106 var a = response.argument;
36107 this.fireEvent("loadexception", this, a.node, response);
36108 Roo.log("Load failed - should have a handler really");
36114 if (this.root !== false) {
36118 for(var i = 0, len = o.length; i < len; i++){
36119 var n = this.createNode(o[i]);
36121 node.appendChild(n);
36124 if(typeof callback == "function"){
36125 callback(this, node);
36128 this.handleFailure(response);
36132 handleResponse : function(response){
36133 this.transId = false;
36134 var a = response.argument;
36135 this.processResponse(response, a.node, a.callback);
36136 this.fireEvent("load", this, a.node, response);
36139 handleFailure : function(response)
36141 // should handle failure better..
36142 this.transId = false;
36143 var a = response.argument;
36144 this.fireEvent("loadexception", this, a.node, response);
36145 if(typeof a.callback == "function"){
36146 a.callback(this, a.node);
36151 * Ext JS Library 1.1.1
36152 * Copyright(c) 2006-2007, Ext JS, LLC.
36154 * Originally Released Under LGPL - original licence link has changed is not relivant.
36157 * <script type="text/javascript">
36161 * @class Roo.tree.TreeFilter
36162 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36163 * @param {TreePanel} tree
36164 * @param {Object} config (optional)
36166 Roo.tree.TreeFilter = function(tree, config){
36168 this.filtered = {};
36169 Roo.apply(this, config);
36172 Roo.tree.TreeFilter.prototype = {
36179 * Filter the data by a specific attribute.
36180 * @param {String/RegExp} value Either string that the attribute value
36181 * should start with or a RegExp to test against the attribute
36182 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36183 * @param {TreeNode} startNode (optional) The node to start the filter at.
36185 filter : function(value, attr, startNode){
36186 attr = attr || "text";
36188 if(typeof value == "string"){
36189 var vlen = value.length;
36190 // auto clear empty filter
36191 if(vlen == 0 && this.clearBlank){
36195 value = value.toLowerCase();
36197 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36199 }else if(value.exec){ // regex?
36201 return value.test(n.attributes[attr]);
36204 throw 'Illegal filter type, must be string or regex';
36206 this.filterBy(f, null, startNode);
36210 * Filter by a function. The passed function will be called with each
36211 * node in the tree (or from the startNode). If the function returns true, the node is kept
36212 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36213 * @param {Function} fn The filter function
36214 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36216 filterBy : function(fn, scope, startNode){
36217 startNode = startNode || this.tree.root;
36218 if(this.autoClear){
36221 var af = this.filtered, rv = this.reverse;
36222 var f = function(n){
36223 if(n == startNode){
36229 var m = fn.call(scope || n, n);
36237 startNode.cascade(f);
36240 if(typeof id != "function"){
36242 if(n && n.parentNode){
36243 n.parentNode.removeChild(n);
36251 * Clears the current filter. Note: with the "remove" option
36252 * set a filter cannot be cleared.
36254 clear : function(){
36256 var af = this.filtered;
36258 if(typeof id != "function"){
36265 this.filtered = {};
36270 * Ext JS Library 1.1.1
36271 * Copyright(c) 2006-2007, Ext JS, LLC.
36273 * Originally Released Under LGPL - original licence link has changed is not relivant.
36276 * <script type="text/javascript">
36281 * @class Roo.tree.TreeSorter
36282 * Provides sorting of nodes in a TreePanel
36284 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36285 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36286 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36287 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36288 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36289 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36291 * @param {TreePanel} tree
36292 * @param {Object} config
36294 Roo.tree.TreeSorter = function(tree, config){
36295 Roo.apply(this, config);
36296 tree.on("beforechildrenrendered", this.doSort, this);
36297 tree.on("append", this.updateSort, this);
36298 tree.on("insert", this.updateSort, this);
36300 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36301 var p = this.property || "text";
36302 var sortType = this.sortType;
36303 var fs = this.folderSort;
36304 var cs = this.caseSensitive === true;
36305 var leafAttr = this.leafAttr || 'leaf';
36307 this.sortFn = function(n1, n2){
36309 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36312 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36316 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36317 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36319 return dsc ? +1 : -1;
36321 return dsc ? -1 : +1;
36328 Roo.tree.TreeSorter.prototype = {
36329 doSort : function(node){
36330 node.sort(this.sortFn);
36333 compareNodes : function(n1, n2){
36334 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36337 updateSort : function(tree, node){
36338 if(node.childrenRendered){
36339 this.doSort.defer(1, this, [node]);
36344 * Ext JS Library 1.1.1
36345 * Copyright(c) 2006-2007, Ext JS, LLC.
36347 * Originally Released Under LGPL - original licence link has changed is not relivant.
36350 * <script type="text/javascript">
36353 if(Roo.dd.DropZone){
36355 Roo.tree.TreeDropZone = function(tree, config){
36356 this.allowParentInsert = false;
36357 this.allowContainerDrop = false;
36358 this.appendOnly = false;
36359 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36361 this.lastInsertClass = "x-tree-no-status";
36362 this.dragOverData = {};
36365 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36366 ddGroup : "TreeDD",
36369 expandDelay : 1000,
36371 expandNode : function(node){
36372 if(node.hasChildNodes() && !node.isExpanded()){
36373 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36377 queueExpand : function(node){
36378 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36381 cancelExpand : function(){
36382 if(this.expandProcId){
36383 clearTimeout(this.expandProcId);
36384 this.expandProcId = false;
36388 isValidDropPoint : function(n, pt, dd, e, data){
36389 if(!n || !data){ return false; }
36390 var targetNode = n.node;
36391 var dropNode = data.node;
36392 // default drop rules
36393 if(!(targetNode && targetNode.isTarget && pt)){
36396 if(pt == "append" && targetNode.allowChildren === false){
36399 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36402 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36405 // reuse the object
36406 var overEvent = this.dragOverData;
36407 overEvent.tree = this.tree;
36408 overEvent.target = targetNode;
36409 overEvent.data = data;
36410 overEvent.point = pt;
36411 overEvent.source = dd;
36412 overEvent.rawEvent = e;
36413 overEvent.dropNode = dropNode;
36414 overEvent.cancel = false;
36415 var result = this.tree.fireEvent("nodedragover", overEvent);
36416 return overEvent.cancel === false && result !== false;
36419 getDropPoint : function(e, n, dd)
36423 return tn.allowChildren !== false ? "append" : false; // always append for root
36425 var dragEl = n.ddel;
36426 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36427 var y = Roo.lib.Event.getPageY(e);
36428 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36430 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36431 var noAppend = tn.allowChildren === false;
36432 if(this.appendOnly || tn.parentNode.allowChildren === false){
36433 return noAppend ? false : "append";
36435 var noBelow = false;
36436 if(!this.allowParentInsert){
36437 noBelow = tn.hasChildNodes() && tn.isExpanded();
36439 var q = (b - t) / (noAppend ? 2 : 3);
36440 if(y >= t && y < (t + q)){
36442 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36449 onNodeEnter : function(n, dd, e, data)
36451 this.cancelExpand();
36454 onNodeOver : function(n, dd, e, data)
36457 var pt = this.getDropPoint(e, n, dd);
36460 // auto node expand check
36461 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36462 this.queueExpand(node);
36463 }else if(pt != "append"){
36464 this.cancelExpand();
36467 // set the insert point style on the target node
36468 var returnCls = this.dropNotAllowed;
36469 if(this.isValidDropPoint(n, pt, dd, e, data)){
36474 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36475 cls = "x-tree-drag-insert-above";
36476 }else if(pt == "below"){
36477 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36478 cls = "x-tree-drag-insert-below";
36480 returnCls = "x-tree-drop-ok-append";
36481 cls = "x-tree-drag-append";
36483 if(this.lastInsertClass != cls){
36484 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36485 this.lastInsertClass = cls;
36492 onNodeOut : function(n, dd, e, data){
36494 this.cancelExpand();
36495 this.removeDropIndicators(n);
36498 onNodeDrop : function(n, dd, e, data){
36499 var point = this.getDropPoint(e, n, dd);
36500 var targetNode = n.node;
36501 targetNode.ui.startDrop();
36502 if(!this.isValidDropPoint(n, point, dd, e, data)){
36503 targetNode.ui.endDrop();
36506 // first try to find the drop node
36507 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36510 target: targetNode,
36515 dropNode: dropNode,
36518 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36519 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36520 targetNode.ui.endDrop();
36523 // allow target changing
36524 targetNode = dropEvent.target;
36525 if(point == "append" && !targetNode.isExpanded()){
36526 targetNode.expand(false, null, function(){
36527 this.completeDrop(dropEvent);
36528 }.createDelegate(this));
36530 this.completeDrop(dropEvent);
36535 completeDrop : function(de){
36536 var ns = de.dropNode, p = de.point, t = de.target;
36537 if(!(ns instanceof Array)){
36541 for(var i = 0, len = ns.length; i < len; i++){
36544 t.parentNode.insertBefore(n, t);
36545 }else if(p == "below"){
36546 t.parentNode.insertBefore(n, t.nextSibling);
36552 if(this.tree.hlDrop){
36556 this.tree.fireEvent("nodedrop", de);
36559 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36560 if(this.tree.hlDrop){
36561 dropNode.ui.focus();
36562 dropNode.ui.highlight();
36564 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36567 getTree : function(){
36571 removeDropIndicators : function(n){
36574 Roo.fly(el).removeClass([
36575 "x-tree-drag-insert-above",
36576 "x-tree-drag-insert-below",
36577 "x-tree-drag-append"]);
36578 this.lastInsertClass = "_noclass";
36582 beforeDragDrop : function(target, e, id){
36583 this.cancelExpand();
36587 afterRepair : function(data){
36588 if(data && Roo.enableFx){
36589 data.node.ui.highlight();
36599 * Ext JS Library 1.1.1
36600 * Copyright(c) 2006-2007, Ext JS, LLC.
36602 * Originally Released Under LGPL - original licence link has changed is not relivant.
36605 * <script type="text/javascript">
36609 if(Roo.dd.DragZone){
36610 Roo.tree.TreeDragZone = function(tree, config){
36611 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
36615 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
36616 ddGroup : "TreeDD",
36618 onBeforeDrag : function(data, e){
36620 return n && n.draggable && !n.disabled;
36624 onInitDrag : function(e){
36625 var data = this.dragData;
36626 this.tree.getSelectionModel().select(data.node);
36627 this.proxy.update("");
36628 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
36629 this.tree.fireEvent("startdrag", this.tree, data.node, e);
36632 getRepairXY : function(e, data){
36633 return data.node.ui.getDDRepairXY();
36636 onEndDrag : function(data, e){
36637 this.tree.fireEvent("enddrag", this.tree, data.node, e);
36642 onValidDrop : function(dd, e, id){
36643 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
36647 beforeInvalidDrop : function(e, id){
36648 // this scrolls the original position back into view
36649 var sm = this.tree.getSelectionModel();
36650 sm.clearSelections();
36651 sm.select(this.dragData.node);
36656 * Ext JS Library 1.1.1
36657 * Copyright(c) 2006-2007, Ext JS, LLC.
36659 * Originally Released Under LGPL - original licence link has changed is not relivant.
36662 * <script type="text/javascript">
36665 * @class Roo.tree.TreeEditor
36666 * @extends Roo.Editor
36667 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
36668 * as the editor field.
36670 * @param {Object} config (used to be the tree panel.)
36671 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
36673 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
36674 * @cfg {Roo.form.TextField|Object} field The field configuration
36678 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
36681 if (oldconfig) { // old style..
36682 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
36685 tree = config.tree;
36686 config.field = config.field || {};
36687 config.field.xtype = 'TextField';
36688 field = Roo.factory(config.field, Roo.form);
36690 config = config || {};
36695 * @event beforenodeedit
36696 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
36697 * false from the handler of this event.
36698 * @param {Editor} this
36699 * @param {Roo.tree.Node} node
36701 "beforenodeedit" : true
36705 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
36709 tree.on('beforeclick', this.beforeNodeClick, this);
36710 tree.getTreeEl().on('mousedown', this.hide, this);
36711 this.on('complete', this.updateNode, this);
36712 this.on('beforestartedit', this.fitToTree, this);
36713 this.on('startedit', this.bindScroll, this, {delay:10});
36714 this.on('specialkey', this.onSpecialKey, this);
36717 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
36719 * @cfg {String} alignment
36720 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
36726 * @cfg {Boolean} hideEl
36727 * True to hide the bound element while the editor is displayed (defaults to false)
36731 * @cfg {String} cls
36732 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
36734 cls: "x-small-editor x-tree-editor",
36736 * @cfg {Boolean} shim
36737 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
36743 * @cfg {Number} maxWidth
36744 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
36745 * the containing tree element's size, it will be automatically limited for you to the container width, taking
36746 * scroll and client offsets into account prior to each edit.
36753 fitToTree : function(ed, el){
36754 var td = this.tree.getTreeEl().dom, nd = el.dom;
36755 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
36756 td.scrollLeft = nd.offsetLeft;
36760 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
36761 this.setSize(w, '');
36763 return this.fireEvent('beforenodeedit', this, this.editNode);
36768 triggerEdit : function(node){
36769 this.completeEdit();
36770 this.editNode = node;
36771 this.startEdit(node.ui.textNode, node.text);
36775 bindScroll : function(){
36776 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
36780 beforeNodeClick : function(node, e){
36781 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
36782 this.lastClick = new Date();
36783 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
36785 this.triggerEdit(node);
36792 updateNode : function(ed, value){
36793 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
36794 this.editNode.setText(value);
36798 onHide : function(){
36799 Roo.tree.TreeEditor.superclass.onHide.call(this);
36801 this.editNode.ui.focus();
36806 onSpecialKey : function(field, e){
36807 var k = e.getKey();
36811 }else if(k == e.ENTER && !e.hasModifier()){
36813 this.completeEdit();
36816 });//<Script type="text/javascript">
36819 * Ext JS Library 1.1.1
36820 * Copyright(c) 2006-2007, Ext JS, LLC.
36822 * Originally Released Under LGPL - original licence link has changed is not relivant.
36825 * <script type="text/javascript">
36829 * Not documented??? - probably should be...
36832 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
36833 //focus: Roo.emptyFn, // prevent odd scrolling behavior
36835 renderElements : function(n, a, targetNode, bulkRender){
36836 //consel.log("renderElements?");
36837 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36839 var t = n.getOwnerTree();
36840 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
36842 var cols = t.columns;
36843 var bw = t.borderWidth;
36845 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36846 var cb = typeof a.checked == "boolean";
36847 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36848 var colcls = 'x-t-' + tid + '-c0';
36850 '<li class="x-tree-node">',
36853 '<div class="x-tree-node-el ', a.cls,'">',
36855 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
36858 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
36859 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
36860 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
36861 (a.icon ? ' x-tree-node-inline-icon' : ''),
36862 (a.iconCls ? ' '+a.iconCls : ''),
36863 '" unselectable="on" />',
36864 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
36865 (a.checked ? 'checked="checked" />' : ' />')) : ''),
36867 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36868 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
36869 '<span unselectable="on" qtip="' + tx + '">',
36873 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
36874 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
36876 for(var i = 1, len = cols.length; i < len; i++){
36878 colcls = 'x-t-' + tid + '-c' +i;
36879 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
36880 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
36881 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
36887 '<div class="x-clear"></div></div>',
36888 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36891 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36892 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36893 n.nextSibling.ui.getEl(), buf.join(""));
36895 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36897 var el = this.wrap.firstChild;
36899 this.elNode = el.firstChild;
36900 this.ranchor = el.childNodes[1];
36901 this.ctNode = this.wrap.childNodes[1];
36902 var cs = el.firstChild.childNodes;
36903 this.indentNode = cs[0];
36904 this.ecNode = cs[1];
36905 this.iconNode = cs[2];
36908 this.checkbox = cs[3];
36911 this.anchor = cs[index];
36913 this.textNode = cs[index].firstChild;
36915 //el.on("click", this.onClick, this);
36916 //el.on("dblclick", this.onDblClick, this);
36919 // console.log(this);
36921 initEvents : function(){
36922 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
36925 var a = this.ranchor;
36927 var el = Roo.get(a);
36929 if(Roo.isOpera){ // opera render bug ignores the CSS
36930 el.setStyle("text-decoration", "none");
36933 el.on("click", this.onClick, this);
36934 el.on("dblclick", this.onDblClick, this);
36935 el.on("contextmenu", this.onContextMenu, this);
36939 /*onSelectedChange : function(state){
36942 this.addClass("x-tree-selected");
36945 this.removeClass("x-tree-selected");
36948 addClass : function(cls){
36950 Roo.fly(this.elRow).addClass(cls);
36956 removeClass : function(cls){
36958 Roo.fly(this.elRow).removeClass(cls);
36964 });//<Script type="text/javascript">
36968 * Ext JS Library 1.1.1
36969 * Copyright(c) 2006-2007, Ext JS, LLC.
36971 * Originally Released Under LGPL - original licence link has changed is not relivant.
36974 * <script type="text/javascript">
36979 * @class Roo.tree.ColumnTree
36980 * @extends Roo.data.TreePanel
36981 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
36982 * @cfg {int} borderWidth compined right/left border allowance
36984 * @param {String/HTMLElement/Element} el The container element
36985 * @param {Object} config
36987 Roo.tree.ColumnTree = function(el, config)
36989 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
36993 * Fire this event on a container when it resizes
36994 * @param {int} w Width
36995 * @param {int} h Height
36999 this.on('resize', this.onResize, this);
37002 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37006 borderWidth: Roo.isBorderBox ? 0 : 2,
37009 render : function(){
37010 // add the header.....
37012 Roo.tree.ColumnTree.superclass.render.apply(this);
37014 this.el.addClass('x-column-tree');
37016 this.headers = this.el.createChild(
37017 {cls:'x-tree-headers'},this.innerCt.dom);
37019 var cols = this.columns, c;
37020 var totalWidth = 0;
37022 var len = cols.length;
37023 for(var i = 0; i < len; i++){
37025 totalWidth += c.width;
37026 this.headEls.push(this.headers.createChild({
37027 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37029 cls:'x-tree-hd-text',
37032 style:'width:'+(c.width-this.borderWidth)+'px;'
37035 this.headers.createChild({cls:'x-clear'});
37036 // prevent floats from wrapping when clipped
37037 this.headers.setWidth(totalWidth);
37038 //this.innerCt.setWidth(totalWidth);
37039 this.innerCt.setStyle({ overflow: 'auto' });
37040 this.onResize(this.width, this.height);
37044 onResize : function(w,h)
37049 this.innerCt.setWidth(this.width);
37050 this.innerCt.setHeight(this.height-20);
37053 var cols = this.columns, c;
37054 var totalWidth = 0;
37056 var len = cols.length;
37057 for(var i = 0; i < len; i++){
37059 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37060 // it's the expander..
37061 expEl = this.headEls[i];
37064 totalWidth += c.width;
37068 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37070 this.headers.setWidth(w-20);
37079 * Ext JS Library 1.1.1
37080 * Copyright(c) 2006-2007, Ext JS, LLC.
37082 * Originally Released Under LGPL - original licence link has changed is not relivant.
37085 * <script type="text/javascript">
37089 * @class Roo.menu.Menu
37090 * @extends Roo.util.Observable
37091 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37092 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37094 * Creates a new Menu
37095 * @param {Object} config Configuration options
37097 Roo.menu.Menu = function(config){
37098 Roo.apply(this, config);
37099 this.id = this.id || Roo.id();
37102 * @event beforeshow
37103 * Fires before this menu is displayed
37104 * @param {Roo.menu.Menu} this
37108 * @event beforehide
37109 * Fires before this menu is hidden
37110 * @param {Roo.menu.Menu} this
37115 * Fires after this menu is displayed
37116 * @param {Roo.menu.Menu} this
37121 * Fires after this menu is hidden
37122 * @param {Roo.menu.Menu} this
37127 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37128 * @param {Roo.menu.Menu} this
37129 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37130 * @param {Roo.EventObject} e
37135 * Fires when the mouse is hovering over this menu
37136 * @param {Roo.menu.Menu} this
37137 * @param {Roo.EventObject} e
37138 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37143 * Fires when the mouse exits this menu
37144 * @param {Roo.menu.Menu} this
37145 * @param {Roo.EventObject} e
37146 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37151 * Fires when a menu item contained in this menu is clicked
37152 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37153 * @param {Roo.EventObject} e
37157 if (this.registerMenu) {
37158 Roo.menu.MenuMgr.register(this);
37161 var mis = this.items;
37162 this.items = new Roo.util.MixedCollection();
37164 this.add.apply(this, mis);
37168 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37170 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37174 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37175 * for bottom-right shadow (defaults to "sides")
37179 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37180 * this menu (defaults to "tl-tr?")
37182 subMenuAlign : "tl-tr?",
37184 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37185 * relative to its element of origin (defaults to "tl-bl?")
37187 defaultAlign : "tl-bl?",
37189 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37191 allowOtherMenus : false,
37193 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37195 registerMenu : true,
37200 render : function(){
37204 var el = this.el = new Roo.Layer({
37206 shadow:this.shadow,
37208 parentEl: this.parentEl || document.body,
37212 this.keyNav = new Roo.menu.MenuNav(this);
37215 el.addClass("x-menu-plain");
37218 el.addClass(this.cls);
37220 // generic focus element
37221 this.focusEl = el.createChild({
37222 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37224 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37225 //disabling touch- as it's causing issues ..
37226 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37227 ul.on('click' , this.onClick, this);
37230 ul.on("mouseover", this.onMouseOver, this);
37231 ul.on("mouseout", this.onMouseOut, this);
37232 this.items.each(function(item){
37237 var li = document.createElement("li");
37238 li.className = "x-menu-list-item";
37239 ul.dom.appendChild(li);
37240 item.render(li, this);
37247 autoWidth : function(){
37248 var el = this.el, ul = this.ul;
37252 var w = this.width;
37255 }else if(Roo.isIE){
37256 el.setWidth(this.minWidth);
37257 var t = el.dom.offsetWidth; // force recalc
37258 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37263 delayAutoWidth : function(){
37266 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37268 this.awTask.delay(20);
37273 findTargetItem : function(e){
37274 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37275 if(t && t.menuItemId){
37276 return this.items.get(t.menuItemId);
37281 onClick : function(e){
37282 Roo.log("menu.onClick");
37283 var t = this.findTargetItem(e);
37288 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37289 if(t == this.activeItem && t.shouldDeactivate(e)){
37290 this.activeItem.deactivate();
37291 delete this.activeItem;
37295 this.setActiveItem(t, true);
37303 this.fireEvent("click", this, t, e);
37307 setActiveItem : function(item, autoExpand){
37308 if(item != this.activeItem){
37309 if(this.activeItem){
37310 this.activeItem.deactivate();
37312 this.activeItem = item;
37313 item.activate(autoExpand);
37314 }else if(autoExpand){
37320 tryActivate : function(start, step){
37321 var items = this.items;
37322 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37323 var item = items.get(i);
37324 if(!item.disabled && item.canActivate){
37325 this.setActiveItem(item, false);
37333 onMouseOver : function(e){
37335 if(t = this.findTargetItem(e)){
37336 if(t.canActivate && !t.disabled){
37337 this.setActiveItem(t, true);
37340 this.fireEvent("mouseover", this, e, t);
37344 onMouseOut : function(e){
37346 if(t = this.findTargetItem(e)){
37347 if(t == this.activeItem && t.shouldDeactivate(e)){
37348 this.activeItem.deactivate();
37349 delete this.activeItem;
37352 this.fireEvent("mouseout", this, e, t);
37356 * Read-only. Returns true if the menu is currently displayed, else false.
37359 isVisible : function(){
37360 return this.el && !this.hidden;
37364 * Displays this menu relative to another element
37365 * @param {String/HTMLElement/Roo.Element} element The element to align to
37366 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37367 * the element (defaults to this.defaultAlign)
37368 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37370 show : function(el, pos, parentMenu){
37371 this.parentMenu = parentMenu;
37375 this.fireEvent("beforeshow", this);
37376 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37380 * Displays this menu at a specific xy position
37381 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37382 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37384 showAt : function(xy, parentMenu, /* private: */_e){
37385 this.parentMenu = parentMenu;
37390 this.fireEvent("beforeshow", this);
37391 xy = this.el.adjustForConstraints(xy);
37395 this.hidden = false;
37397 this.fireEvent("show", this);
37400 focus : function(){
37402 this.doFocus.defer(50, this);
37406 doFocus : function(){
37408 this.focusEl.focus();
37413 * Hides this menu and optionally all parent menus
37414 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37416 hide : function(deep){
37417 if(this.el && this.isVisible()){
37418 this.fireEvent("beforehide", this);
37419 if(this.activeItem){
37420 this.activeItem.deactivate();
37421 this.activeItem = null;
37424 this.hidden = true;
37425 this.fireEvent("hide", this);
37427 if(deep === true && this.parentMenu){
37428 this.parentMenu.hide(true);
37433 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37434 * Any of the following are valid:
37436 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37437 * <li>An HTMLElement object which will be converted to a menu item</li>
37438 * <li>A menu item config object that will be created as a new menu item</li>
37439 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37440 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37445 var menu = new Roo.menu.Menu();
37447 // Create a menu item to add by reference
37448 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37450 // Add a bunch of items at once using different methods.
37451 // Only the last item added will be returned.
37452 var item = menu.add(
37453 menuItem, // add existing item by ref
37454 'Dynamic Item', // new TextItem
37455 '-', // new separator
37456 { text: 'Config Item' } // new item by config
37459 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37460 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37463 var a = arguments, l = a.length, item;
37464 for(var i = 0; i < l; i++){
37466 if ((typeof(el) == "object") && el.xtype && el.xns) {
37467 el = Roo.factory(el, Roo.menu);
37470 if(el.render){ // some kind of Item
37471 item = this.addItem(el);
37472 }else if(typeof el == "string"){ // string
37473 if(el == "separator" || el == "-"){
37474 item = this.addSeparator();
37476 item = this.addText(el);
37478 }else if(el.tagName || el.el){ // element
37479 item = this.addElement(el);
37480 }else if(typeof el == "object"){ // must be menu item config?
37481 item = this.addMenuItem(el);
37488 * Returns this menu's underlying {@link Roo.Element} object
37489 * @return {Roo.Element} The element
37491 getEl : function(){
37499 * Adds a separator bar to the menu
37500 * @return {Roo.menu.Item} The menu item that was added
37502 addSeparator : function(){
37503 return this.addItem(new Roo.menu.Separator());
37507 * Adds an {@link Roo.Element} object to the menu
37508 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37509 * @return {Roo.menu.Item} The menu item that was added
37511 addElement : function(el){
37512 return this.addItem(new Roo.menu.BaseItem(el));
37516 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37517 * @param {Roo.menu.Item} item The menu item to add
37518 * @return {Roo.menu.Item} The menu item that was added
37520 addItem : function(item){
37521 this.items.add(item);
37523 var li = document.createElement("li");
37524 li.className = "x-menu-list-item";
37525 this.ul.dom.appendChild(li);
37526 item.render(li, this);
37527 this.delayAutoWidth();
37533 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37534 * @param {Object} config A MenuItem config object
37535 * @return {Roo.menu.Item} The menu item that was added
37537 addMenuItem : function(config){
37538 if(!(config instanceof Roo.menu.Item)){
37539 if(typeof config.checked == "boolean"){ // must be check menu item config?
37540 config = new Roo.menu.CheckItem(config);
37542 config = new Roo.menu.Item(config);
37545 return this.addItem(config);
37549 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37550 * @param {String} text The text to display in the menu item
37551 * @return {Roo.menu.Item} The menu item that was added
37553 addText : function(text){
37554 return this.addItem(new Roo.menu.TextItem({ text : text }));
37558 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37559 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37560 * @param {Roo.menu.Item} item The menu item to add
37561 * @return {Roo.menu.Item} The menu item that was added
37563 insert : function(index, item){
37564 this.items.insert(index, item);
37566 var li = document.createElement("li");
37567 li.className = "x-menu-list-item";
37568 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37569 item.render(li, this);
37570 this.delayAutoWidth();
37576 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
37577 * @param {Roo.menu.Item} item The menu item to remove
37579 remove : function(item){
37580 this.items.removeKey(item.id);
37585 * Removes and destroys all items in the menu
37587 removeAll : function(){
37589 while(f = this.items.first()){
37595 // MenuNav is a private utility class used internally by the Menu
37596 Roo.menu.MenuNav = function(menu){
37597 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
37598 this.scope = this.menu = menu;
37601 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
37602 doRelay : function(e, h){
37603 var k = e.getKey();
37604 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
37605 this.menu.tryActivate(0, 1);
37608 return h.call(this.scope || this, e, this.menu);
37611 up : function(e, m){
37612 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
37613 m.tryActivate(m.items.length-1, -1);
37617 down : function(e, m){
37618 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
37619 m.tryActivate(0, 1);
37623 right : function(e, m){
37625 m.activeItem.expandMenu(true);
37629 left : function(e, m){
37631 if(m.parentMenu && m.parentMenu.activeItem){
37632 m.parentMenu.activeItem.activate();
37636 enter : function(e, m){
37638 e.stopPropagation();
37639 m.activeItem.onClick(e);
37640 m.fireEvent("click", this, m.activeItem);
37646 * Ext JS Library 1.1.1
37647 * Copyright(c) 2006-2007, Ext JS, LLC.
37649 * Originally Released Under LGPL - original licence link has changed is not relivant.
37652 * <script type="text/javascript">
37656 * @class Roo.menu.MenuMgr
37657 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
37660 Roo.menu.MenuMgr = function(){
37661 var menus, active, groups = {}, attached = false, lastShow = new Date();
37663 // private - called when first menu is created
37666 active = new Roo.util.MixedCollection();
37667 Roo.get(document).addKeyListener(27, function(){
37668 if(active.length > 0){
37675 function hideAll(){
37676 if(active && active.length > 0){
37677 var c = active.clone();
37678 c.each(function(m){
37685 function onHide(m){
37687 if(active.length < 1){
37688 Roo.get(document).un("mousedown", onMouseDown);
37694 function onShow(m){
37695 var last = active.last();
37696 lastShow = new Date();
37699 Roo.get(document).on("mousedown", onMouseDown);
37703 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
37704 m.parentMenu.activeChild = m;
37705 }else if(last && last.isVisible()){
37706 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
37711 function onBeforeHide(m){
37713 m.activeChild.hide();
37715 if(m.autoHideTimer){
37716 clearTimeout(m.autoHideTimer);
37717 delete m.autoHideTimer;
37722 function onBeforeShow(m){
37723 var pm = m.parentMenu;
37724 if(!pm && !m.allowOtherMenus){
37726 }else if(pm && pm.activeChild && active != m){
37727 pm.activeChild.hide();
37732 function onMouseDown(e){
37733 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
37739 function onBeforeCheck(mi, state){
37741 var g = groups[mi.group];
37742 for(var i = 0, l = g.length; i < l; i++){
37744 g[i].setChecked(false);
37753 * Hides all menus that are currently visible
37755 hideAll : function(){
37760 register : function(menu){
37764 menus[menu.id] = menu;
37765 menu.on("beforehide", onBeforeHide);
37766 menu.on("hide", onHide);
37767 menu.on("beforeshow", onBeforeShow);
37768 menu.on("show", onShow);
37769 var g = menu.group;
37770 if(g && menu.events["checkchange"]){
37774 groups[g].push(menu);
37775 menu.on("checkchange", onCheck);
37780 * Returns a {@link Roo.menu.Menu} object
37781 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
37782 * be used to generate and return a new Menu instance.
37784 get : function(menu){
37785 if(typeof menu == "string"){ // menu id
37786 return menus[menu];
37787 }else if(menu.events){ // menu instance
37789 }else if(typeof menu.length == 'number'){ // array of menu items?
37790 return new Roo.menu.Menu({items:menu});
37791 }else{ // otherwise, must be a config
37792 return new Roo.menu.Menu(menu);
37797 unregister : function(menu){
37798 delete menus[menu.id];
37799 menu.un("beforehide", onBeforeHide);
37800 menu.un("hide", onHide);
37801 menu.un("beforeshow", onBeforeShow);
37802 menu.un("show", onShow);
37803 var g = menu.group;
37804 if(g && menu.events["checkchange"]){
37805 groups[g].remove(menu);
37806 menu.un("checkchange", onCheck);
37811 registerCheckable : function(menuItem){
37812 var g = menuItem.group;
37817 groups[g].push(menuItem);
37818 menuItem.on("beforecheckchange", onBeforeCheck);
37823 unregisterCheckable : function(menuItem){
37824 var g = menuItem.group;
37826 groups[g].remove(menuItem);
37827 menuItem.un("beforecheckchange", onBeforeCheck);
37833 * Ext JS Library 1.1.1
37834 * Copyright(c) 2006-2007, Ext JS, LLC.
37836 * Originally Released Under LGPL - original licence link has changed is not relivant.
37839 * <script type="text/javascript">
37844 * @class Roo.menu.BaseItem
37845 * @extends Roo.Component
37846 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
37847 * management and base configuration options shared by all menu components.
37849 * Creates a new BaseItem
37850 * @param {Object} config Configuration options
37852 Roo.menu.BaseItem = function(config){
37853 Roo.menu.BaseItem.superclass.constructor.call(this, config);
37858 * Fires when this item is clicked
37859 * @param {Roo.menu.BaseItem} this
37860 * @param {Roo.EventObject} e
37865 * Fires when this item is activated
37866 * @param {Roo.menu.BaseItem} this
37870 * @event deactivate
37871 * Fires when this item is deactivated
37872 * @param {Roo.menu.BaseItem} this
37878 this.on("click", this.handler, this.scope, true);
37882 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
37884 * @cfg {Function} handler
37885 * A function that will handle the click event of this menu item (defaults to undefined)
37888 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
37890 canActivate : false,
37893 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
37898 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
37900 activeClass : "x-menu-item-active",
37902 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
37904 hideOnClick : true,
37906 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
37911 ctype: "Roo.menu.BaseItem",
37914 actionMode : "container",
37917 render : function(container, parentMenu){
37918 this.parentMenu = parentMenu;
37919 Roo.menu.BaseItem.superclass.render.call(this, container);
37920 this.container.menuItemId = this.id;
37924 onRender : function(container, position){
37925 this.el = Roo.get(this.el);
37926 container.dom.appendChild(this.el.dom);
37930 onClick : function(e){
37931 if(!this.disabled && this.fireEvent("click", this, e) !== false
37932 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
37933 this.handleClick(e);
37940 activate : function(){
37944 var li = this.container;
37945 li.addClass(this.activeClass);
37946 this.region = li.getRegion().adjust(2, 2, -2, -2);
37947 this.fireEvent("activate", this);
37952 deactivate : function(){
37953 this.container.removeClass(this.activeClass);
37954 this.fireEvent("deactivate", this);
37958 shouldDeactivate : function(e){
37959 return !this.region || !this.region.contains(e.getPoint());
37963 handleClick : function(e){
37964 if(this.hideOnClick){
37965 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
37970 expandMenu : function(autoActivate){
37975 hideMenu : function(){
37980 * Ext JS Library 1.1.1
37981 * Copyright(c) 2006-2007, Ext JS, LLC.
37983 * Originally Released Under LGPL - original licence link has changed is not relivant.
37986 * <script type="text/javascript">
37990 * @class Roo.menu.Adapter
37991 * @extends Roo.menu.BaseItem
37992 * 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.
37993 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
37995 * Creates a new Adapter
37996 * @param {Object} config Configuration options
37998 Roo.menu.Adapter = function(component, config){
37999 Roo.menu.Adapter.superclass.constructor.call(this, config);
38000 this.component = component;
38002 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38004 canActivate : true,
38007 onRender : function(container, position){
38008 this.component.render(container);
38009 this.el = this.component.getEl();
38013 activate : function(){
38017 this.component.focus();
38018 this.fireEvent("activate", this);
38023 deactivate : function(){
38024 this.fireEvent("deactivate", this);
38028 disable : function(){
38029 this.component.disable();
38030 Roo.menu.Adapter.superclass.disable.call(this);
38034 enable : function(){
38035 this.component.enable();
38036 Roo.menu.Adapter.superclass.enable.call(this);
38040 * Ext JS Library 1.1.1
38041 * Copyright(c) 2006-2007, Ext JS, LLC.
38043 * Originally Released Under LGPL - original licence link has changed is not relivant.
38046 * <script type="text/javascript">
38050 * @class Roo.menu.TextItem
38051 * @extends Roo.menu.BaseItem
38052 * Adds a static text string to a menu, usually used as either a heading or group separator.
38053 * Note: old style constructor with text is still supported.
38056 * Creates a new TextItem
38057 * @param {Object} cfg Configuration
38059 Roo.menu.TextItem = function(cfg){
38060 if (typeof(cfg) == 'string') {
38063 Roo.apply(this,cfg);
38066 Roo.menu.TextItem.superclass.constructor.call(this);
38069 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38071 * @cfg {Boolean} text Text to show on item.
38076 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38078 hideOnClick : false,
38080 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38082 itemCls : "x-menu-text",
38085 onRender : function(){
38086 var s = document.createElement("span");
38087 s.className = this.itemCls;
38088 s.innerHTML = this.text;
38090 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38094 * Ext JS Library 1.1.1
38095 * Copyright(c) 2006-2007, Ext JS, LLC.
38097 * Originally Released Under LGPL - original licence link has changed is not relivant.
38100 * <script type="text/javascript">
38104 * @class Roo.menu.Separator
38105 * @extends Roo.menu.BaseItem
38106 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38107 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38109 * @param {Object} config Configuration options
38111 Roo.menu.Separator = function(config){
38112 Roo.menu.Separator.superclass.constructor.call(this, config);
38115 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38117 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38119 itemCls : "x-menu-sep",
38121 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38123 hideOnClick : false,
38126 onRender : function(li){
38127 var s = document.createElement("span");
38128 s.className = this.itemCls;
38129 s.innerHTML = " ";
38131 li.addClass("x-menu-sep-li");
38132 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38136 * Ext JS Library 1.1.1
38137 * Copyright(c) 2006-2007, Ext JS, LLC.
38139 * Originally Released Under LGPL - original licence link has changed is not relivant.
38142 * <script type="text/javascript">
38145 * @class Roo.menu.Item
38146 * @extends Roo.menu.BaseItem
38147 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38148 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38149 * activation and click handling.
38151 * Creates a new Item
38152 * @param {Object} config Configuration options
38154 Roo.menu.Item = function(config){
38155 Roo.menu.Item.superclass.constructor.call(this, config);
38157 this.menu = Roo.menu.MenuMgr.get(this.menu);
38160 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38163 * @cfg {String} text
38164 * The text to show on the menu item.
38168 * @cfg {String} HTML to render in menu
38169 * The text to show on the menu item (HTML version).
38173 * @cfg {String} icon
38174 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38178 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38180 itemCls : "x-menu-item",
38182 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38184 canActivate : true,
38186 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38189 // doc'd in BaseItem
38193 ctype: "Roo.menu.Item",
38196 onRender : function(container, position){
38197 var el = document.createElement("a");
38198 el.hideFocus = true;
38199 el.unselectable = "on";
38200 el.href = this.href || "#";
38201 if(this.hrefTarget){
38202 el.target = this.hrefTarget;
38204 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38206 var html = this.html.length ? this.html : String.format('{0}',this.text);
38208 el.innerHTML = String.format(
38209 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38210 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38212 Roo.menu.Item.superclass.onRender.call(this, container, position);
38216 * Sets the text to display in this menu item
38217 * @param {String} text The text to display
38218 * @param {Boolean} isHTML true to indicate text is pure html.
38220 setText : function(text, isHTML){
38228 var html = this.html.length ? this.html : String.format('{0}',this.text);
38230 this.el.update(String.format(
38231 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38232 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38233 this.parentMenu.autoWidth();
38238 handleClick : function(e){
38239 if(!this.href){ // if no link defined, stop the event automatically
38242 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38246 activate : function(autoExpand){
38247 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38257 shouldDeactivate : function(e){
38258 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38259 if(this.menu && this.menu.isVisible()){
38260 return !this.menu.getEl().getRegion().contains(e.getPoint());
38268 deactivate : function(){
38269 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38274 expandMenu : function(autoActivate){
38275 if(!this.disabled && this.menu){
38276 clearTimeout(this.hideTimer);
38277 delete this.hideTimer;
38278 if(!this.menu.isVisible() && !this.showTimer){
38279 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38280 }else if (this.menu.isVisible() && autoActivate){
38281 this.menu.tryActivate(0, 1);
38287 deferExpand : function(autoActivate){
38288 delete this.showTimer;
38289 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38291 this.menu.tryActivate(0, 1);
38296 hideMenu : function(){
38297 clearTimeout(this.showTimer);
38298 delete this.showTimer;
38299 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38300 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38305 deferHide : function(){
38306 delete this.hideTimer;
38311 * Ext JS Library 1.1.1
38312 * Copyright(c) 2006-2007, Ext JS, LLC.
38314 * Originally Released Under LGPL - original licence link has changed is not relivant.
38317 * <script type="text/javascript">
38321 * @class Roo.menu.CheckItem
38322 * @extends Roo.menu.Item
38323 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38325 * Creates a new CheckItem
38326 * @param {Object} config Configuration options
38328 Roo.menu.CheckItem = function(config){
38329 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38332 * @event beforecheckchange
38333 * Fires before the checked value is set, providing an opportunity to cancel if needed
38334 * @param {Roo.menu.CheckItem} this
38335 * @param {Boolean} checked The new checked value that will be set
38337 "beforecheckchange" : true,
38339 * @event checkchange
38340 * Fires after the checked value has been set
38341 * @param {Roo.menu.CheckItem} this
38342 * @param {Boolean} checked The checked value that was set
38344 "checkchange" : true
38346 if(this.checkHandler){
38347 this.on('checkchange', this.checkHandler, this.scope);
38350 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38352 * @cfg {String} group
38353 * All check items with the same group name will automatically be grouped into a single-select
38354 * radio button group (defaults to '')
38357 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38359 itemCls : "x-menu-item x-menu-check-item",
38361 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38363 groupClass : "x-menu-group-item",
38366 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38367 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38368 * initialized with checked = true will be rendered as checked.
38373 ctype: "Roo.menu.CheckItem",
38376 onRender : function(c){
38377 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38379 this.el.addClass(this.groupClass);
38381 Roo.menu.MenuMgr.registerCheckable(this);
38383 this.checked = false;
38384 this.setChecked(true, true);
38389 destroy : function(){
38391 Roo.menu.MenuMgr.unregisterCheckable(this);
38393 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38397 * Set the checked state of this item
38398 * @param {Boolean} checked The new checked value
38399 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38401 setChecked : function(state, suppressEvent){
38402 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38403 if(this.container){
38404 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38406 this.checked = state;
38407 if(suppressEvent !== true){
38408 this.fireEvent("checkchange", this, state);
38414 handleClick : function(e){
38415 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38416 this.setChecked(!this.checked);
38418 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38422 * Ext JS Library 1.1.1
38423 * Copyright(c) 2006-2007, Ext JS, LLC.
38425 * Originally Released Under LGPL - original licence link has changed is not relivant.
38428 * <script type="text/javascript">
38432 * @class Roo.menu.DateItem
38433 * @extends Roo.menu.Adapter
38434 * A menu item that wraps the {@link Roo.DatPicker} component.
38436 * Creates a new DateItem
38437 * @param {Object} config Configuration options
38439 Roo.menu.DateItem = function(config){
38440 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38441 /** The Roo.DatePicker object @type Roo.DatePicker */
38442 this.picker = this.component;
38443 this.addEvents({select: true});
38445 this.picker.on("render", function(picker){
38446 picker.getEl().swallowEvent("click");
38447 picker.container.addClass("x-menu-date-item");
38450 this.picker.on("select", this.onSelect, this);
38453 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38455 onSelect : function(picker, date){
38456 this.fireEvent("select", this, date, picker);
38457 Roo.menu.DateItem.superclass.handleClick.call(this);
38461 * Ext JS Library 1.1.1
38462 * Copyright(c) 2006-2007, Ext JS, LLC.
38464 * Originally Released Under LGPL - original licence link has changed is not relivant.
38467 * <script type="text/javascript">
38471 * @class Roo.menu.ColorItem
38472 * @extends Roo.menu.Adapter
38473 * A menu item that wraps the {@link Roo.ColorPalette} component.
38475 * Creates a new ColorItem
38476 * @param {Object} config Configuration options
38478 Roo.menu.ColorItem = function(config){
38479 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38480 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38481 this.palette = this.component;
38482 this.relayEvents(this.palette, ["select"]);
38483 if(this.selectHandler){
38484 this.on('select', this.selectHandler, this.scope);
38487 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38489 * Ext JS Library 1.1.1
38490 * Copyright(c) 2006-2007, Ext JS, LLC.
38492 * Originally Released Under LGPL - original licence link has changed is not relivant.
38495 * <script type="text/javascript">
38500 * @class Roo.menu.DateMenu
38501 * @extends Roo.menu.Menu
38502 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38504 * Creates a new DateMenu
38505 * @param {Object} config Configuration options
38507 Roo.menu.DateMenu = function(config){
38508 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38510 var di = new Roo.menu.DateItem(config);
38513 * The {@link Roo.DatePicker} instance for this DateMenu
38516 this.picker = di.picker;
38519 * @param {DatePicker} picker
38520 * @param {Date} date
38522 this.relayEvents(di, ["select"]);
38523 this.on('beforeshow', function(){
38525 this.picker.hideMonthPicker(false);
38529 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38533 * Ext JS Library 1.1.1
38534 * Copyright(c) 2006-2007, Ext JS, LLC.
38536 * Originally Released Under LGPL - original licence link has changed is not relivant.
38539 * <script type="text/javascript">
38544 * @class Roo.menu.ColorMenu
38545 * @extends Roo.menu.Menu
38546 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38548 * Creates a new ColorMenu
38549 * @param {Object} config Configuration options
38551 Roo.menu.ColorMenu = function(config){
38552 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38554 var ci = new Roo.menu.ColorItem(config);
38557 * The {@link Roo.ColorPalette} instance for this ColorMenu
38558 * @type ColorPalette
38560 this.palette = ci.palette;
38563 * @param {ColorPalette} palette
38564 * @param {String} color
38566 this.relayEvents(ci, ["select"]);
38568 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38570 * Ext JS Library 1.1.1
38571 * Copyright(c) 2006-2007, Ext JS, LLC.
38573 * Originally Released Under LGPL - original licence link has changed is not relivant.
38576 * <script type="text/javascript">
38580 * @class Roo.form.Field
38581 * @extends Roo.BoxComponent
38582 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
38584 * Creates a new Field
38585 * @param {Object} config Configuration options
38587 Roo.form.Field = function(config){
38588 Roo.form.Field.superclass.constructor.call(this, config);
38591 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
38593 * @cfg {String} fieldLabel Label to use when rendering a form.
38596 * @cfg {String} qtip Mouse over tip
38600 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
38602 invalidClass : "x-form-invalid",
38604 * @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")
38606 invalidText : "The value in this field is invalid",
38608 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
38610 focusClass : "x-form-focus",
38612 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
38613 automatic validation (defaults to "keyup").
38615 validationEvent : "keyup",
38617 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
38619 validateOnBlur : true,
38621 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
38623 validationDelay : 250,
38625 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
38626 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
38628 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
38630 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
38632 fieldClass : "x-form-field",
38634 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
38637 ----------- ----------------------------------------------------------------------
38638 qtip Display a quick tip when the user hovers over the field
38639 title Display a default browser title attribute popup
38640 under Add a block div beneath the field containing the error text
38641 side Add an error icon to the right of the field with a popup on hover
38642 [element id] Add the error text directly to the innerHTML of the specified element
38645 msgTarget : 'qtip',
38647 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
38652 * @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.
38657 * @cfg {Boolean} disabled True to disable the field (defaults to false).
38662 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
38664 inputType : undefined,
38667 * @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).
38669 tabIndex : undefined,
38672 isFormField : true,
38677 * @property {Roo.Element} fieldEl
38678 * Element Containing the rendered Field (with label etc.)
38681 * @cfg {Mixed} value A value to initialize this field with.
38686 * @cfg {String} name The field's HTML name attribute.
38689 * @cfg {String} cls A CSS class to apply to the field's underlying element.
38692 loadedValue : false,
38696 initComponent : function(){
38697 Roo.form.Field.superclass.initComponent.call(this);
38701 * Fires when this field receives input focus.
38702 * @param {Roo.form.Field} this
38707 * Fires when this field loses input focus.
38708 * @param {Roo.form.Field} this
38712 * @event specialkey
38713 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
38714 * {@link Roo.EventObject#getKey} to determine which key was pressed.
38715 * @param {Roo.form.Field} this
38716 * @param {Roo.EventObject} e The event object
38721 * Fires just before the field blurs if the field value has changed.
38722 * @param {Roo.form.Field} this
38723 * @param {Mixed} newValue The new value
38724 * @param {Mixed} oldValue The original value
38729 * Fires after the field has been marked as invalid.
38730 * @param {Roo.form.Field} this
38731 * @param {String} msg The validation message
38736 * Fires after the field has been validated with no errors.
38737 * @param {Roo.form.Field} this
38742 * Fires after the key up
38743 * @param {Roo.form.Field} this
38744 * @param {Roo.EventObject} e The event Object
38751 * Returns the name attribute of the field if available
38752 * @return {String} name The field name
38754 getName: function(){
38755 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
38759 onRender : function(ct, position){
38760 Roo.form.Field.superclass.onRender.call(this, ct, position);
38762 var cfg = this.getAutoCreate();
38764 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
38766 if (!cfg.name.length) {
38769 if(this.inputType){
38770 cfg.type = this.inputType;
38772 this.el = ct.createChild(cfg, position);
38774 var type = this.el.dom.type;
38776 if(type == 'password'){
38779 this.el.addClass('x-form-'+type);
38782 this.el.dom.readOnly = true;
38784 if(this.tabIndex !== undefined){
38785 this.el.dom.setAttribute('tabIndex', this.tabIndex);
38788 this.el.addClass([this.fieldClass, this.cls]);
38793 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
38794 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
38795 * @return {Roo.form.Field} this
38797 applyTo : function(target){
38798 this.allowDomMove = false;
38799 this.el = Roo.get(target);
38800 this.render(this.el.dom.parentNode);
38805 initValue : function(){
38806 if(this.value !== undefined){
38807 this.setValue(this.value);
38808 }else if(this.el.dom.value.length > 0){
38809 this.setValue(this.el.dom.value);
38814 * Returns true if this field has been changed since it was originally loaded and is not disabled.
38815 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
38817 isDirty : function() {
38818 if(this.disabled) {
38821 return String(this.getValue()) !== String(this.originalValue);
38825 * stores the current value in loadedValue
38827 resetHasChanged : function()
38829 this.loadedValue = String(this.getValue());
38832 * checks the current value against the 'loaded' value.
38833 * Note - will return false if 'resetHasChanged' has not been called first.
38835 hasChanged : function()
38837 if(this.disabled || this.readOnly) {
38840 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
38846 afterRender : function(){
38847 Roo.form.Field.superclass.afterRender.call(this);
38852 fireKey : function(e){
38853 //Roo.log('field ' + e.getKey());
38854 if(e.isNavKeyPress()){
38855 this.fireEvent("specialkey", this, e);
38860 * Resets the current field value to the originally loaded value and clears any validation messages
38862 reset : function(){
38863 this.setValue(this.resetValue);
38864 this.clearInvalid();
38868 initEvents : function(){
38869 // safari killled keypress - so keydown is now used..
38870 this.el.on("keydown" , this.fireKey, this);
38871 this.el.on("focus", this.onFocus, this);
38872 this.el.on("blur", this.onBlur, this);
38873 this.el.relayEvent('keyup', this);
38875 // reference to original value for reset
38876 this.originalValue = this.getValue();
38877 this.resetValue = this.getValue();
38881 onFocus : function(){
38882 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38883 this.el.addClass(this.focusClass);
38885 if(!this.hasFocus){
38886 this.hasFocus = true;
38887 this.startValue = this.getValue();
38888 this.fireEvent("focus", this);
38892 beforeBlur : Roo.emptyFn,
38895 onBlur : function(){
38897 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
38898 this.el.removeClass(this.focusClass);
38900 this.hasFocus = false;
38901 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
38904 var v = this.getValue();
38905 if(String(v) !== String(this.startValue)){
38906 this.fireEvent('change', this, v, this.startValue);
38908 this.fireEvent("blur", this);
38912 * Returns whether or not the field value is currently valid
38913 * @param {Boolean} preventMark True to disable marking the field invalid
38914 * @return {Boolean} True if the value is valid, else false
38916 isValid : function(preventMark){
38920 var restore = this.preventMark;
38921 this.preventMark = preventMark === true;
38922 var v = this.validateValue(this.processValue(this.getRawValue()));
38923 this.preventMark = restore;
38928 * Validates the field value
38929 * @return {Boolean} True if the value is valid, else false
38931 validate : function(){
38932 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
38933 this.clearInvalid();
38939 processValue : function(value){
38944 // Subclasses should provide the validation implementation by overriding this
38945 validateValue : function(value){
38950 * Mark this field as invalid
38951 * @param {String} msg The validation message
38953 markInvalid : function(msg){
38954 if(!this.rendered || this.preventMark){ // not rendered
38958 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
38960 obj.el.addClass(this.invalidClass);
38961 msg = msg || this.invalidText;
38962 switch(this.msgTarget){
38964 obj.el.dom.qtip = msg;
38965 obj.el.dom.qclass = 'x-form-invalid-tip';
38966 if(Roo.QuickTips){ // fix for floating editors interacting with DND
38967 Roo.QuickTips.enable();
38971 this.el.dom.title = msg;
38975 var elp = this.el.findParent('.x-form-element', 5, true);
38976 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
38977 this.errorEl.setWidth(elp.getWidth(true)-20);
38979 this.errorEl.update(msg);
38980 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
38983 if(!this.errorIcon){
38984 var elp = this.el.findParent('.x-form-element', 5, true);
38985 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
38987 this.alignErrorIcon();
38988 this.errorIcon.dom.qtip = msg;
38989 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
38990 this.errorIcon.show();
38991 this.on('resize', this.alignErrorIcon, this);
38994 var t = Roo.getDom(this.msgTarget);
38996 t.style.display = this.msgDisplay;
38999 this.fireEvent('invalid', this, msg);
39003 alignErrorIcon : function(){
39004 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39008 * Clear any invalid styles/messages for this field
39010 clearInvalid : function(){
39011 if(!this.rendered || this.preventMark){ // not rendered
39014 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39016 obj.el.removeClass(this.invalidClass);
39017 switch(this.msgTarget){
39019 obj.el.dom.qtip = '';
39022 this.el.dom.title = '';
39026 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39030 if(this.errorIcon){
39031 this.errorIcon.dom.qtip = '';
39032 this.errorIcon.hide();
39033 this.un('resize', this.alignErrorIcon, this);
39037 var t = Roo.getDom(this.msgTarget);
39039 t.style.display = 'none';
39042 this.fireEvent('valid', this);
39046 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39047 * @return {Mixed} value The field value
39049 getRawValue : function(){
39050 var v = this.el.getValue();
39056 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39057 * @return {Mixed} value The field value
39059 getValue : function(){
39060 var v = this.el.getValue();
39066 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39067 * @param {Mixed} value The value to set
39069 setRawValue : function(v){
39070 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39074 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39075 * @param {Mixed} value The value to set
39077 setValue : function(v){
39080 this.el.dom.value = (v === null || v === undefined ? '' : v);
39085 adjustSize : function(w, h){
39086 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39087 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39091 adjustWidth : function(tag, w){
39092 tag = tag.toLowerCase();
39093 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39094 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39095 if(tag == 'input'){
39098 if(tag == 'textarea'){
39101 }else if(Roo.isOpera){
39102 if(tag == 'input'){
39105 if(tag == 'textarea'){
39115 // anything other than normal should be considered experimental
39116 Roo.form.Field.msgFx = {
39118 show: function(msgEl, f){
39119 msgEl.setDisplayed('block');
39122 hide : function(msgEl, f){
39123 msgEl.setDisplayed(false).update('');
39128 show: function(msgEl, f){
39129 msgEl.slideIn('t', {stopFx:true});
39132 hide : function(msgEl, f){
39133 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39138 show: function(msgEl, f){
39139 msgEl.fixDisplay();
39140 msgEl.alignTo(f.el, 'tl-tr');
39141 msgEl.slideIn('l', {stopFx:true});
39144 hide : function(msgEl, f){
39145 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39150 * Ext JS Library 1.1.1
39151 * Copyright(c) 2006-2007, Ext JS, LLC.
39153 * Originally Released Under LGPL - original licence link has changed is not relivant.
39156 * <script type="text/javascript">
39161 * @class Roo.form.TextField
39162 * @extends Roo.form.Field
39163 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39164 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39166 * Creates a new TextField
39167 * @param {Object} config Configuration options
39169 Roo.form.TextField = function(config){
39170 Roo.form.TextField.superclass.constructor.call(this, config);
39174 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39175 * according to the default logic, but this event provides a hook for the developer to apply additional
39176 * logic at runtime to resize the field if needed.
39177 * @param {Roo.form.Field} this This text field
39178 * @param {Number} width The new field width
39184 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39186 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39190 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39194 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39198 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39202 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39206 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39208 disableKeyFilter : false,
39210 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39214 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39218 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39220 maxLength : Number.MAX_VALUE,
39222 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39224 minLengthText : "The minimum length for this field is {0}",
39226 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39228 maxLengthText : "The maximum length for this field is {0}",
39230 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39232 selectOnFocus : false,
39234 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39236 blankText : "This field is required",
39238 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39239 * If available, this function will be called only after the basic validators all return true, and will be passed the
39240 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39244 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39245 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39246 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39250 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39254 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39260 initEvents : function()
39262 if (this.emptyText) {
39263 this.el.attr('placeholder', this.emptyText);
39266 Roo.form.TextField.superclass.initEvents.call(this);
39267 if(this.validationEvent == 'keyup'){
39268 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39269 this.el.on('keyup', this.filterValidation, this);
39271 else if(this.validationEvent !== false){
39272 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39275 if(this.selectOnFocus){
39276 this.on("focus", this.preFocus, this);
39279 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39280 this.el.on("keypress", this.filterKeys, this);
39283 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39284 this.el.on("click", this.autoSize, this);
39286 if(this.el.is('input[type=password]') && Roo.isSafari){
39287 this.el.on('keydown', this.SafariOnKeyDown, this);
39291 processValue : function(value){
39292 if(this.stripCharsRe){
39293 var newValue = value.replace(this.stripCharsRe, '');
39294 if(newValue !== value){
39295 this.setRawValue(newValue);
39302 filterValidation : function(e){
39303 if(!e.isNavKeyPress()){
39304 this.validationTask.delay(this.validationDelay);
39309 onKeyUp : function(e){
39310 if(!e.isNavKeyPress()){
39316 * Resets the current field value to the originally-loaded value and clears any validation messages.
39319 reset : function(){
39320 Roo.form.TextField.superclass.reset.call(this);
39326 preFocus : function(){
39328 if(this.selectOnFocus){
39329 this.el.dom.select();
39335 filterKeys : function(e){
39336 var k = e.getKey();
39337 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39340 var c = e.getCharCode(), cc = String.fromCharCode(c);
39341 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39344 if(!this.maskRe.test(cc)){
39349 setValue : function(v){
39351 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39357 * Validates a value according to the field's validation rules and marks the field as invalid
39358 * if the validation fails
39359 * @param {Mixed} value The value to validate
39360 * @return {Boolean} True if the value is valid, else false
39362 validateValue : function(value){
39363 if(value.length < 1) { // if it's blank
39364 if(this.allowBlank){
39365 this.clearInvalid();
39368 this.markInvalid(this.blankText);
39372 if(value.length < this.minLength){
39373 this.markInvalid(String.format(this.minLengthText, this.minLength));
39376 if(value.length > this.maxLength){
39377 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39381 var vt = Roo.form.VTypes;
39382 if(!vt[this.vtype](value, this)){
39383 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39387 if(typeof this.validator == "function"){
39388 var msg = this.validator(value);
39390 this.markInvalid(msg);
39394 if(this.regex && !this.regex.test(value)){
39395 this.markInvalid(this.regexText);
39402 * Selects text in this field
39403 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39404 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39406 selectText : function(start, end){
39407 var v = this.getRawValue();
39409 start = start === undefined ? 0 : start;
39410 end = end === undefined ? v.length : end;
39411 var d = this.el.dom;
39412 if(d.setSelectionRange){
39413 d.setSelectionRange(start, end);
39414 }else if(d.createTextRange){
39415 var range = d.createTextRange();
39416 range.moveStart("character", start);
39417 range.moveEnd("character", v.length-end);
39424 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39425 * This only takes effect if grow = true, and fires the autosize event.
39427 autoSize : function(){
39428 if(!this.grow || !this.rendered){
39432 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39435 var v = el.dom.value;
39436 var d = document.createElement('div');
39437 d.appendChild(document.createTextNode(v));
39441 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39442 this.el.setWidth(w);
39443 this.fireEvent("autosize", this, w);
39447 SafariOnKeyDown : function(event)
39449 // this is a workaround for a password hang bug on chrome/ webkit.
39451 var isSelectAll = false;
39453 if(this.el.dom.selectionEnd > 0){
39454 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39456 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39457 event.preventDefault();
39462 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39464 event.preventDefault();
39465 // this is very hacky as keydown always get's upper case.
39467 var cc = String.fromCharCode(event.getCharCode());
39470 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39478 * Ext JS Library 1.1.1
39479 * Copyright(c) 2006-2007, Ext JS, LLC.
39481 * Originally Released Under LGPL - original licence link has changed is not relivant.
39484 * <script type="text/javascript">
39488 * @class Roo.form.Hidden
39489 * @extends Roo.form.TextField
39490 * Simple Hidden element used on forms
39492 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
39495 * Creates a new Hidden form element.
39496 * @param {Object} config Configuration options
39501 // easy hidden field...
39502 Roo.form.Hidden = function(config){
39503 Roo.form.Hidden.superclass.constructor.call(this, config);
39506 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
39508 inputType: 'hidden',
39511 labelSeparator: '',
39513 itemCls : 'x-form-item-display-none'
39521 * Ext JS Library 1.1.1
39522 * Copyright(c) 2006-2007, Ext JS, LLC.
39524 * Originally Released Under LGPL - original licence link has changed is not relivant.
39527 * <script type="text/javascript">
39531 * @class Roo.form.TriggerField
39532 * @extends Roo.form.TextField
39533 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
39534 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
39535 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
39536 * for which you can provide a custom implementation. For example:
39538 var trigger = new Roo.form.TriggerField();
39539 trigger.onTriggerClick = myTriggerFn;
39540 trigger.applyTo('my-field');
39543 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
39544 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
39545 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
39546 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
39548 * Create a new TriggerField.
39549 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
39550 * to the base TextField)
39552 Roo.form.TriggerField = function(config){
39553 this.mimicing = false;
39554 Roo.form.TriggerField.superclass.constructor.call(this, config);
39557 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
39559 * @cfg {String} triggerClass A CSS class to apply to the trigger
39562 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39563 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
39565 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
39567 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
39571 /** @cfg {Boolean} grow @hide */
39572 /** @cfg {Number} growMin @hide */
39573 /** @cfg {Number} growMax @hide */
39579 autoSize: Roo.emptyFn,
39583 deferHeight : true,
39586 actionMode : 'wrap',
39588 onResize : function(w, h){
39589 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
39590 if(typeof w == 'number'){
39591 var x = w - this.trigger.getWidth();
39592 this.el.setWidth(this.adjustWidth('input', x));
39593 this.trigger.setStyle('left', x+'px');
39598 adjustSize : Roo.BoxComponent.prototype.adjustSize,
39601 getResizeEl : function(){
39606 getPositionEl : function(){
39611 alignErrorIcon : function(){
39612 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
39616 onRender : function(ct, position){
39617 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
39618 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
39619 this.trigger = this.wrap.createChild(this.triggerConfig ||
39620 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
39621 if(this.hideTrigger){
39622 this.trigger.setDisplayed(false);
39624 this.initTrigger();
39626 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
39631 initTrigger : function(){
39632 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
39633 this.trigger.addClassOnOver('x-form-trigger-over');
39634 this.trigger.addClassOnClick('x-form-trigger-click');
39638 onDestroy : function(){
39640 this.trigger.removeAllListeners();
39641 this.trigger.remove();
39644 this.wrap.remove();
39646 Roo.form.TriggerField.superclass.onDestroy.call(this);
39650 onFocus : function(){
39651 Roo.form.TriggerField.superclass.onFocus.call(this);
39652 if(!this.mimicing){
39653 this.wrap.addClass('x-trigger-wrap-focus');
39654 this.mimicing = true;
39655 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
39656 if(this.monitorTab){
39657 this.el.on("keydown", this.checkTab, this);
39663 checkTab : function(e){
39664 if(e.getKey() == e.TAB){
39665 this.triggerBlur();
39670 onBlur : function(){
39675 mimicBlur : function(e, t){
39676 if(!this.wrap.contains(t) && this.validateBlur()){
39677 this.triggerBlur();
39682 triggerBlur : function(){
39683 this.mimicing = false;
39684 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
39685 if(this.monitorTab){
39686 this.el.un("keydown", this.checkTab, this);
39688 this.wrap.removeClass('x-trigger-wrap-focus');
39689 Roo.form.TriggerField.superclass.onBlur.call(this);
39693 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
39694 validateBlur : function(e, t){
39699 onDisable : function(){
39700 Roo.form.TriggerField.superclass.onDisable.call(this);
39702 this.wrap.addClass('x-item-disabled');
39707 onEnable : function(){
39708 Roo.form.TriggerField.superclass.onEnable.call(this);
39710 this.wrap.removeClass('x-item-disabled');
39715 onShow : function(){
39716 var ae = this.getActionEl();
39719 ae.dom.style.display = '';
39720 ae.dom.style.visibility = 'visible';
39726 onHide : function(){
39727 var ae = this.getActionEl();
39728 ae.dom.style.display = 'none';
39732 * The function that should handle the trigger's click event. This method does nothing by default until overridden
39733 * by an implementing function.
39735 * @param {EventObject} e
39737 onTriggerClick : Roo.emptyFn
39740 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
39741 // to be extended by an implementing class. For an example of implementing this class, see the custom
39742 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
39743 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
39744 initComponent : function(){
39745 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
39747 this.triggerConfig = {
39748 tag:'span', cls:'x-form-twin-triggers', cn:[
39749 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
39750 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
39754 getTrigger : function(index){
39755 return this.triggers[index];
39758 initTrigger : function(){
39759 var ts = this.trigger.select('.x-form-trigger', true);
39760 this.wrap.setStyle('overflow', 'hidden');
39761 var triggerField = this;
39762 ts.each(function(t, all, index){
39763 t.hide = function(){
39764 var w = triggerField.wrap.getWidth();
39765 this.dom.style.display = 'none';
39766 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39768 t.show = function(){
39769 var w = triggerField.wrap.getWidth();
39770 this.dom.style.display = '';
39771 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
39773 var triggerIndex = 'Trigger'+(index+1);
39775 if(this['hide'+triggerIndex]){
39776 t.dom.style.display = 'none';
39778 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
39779 t.addClassOnOver('x-form-trigger-over');
39780 t.addClassOnClick('x-form-trigger-click');
39782 this.triggers = ts.elements;
39785 onTrigger1Click : Roo.emptyFn,
39786 onTrigger2Click : Roo.emptyFn
39789 * Ext JS Library 1.1.1
39790 * Copyright(c) 2006-2007, Ext JS, LLC.
39792 * Originally Released Under LGPL - original licence link has changed is not relivant.
39795 * <script type="text/javascript">
39799 * @class Roo.form.TextArea
39800 * @extends Roo.form.TextField
39801 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
39802 * support for auto-sizing.
39804 * Creates a new TextArea
39805 * @param {Object} config Configuration options
39807 Roo.form.TextArea = function(config){
39808 Roo.form.TextArea.superclass.constructor.call(this, config);
39809 // these are provided exchanges for backwards compat
39810 // minHeight/maxHeight were replaced by growMin/growMax to be
39811 // compatible with TextField growing config values
39812 if(this.minHeight !== undefined){
39813 this.growMin = this.minHeight;
39815 if(this.maxHeight !== undefined){
39816 this.growMax = this.maxHeight;
39820 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
39822 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
39826 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
39830 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
39831 * in the field (equivalent to setting overflow: hidden, defaults to false)
39833 preventScrollbars: false,
39835 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39836 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
39840 onRender : function(ct, position){
39842 this.defaultAutoCreate = {
39844 style:"width:300px;height:60px;",
39845 autocomplete: "new-password"
39848 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
39850 this.textSizeEl = Roo.DomHelper.append(document.body, {
39851 tag: "pre", cls: "x-form-grow-sizer"
39853 if(this.preventScrollbars){
39854 this.el.setStyle("overflow", "hidden");
39856 this.el.setHeight(this.growMin);
39860 onDestroy : function(){
39861 if(this.textSizeEl){
39862 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
39864 Roo.form.TextArea.superclass.onDestroy.call(this);
39868 onKeyUp : function(e){
39869 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
39875 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
39876 * This only takes effect if grow = true, and fires the autosize event if the height changes.
39878 autoSize : function(){
39879 if(!this.grow || !this.textSizeEl){
39883 var v = el.dom.value;
39884 var ts = this.textSizeEl;
39887 ts.appendChild(document.createTextNode(v));
39890 Roo.fly(ts).setWidth(this.el.getWidth());
39892 v = "  ";
39895 v = v.replace(/\n/g, '<p> </p>');
39897 v += " \n ";
39900 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
39901 if(h != this.lastHeight){
39902 this.lastHeight = h;
39903 this.el.setHeight(h);
39904 this.fireEvent("autosize", this, h);
39909 * Ext JS Library 1.1.1
39910 * Copyright(c) 2006-2007, Ext JS, LLC.
39912 * Originally Released Under LGPL - original licence link has changed is not relivant.
39915 * <script type="text/javascript">
39920 * @class Roo.form.NumberField
39921 * @extends Roo.form.TextField
39922 * Numeric text field that provides automatic keystroke filtering and numeric validation.
39924 * Creates a new NumberField
39925 * @param {Object} config Configuration options
39927 Roo.form.NumberField = function(config){
39928 Roo.form.NumberField.superclass.constructor.call(this, config);
39931 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
39933 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
39935 fieldClass: "x-form-field x-form-num-field",
39937 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
39939 allowDecimals : true,
39941 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
39943 decimalSeparator : ".",
39945 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
39947 decimalPrecision : 2,
39949 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
39951 allowNegative : true,
39953 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
39955 minValue : Number.NEGATIVE_INFINITY,
39957 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
39959 maxValue : Number.MAX_VALUE,
39961 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
39963 minText : "The minimum value for this field is {0}",
39965 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
39967 maxText : "The maximum value for this field is {0}",
39969 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
39970 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
39972 nanText : "{0} is not a valid number",
39975 initEvents : function(){
39976 Roo.form.NumberField.superclass.initEvents.call(this);
39977 var allowed = "0123456789";
39978 if(this.allowDecimals){
39979 allowed += this.decimalSeparator;
39981 if(this.allowNegative){
39984 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
39985 var keyPress = function(e){
39986 var k = e.getKey();
39987 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
39990 var c = e.getCharCode();
39991 if(allowed.indexOf(String.fromCharCode(c)) === -1){
39995 this.el.on("keypress", keyPress, this);
39999 validateValue : function(value){
40000 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40003 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40006 var num = this.parseValue(value);
40008 this.markInvalid(String.format(this.nanText, value));
40011 if(num < this.minValue){
40012 this.markInvalid(String.format(this.minText, this.minValue));
40015 if(num > this.maxValue){
40016 this.markInvalid(String.format(this.maxText, this.maxValue));
40022 getValue : function(){
40023 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40027 parseValue : function(value){
40028 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40029 return isNaN(value) ? '' : value;
40033 fixPrecision : function(value){
40034 var nan = isNaN(value);
40035 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40036 return nan ? '' : value;
40038 return parseFloat(value).toFixed(this.decimalPrecision);
40041 setValue : function(v){
40042 v = this.fixPrecision(v);
40043 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40047 decimalPrecisionFcn : function(v){
40048 return Math.floor(v);
40051 beforeBlur : function(){
40052 var v = this.parseValue(this.getRawValue());
40059 * Ext JS Library 1.1.1
40060 * Copyright(c) 2006-2007, Ext JS, LLC.
40062 * Originally Released Under LGPL - original licence link has changed is not relivant.
40065 * <script type="text/javascript">
40069 * @class Roo.form.DateField
40070 * @extends Roo.form.TriggerField
40071 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40073 * Create a new DateField
40074 * @param {Object} config
40076 Roo.form.DateField = function(config){
40077 Roo.form.DateField.superclass.constructor.call(this, config);
40083 * Fires when a date is selected
40084 * @param {Roo.form.DateField} combo This combo box
40085 * @param {Date} date The date selected
40092 if(typeof this.minValue == "string") {
40093 this.minValue = this.parseDate(this.minValue);
40095 if(typeof this.maxValue == "string") {
40096 this.maxValue = this.parseDate(this.maxValue);
40098 this.ddMatch = null;
40099 if(this.disabledDates){
40100 var dd = this.disabledDates;
40102 for(var i = 0; i < dd.length; i++){
40104 if(i != dd.length-1) {
40108 this.ddMatch = new RegExp(re + ")");
40112 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40114 * @cfg {String} format
40115 * The default date format string which can be overriden for localization support. The format must be
40116 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40120 * @cfg {String} altFormats
40121 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40122 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40124 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40126 * @cfg {Array} disabledDays
40127 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40129 disabledDays : null,
40131 * @cfg {String} disabledDaysText
40132 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40134 disabledDaysText : "Disabled",
40136 * @cfg {Array} disabledDates
40137 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40138 * expression so they are very powerful. Some examples:
40140 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40141 * <li>["03/08", "09/16"] would disable those days for every year</li>
40142 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40143 * <li>["03/../2006"] would disable every day in March 2006</li>
40144 * <li>["^03"] would disable every day in every March</li>
40146 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40147 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40149 disabledDates : null,
40151 * @cfg {String} disabledDatesText
40152 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40154 disabledDatesText : "Disabled",
40156 * @cfg {Date/String} minValue
40157 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40158 * valid format (defaults to null).
40162 * @cfg {Date/String} maxValue
40163 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40164 * valid format (defaults to null).
40168 * @cfg {String} minText
40169 * The error text to display when the date in the cell is before minValue (defaults to
40170 * 'The date in this field must be after {minValue}').
40172 minText : "The date in this field must be equal to or after {0}",
40174 * @cfg {String} maxText
40175 * The error text to display when the date in the cell is after maxValue (defaults to
40176 * 'The date in this field must be before {maxValue}').
40178 maxText : "The date in this field must be equal to or before {0}",
40180 * @cfg {String} invalidText
40181 * The error text to display when the date in the field is invalid (defaults to
40182 * '{value} is not a valid date - it must be in the format {format}').
40184 invalidText : "{0} is not a valid date - it must be in the format {1}",
40186 * @cfg {String} triggerClass
40187 * An additional CSS class used to style the trigger button. The trigger will always get the
40188 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40189 * which displays a calendar icon).
40191 triggerClass : 'x-form-date-trigger',
40195 * @cfg {Boolean} useIso
40196 * if enabled, then the date field will use a hidden field to store the
40197 * real value as iso formated date. default (false)
40201 * @cfg {String/Object} autoCreate
40202 * A DomHelper element spec, or true for a default element spec (defaults to
40203 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40206 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40209 hiddenField: false,
40211 onRender : function(ct, position)
40213 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40215 //this.el.dom.removeAttribute('name');
40216 Roo.log("Changing name?");
40217 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40218 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40220 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40221 // prevent input submission
40222 this.hiddenName = this.name;
40229 validateValue : function(value)
40231 value = this.formatDate(value);
40232 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40233 Roo.log('super failed');
40236 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40239 var svalue = value;
40240 value = this.parseDate(value);
40242 Roo.log('parse date failed' + svalue);
40243 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40246 var time = value.getTime();
40247 if(this.minValue && time < this.minValue.getTime()){
40248 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40251 if(this.maxValue && time > this.maxValue.getTime()){
40252 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40255 if(this.disabledDays){
40256 var day = value.getDay();
40257 for(var i = 0; i < this.disabledDays.length; i++) {
40258 if(day === this.disabledDays[i]){
40259 this.markInvalid(this.disabledDaysText);
40264 var fvalue = this.formatDate(value);
40265 if(this.ddMatch && this.ddMatch.test(fvalue)){
40266 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40273 // Provides logic to override the default TriggerField.validateBlur which just returns true
40274 validateBlur : function(){
40275 return !this.menu || !this.menu.isVisible();
40278 getName: function()
40280 // returns hidden if it's set..
40281 if (!this.rendered) {return ''};
40282 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40287 * Returns the current date value of the date field.
40288 * @return {Date} The date value
40290 getValue : function(){
40292 return this.hiddenField ?
40293 this.hiddenField.value :
40294 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40298 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40299 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40300 * (the default format used is "m/d/y").
40303 //All of these calls set the same date value (May 4, 2006)
40305 //Pass a date object:
40306 var dt = new Date('5/4/06');
40307 dateField.setValue(dt);
40309 //Pass a date string (default format):
40310 dateField.setValue('5/4/06');
40312 //Pass a date string (custom format):
40313 dateField.format = 'Y-m-d';
40314 dateField.setValue('2006-5-4');
40316 * @param {String/Date} date The date or valid date string
40318 setValue : function(date){
40319 if (this.hiddenField) {
40320 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40322 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40323 // make sure the value field is always stored as a date..
40324 this.value = this.parseDate(date);
40330 parseDate : function(value){
40331 if(!value || value instanceof Date){
40334 var v = Date.parseDate(value, this.format);
40335 if (!v && this.useIso) {
40336 v = Date.parseDate(value, 'Y-m-d');
40338 if(!v && this.altFormats){
40339 if(!this.altFormatsArray){
40340 this.altFormatsArray = this.altFormats.split("|");
40342 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40343 v = Date.parseDate(value, this.altFormatsArray[i]);
40350 formatDate : function(date, fmt){
40351 return (!date || !(date instanceof Date)) ?
40352 date : date.dateFormat(fmt || this.format);
40357 select: function(m, d){
40360 this.fireEvent('select', this, d);
40362 show : function(){ // retain focus styling
40366 this.focus.defer(10, this);
40367 var ml = this.menuListeners;
40368 this.menu.un("select", ml.select, this);
40369 this.menu.un("show", ml.show, this);
40370 this.menu.un("hide", ml.hide, this);
40375 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40376 onTriggerClick : function(){
40380 if(this.menu == null){
40381 this.menu = new Roo.menu.DateMenu();
40383 Roo.apply(this.menu.picker, {
40384 showClear: this.allowBlank,
40385 minDate : this.minValue,
40386 maxDate : this.maxValue,
40387 disabledDatesRE : this.ddMatch,
40388 disabledDatesText : this.disabledDatesText,
40389 disabledDays : this.disabledDays,
40390 disabledDaysText : this.disabledDaysText,
40391 format : this.useIso ? 'Y-m-d' : this.format,
40392 minText : String.format(this.minText, this.formatDate(this.minValue)),
40393 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40395 this.menu.on(Roo.apply({}, this.menuListeners, {
40398 this.menu.picker.setValue(this.getValue() || new Date());
40399 this.menu.show(this.el, "tl-bl?");
40402 beforeBlur : function(){
40403 var v = this.parseDate(this.getRawValue());
40413 isDirty : function() {
40414 if(this.disabled) {
40418 if(typeof(this.startValue) === 'undefined'){
40422 return String(this.getValue()) !== String(this.startValue);
40427 * Ext JS Library 1.1.1
40428 * Copyright(c) 2006-2007, Ext JS, LLC.
40430 * Originally Released Under LGPL - original licence link has changed is not relivant.
40433 * <script type="text/javascript">
40437 * @class Roo.form.MonthField
40438 * @extends Roo.form.TriggerField
40439 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40441 * Create a new MonthField
40442 * @param {Object} config
40444 Roo.form.MonthField = function(config){
40446 Roo.form.MonthField.superclass.constructor.call(this, config);
40452 * Fires when a date is selected
40453 * @param {Roo.form.MonthFieeld} combo This combo box
40454 * @param {Date} date The date selected
40461 if(typeof this.minValue == "string") {
40462 this.minValue = this.parseDate(this.minValue);
40464 if(typeof this.maxValue == "string") {
40465 this.maxValue = this.parseDate(this.maxValue);
40467 this.ddMatch = null;
40468 if(this.disabledDates){
40469 var dd = this.disabledDates;
40471 for(var i = 0; i < dd.length; i++){
40473 if(i != dd.length-1) {
40477 this.ddMatch = new RegExp(re + ")");
40481 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
40483 * @cfg {String} format
40484 * The default date format string which can be overriden for localization support. The format must be
40485 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40489 * @cfg {String} altFormats
40490 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40491 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40493 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
40495 * @cfg {Array} disabledDays
40496 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40498 disabledDays : [0,1,2,3,4,5,6],
40500 * @cfg {String} disabledDaysText
40501 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40503 disabledDaysText : "Disabled",
40505 * @cfg {Array} disabledDates
40506 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40507 * expression so they are very powerful. Some examples:
40509 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40510 * <li>["03/08", "09/16"] would disable those days for every year</li>
40511 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40512 * <li>["03/../2006"] would disable every day in March 2006</li>
40513 * <li>["^03"] would disable every day in every March</li>
40515 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40516 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40518 disabledDates : null,
40520 * @cfg {String} disabledDatesText
40521 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40523 disabledDatesText : "Disabled",
40525 * @cfg {Date/String} minValue
40526 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40527 * valid format (defaults to null).
40531 * @cfg {Date/String} maxValue
40532 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40533 * valid format (defaults to null).
40537 * @cfg {String} minText
40538 * The error text to display when the date in the cell is before minValue (defaults to
40539 * 'The date in this field must be after {minValue}').
40541 minText : "The date in this field must be equal to or after {0}",
40543 * @cfg {String} maxTextf
40544 * The error text to display when the date in the cell is after maxValue (defaults to
40545 * 'The date in this field must be before {maxValue}').
40547 maxText : "The date in this field must be equal to or before {0}",
40549 * @cfg {String} invalidText
40550 * The error text to display when the date in the field is invalid (defaults to
40551 * '{value} is not a valid date - it must be in the format {format}').
40553 invalidText : "{0} is not a valid date - it must be in the format {1}",
40555 * @cfg {String} triggerClass
40556 * An additional CSS class used to style the trigger button. The trigger will always get the
40557 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40558 * which displays a calendar icon).
40560 triggerClass : 'x-form-date-trigger',
40564 * @cfg {Boolean} useIso
40565 * if enabled, then the date field will use a hidden field to store the
40566 * real value as iso formated date. default (true)
40570 * @cfg {String/Object} autoCreate
40571 * A DomHelper element spec, or true for a default element spec (defaults to
40572 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40575 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
40578 hiddenField: false,
40580 hideMonthPicker : false,
40582 onRender : function(ct, position)
40584 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
40586 this.el.dom.removeAttribute('name');
40587 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40589 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40590 // prevent input submission
40591 this.hiddenName = this.name;
40598 validateValue : function(value)
40600 value = this.formatDate(value);
40601 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
40604 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40607 var svalue = value;
40608 value = this.parseDate(value);
40610 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40613 var time = value.getTime();
40614 if(this.minValue && time < this.minValue.getTime()){
40615 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40618 if(this.maxValue && time > this.maxValue.getTime()){
40619 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40622 /*if(this.disabledDays){
40623 var day = value.getDay();
40624 for(var i = 0; i < this.disabledDays.length; i++) {
40625 if(day === this.disabledDays[i]){
40626 this.markInvalid(this.disabledDaysText);
40632 var fvalue = this.formatDate(value);
40633 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
40634 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40642 // Provides logic to override the default TriggerField.validateBlur which just returns true
40643 validateBlur : function(){
40644 return !this.menu || !this.menu.isVisible();
40648 * Returns the current date value of the date field.
40649 * @return {Date} The date value
40651 getValue : function(){
40655 return this.hiddenField ?
40656 this.hiddenField.value :
40657 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
40661 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40662 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
40663 * (the default format used is "m/d/y").
40666 //All of these calls set the same date value (May 4, 2006)
40668 //Pass a date object:
40669 var dt = new Date('5/4/06');
40670 monthField.setValue(dt);
40672 //Pass a date string (default format):
40673 monthField.setValue('5/4/06');
40675 //Pass a date string (custom format):
40676 monthField.format = 'Y-m-d';
40677 monthField.setValue('2006-5-4');
40679 * @param {String/Date} date The date or valid date string
40681 setValue : function(date){
40682 Roo.log('month setValue' + date);
40683 // can only be first of month..
40685 var val = this.parseDate(date);
40687 if (this.hiddenField) {
40688 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40690 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40691 this.value = this.parseDate(date);
40695 parseDate : function(value){
40696 if(!value || value instanceof Date){
40697 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
40700 var v = Date.parseDate(value, this.format);
40701 if (!v && this.useIso) {
40702 v = Date.parseDate(value, 'Y-m-d');
40706 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
40710 if(!v && this.altFormats){
40711 if(!this.altFormatsArray){
40712 this.altFormatsArray = this.altFormats.split("|");
40714 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40715 v = Date.parseDate(value, this.altFormatsArray[i]);
40722 formatDate : function(date, fmt){
40723 return (!date || !(date instanceof Date)) ?
40724 date : date.dateFormat(fmt || this.format);
40729 select: function(m, d){
40731 this.fireEvent('select', this, d);
40733 show : function(){ // retain focus styling
40737 this.focus.defer(10, this);
40738 var ml = this.menuListeners;
40739 this.menu.un("select", ml.select, this);
40740 this.menu.un("show", ml.show, this);
40741 this.menu.un("hide", ml.hide, this);
40745 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40746 onTriggerClick : function(){
40750 if(this.menu == null){
40751 this.menu = new Roo.menu.DateMenu();
40755 Roo.apply(this.menu.picker, {
40757 showClear: this.allowBlank,
40758 minDate : this.minValue,
40759 maxDate : this.maxValue,
40760 disabledDatesRE : this.ddMatch,
40761 disabledDatesText : this.disabledDatesText,
40763 format : this.useIso ? 'Y-m-d' : this.format,
40764 minText : String.format(this.minText, this.formatDate(this.minValue)),
40765 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40768 this.menu.on(Roo.apply({}, this.menuListeners, {
40776 // hide month picker get's called when we called by 'before hide';
40778 var ignorehide = true;
40779 p.hideMonthPicker = function(disableAnim){
40783 if(this.monthPicker){
40784 Roo.log("hideMonthPicker called");
40785 if(disableAnim === true){
40786 this.monthPicker.hide();
40788 this.monthPicker.slideOut('t', {duration:.2});
40789 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
40790 p.fireEvent("select", this, this.value);
40796 Roo.log('picker set value');
40797 Roo.log(this.getValue());
40798 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
40799 m.show(this.el, 'tl-bl?');
40800 ignorehide = false;
40801 // this will trigger hideMonthPicker..
40804 // hidden the day picker
40805 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
40811 p.showMonthPicker.defer(100, p);
40817 beforeBlur : function(){
40818 var v = this.parseDate(this.getRawValue());
40824 /** @cfg {Boolean} grow @hide */
40825 /** @cfg {Number} growMin @hide */
40826 /** @cfg {Number} growMax @hide */
40833 * Ext JS Library 1.1.1
40834 * Copyright(c) 2006-2007, Ext JS, LLC.
40836 * Originally Released Under LGPL - original licence link has changed is not relivant.
40839 * <script type="text/javascript">
40844 * @class Roo.form.ComboBox
40845 * @extends Roo.form.TriggerField
40846 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
40848 * Create a new ComboBox.
40849 * @param {Object} config Configuration options
40851 Roo.form.ComboBox = function(config){
40852 Roo.form.ComboBox.superclass.constructor.call(this, config);
40856 * Fires when the dropdown list is expanded
40857 * @param {Roo.form.ComboBox} combo This combo box
40862 * Fires when the dropdown list is collapsed
40863 * @param {Roo.form.ComboBox} combo This combo box
40867 * @event beforeselect
40868 * Fires before a list item is selected. Return false to cancel the selection.
40869 * @param {Roo.form.ComboBox} combo This combo box
40870 * @param {Roo.data.Record} record The data record returned from the underlying store
40871 * @param {Number} index The index of the selected item in the dropdown list
40873 'beforeselect' : true,
40876 * Fires when a list item is selected
40877 * @param {Roo.form.ComboBox} combo This combo box
40878 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
40879 * @param {Number} index The index of the selected item in the dropdown list
40883 * @event beforequery
40884 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
40885 * The event object passed has these properties:
40886 * @param {Roo.form.ComboBox} combo This combo box
40887 * @param {String} query The query
40888 * @param {Boolean} forceAll true to force "all" query
40889 * @param {Boolean} cancel true to cancel the query
40890 * @param {Object} e The query event object
40892 'beforequery': true,
40895 * Fires when the 'add' icon is pressed (add a listener to enable add button)
40896 * @param {Roo.form.ComboBox} combo This combo box
40901 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
40902 * @param {Roo.form.ComboBox} combo This combo box
40903 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
40909 if(this.transform){
40910 this.allowDomMove = false;
40911 var s = Roo.getDom(this.transform);
40912 if(!this.hiddenName){
40913 this.hiddenName = s.name;
40916 this.mode = 'local';
40917 var d = [], opts = s.options;
40918 for(var i = 0, len = opts.length;i < len; i++){
40920 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
40922 this.value = value;
40924 d.push([value, o.text]);
40926 this.store = new Roo.data.SimpleStore({
40928 fields: ['value', 'text'],
40931 this.valueField = 'value';
40932 this.displayField = 'text';
40934 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
40935 if(!this.lazyRender){
40936 this.target = true;
40937 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
40938 s.parentNode.removeChild(s); // remove it
40939 this.render(this.el.parentNode);
40941 s.parentNode.removeChild(s); // remove it
40946 this.store = Roo.factory(this.store, Roo.data);
40949 this.selectedIndex = -1;
40950 if(this.mode == 'local'){
40951 if(config.queryDelay === undefined){
40952 this.queryDelay = 10;
40954 if(config.minChars === undefined){
40960 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
40962 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
40965 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
40966 * rendering into an Roo.Editor, defaults to false)
40969 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
40970 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
40973 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
40976 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
40977 * the dropdown list (defaults to undefined, with no header element)
40981 * @cfg {String/Roo.Template} tpl The template to use to render the output
40985 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
40987 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
40989 listWidth: undefined,
40991 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
40992 * mode = 'remote' or 'text' if mode = 'local')
40994 displayField: undefined,
40996 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
40997 * mode = 'remote' or 'value' if mode = 'local').
40998 * Note: use of a valueField requires the user make a selection
40999 * in order for a value to be mapped.
41001 valueField: undefined,
41005 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41006 * field's data value (defaults to the underlying DOM element's name)
41008 hiddenName: undefined,
41010 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41014 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41016 selectedClass: 'x-combo-selected',
41018 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41019 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41020 * which displays a downward arrow icon).
41022 triggerClass : 'x-form-arrow-trigger',
41024 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41028 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41029 * anchor positions (defaults to 'tl-bl')
41031 listAlign: 'tl-bl?',
41033 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41037 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41038 * query specified by the allQuery config option (defaults to 'query')
41040 triggerAction: 'query',
41042 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41043 * (defaults to 4, does not apply if editable = false)
41047 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41048 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41052 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41053 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41057 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41058 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41062 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41063 * when editable = true (defaults to false)
41065 selectOnFocus:false,
41067 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41069 queryParam: 'query',
41071 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41072 * when mode = 'remote' (defaults to 'Loading...')
41074 loadingText: 'Loading...',
41076 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41080 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41084 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41085 * traditional select (defaults to true)
41089 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41093 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41097 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41098 * listWidth has a higher value)
41102 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41103 * allow the user to set arbitrary text into the field (defaults to false)
41105 forceSelection:false,
41107 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41108 * if typeAhead = true (defaults to 250)
41110 typeAheadDelay : 250,
41112 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41113 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41115 valueNotFoundText : undefined,
41117 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41119 blockFocus : false,
41122 * @cfg {Boolean} disableClear Disable showing of clear button.
41124 disableClear : false,
41126 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41128 alwaysQuery : false,
41134 // element that contains real text value.. (when hidden is used..)
41137 onRender : function(ct, position){
41138 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41139 if(this.hiddenName){
41140 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41142 this.hiddenField.value =
41143 this.hiddenValue !== undefined ? this.hiddenValue :
41144 this.value !== undefined ? this.value : '';
41146 // prevent input submission
41147 this.el.dom.removeAttribute('name');
41152 this.el.dom.setAttribute('autocomplete', 'off');
41155 var cls = 'x-combo-list';
41157 this.list = new Roo.Layer({
41158 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41161 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41162 this.list.setWidth(lw);
41163 this.list.swallowEvent('mousewheel');
41164 this.assetHeight = 0;
41167 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41168 this.assetHeight += this.header.getHeight();
41171 this.innerList = this.list.createChild({cls:cls+'-inner'});
41172 this.innerList.on('mouseover', this.onViewOver, this);
41173 this.innerList.on('mousemove', this.onViewMove, this);
41174 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41176 if(this.allowBlank && !this.pageSize && !this.disableClear){
41177 this.footer = this.list.createChild({cls:cls+'-ft'});
41178 this.pageTb = new Roo.Toolbar(this.footer);
41182 this.footer = this.list.createChild({cls:cls+'-ft'});
41183 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41184 {pageSize: this.pageSize});
41188 if (this.pageTb && this.allowBlank && !this.disableClear) {
41190 this.pageTb.add(new Roo.Toolbar.Fill(), {
41191 cls: 'x-btn-icon x-btn-clear',
41193 handler: function()
41196 _this.clearValue();
41197 _this.onSelect(false, -1);
41202 this.assetHeight += this.footer.getHeight();
41207 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41210 this.view = new Roo.View(this.innerList, this.tpl, {
41211 singleSelect:true, store: this.store, selectedClass: this.selectedClass
41214 this.view.on('click', this.onViewClick, this);
41216 this.store.on('beforeload', this.onBeforeLoad, this);
41217 this.store.on('load', this.onLoad, this);
41218 this.store.on('loadexception', this.onLoadException, this);
41220 if(this.resizable){
41221 this.resizer = new Roo.Resizable(this.list, {
41222 pinned:true, handles:'se'
41224 this.resizer.on('resize', function(r, w, h){
41225 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41226 this.listWidth = w;
41227 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41228 this.restrictHeight();
41230 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41232 if(!this.editable){
41233 this.editable = true;
41234 this.setEditable(false);
41238 if (typeof(this.events.add.listeners) != 'undefined') {
41240 this.addicon = this.wrap.createChild(
41241 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41243 this.addicon.on('click', function(e) {
41244 this.fireEvent('add', this);
41247 if (typeof(this.events.edit.listeners) != 'undefined') {
41249 this.editicon = this.wrap.createChild(
41250 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41251 if (this.addicon) {
41252 this.editicon.setStyle('margin-left', '40px');
41254 this.editicon.on('click', function(e) {
41256 // we fire even if inothing is selected..
41257 this.fireEvent('edit', this, this.lastData );
41267 initEvents : function(){
41268 Roo.form.ComboBox.superclass.initEvents.call(this);
41270 this.keyNav = new Roo.KeyNav(this.el, {
41271 "up" : function(e){
41272 this.inKeyMode = true;
41276 "down" : function(e){
41277 if(!this.isExpanded()){
41278 this.onTriggerClick();
41280 this.inKeyMode = true;
41285 "enter" : function(e){
41286 this.onViewClick();
41290 "esc" : function(e){
41294 "tab" : function(e){
41295 this.onViewClick(false);
41296 this.fireEvent("specialkey", this, e);
41302 doRelay : function(foo, bar, hname){
41303 if(hname == 'down' || this.scope.isExpanded()){
41304 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41311 this.queryDelay = Math.max(this.queryDelay || 10,
41312 this.mode == 'local' ? 10 : 250);
41313 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41314 if(this.typeAhead){
41315 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41317 if(this.editable !== false){
41318 this.el.on("keyup", this.onKeyUp, this);
41320 if(this.forceSelection){
41321 this.on('blur', this.doForce, this);
41325 onDestroy : function(){
41327 this.view.setStore(null);
41328 this.view.el.removeAllListeners();
41329 this.view.el.remove();
41330 this.view.purgeListeners();
41333 this.list.destroy();
41336 this.store.un('beforeload', this.onBeforeLoad, this);
41337 this.store.un('load', this.onLoad, this);
41338 this.store.un('loadexception', this.onLoadException, this);
41340 Roo.form.ComboBox.superclass.onDestroy.call(this);
41344 fireKey : function(e){
41345 if(e.isNavKeyPress() && !this.list.isVisible()){
41346 this.fireEvent("specialkey", this, e);
41351 onResize: function(w, h){
41352 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41354 if(typeof w != 'number'){
41355 // we do not handle it!?!?
41358 var tw = this.trigger.getWidth();
41359 tw += this.addicon ? this.addicon.getWidth() : 0;
41360 tw += this.editicon ? this.editicon.getWidth() : 0;
41362 this.el.setWidth( this.adjustWidth('input', x));
41364 this.trigger.setStyle('left', x+'px');
41366 if(this.list && this.listWidth === undefined){
41367 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41368 this.list.setWidth(lw);
41369 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41377 * Allow or prevent the user from directly editing the field text. If false is passed,
41378 * the user will only be able to select from the items defined in the dropdown list. This method
41379 * is the runtime equivalent of setting the 'editable' config option at config time.
41380 * @param {Boolean} value True to allow the user to directly edit the field text
41382 setEditable : function(value){
41383 if(value == this.editable){
41386 this.editable = value;
41388 this.el.dom.setAttribute('readOnly', true);
41389 this.el.on('mousedown', this.onTriggerClick, this);
41390 this.el.addClass('x-combo-noedit');
41392 this.el.dom.setAttribute('readOnly', false);
41393 this.el.un('mousedown', this.onTriggerClick, this);
41394 this.el.removeClass('x-combo-noedit');
41399 onBeforeLoad : function(){
41400 if(!this.hasFocus){
41403 this.innerList.update(this.loadingText ?
41404 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41405 this.restrictHeight();
41406 this.selectedIndex = -1;
41410 onLoad : function(){
41411 if(!this.hasFocus){
41414 if(this.store.getCount() > 0){
41416 this.restrictHeight();
41417 if(this.lastQuery == this.allQuery){
41419 this.el.dom.select();
41421 if(!this.selectByValue(this.value, true)){
41422 this.select(0, true);
41426 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41427 this.taTask.delay(this.typeAheadDelay);
41431 this.onEmptyResults();
41436 onLoadException : function()
41439 Roo.log(this.store.reader.jsonData);
41440 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41441 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41447 onTypeAhead : function(){
41448 if(this.store.getCount() > 0){
41449 var r = this.store.getAt(0);
41450 var newValue = r.data[this.displayField];
41451 var len = newValue.length;
41452 var selStart = this.getRawValue().length;
41453 if(selStart != len){
41454 this.setRawValue(newValue);
41455 this.selectText(selStart, newValue.length);
41461 onSelect : function(record, index){
41462 if(this.fireEvent('beforeselect', this, record, index) !== false){
41463 this.setFromData(index > -1 ? record.data : false);
41465 this.fireEvent('select', this, record, index);
41470 * Returns the currently selected field value or empty string if no value is set.
41471 * @return {String} value The selected value
41473 getValue : function(){
41474 if(this.valueField){
41475 return typeof this.value != 'undefined' ? this.value : '';
41477 return Roo.form.ComboBox.superclass.getValue.call(this);
41481 * Clears any text/value currently set in the field
41483 clearValue : function(){
41484 if(this.hiddenField){
41485 this.hiddenField.value = '';
41488 this.setRawValue('');
41489 this.lastSelectionText = '';
41494 * Sets the specified value into the field. If the value finds a match, the corresponding record text
41495 * will be displayed in the field. If the value does not match the data value of an existing item,
41496 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
41497 * Otherwise the field will be blank (although the value will still be set).
41498 * @param {String} value The value to match
41500 setValue : function(v){
41502 if(this.valueField){
41503 var r = this.findRecord(this.valueField, v);
41505 text = r.data[this.displayField];
41506 }else if(this.valueNotFoundText !== undefined){
41507 text = this.valueNotFoundText;
41510 this.lastSelectionText = text;
41511 if(this.hiddenField){
41512 this.hiddenField.value = v;
41514 Roo.form.ComboBox.superclass.setValue.call(this, text);
41518 * @property {Object} the last set data for the element
41523 * Sets the value of the field based on a object which is related to the record format for the store.
41524 * @param {Object} value the value to set as. or false on reset?
41526 setFromData : function(o){
41527 var dv = ''; // display value
41528 var vv = ''; // value value..
41530 if (this.displayField) {
41531 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
41533 // this is an error condition!!!
41534 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
41537 if(this.valueField){
41538 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
41540 if(this.hiddenField){
41541 this.hiddenField.value = vv;
41543 this.lastSelectionText = dv;
41544 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41548 // no hidden field.. - we store the value in 'value', but still display
41549 // display field!!!!
41550 this.lastSelectionText = dv;
41551 Roo.form.ComboBox.superclass.setValue.call(this, dv);
41557 reset : function(){
41558 // overridden so that last data is reset..
41559 this.setValue(this.resetValue);
41560 this.clearInvalid();
41561 this.lastData = false;
41563 this.view.clearSelections();
41567 findRecord : function(prop, value){
41569 if(this.store.getCount() > 0){
41570 this.store.each(function(r){
41571 if(r.data[prop] == value){
41581 getName: function()
41583 // returns hidden if it's set..
41584 if (!this.rendered) {return ''};
41585 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
41589 onViewMove : function(e, t){
41590 this.inKeyMode = false;
41594 onViewOver : function(e, t){
41595 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
41598 var item = this.view.findItemFromChild(t);
41600 var index = this.view.indexOf(item);
41601 this.select(index, false);
41606 onViewClick : function(doFocus)
41608 var index = this.view.getSelectedIndexes()[0];
41609 var r = this.store.getAt(index);
41611 this.onSelect(r, index);
41613 if(doFocus !== false && !this.blockFocus){
41619 restrictHeight : function(){
41620 this.innerList.dom.style.height = '';
41621 var inner = this.innerList.dom;
41622 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
41623 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
41624 this.list.beginUpdate();
41625 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
41626 this.list.alignTo(this.el, this.listAlign);
41627 this.list.endUpdate();
41631 onEmptyResults : function(){
41636 * Returns true if the dropdown list is expanded, else false.
41638 isExpanded : function(){
41639 return this.list.isVisible();
41643 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
41644 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41645 * @param {String} value The data value of the item to select
41646 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41647 * selected item if it is not currently in view (defaults to true)
41648 * @return {Boolean} True if the value matched an item in the list, else false
41650 selectByValue : function(v, scrollIntoView){
41651 if(v !== undefined && v !== null){
41652 var r = this.findRecord(this.valueField || this.displayField, v);
41654 this.select(this.store.indexOf(r), scrollIntoView);
41662 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
41663 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
41664 * @param {Number} index The zero-based index of the list item to select
41665 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
41666 * selected item if it is not currently in view (defaults to true)
41668 select : function(index, scrollIntoView){
41669 this.selectedIndex = index;
41670 this.view.select(index);
41671 if(scrollIntoView !== false){
41672 var el = this.view.getNode(index);
41674 this.innerList.scrollChildIntoView(el, false);
41680 selectNext : function(){
41681 var ct = this.store.getCount();
41683 if(this.selectedIndex == -1){
41685 }else if(this.selectedIndex < ct-1){
41686 this.select(this.selectedIndex+1);
41692 selectPrev : function(){
41693 var ct = this.store.getCount();
41695 if(this.selectedIndex == -1){
41697 }else if(this.selectedIndex != 0){
41698 this.select(this.selectedIndex-1);
41704 onKeyUp : function(e){
41705 if(this.editable !== false && !e.isSpecialKey()){
41706 this.lastKey = e.getKey();
41707 this.dqTask.delay(this.queryDelay);
41712 validateBlur : function(){
41713 return !this.list || !this.list.isVisible();
41717 initQuery : function(){
41718 this.doQuery(this.getRawValue());
41722 doForce : function(){
41723 if(this.el.dom.value.length > 0){
41724 this.el.dom.value =
41725 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
41731 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
41732 * query allowing the query action to be canceled if needed.
41733 * @param {String} query The SQL query to execute
41734 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
41735 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
41736 * saved in the current store (defaults to false)
41738 doQuery : function(q, forceAll){
41739 if(q === undefined || q === null){
41744 forceAll: forceAll,
41748 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
41752 forceAll = qe.forceAll;
41753 if(forceAll === true || (q.length >= this.minChars)){
41754 if(this.lastQuery != q || this.alwaysQuery){
41755 this.lastQuery = q;
41756 if(this.mode == 'local'){
41757 this.selectedIndex = -1;
41759 this.store.clearFilter();
41761 this.store.filter(this.displayField, q);
41765 this.store.baseParams[this.queryParam] = q;
41767 params: this.getParams(q)
41772 this.selectedIndex = -1;
41779 getParams : function(q){
41781 //p[this.queryParam] = q;
41784 p.limit = this.pageSize;
41790 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
41792 collapse : function(){
41793 if(!this.isExpanded()){
41797 Roo.get(document).un('mousedown', this.collapseIf, this);
41798 Roo.get(document).un('mousewheel', this.collapseIf, this);
41799 if (!this.editable) {
41800 Roo.get(document).un('keydown', this.listKeyPress, this);
41802 this.fireEvent('collapse', this);
41806 collapseIf : function(e){
41807 if(!e.within(this.wrap) && !e.within(this.list)){
41813 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
41815 expand : function(){
41816 if(this.isExpanded() || !this.hasFocus){
41819 this.list.alignTo(this.el, this.listAlign);
41821 Roo.get(document).on('mousedown', this.collapseIf, this);
41822 Roo.get(document).on('mousewheel', this.collapseIf, this);
41823 if (!this.editable) {
41824 Roo.get(document).on('keydown', this.listKeyPress, this);
41827 this.fireEvent('expand', this);
41831 // Implements the default empty TriggerField.onTriggerClick function
41832 onTriggerClick : function(){
41836 if(this.isExpanded()){
41838 if (!this.blockFocus) {
41843 this.hasFocus = true;
41844 if(this.triggerAction == 'all') {
41845 this.doQuery(this.allQuery, true);
41847 this.doQuery(this.getRawValue());
41849 if (!this.blockFocus) {
41854 listKeyPress : function(e)
41856 //Roo.log('listkeypress');
41857 // scroll to first matching element based on key pres..
41858 if (e.isSpecialKey()) {
41861 var k = String.fromCharCode(e.getKey()).toUpperCase();
41864 var csel = this.view.getSelectedNodes();
41865 var cselitem = false;
41867 var ix = this.view.indexOf(csel[0]);
41868 cselitem = this.store.getAt(ix);
41869 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
41875 this.store.each(function(v) {
41877 // start at existing selection.
41878 if (cselitem.id == v.id) {
41884 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
41885 match = this.store.indexOf(v);
41890 if (match === false) {
41891 return true; // no more action?
41894 this.view.select(match);
41895 var sn = Roo.get(this.view.getSelectedNodes()[0]);
41896 sn.scrollIntoView(sn.dom.parentNode, false);
41900 * @cfg {Boolean} grow
41904 * @cfg {Number} growMin
41908 * @cfg {Number} growMax
41916 * Copyright(c) 2010-2012, Roo J Solutions Limited
41923 * @class Roo.form.ComboBoxArray
41924 * @extends Roo.form.TextField
41925 * A facebook style adder... for lists of email / people / countries etc...
41926 * pick multiple items from a combo box, and shows each one.
41928 * Fred [x] Brian [x] [Pick another |v]
41931 * For this to work: it needs various extra information
41932 * - normal combo problay has
41934 * + displayField, valueField
41936 * For our purpose...
41939 * If we change from 'extends' to wrapping...
41946 * Create a new ComboBoxArray.
41947 * @param {Object} config Configuration options
41951 Roo.form.ComboBoxArray = function(config)
41955 * @event beforeremove
41956 * Fires before remove the value from the list
41957 * @param {Roo.form.ComboBoxArray} _self This combo box array
41958 * @param {Roo.form.ComboBoxArray.Item} item removed item
41960 'beforeremove' : true,
41963 * Fires when remove the value from the list
41964 * @param {Roo.form.ComboBoxArray} _self This combo box array
41965 * @param {Roo.form.ComboBoxArray.Item} item removed item
41972 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
41974 this.items = new Roo.util.MixedCollection(false);
41976 // construct the child combo...
41986 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
41989 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
41994 // behavies liek a hiddne field
41995 inputType: 'hidden',
41997 * @cfg {Number} width The width of the box that displays the selected element
42004 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42008 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42010 hiddenName : false,
42013 // private the array of items that are displayed..
42015 // private - the hidden field el.
42017 // private - the filed el..
42020 //validateValue : function() { return true; }, // all values are ok!
42021 //onAddClick: function() { },
42023 onRender : function(ct, position)
42026 // create the standard hidden element
42027 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42030 // give fake names to child combo;
42031 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42032 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
42034 this.combo = Roo.factory(this.combo, Roo.form);
42035 this.combo.onRender(ct, position);
42036 if (typeof(this.combo.width) != 'undefined') {
42037 this.combo.onResize(this.combo.width,0);
42040 this.combo.initEvents();
42042 // assigned so form know we need to do this..
42043 this.store = this.combo.store;
42044 this.valueField = this.combo.valueField;
42045 this.displayField = this.combo.displayField ;
42048 this.combo.wrap.addClass('x-cbarray-grp');
42050 var cbwrap = this.combo.wrap.createChild(
42051 {tag: 'div', cls: 'x-cbarray-cb'},
42056 this.hiddenEl = this.combo.wrap.createChild({
42057 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42059 this.el = this.combo.wrap.createChild({
42060 tag: 'input', type:'hidden' , name: this.name, value : ''
42062 // this.el.dom.removeAttribute("name");
42065 this.outerWrap = this.combo.wrap;
42066 this.wrap = cbwrap;
42068 this.outerWrap.setWidth(this.width);
42069 this.outerWrap.dom.removeChild(this.el.dom);
42071 this.wrap.dom.appendChild(this.el.dom);
42072 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42073 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42075 this.combo.trigger.setStyle('position','relative');
42076 this.combo.trigger.setStyle('left', '0px');
42077 this.combo.trigger.setStyle('top', '2px');
42079 this.combo.el.setStyle('vertical-align', 'text-bottom');
42081 //this.trigger.setStyle('vertical-align', 'top');
42083 // this should use the code from combo really... on('add' ....)
42087 this.adder = this.outerWrap.createChild(
42088 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42090 this.adder.on('click', function(e) {
42091 _t.fireEvent('adderclick', this, e);
42095 //this.adder.on('click', this.onAddClick, _t);
42098 this.combo.on('select', function(cb, rec, ix) {
42099 this.addItem(rec.data);
42102 cb.el.dom.value = '';
42103 //cb.lastData = rec.data;
42112 getName: function()
42114 // returns hidden if it's set..
42115 if (!this.rendered) {return ''};
42116 return this.hiddenName ? this.hiddenName : this.name;
42121 onResize: function(w, h){
42124 // not sure if this is needed..
42125 //this.combo.onResize(w,h);
42127 if(typeof w != 'number'){
42128 // we do not handle it!?!?
42131 var tw = this.combo.trigger.getWidth();
42132 tw += this.addicon ? this.addicon.getWidth() : 0;
42133 tw += this.editicon ? this.editicon.getWidth() : 0;
42135 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42137 this.combo.trigger.setStyle('left', '0px');
42139 if(this.list && this.listWidth === undefined){
42140 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42141 this.list.setWidth(lw);
42142 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42149 addItem: function(rec)
42151 var valueField = this.combo.valueField;
42152 var displayField = this.combo.displayField;
42153 if (this.items.indexOfKey(rec[valueField]) > -1) {
42154 //console.log("GOT " + rec.data.id);
42158 var x = new Roo.form.ComboBoxArray.Item({
42159 //id : rec[this.idField],
42161 displayField : displayField ,
42162 tipField : displayField ,
42166 this.items.add(rec[valueField],x);
42167 // add it before the element..
42168 this.updateHiddenEl();
42169 x.render(this.outerWrap, this.wrap.dom);
42170 // add the image handler..
42173 updateHiddenEl : function()
42176 if (!this.hiddenEl) {
42180 var idField = this.combo.valueField;
42182 this.items.each(function(f) {
42183 ar.push(f.data[idField]);
42186 this.hiddenEl.dom.value = ar.join(',');
42192 this.items.clear();
42194 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42198 this.el.dom.value = '';
42199 if (this.hiddenEl) {
42200 this.hiddenEl.dom.value = '';
42204 getValue: function()
42206 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42208 setValue: function(v) // not a valid action - must use addItems..
42215 if (this.store.isLocal && (typeof(v) == 'string')) {
42216 // then we can use the store to find the values..
42217 // comma seperated at present.. this needs to allow JSON based encoding..
42218 this.hiddenEl.value = v;
42220 Roo.each(v.split(','), function(k) {
42221 Roo.log("CHECK " + this.valueField + ',' + k);
42222 var li = this.store.query(this.valueField, k);
42227 add[this.valueField] = k;
42228 add[this.displayField] = li.item(0).data[this.displayField];
42234 if (typeof(v) == 'object' ) {
42235 // then let's assume it's an array of objects..
42236 Roo.each(v, function(l) {
42244 setFromData: function(v)
42246 // this recieves an object, if setValues is called.
42248 this.el.dom.value = v[this.displayField];
42249 this.hiddenEl.dom.value = v[this.valueField];
42250 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42253 var kv = v[this.valueField];
42254 var dv = v[this.displayField];
42255 kv = typeof(kv) != 'string' ? '' : kv;
42256 dv = typeof(dv) != 'string' ? '' : dv;
42259 var keys = kv.split(',');
42260 var display = dv.split(',');
42261 for (var i = 0 ; i < keys.length; i++) {
42264 add[this.valueField] = keys[i];
42265 add[this.displayField] = display[i];
42273 * Validates the combox array value
42274 * @return {Boolean} True if the value is valid, else false
42276 validate : function(){
42277 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42278 this.clearInvalid();
42284 validateValue : function(value){
42285 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42293 isDirty : function() {
42294 if(this.disabled) {
42299 var d = Roo.decode(String(this.originalValue));
42301 return String(this.getValue()) !== String(this.originalValue);
42304 var originalValue = [];
42306 for (var i = 0; i < d.length; i++){
42307 originalValue.push(d[i][this.valueField]);
42310 return String(this.getValue()) !== String(originalValue.join(','));
42319 * @class Roo.form.ComboBoxArray.Item
42320 * @extends Roo.BoxComponent
42321 * A selected item in the list
42322 * Fred [x] Brian [x] [Pick another |v]
42325 * Create a new item.
42326 * @param {Object} config Configuration options
42329 Roo.form.ComboBoxArray.Item = function(config) {
42330 config.id = Roo.id();
42331 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42334 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42337 displayField : false,
42341 defaultAutoCreate : {
42343 cls: 'x-cbarray-item',
42350 src : Roo.BLANK_IMAGE_URL ,
42358 onRender : function(ct, position)
42360 Roo.form.Field.superclass.onRender.call(this, ct, position);
42363 var cfg = this.getAutoCreate();
42364 this.el = ct.createChild(cfg, position);
42367 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42369 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42370 this.cb.renderer(this.data) :
42371 String.format('{0}',this.data[this.displayField]);
42374 this.el.child('div').dom.setAttribute('qtip',
42375 String.format('{0}',this.data[this.tipField])
42378 this.el.child('img').on('click', this.remove, this);
42382 remove : function()
42384 if(this.cb.disabled){
42388 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42389 this.cb.items.remove(this);
42390 this.el.child('img').un('click', this.remove, this);
42392 this.cb.updateHiddenEl();
42394 this.cb.fireEvent('remove', this.cb, this);
42400 * Ext JS Library 1.1.1
42401 * Copyright(c) 2006-2007, Ext JS, LLC.
42403 * Originally Released Under LGPL - original licence link has changed is not relivant.
42406 * <script type="text/javascript">
42409 * @class Roo.form.Checkbox
42410 * @extends Roo.form.Field
42411 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
42413 * Creates a new Checkbox
42414 * @param {Object} config Configuration options
42416 Roo.form.Checkbox = function(config){
42417 Roo.form.Checkbox.superclass.constructor.call(this, config);
42421 * Fires when the checkbox is checked or unchecked.
42422 * @param {Roo.form.Checkbox} this This checkbox
42423 * @param {Boolean} checked The new checked value
42429 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
42431 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
42433 focusClass : undefined,
42435 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
42437 fieldClass: "x-form-field",
42439 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
42443 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
42444 * {tag: "input", type: "checkbox", autocomplete: "off"})
42446 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
42448 * @cfg {String} boxLabel The text that appears beside the checkbox
42452 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
42456 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
42458 valueOff: '0', // value when not checked..
42460 actionMode : 'viewEl',
42463 itemCls : 'x-menu-check-item x-form-item',
42464 groupClass : 'x-menu-group-item',
42465 inputType : 'hidden',
42468 inSetChecked: false, // check that we are not calling self...
42470 inputElement: false, // real input element?
42471 basedOn: false, // ????
42473 isFormField: true, // not sure where this is needed!!!!
42475 onResize : function(){
42476 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
42477 if(!this.boxLabel){
42478 this.el.alignTo(this.wrap, 'c-c');
42482 initEvents : function(){
42483 Roo.form.Checkbox.superclass.initEvents.call(this);
42484 this.el.on("click", this.onClick, this);
42485 this.el.on("change", this.onClick, this);
42489 getResizeEl : function(){
42493 getPositionEl : function(){
42498 onRender : function(ct, position){
42499 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42501 if(this.inputValue !== undefined){
42502 this.el.dom.value = this.inputValue;
42505 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42506 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42507 var viewEl = this.wrap.createChild({
42508 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42509 this.viewEl = viewEl;
42510 this.wrap.on('click', this.onClick, this);
42512 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42513 this.el.on('propertychange', this.setFromHidden, this); //ie
42518 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42519 // viewEl.on('click', this.onClick, this);
42521 //if(this.checked){
42522 this.setChecked(this.checked);
42524 //this.checked = this.el.dom;
42530 initValue : Roo.emptyFn,
42533 * Returns the checked state of the checkbox.
42534 * @return {Boolean} True if checked, else false
42536 getValue : function(){
42538 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
42540 return this.valueOff;
42545 onClick : function(){
42546 if (this.disabled) {
42549 this.setChecked(!this.checked);
42551 //if(this.el.dom.checked != this.checked){
42552 // this.setValue(this.el.dom.checked);
42557 * Sets the checked state of the checkbox.
42558 * On is always based on a string comparison between inputValue and the param.
42559 * @param {Boolean/String} value - the value to set
42560 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
42562 setValue : function(v,suppressEvent){
42565 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
42566 //if(this.el && this.el.dom){
42567 // this.el.dom.checked = this.checked;
42568 // this.el.dom.defaultChecked = this.checked;
42570 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
42571 //this.fireEvent("check", this, this.checked);
42574 setChecked : function(state,suppressEvent)
42576 if (this.inSetChecked) {
42577 this.checked = state;
42583 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
42585 this.checked = state;
42586 if(suppressEvent !== true){
42587 this.fireEvent('check', this, state);
42589 this.inSetChecked = true;
42590 this.el.dom.value = state ? this.inputValue : this.valueOff;
42591 this.inSetChecked = false;
42594 // handle setting of hidden value by some other method!!?!?
42595 setFromHidden: function()
42600 //console.log("SET FROM HIDDEN");
42601 //alert('setFrom hidden');
42602 this.setValue(this.el.dom.value);
42605 onDestroy : function()
42608 Roo.get(this.viewEl).remove();
42611 Roo.form.Checkbox.superclass.onDestroy.call(this);
42614 setBoxLabel : function(str)
42616 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
42621 * Ext JS Library 1.1.1
42622 * Copyright(c) 2006-2007, Ext JS, LLC.
42624 * Originally Released Under LGPL - original licence link has changed is not relivant.
42627 * <script type="text/javascript">
42631 * @class Roo.form.Radio
42632 * @extends Roo.form.Checkbox
42633 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
42634 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
42636 * Creates a new Radio
42637 * @param {Object} config Configuration options
42639 Roo.form.Radio = function(){
42640 Roo.form.Radio.superclass.constructor.apply(this, arguments);
42642 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
42643 inputType: 'radio',
42646 * If this radio is part of a group, it will return the selected value
42649 getGroupValue : function(){
42650 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
42654 onRender : function(ct, position){
42655 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
42657 if(this.inputValue !== undefined){
42658 this.el.dom.value = this.inputValue;
42661 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
42662 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
42663 //var viewEl = this.wrap.createChild({
42664 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
42665 //this.viewEl = viewEl;
42666 //this.wrap.on('click', this.onClick, this);
42668 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
42669 //this.el.on('propertychange', this.setFromHidden, this); //ie
42674 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
42675 // viewEl.on('click', this.onClick, this);
42678 this.el.dom.checked = 'checked' ;
42684 });//<script type="text/javascript">
42687 * Based Ext JS Library 1.1.1
42688 * Copyright(c) 2006-2007, Ext JS, LLC.
42694 * @class Roo.HtmlEditorCore
42695 * @extends Roo.Component
42696 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
42698 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
42701 Roo.HtmlEditorCore = function(config){
42704 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
42709 * @event initialize
42710 * Fires when the editor is fully initialized (including the iframe)
42711 * @param {Roo.HtmlEditorCore} this
42716 * Fires when the editor is first receives the focus. Any insertion must wait
42717 * until after this event.
42718 * @param {Roo.HtmlEditorCore} this
42722 * @event beforesync
42723 * Fires before the textarea is updated with content from the editor iframe. Return false
42724 * to cancel the sync.
42725 * @param {Roo.HtmlEditorCore} this
42726 * @param {String} html
42730 * @event beforepush
42731 * Fires before the iframe editor is updated with content from the textarea. Return false
42732 * to cancel the push.
42733 * @param {Roo.HtmlEditorCore} this
42734 * @param {String} html
42739 * Fires when the textarea is updated with content from the editor iframe.
42740 * @param {Roo.HtmlEditorCore} this
42741 * @param {String} html
42746 * Fires when the iframe editor is updated with content from the textarea.
42747 * @param {Roo.HtmlEditorCore} this
42748 * @param {String} html
42753 * @event editorevent
42754 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
42755 * @param {Roo.HtmlEditorCore} this
42761 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
42763 // defaults : white / black...
42764 this.applyBlacklists();
42771 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
42775 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
42781 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
42786 * @cfg {Number} height (in pixels)
42790 * @cfg {Number} width (in pixels)
42795 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
42798 stylesheets: false,
42803 // private properties
42804 validationEvent : false,
42806 initialized : false,
42808 sourceEditMode : false,
42809 onFocus : Roo.emptyFn,
42811 hideMode:'offsets',
42815 // blacklist + whitelisted elements..
42822 * Protected method that will not generally be called directly. It
42823 * is called when the editor initializes the iframe with HTML contents. Override this method if you
42824 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
42826 getDocMarkup : function(){
42830 // inherit styels from page...??
42831 if (this.stylesheets === false) {
42833 Roo.get(document.head).select('style').each(function(node) {
42834 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42837 Roo.get(document.head).select('link').each(function(node) {
42838 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
42841 } else if (!this.stylesheets.length) {
42843 st = '<style type="text/css">' +
42844 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42847 st = '<style type="text/css">' +
42852 st += '<style type="text/css">' +
42853 'IMG { cursor: pointer } ' +
42857 return '<html><head>' + st +
42858 //<style type="text/css">' +
42859 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42861 ' </head><body class="roo-htmleditor-body"></body></html>';
42865 onRender : function(ct, position)
42868 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42869 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42872 this.el.dom.style.border = '0 none';
42873 this.el.dom.setAttribute('tabIndex', -1);
42874 this.el.addClass('x-hidden hide');
42878 if(Roo.isIE){ // fix IE 1px bogus margin
42879 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42883 this.frameId = Roo.id();
42887 var iframe = this.owner.wrap.createChild({
42889 cls: 'form-control', // bootstrap..
42891 name: this.frameId,
42892 frameBorder : 'no',
42893 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42898 this.iframe = iframe.dom;
42900 this.assignDocWin();
42902 this.doc.designMode = 'on';
42905 this.doc.write(this.getDocMarkup());
42909 var task = { // must defer to wait for browser to be ready
42911 //console.log("run task?" + this.doc.readyState);
42912 this.assignDocWin();
42913 if(this.doc.body || this.doc.readyState == 'complete'){
42915 this.doc.designMode="on";
42919 Roo.TaskMgr.stop(task);
42920 this.initEditor.defer(10, this);
42927 Roo.TaskMgr.start(task);
42932 onResize : function(w, h)
42934 Roo.log('resize: ' +w + ',' + h );
42935 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42939 if(typeof w == 'number'){
42941 this.iframe.style.width = w + 'px';
42943 if(typeof h == 'number'){
42945 this.iframe.style.height = h + 'px';
42947 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42954 * Toggles the editor between standard and source edit mode.
42955 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42957 toggleSourceEdit : function(sourceEditMode){
42959 this.sourceEditMode = sourceEditMode === true;
42961 if(this.sourceEditMode){
42963 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42966 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42967 //this.iframe.className = '';
42970 //this.setSize(this.owner.wrap.getSize());
42971 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42978 * Protected method that will not generally be called directly. If you need/want
42979 * custom HTML cleanup, this is the method you should override.
42980 * @param {String} html The HTML to be cleaned
42981 * return {String} The cleaned HTML
42983 cleanHtml : function(html){
42984 html = String(html);
42985 if(html.length > 5){
42986 if(Roo.isSafari){ // strip safari nonsense
42987 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42990 if(html == ' '){
42997 * HTML Editor -> Textarea
42998 * Protected method that will not generally be called directly. Syncs the contents
42999 * of the editor iframe with the textarea.
43001 syncValue : function(){
43002 if(this.initialized){
43003 var bd = (this.doc.body || this.doc.documentElement);
43004 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43005 var html = bd.innerHTML;
43007 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43008 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43010 html = '<div style="'+m[0]+'">' + html + '</div>';
43013 html = this.cleanHtml(html);
43014 // fix up the special chars.. normaly like back quotes in word...
43015 // however we do not want to do this with chinese..
43016 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
43017 var cc = b.charCodeAt();
43019 (cc >= 0x4E00 && cc < 0xA000 ) ||
43020 (cc >= 0x3400 && cc < 0x4E00 ) ||
43021 (cc >= 0xf900 && cc < 0xfb00 )
43027 if(this.owner.fireEvent('beforesync', this, html) !== false){
43028 this.el.dom.value = html;
43029 this.owner.fireEvent('sync', this, html);
43035 * Protected method that will not generally be called directly. Pushes the value of the textarea
43036 * into the iframe editor.
43038 pushValue : function(){
43039 if(this.initialized){
43040 var v = this.el.dom.value.trim();
43042 // if(v.length < 1){
43046 if(this.owner.fireEvent('beforepush', this, v) !== false){
43047 var d = (this.doc.body || this.doc.documentElement);
43049 this.cleanUpPaste();
43050 this.el.dom.value = d.innerHTML;
43051 this.owner.fireEvent('push', this, v);
43057 deferFocus : function(){
43058 this.focus.defer(10, this);
43062 focus : function(){
43063 if(this.win && !this.sourceEditMode){
43070 assignDocWin: function()
43072 var iframe = this.iframe;
43075 this.doc = iframe.contentWindow.document;
43076 this.win = iframe.contentWindow;
43078 // if (!Roo.get(this.frameId)) {
43081 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43082 // this.win = Roo.get(this.frameId).dom.contentWindow;
43084 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43088 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43089 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43094 initEditor : function(){
43095 //console.log("INIT EDITOR");
43096 this.assignDocWin();
43100 this.doc.designMode="on";
43102 this.doc.write(this.getDocMarkup());
43105 var dbody = (this.doc.body || this.doc.documentElement);
43106 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43107 // this copies styles from the containing element into thsi one..
43108 // not sure why we need all of this..
43109 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43111 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43112 //ss['background-attachment'] = 'fixed'; // w3c
43113 dbody.bgProperties = 'fixed'; // ie
43114 //Roo.DomHelper.applyStyles(dbody, ss);
43115 Roo.EventManager.on(this.doc, {
43116 //'mousedown': this.onEditorEvent,
43117 'mouseup': this.onEditorEvent,
43118 'dblclick': this.onEditorEvent,
43119 'click': this.onEditorEvent,
43120 'keyup': this.onEditorEvent,
43125 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43127 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43128 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43130 this.initialized = true;
43132 this.owner.fireEvent('initialize', this);
43137 onDestroy : function(){
43143 //for (var i =0; i < this.toolbars.length;i++) {
43144 // // fixme - ask toolbars for heights?
43145 // this.toolbars[i].onDestroy();
43148 //this.wrap.dom.innerHTML = '';
43149 //this.wrap.remove();
43154 onFirstFocus : function(){
43156 this.assignDocWin();
43159 this.activated = true;
43162 if(Roo.isGecko){ // prevent silly gecko errors
43164 var s = this.win.getSelection();
43165 if(!s.focusNode || s.focusNode.nodeType != 3){
43166 var r = s.getRangeAt(0);
43167 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43172 this.execCmd('useCSS', true);
43173 this.execCmd('styleWithCSS', false);
43176 this.owner.fireEvent('activate', this);
43180 adjustFont: function(btn){
43181 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43182 //if(Roo.isSafari){ // safari
43185 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43186 if(Roo.isSafari){ // safari
43187 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43188 v = (v < 10) ? 10 : v;
43189 v = (v > 48) ? 48 : v;
43190 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43195 v = Math.max(1, v+adjust);
43197 this.execCmd('FontSize', v );
43200 onEditorEvent : function(e)
43202 this.owner.fireEvent('editorevent', this, e);
43203 // this.updateToolbar();
43204 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43207 insertTag : function(tg)
43209 // could be a bit smarter... -> wrap the current selected tRoo..
43210 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43212 range = this.createRange(this.getSelection());
43213 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43214 wrappingNode.appendChild(range.extractContents());
43215 range.insertNode(wrappingNode);
43222 this.execCmd("formatblock", tg);
43226 insertText : function(txt)
43230 var range = this.createRange();
43231 range.deleteContents();
43232 //alert(Sender.getAttribute('label'));
43234 range.insertNode(this.doc.createTextNode(txt));
43240 * Executes a Midas editor command on the editor document and performs necessary focus and
43241 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43242 * @param {String} cmd The Midas command
43243 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43245 relayCmd : function(cmd, value){
43247 this.execCmd(cmd, value);
43248 this.owner.fireEvent('editorevent', this);
43249 //this.updateToolbar();
43250 this.owner.deferFocus();
43254 * Executes a Midas editor command directly on the editor document.
43255 * For visual commands, you should use {@link #relayCmd} instead.
43256 * <b>This should only be called after the editor is initialized.</b>
43257 * @param {String} cmd The Midas command
43258 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43260 execCmd : function(cmd, value){
43261 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43268 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43270 * @param {String} text | dom node..
43272 insertAtCursor : function(text)
43275 if(!this.activated){
43281 var r = this.doc.selection.createRange();
43292 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43296 // from jquery ui (MIT licenced)
43298 var win = this.win;
43300 if (win.getSelection && win.getSelection().getRangeAt) {
43301 range = win.getSelection().getRangeAt(0);
43302 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43303 range.insertNode(node);
43304 } else if (win.document.selection && win.document.selection.createRange) {
43305 // no firefox support
43306 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43307 win.document.selection.createRange().pasteHTML(txt);
43309 // no firefox support
43310 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43311 this.execCmd('InsertHTML', txt);
43320 mozKeyPress : function(e){
43322 var c = e.getCharCode(), cmd;
43325 c = String.fromCharCode(c).toLowerCase();
43339 this.cleanUpPaste.defer(100, this);
43347 e.preventDefault();
43355 fixKeys : function(){ // load time branching for fastest keydown performance
43357 return function(e){
43358 var k = e.getKey(), r;
43361 r = this.doc.selection.createRange();
43364 r.pasteHTML('    ');
43371 r = this.doc.selection.createRange();
43373 var target = r.parentElement();
43374 if(!target || target.tagName.toLowerCase() != 'li'){
43376 r.pasteHTML('<br />');
43382 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43383 this.cleanUpPaste.defer(100, this);
43389 }else if(Roo.isOpera){
43390 return function(e){
43391 var k = e.getKey();
43395 this.execCmd('InsertHTML','    ');
43398 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43399 this.cleanUpPaste.defer(100, this);
43404 }else if(Roo.isSafari){
43405 return function(e){
43406 var k = e.getKey();
43410 this.execCmd('InsertText','\t');
43414 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43415 this.cleanUpPaste.defer(100, this);
43423 getAllAncestors: function()
43425 var p = this.getSelectedNode();
43428 a.push(p); // push blank onto stack..
43429 p = this.getParentElement();
43433 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43437 a.push(this.doc.body);
43441 lastSelNode : false,
43444 getSelection : function()
43446 this.assignDocWin();
43447 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43450 getSelectedNode: function()
43452 // this may only work on Gecko!!!
43454 // should we cache this!!!!
43459 var range = this.createRange(this.getSelection()).cloneRange();
43462 var parent = range.parentElement();
43464 var testRange = range.duplicate();
43465 testRange.moveToElementText(parent);
43466 if (testRange.inRange(range)) {
43469 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43472 parent = parent.parentElement;
43477 // is ancestor a text element.
43478 var ac = range.commonAncestorContainer;
43479 if (ac.nodeType == 3) {
43480 ac = ac.parentNode;
43483 var ar = ac.childNodes;
43486 var other_nodes = [];
43487 var has_other_nodes = false;
43488 for (var i=0;i<ar.length;i++) {
43489 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43492 // fullly contained node.
43494 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43499 // probably selected..
43500 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43501 other_nodes.push(ar[i]);
43505 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43510 has_other_nodes = true;
43512 if (!nodes.length && other_nodes.length) {
43513 nodes= other_nodes;
43515 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43521 createRange: function(sel)
43523 // this has strange effects when using with
43524 // top toolbar - not sure if it's a great idea.
43525 //this.editor.contentWindow.focus();
43526 if (typeof sel != "undefined") {
43528 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43530 return this.doc.createRange();
43533 return this.doc.createRange();
43536 getParentElement: function()
43539 this.assignDocWin();
43540 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43542 var range = this.createRange(sel);
43545 var p = range.commonAncestorContainer;
43546 while (p.nodeType == 3) { // text node
43557 * Range intersection.. the hard stuff...
43561 * [ -- selected range --- ]
43565 * if end is before start or hits it. fail.
43566 * if start is after end or hits it fail.
43568 * if either hits (but other is outside. - then it's not
43574 // @see http://www.thismuchiknow.co.uk/?p=64.
43575 rangeIntersectsNode : function(range, node)
43577 var nodeRange = node.ownerDocument.createRange();
43579 nodeRange.selectNode(node);
43581 nodeRange.selectNodeContents(node);
43584 var rangeStartRange = range.cloneRange();
43585 rangeStartRange.collapse(true);
43587 var rangeEndRange = range.cloneRange();
43588 rangeEndRange.collapse(false);
43590 var nodeStartRange = nodeRange.cloneRange();
43591 nodeStartRange.collapse(true);
43593 var nodeEndRange = nodeRange.cloneRange();
43594 nodeEndRange.collapse(false);
43596 return rangeStartRange.compareBoundaryPoints(
43597 Range.START_TO_START, nodeEndRange) == -1 &&
43598 rangeEndRange.compareBoundaryPoints(
43599 Range.START_TO_START, nodeStartRange) == 1;
43603 rangeCompareNode : function(range, node)
43605 var nodeRange = node.ownerDocument.createRange();
43607 nodeRange.selectNode(node);
43609 nodeRange.selectNodeContents(node);
43613 range.collapse(true);
43615 nodeRange.collapse(true);
43617 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43618 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43620 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43622 var nodeIsBefore = ss == 1;
43623 var nodeIsAfter = ee == -1;
43625 if (nodeIsBefore && nodeIsAfter) {
43628 if (!nodeIsBefore && nodeIsAfter) {
43629 return 1; //right trailed.
43632 if (nodeIsBefore && !nodeIsAfter) {
43633 return 2; // left trailed.
43639 // private? - in a new class?
43640 cleanUpPaste : function()
43642 // cleans up the whole document..
43643 Roo.log('cleanuppaste');
43645 this.cleanUpChildren(this.doc.body);
43646 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43647 if (clean != this.doc.body.innerHTML) {
43648 this.doc.body.innerHTML = clean;
43653 cleanWordChars : function(input) {// change the chars to hex code
43654 var he = Roo.HtmlEditorCore;
43656 var output = input;
43657 Roo.each(he.swapCodes, function(sw) {
43658 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43660 output = output.replace(swapper, sw[1]);
43667 cleanUpChildren : function (n)
43669 if (!n.childNodes.length) {
43672 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43673 this.cleanUpChild(n.childNodes[i]);
43680 cleanUpChild : function (node)
43683 //console.log(node);
43684 if (node.nodeName == "#text") {
43685 // clean up silly Windows -- stuff?
43688 if (node.nodeName == "#comment") {
43689 node.parentNode.removeChild(node);
43690 // clean up silly Windows -- stuff?
43693 var lcname = node.tagName.toLowerCase();
43694 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43695 // whitelist of tags..
43697 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43699 node.parentNode.removeChild(node);
43704 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43706 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43707 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43709 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43710 // remove_keep_children = true;
43713 if (remove_keep_children) {
43714 this.cleanUpChildren(node);
43715 // inserts everything just before this node...
43716 while (node.childNodes.length) {
43717 var cn = node.childNodes[0];
43718 node.removeChild(cn);
43719 node.parentNode.insertBefore(cn, node);
43721 node.parentNode.removeChild(node);
43725 if (!node.attributes || !node.attributes.length) {
43726 this.cleanUpChildren(node);
43730 function cleanAttr(n,v)
43733 if (v.match(/^\./) || v.match(/^\//)) {
43736 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43739 if (v.match(/^#/)) {
43742 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43743 node.removeAttribute(n);
43747 var cwhite = this.cwhite;
43748 var cblack = this.cblack;
43750 function cleanStyle(n,v)
43752 if (v.match(/expression/)) { //XSS?? should we even bother..
43753 node.removeAttribute(n);
43757 var parts = v.split(/;/);
43760 Roo.each(parts, function(p) {
43761 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43765 var l = p.split(':').shift().replace(/\s+/g,'');
43766 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43768 if ( cwhite.length && cblack.indexOf(l) > -1) {
43769 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43770 //node.removeAttribute(n);
43774 // only allow 'c whitelisted system attributes'
43775 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43776 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43777 //node.removeAttribute(n);
43787 if (clean.length) {
43788 node.setAttribute(n, clean.join(';'));
43790 node.removeAttribute(n);
43796 for (var i = node.attributes.length-1; i > -1 ; i--) {
43797 var a = node.attributes[i];
43800 if (a.name.toLowerCase().substr(0,2)=='on') {
43801 node.removeAttribute(a.name);
43804 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43805 node.removeAttribute(a.name);
43808 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43809 cleanAttr(a.name,a.value); // fixme..
43812 if (a.name == 'style') {
43813 cleanStyle(a.name,a.value);
43816 /// clean up MS crap..
43817 // tecnically this should be a list of valid class'es..
43820 if (a.name == 'class') {
43821 if (a.value.match(/^Mso/)) {
43822 node.className = '';
43825 if (a.value.match(/^body$/)) {
43826 node.className = '';
43837 this.cleanUpChildren(node);
43843 * Clean up MS wordisms...
43845 cleanWord : function(node)
43850 this.cleanWord(this.doc.body);
43853 if (node.nodeName == "#text") {
43854 // clean up silly Windows -- stuff?
43857 if (node.nodeName == "#comment") {
43858 node.parentNode.removeChild(node);
43859 // clean up silly Windows -- stuff?
43863 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43864 node.parentNode.removeChild(node);
43868 // remove - but keep children..
43869 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43870 while (node.childNodes.length) {
43871 var cn = node.childNodes[0];
43872 node.removeChild(cn);
43873 node.parentNode.insertBefore(cn, node);
43875 node.parentNode.removeChild(node);
43876 this.iterateChildren(node, this.cleanWord);
43880 if (node.className.length) {
43882 var cn = node.className.split(/\W+/);
43884 Roo.each(cn, function(cls) {
43885 if (cls.match(/Mso[a-zA-Z]+/)) {
43890 node.className = cna.length ? cna.join(' ') : '';
43892 node.removeAttribute("class");
43896 if (node.hasAttribute("lang")) {
43897 node.removeAttribute("lang");
43900 if (node.hasAttribute("style")) {
43902 var styles = node.getAttribute("style").split(";");
43904 Roo.each(styles, function(s) {
43905 if (!s.match(/:/)) {
43908 var kv = s.split(":");
43909 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43912 // what ever is left... we allow.
43915 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43916 if (!nstyle.length) {
43917 node.removeAttribute('style');
43920 this.iterateChildren(node, this.cleanWord);
43926 * iterateChildren of a Node, calling fn each time, using this as the scole..
43927 * @param {DomNode} node node to iterate children of.
43928 * @param {Function} fn method of this class to call on each item.
43930 iterateChildren : function(node, fn)
43932 if (!node.childNodes.length) {
43935 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43936 fn.call(this, node.childNodes[i])
43942 * cleanTableWidths.
43944 * Quite often pasting from word etc.. results in tables with column and widths.
43945 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43948 cleanTableWidths : function(node)
43953 this.cleanTableWidths(this.doc.body);
43958 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43961 Roo.log(node.tagName);
43962 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43963 this.iterateChildren(node, this.cleanTableWidths);
43966 if (node.hasAttribute('width')) {
43967 node.removeAttribute('width');
43971 if (node.hasAttribute("style")) {
43974 var styles = node.getAttribute("style").split(";");
43976 Roo.each(styles, function(s) {
43977 if (!s.match(/:/)) {
43980 var kv = s.split(":");
43981 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43984 // what ever is left... we allow.
43987 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43988 if (!nstyle.length) {
43989 node.removeAttribute('style');
43993 this.iterateChildren(node, this.cleanTableWidths);
44001 domToHTML : function(currentElement, depth, nopadtext) {
44003 depth = depth || 0;
44004 nopadtext = nopadtext || false;
44006 if (!currentElement) {
44007 return this.domToHTML(this.doc.body);
44010 //Roo.log(currentElement);
44012 var allText = false;
44013 var nodeName = currentElement.nodeName;
44014 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44016 if (nodeName == '#text') {
44018 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44023 if (nodeName != 'BODY') {
44026 // Prints the node tagName, such as <A>, <IMG>, etc
44029 for(i = 0; i < currentElement.attributes.length;i++) {
44031 var aname = currentElement.attributes.item(i).name;
44032 if (!currentElement.attributes.item(i).value.length) {
44035 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44038 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44047 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44050 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44055 // Traverse the tree
44057 var currentElementChild = currentElement.childNodes.item(i);
44058 var allText = true;
44059 var innerHTML = '';
44061 while (currentElementChild) {
44062 // Formatting code (indent the tree so it looks nice on the screen)
44063 var nopad = nopadtext;
44064 if (lastnode == 'SPAN') {
44068 if (currentElementChild.nodeName == '#text') {
44069 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44070 toadd = nopadtext ? toadd : toadd.trim();
44071 if (!nopad && toadd.length > 80) {
44072 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44074 innerHTML += toadd;
44077 currentElementChild = currentElement.childNodes.item(i);
44083 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44085 // Recursively traverse the tree structure of the child node
44086 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44087 lastnode = currentElementChild.nodeName;
44089 currentElementChild=currentElement.childNodes.item(i);
44095 // The remaining code is mostly for formatting the tree
44096 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44101 ret+= "</"+tagName+">";
44107 applyBlacklists : function()
44109 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44110 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44114 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44115 if (b.indexOf(tag) > -1) {
44118 this.white.push(tag);
44122 Roo.each(w, function(tag) {
44123 if (b.indexOf(tag) > -1) {
44126 if (this.white.indexOf(tag) > -1) {
44129 this.white.push(tag);
44134 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44135 if (w.indexOf(tag) > -1) {
44138 this.black.push(tag);
44142 Roo.each(b, function(tag) {
44143 if (w.indexOf(tag) > -1) {
44146 if (this.black.indexOf(tag) > -1) {
44149 this.black.push(tag);
44154 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44155 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44159 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44160 if (b.indexOf(tag) > -1) {
44163 this.cwhite.push(tag);
44167 Roo.each(w, function(tag) {
44168 if (b.indexOf(tag) > -1) {
44171 if (this.cwhite.indexOf(tag) > -1) {
44174 this.cwhite.push(tag);
44179 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44180 if (w.indexOf(tag) > -1) {
44183 this.cblack.push(tag);
44187 Roo.each(b, function(tag) {
44188 if (w.indexOf(tag) > -1) {
44191 if (this.cblack.indexOf(tag) > -1) {
44194 this.cblack.push(tag);
44199 setStylesheets : function(stylesheets)
44201 if(typeof(stylesheets) == 'string'){
44202 Roo.get(this.iframe.contentDocument.head).createChild({
44204 rel : 'stylesheet',
44213 Roo.each(stylesheets, function(s) {
44218 Roo.get(_this.iframe.contentDocument.head).createChild({
44220 rel : 'stylesheet',
44229 removeStylesheets : function()
44233 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44238 setStyle : function(style)
44240 Roo.get(this.iframe.contentDocument.head).createChild({
44249 // hide stuff that is not compatible
44263 * @event specialkey
44267 * @cfg {String} fieldClass @hide
44270 * @cfg {String} focusClass @hide
44273 * @cfg {String} autoCreate @hide
44276 * @cfg {String} inputType @hide
44279 * @cfg {String} invalidClass @hide
44282 * @cfg {String} invalidText @hide
44285 * @cfg {String} msgFx @hide
44288 * @cfg {String} validateOnBlur @hide
44292 Roo.HtmlEditorCore.white = [
44293 'area', 'br', 'img', 'input', 'hr', 'wbr',
44295 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44296 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44297 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44298 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44299 'table', 'ul', 'xmp',
44301 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44304 'dir', 'menu', 'ol', 'ul', 'dl',
44310 Roo.HtmlEditorCore.black = [
44311 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44313 'base', 'basefont', 'bgsound', 'blink', 'body',
44314 'frame', 'frameset', 'head', 'html', 'ilayer',
44315 'iframe', 'layer', 'link', 'meta', 'object',
44316 'script', 'style' ,'title', 'xml' // clean later..
44318 Roo.HtmlEditorCore.clean = [
44319 'script', 'style', 'title', 'xml'
44321 Roo.HtmlEditorCore.remove = [
44326 Roo.HtmlEditorCore.ablack = [
44330 Roo.HtmlEditorCore.aclean = [
44331 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44335 Roo.HtmlEditorCore.pwhite= [
44336 'http', 'https', 'mailto'
44339 // white listed style attributes.
44340 Roo.HtmlEditorCore.cwhite= [
44341 // 'text-align', /// default is to allow most things..
44347 // black listed style attributes.
44348 Roo.HtmlEditorCore.cblack= [
44349 // 'font-size' -- this can be set by the project
44353 Roo.HtmlEditorCore.swapCodes =[
44364 //<script type="text/javascript">
44367 * Ext JS Library 1.1.1
44368 * Copyright(c) 2006-2007, Ext JS, LLC.
44374 Roo.form.HtmlEditor = function(config){
44378 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44380 if (!this.toolbars) {
44381 this.toolbars = [];
44383 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44389 * @class Roo.form.HtmlEditor
44390 * @extends Roo.form.Field
44391 * Provides a lightweight HTML Editor component.
44393 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44395 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44396 * supported by this editor.</b><br/><br/>
44397 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44398 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44400 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44402 * @cfg {Boolean} clearUp
44406 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44411 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44416 * @cfg {Number} height (in pixels)
44420 * @cfg {Number} width (in pixels)
44425 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44428 stylesheets: false,
44432 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44437 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44443 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44448 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44456 // private properties
44457 validationEvent : false,
44459 initialized : false,
44462 onFocus : Roo.emptyFn,
44464 hideMode:'offsets',
44466 actionMode : 'container', // defaults to hiding it...
44468 defaultAutoCreate : { // modified by initCompnoent..
44470 style:"width:500px;height:300px;",
44471 autocomplete: "new-password"
44475 initComponent : function(){
44478 * @event initialize
44479 * Fires when the editor is fully initialized (including the iframe)
44480 * @param {HtmlEditor} this
44485 * Fires when the editor is first receives the focus. Any insertion must wait
44486 * until after this event.
44487 * @param {HtmlEditor} this
44491 * @event beforesync
44492 * Fires before the textarea is updated with content from the editor iframe. Return false
44493 * to cancel the sync.
44494 * @param {HtmlEditor} this
44495 * @param {String} html
44499 * @event beforepush
44500 * Fires before the iframe editor is updated with content from the textarea. Return false
44501 * to cancel the push.
44502 * @param {HtmlEditor} this
44503 * @param {String} html
44508 * Fires when the textarea is updated with content from the editor iframe.
44509 * @param {HtmlEditor} this
44510 * @param {String} html
44515 * Fires when the iframe editor is updated with content from the textarea.
44516 * @param {HtmlEditor} this
44517 * @param {String} html
44521 * @event editmodechange
44522 * Fires when the editor switches edit modes
44523 * @param {HtmlEditor} this
44524 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44526 editmodechange: true,
44528 * @event editorevent
44529 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44530 * @param {HtmlEditor} this
44534 * @event firstfocus
44535 * Fires when on first focus - needed by toolbars..
44536 * @param {HtmlEditor} this
44541 * Auto save the htmlEditor value as a file into Events
44542 * @param {HtmlEditor} this
44546 * @event savedpreview
44547 * preview the saved version of htmlEditor
44548 * @param {HtmlEditor} this
44550 savedpreview: true,
44553 * @event stylesheetsclick
44554 * Fires when press the Sytlesheets button
44555 * @param {Roo.HtmlEditorCore} this
44557 stylesheetsclick: true
44559 this.defaultAutoCreate = {
44561 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44562 autocomplete: "new-password"
44567 * Protected method that will not generally be called directly. It
44568 * is called when the editor creates its toolbar. Override this method if you need to
44569 * add custom toolbar buttons.
44570 * @param {HtmlEditor} editor
44572 createToolbar : function(editor){
44573 Roo.log("create toolbars");
44574 if (!editor.toolbars || !editor.toolbars.length) {
44575 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44578 for (var i =0 ; i < editor.toolbars.length;i++) {
44579 editor.toolbars[i] = Roo.factory(
44580 typeof(editor.toolbars[i]) == 'string' ?
44581 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44582 Roo.form.HtmlEditor);
44583 editor.toolbars[i].init(editor);
44591 onRender : function(ct, position)
44594 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44596 this.wrap = this.el.wrap({
44597 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44600 this.editorcore.onRender(ct, position);
44602 if (this.resizable) {
44603 this.resizeEl = new Roo.Resizable(this.wrap, {
44607 minHeight : this.height,
44608 height: this.height,
44609 handles : this.resizable,
44612 resize : function(r, w, h) {
44613 _t.onResize(w,h); // -something
44619 this.createToolbar(this);
44623 this.setSize(this.wrap.getSize());
44625 if (this.resizeEl) {
44626 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44627 // should trigger onReize..
44630 this.keyNav = new Roo.KeyNav(this.el, {
44632 "tab" : function(e){
44633 e.preventDefault();
44635 var value = this.getValue();
44637 var start = this.el.dom.selectionStart;
44638 var end = this.el.dom.selectionEnd;
44642 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44643 this.el.dom.setSelectionRange(end + 1, end + 1);
44647 var f = value.substring(0, start).split("\t");
44649 if(f.pop().length != 0){
44653 this.setValue(f.join("\t") + value.substring(end));
44654 this.el.dom.setSelectionRange(start - 1, start - 1);
44658 "home" : function(e){
44659 e.preventDefault();
44661 var curr = this.el.dom.selectionStart;
44662 var lines = this.getValue().split("\n");
44669 this.el.dom.setSelectionRange(0, 0);
44675 for (var i = 0; i < lines.length;i++) {
44676 pos += lines[i].length;
44686 pos -= lines[i].length;
44692 this.el.dom.setSelectionRange(pos, pos);
44696 this.el.dom.selectionStart = pos;
44697 this.el.dom.selectionEnd = curr;
44700 "end" : function(e){
44701 e.preventDefault();
44703 var curr = this.el.dom.selectionStart;
44704 var lines = this.getValue().split("\n");
44711 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44717 for (var i = 0; i < lines.length;i++) {
44719 pos += lines[i].length;
44733 this.el.dom.setSelectionRange(pos, pos);
44737 this.el.dom.selectionStart = curr;
44738 this.el.dom.selectionEnd = pos;
44743 doRelay : function(foo, bar, hname){
44744 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44750 // if(this.autosave && this.w){
44751 // this.autoSaveFn = setInterval(this.autosave, 1000);
44756 onResize : function(w, h)
44758 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44763 if(typeof w == 'number'){
44764 var aw = w - this.wrap.getFrameWidth('lr');
44765 this.el.setWidth(this.adjustWidth('textarea', aw));
44768 if(typeof h == 'number'){
44770 for (var i =0; i < this.toolbars.length;i++) {
44771 // fixme - ask toolbars for heights?
44772 tbh += this.toolbars[i].tb.el.getHeight();
44773 if (this.toolbars[i].footer) {
44774 tbh += this.toolbars[i].footer.el.getHeight();
44781 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44782 ah -= 5; // knock a few pixes off for look..
44784 this.el.setHeight(this.adjustWidth('textarea', ah));
44788 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44789 this.editorcore.onResize(ew,eh);
44794 * Toggles the editor between standard and source edit mode.
44795 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44797 toggleSourceEdit : function(sourceEditMode)
44799 this.editorcore.toggleSourceEdit(sourceEditMode);
44801 if(this.editorcore.sourceEditMode){
44802 Roo.log('editor - showing textarea');
44805 // Roo.log(this.syncValue());
44806 this.editorcore.syncValue();
44807 this.el.removeClass('x-hidden');
44808 this.el.dom.removeAttribute('tabIndex');
44811 for (var i = 0; i < this.toolbars.length; i++) {
44812 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44813 this.toolbars[i].tb.hide();
44814 this.toolbars[i].footer.hide();
44819 Roo.log('editor - hiding textarea');
44821 // Roo.log(this.pushValue());
44822 this.editorcore.pushValue();
44824 this.el.addClass('x-hidden');
44825 this.el.dom.setAttribute('tabIndex', -1);
44827 for (var i = 0; i < this.toolbars.length; i++) {
44828 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44829 this.toolbars[i].tb.show();
44830 this.toolbars[i].footer.show();
44834 //this.deferFocus();
44837 this.setSize(this.wrap.getSize());
44838 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44840 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44843 // private (for BoxComponent)
44844 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44846 // private (for BoxComponent)
44847 getResizeEl : function(){
44851 // private (for BoxComponent)
44852 getPositionEl : function(){
44857 initEvents : function(){
44858 this.originalValue = this.getValue();
44862 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44865 markInvalid : Roo.emptyFn,
44867 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44870 clearInvalid : Roo.emptyFn,
44872 setValue : function(v){
44873 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44874 this.editorcore.pushValue();
44879 deferFocus : function(){
44880 this.focus.defer(10, this);
44884 focus : function(){
44885 this.editorcore.focus();
44891 onDestroy : function(){
44897 for (var i =0; i < this.toolbars.length;i++) {
44898 // fixme - ask toolbars for heights?
44899 this.toolbars[i].onDestroy();
44902 this.wrap.dom.innerHTML = '';
44903 this.wrap.remove();
44908 onFirstFocus : function(){
44909 //Roo.log("onFirstFocus");
44910 this.editorcore.onFirstFocus();
44911 for (var i =0; i < this.toolbars.length;i++) {
44912 this.toolbars[i].onFirstFocus();
44918 syncValue : function()
44920 this.editorcore.syncValue();
44923 pushValue : function()
44925 this.editorcore.pushValue();
44928 setStylesheets : function(stylesheets)
44930 this.editorcore.setStylesheets(stylesheets);
44933 removeStylesheets : function()
44935 this.editorcore.removeStylesheets();
44939 // hide stuff that is not compatible
44953 * @event specialkey
44957 * @cfg {String} fieldClass @hide
44960 * @cfg {String} focusClass @hide
44963 * @cfg {String} autoCreate @hide
44966 * @cfg {String} inputType @hide
44969 * @cfg {String} invalidClass @hide
44972 * @cfg {String} invalidText @hide
44975 * @cfg {String} msgFx @hide
44978 * @cfg {String} validateOnBlur @hide
44982 // <script type="text/javascript">
44985 * Ext JS Library 1.1.1
44986 * Copyright(c) 2006-2007, Ext JS, LLC.
44992 * @class Roo.form.HtmlEditorToolbar1
44997 new Roo.form.HtmlEditor({
45000 new Roo.form.HtmlEditorToolbar1({
45001 disable : { fonts: 1 , format: 1, ..., ... , ...],
45007 * @cfg {Object} disable List of elements to disable..
45008 * @cfg {Array} btns List of additional buttons.
45012 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45015 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45018 Roo.apply(this, config);
45020 // default disabled, based on 'good practice'..
45021 this.disable = this.disable || {};
45022 Roo.applyIf(this.disable, {
45025 specialElements : true
45029 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45030 // dont call parent... till later.
45033 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45040 editorcore : false,
45042 * @cfg {Object} disable List of toolbar elements to disable
45049 * @cfg {String} createLinkText The default text for the create link prompt
45051 createLinkText : 'Please enter the URL for the link:',
45053 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45055 defaultLinkValue : 'http:/'+'/',
45059 * @cfg {Array} fontFamilies An array of available font families
45077 // "á" , ?? a acute?
45082 "°" // , // degrees
45084 // "é" , // e ecute
45085 // "ú" , // u ecute?
45088 specialElements : [
45090 text: "Insert Table",
45093 ihtml : '<table><tr><td>Cell</td></tr></table>'
45097 text: "Insert Image",
45100 ihtml : '<img src="about:blank"/>'
45109 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45110 "input:submit", "input:button", "select", "textarea", "label" ],
45113 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45115 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45123 * @cfg {String} defaultFont default font to use.
45125 defaultFont: 'tahoma',
45127 fontSelect : false,
45130 formatCombo : false,
45132 init : function(editor)
45134 this.editor = editor;
45135 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45136 var editorcore = this.editorcore;
45140 var fid = editorcore.frameId;
45142 function btn(id, toggle, handler){
45143 var xid = fid + '-'+ id ;
45147 cls : 'x-btn-icon x-edit-'+id,
45148 enableToggle:toggle !== false,
45149 scope: _t, // was editor...
45150 handler:handler||_t.relayBtnCmd,
45151 clickEvent:'mousedown',
45152 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45159 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45161 // stop form submits
45162 tb.el.on('click', function(e){
45163 e.preventDefault(); // what does this do?
45166 if(!this.disable.font) { // && !Roo.isSafari){
45167 /* why no safari for fonts
45168 editor.fontSelect = tb.el.createChild({
45171 cls:'x-font-select',
45172 html: this.createFontOptions()
45175 editor.fontSelect.on('change', function(){
45176 var font = editor.fontSelect.dom.value;
45177 editor.relayCmd('fontname', font);
45178 editor.deferFocus();
45182 editor.fontSelect.dom,
45188 if(!this.disable.formats){
45189 this.formatCombo = new Roo.form.ComboBox({
45190 store: new Roo.data.SimpleStore({
45193 data : this.formats // from states.js
45197 //autoCreate : {tag: "div", size: "20"},
45198 displayField:'tag',
45202 triggerAction: 'all',
45203 emptyText:'Add tag',
45204 selectOnFocus:true,
45207 'select': function(c, r, i) {
45208 editorcore.insertTag(r.get('tag'));
45214 tb.addField(this.formatCombo);
45218 if(!this.disable.format){
45223 btn('strikethrough')
45226 if(!this.disable.fontSize){
45231 btn('increasefontsize', false, editorcore.adjustFont),
45232 btn('decreasefontsize', false, editorcore.adjustFont)
45237 if(!this.disable.colors){
45240 id:editorcore.frameId +'-forecolor',
45241 cls:'x-btn-icon x-edit-forecolor',
45242 clickEvent:'mousedown',
45243 tooltip: this.buttonTips['forecolor'] || undefined,
45245 menu : new Roo.menu.ColorMenu({
45246 allowReselect: true,
45247 focus: Roo.emptyFn,
45250 selectHandler: function(cp, color){
45251 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45252 editor.deferFocus();
45255 clickEvent:'mousedown'
45258 id:editorcore.frameId +'backcolor',
45259 cls:'x-btn-icon x-edit-backcolor',
45260 clickEvent:'mousedown',
45261 tooltip: this.buttonTips['backcolor'] || undefined,
45263 menu : new Roo.menu.ColorMenu({
45264 focus: Roo.emptyFn,
45267 allowReselect: true,
45268 selectHandler: function(cp, color){
45270 editorcore.execCmd('useCSS', false);
45271 editorcore.execCmd('hilitecolor', color);
45272 editorcore.execCmd('useCSS', true);
45273 editor.deferFocus();
45275 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45276 Roo.isSafari || Roo.isIE ? '#'+color : color);
45277 editor.deferFocus();
45281 clickEvent:'mousedown'
45286 // now add all the items...
45289 if(!this.disable.alignments){
45292 btn('justifyleft'),
45293 btn('justifycenter'),
45294 btn('justifyright')
45298 //if(!Roo.isSafari){
45299 if(!this.disable.links){
45302 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45306 if(!this.disable.lists){
45309 btn('insertorderedlist'),
45310 btn('insertunorderedlist')
45313 if(!this.disable.sourceEdit){
45316 btn('sourceedit', true, function(btn){
45317 this.toggleSourceEdit(btn.pressed);
45324 // special menu.. - needs to be tidied up..
45325 if (!this.disable.special) {
45328 cls: 'x-edit-none',
45334 for (var i =0; i < this.specialChars.length; i++) {
45335 smenu.menu.items.push({
45337 html: this.specialChars[i],
45338 handler: function(a,b) {
45339 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45340 //editor.insertAtCursor(a.html);
45354 if (!this.disable.cleanStyles) {
45356 cls: 'x-btn-icon x-btn-clear',
45362 for (var i =0; i < this.cleanStyles.length; i++) {
45363 cmenu.menu.items.push({
45364 actiontype : this.cleanStyles[i],
45365 html: 'Remove ' + this.cleanStyles[i],
45366 handler: function(a,b) {
45369 var c = Roo.get(editorcore.doc.body);
45370 c.select('[style]').each(function(s) {
45371 s.dom.style.removeProperty(a.actiontype);
45373 editorcore.syncValue();
45378 cmenu.menu.items.push({
45379 actiontype : 'tablewidths',
45380 html: 'Remove Table Widths',
45381 handler: function(a,b) {
45382 editorcore.cleanTableWidths();
45383 editorcore.syncValue();
45387 cmenu.menu.items.push({
45388 actiontype : 'word',
45389 html: 'Remove MS Word Formating',
45390 handler: function(a,b) {
45391 editorcore.cleanWord();
45392 editorcore.syncValue();
45397 cmenu.menu.items.push({
45398 actiontype : 'all',
45399 html: 'Remove All Styles',
45400 handler: function(a,b) {
45402 var c = Roo.get(editorcore.doc.body);
45403 c.select('[style]').each(function(s) {
45404 s.dom.removeAttribute('style');
45406 editorcore.syncValue();
45411 cmenu.menu.items.push({
45412 actiontype : 'all',
45413 html: 'Remove All CSS Classes',
45414 handler: function(a,b) {
45416 var c = Roo.get(editorcore.doc.body);
45417 c.select('[class]').each(function(s) {
45418 s.dom.className = '';
45420 editorcore.syncValue();
45425 cmenu.menu.items.push({
45426 actiontype : 'tidy',
45427 html: 'Tidy HTML Source',
45428 handler: function(a,b) {
45429 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45430 editorcore.syncValue();
45439 if (!this.disable.specialElements) {
45442 cls: 'x-edit-none',
45447 for (var i =0; i < this.specialElements.length; i++) {
45448 semenu.menu.items.push(
45450 handler: function(a,b) {
45451 editor.insertAtCursor(this.ihtml);
45453 }, this.specialElements[i])
45465 for(var i =0; i< this.btns.length;i++) {
45466 var b = Roo.factory(this.btns[i],Roo.form);
45467 b.cls = 'x-edit-none';
45469 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45470 b.cls += ' x-init-enable';
45473 b.scope = editorcore;
45481 // disable everything...
45483 this.tb.items.each(function(item){
45486 item.id != editorcore.frameId+ '-sourceedit' &&
45487 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45493 this.rendered = true;
45495 // the all the btns;
45496 editor.on('editorevent', this.updateToolbar, this);
45497 // other toolbars need to implement this..
45498 //editor.on('editmodechange', this.updateToolbar, this);
45502 relayBtnCmd : function(btn) {
45503 this.editorcore.relayCmd(btn.cmd);
45505 // private used internally
45506 createLink : function(){
45507 Roo.log("create link?");
45508 var url = prompt(this.createLinkText, this.defaultLinkValue);
45509 if(url && url != 'http:/'+'/'){
45510 this.editorcore.relayCmd('createlink', url);
45516 * Protected method that will not generally be called directly. It triggers
45517 * a toolbar update by reading the markup state of the current selection in the editor.
45519 updateToolbar: function(){
45521 if(!this.editorcore.activated){
45522 this.editor.onFirstFocus();
45526 var btns = this.tb.items.map,
45527 doc = this.editorcore.doc,
45528 frameId = this.editorcore.frameId;
45530 if(!this.disable.font && !Roo.isSafari){
45532 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45533 if(name != this.fontSelect.dom.value){
45534 this.fontSelect.dom.value = name;
45538 if(!this.disable.format){
45539 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45540 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45541 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45542 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45544 if(!this.disable.alignments){
45545 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45546 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45547 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45549 if(!Roo.isSafari && !this.disable.lists){
45550 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45551 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45554 var ans = this.editorcore.getAllAncestors();
45555 if (this.formatCombo) {
45558 var store = this.formatCombo.store;
45559 this.formatCombo.setValue("");
45560 for (var i =0; i < ans.length;i++) {
45561 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45563 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45571 // hides menus... - so this cant be on a menu...
45572 Roo.menu.MenuMgr.hideAll();
45574 //this.editorsyncValue();
45578 createFontOptions : function(){
45579 var buf = [], fs = this.fontFamilies, ff, lc;
45583 for(var i = 0, len = fs.length; i< len; i++){
45585 lc = ff.toLowerCase();
45587 '<option value="',lc,'" style="font-family:',ff,';"',
45588 (this.defaultFont == lc ? ' selected="true">' : '>'),
45593 return buf.join('');
45596 toggleSourceEdit : function(sourceEditMode){
45598 Roo.log("toolbar toogle");
45599 if(sourceEditMode === undefined){
45600 sourceEditMode = !this.sourceEditMode;
45602 this.sourceEditMode = sourceEditMode === true;
45603 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45604 // just toggle the button?
45605 if(btn.pressed !== this.sourceEditMode){
45606 btn.toggle(this.sourceEditMode);
45610 if(sourceEditMode){
45611 Roo.log("disabling buttons");
45612 this.tb.items.each(function(item){
45613 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45619 Roo.log("enabling buttons");
45620 if(this.editorcore.initialized){
45621 this.tb.items.each(function(item){
45627 Roo.log("calling toggole on editor");
45628 // tell the editor that it's been pressed..
45629 this.editor.toggleSourceEdit(sourceEditMode);
45633 * Object collection of toolbar tooltips for the buttons in the editor. The key
45634 * is the command id associated with that button and the value is a valid QuickTips object.
45639 title: 'Bold (Ctrl+B)',
45640 text: 'Make the selected text bold.',
45641 cls: 'x-html-editor-tip'
45644 title: 'Italic (Ctrl+I)',
45645 text: 'Make the selected text italic.',
45646 cls: 'x-html-editor-tip'
45654 title: 'Bold (Ctrl+B)',
45655 text: 'Make the selected text bold.',
45656 cls: 'x-html-editor-tip'
45659 title: 'Italic (Ctrl+I)',
45660 text: 'Make the selected text italic.',
45661 cls: 'x-html-editor-tip'
45664 title: 'Underline (Ctrl+U)',
45665 text: 'Underline the selected text.',
45666 cls: 'x-html-editor-tip'
45669 title: 'Strikethrough',
45670 text: 'Strikethrough the selected text.',
45671 cls: 'x-html-editor-tip'
45673 increasefontsize : {
45674 title: 'Grow Text',
45675 text: 'Increase the font size.',
45676 cls: 'x-html-editor-tip'
45678 decreasefontsize : {
45679 title: 'Shrink Text',
45680 text: 'Decrease the font size.',
45681 cls: 'x-html-editor-tip'
45684 title: 'Text Highlight Color',
45685 text: 'Change the background color of the selected text.',
45686 cls: 'x-html-editor-tip'
45689 title: 'Font Color',
45690 text: 'Change the color of the selected text.',
45691 cls: 'x-html-editor-tip'
45694 title: 'Align Text Left',
45695 text: 'Align text to the left.',
45696 cls: 'x-html-editor-tip'
45699 title: 'Center Text',
45700 text: 'Center text in the editor.',
45701 cls: 'x-html-editor-tip'
45704 title: 'Align Text Right',
45705 text: 'Align text to the right.',
45706 cls: 'x-html-editor-tip'
45708 insertunorderedlist : {
45709 title: 'Bullet List',
45710 text: 'Start a bulleted list.',
45711 cls: 'x-html-editor-tip'
45713 insertorderedlist : {
45714 title: 'Numbered List',
45715 text: 'Start a numbered list.',
45716 cls: 'x-html-editor-tip'
45719 title: 'Hyperlink',
45720 text: 'Make the selected text a hyperlink.',
45721 cls: 'x-html-editor-tip'
45724 title: 'Source Edit',
45725 text: 'Switch to source editing mode.',
45726 cls: 'x-html-editor-tip'
45730 onDestroy : function(){
45733 this.tb.items.each(function(item){
45735 item.menu.removeAll();
45737 item.menu.el.destroy();
45745 onFirstFocus: function() {
45746 this.tb.items.each(function(item){
45755 // <script type="text/javascript">
45758 * Ext JS Library 1.1.1
45759 * Copyright(c) 2006-2007, Ext JS, LLC.
45766 * @class Roo.form.HtmlEditor.ToolbarContext
45771 new Roo.form.HtmlEditor({
45774 { xtype: 'ToolbarStandard', styles : {} }
45775 { xtype: 'ToolbarContext', disable : {} }
45781 * @config : {Object} disable List of elements to disable.. (not done yet.)
45782 * @config : {Object} styles Map of styles available.
45786 Roo.form.HtmlEditor.ToolbarContext = function(config)
45789 Roo.apply(this, config);
45790 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45791 // dont call parent... till later.
45792 this.styles = this.styles || {};
45797 Roo.form.HtmlEditor.ToolbarContext.types = {
45809 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45875 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45880 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45890 style : 'fontFamily',
45891 displayField: 'display',
45892 optname : 'font-family',
45941 // should we really allow this??
45942 // should this just be
45953 style : 'fontFamily',
45954 displayField: 'display',
45955 optname : 'font-family',
45962 style : 'fontFamily',
45963 displayField: 'display',
45964 optname : 'font-family',
45971 style : 'fontFamily',
45972 displayField: 'display',
45973 optname : 'font-family',
45984 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45985 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45987 Roo.form.HtmlEditor.ToolbarContext.options = {
45989 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45990 [ 'Courier New', 'Courier New'],
45991 [ 'Tahoma', 'Tahoma'],
45992 [ 'Times New Roman,serif', 'Times'],
45993 [ 'Verdana','Verdana' ]
45997 // fixme - these need to be configurable..
46000 //Roo.form.HtmlEditor.ToolbarContext.types
46003 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46010 editorcore : false,
46012 * @cfg {Object} disable List of toolbar elements to disable
46017 * @cfg {Object} styles List of styles
46018 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46020 * These must be defined in the page, so they get rendered correctly..
46031 init : function(editor)
46033 this.editor = editor;
46034 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46035 var editorcore = this.editorcore;
46037 var fid = editorcore.frameId;
46039 function btn(id, toggle, handler){
46040 var xid = fid + '-'+ id ;
46044 cls : 'x-btn-icon x-edit-'+id,
46045 enableToggle:toggle !== false,
46046 scope: editorcore, // was editor...
46047 handler:handler||editorcore.relayBtnCmd,
46048 clickEvent:'mousedown',
46049 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46053 // create a new element.
46054 var wdiv = editor.wrap.createChild({
46056 }, editor.wrap.dom.firstChild.nextSibling, true);
46058 // can we do this more than once??
46060 // stop form submits
46063 // disable everything...
46064 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46065 this.toolbars = {};
46067 for (var i in ty) {
46069 this.toolbars[i] = this.buildToolbar(ty[i],i);
46071 this.tb = this.toolbars.BODY;
46073 this.buildFooter();
46074 this.footer.show();
46075 editor.on('hide', function( ) { this.footer.hide() }, this);
46076 editor.on('show', function( ) { this.footer.show() }, this);
46079 this.rendered = true;
46081 // the all the btns;
46082 editor.on('editorevent', this.updateToolbar, this);
46083 // other toolbars need to implement this..
46084 //editor.on('editmodechange', this.updateToolbar, this);
46090 * Protected method that will not generally be called directly. It triggers
46091 * a toolbar update by reading the markup state of the current selection in the editor.
46093 * Note you can force an update by calling on('editorevent', scope, false)
46095 updateToolbar: function(editor,ev,sel){
46098 // capture mouse up - this is handy for selecting images..
46099 // perhaps should go somewhere else...
46100 if(!this.editorcore.activated){
46101 this.editor.onFirstFocus();
46107 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46108 // selectNode - might want to handle IE?
46110 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46111 ev.target && ev.target.tagName == 'IMG') {
46112 // they have click on an image...
46113 // let's see if we can change the selection...
46116 var nodeRange = sel.ownerDocument.createRange();
46118 nodeRange.selectNode(sel);
46120 nodeRange.selectNodeContents(sel);
46122 //nodeRange.collapse(true);
46123 var s = this.editorcore.win.getSelection();
46124 s.removeAllRanges();
46125 s.addRange(nodeRange);
46129 var updateFooter = sel ? false : true;
46132 var ans = this.editorcore.getAllAncestors();
46135 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46138 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46139 sel = sel ? sel : this.editorcore.doc.body;
46140 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46143 // pick a menu that exists..
46144 var tn = sel.tagName.toUpperCase();
46145 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46147 tn = sel.tagName.toUpperCase();
46149 var lastSel = this.tb.selectedNode;
46151 this.tb.selectedNode = sel;
46153 // if current menu does not match..
46155 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46158 ///console.log("show: " + tn);
46159 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46162 this.tb.items.first().el.innerHTML = tn + ': ';
46165 // update attributes
46166 if (this.tb.fields) {
46167 this.tb.fields.each(function(e) {
46169 e.setValue(sel.style[e.stylename]);
46172 e.setValue(sel.getAttribute(e.attrname));
46176 var hasStyles = false;
46177 for(var i in this.styles) {
46184 var st = this.tb.fields.item(0);
46186 st.store.removeAll();
46189 var cn = sel.className.split(/\s+/);
46192 if (this.styles['*']) {
46194 Roo.each(this.styles['*'], function(v) {
46195 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46198 if (this.styles[tn]) {
46199 Roo.each(this.styles[tn], function(v) {
46200 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46204 st.store.loadData(avs);
46208 // flag our selected Node.
46209 this.tb.selectedNode = sel;
46212 Roo.menu.MenuMgr.hideAll();
46216 if (!updateFooter) {
46217 //this.footDisp.dom.innerHTML = '';
46220 // update the footer
46224 this.footerEls = ans.reverse();
46225 Roo.each(this.footerEls, function(a,i) {
46226 if (!a) { return; }
46227 html += html.length ? ' > ' : '';
46229 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46234 var sz = this.footDisp.up('td').getSize();
46235 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46236 this.footDisp.dom.style.marginLeft = '5px';
46238 this.footDisp.dom.style.overflow = 'hidden';
46240 this.footDisp.dom.innerHTML = html;
46242 //this.editorsyncValue();
46249 onDestroy : function(){
46252 this.tb.items.each(function(item){
46254 item.menu.removeAll();
46256 item.menu.el.destroy();
46264 onFirstFocus: function() {
46265 // need to do this for all the toolbars..
46266 this.tb.items.each(function(item){
46270 buildToolbar: function(tlist, nm)
46272 var editor = this.editor;
46273 var editorcore = this.editorcore;
46274 // create a new element.
46275 var wdiv = editor.wrap.createChild({
46277 }, editor.wrap.dom.firstChild.nextSibling, true);
46280 var tb = new Roo.Toolbar(wdiv);
46283 tb.add(nm+ ": ");
46286 for(var i in this.styles) {
46291 if (styles && styles.length) {
46293 // this needs a multi-select checkbox...
46294 tb.addField( new Roo.form.ComboBox({
46295 store: new Roo.data.SimpleStore({
46297 fields: ['val', 'selected'],
46300 name : '-roo-edit-className',
46301 attrname : 'className',
46302 displayField: 'val',
46306 triggerAction: 'all',
46307 emptyText:'Select Style',
46308 selectOnFocus:true,
46311 'select': function(c, r, i) {
46312 // initial support only for on class per el..
46313 tb.selectedNode.className = r ? r.get('val') : '';
46314 editorcore.syncValue();
46321 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46322 var tbops = tbc.options;
46324 for (var i in tlist) {
46326 var item = tlist[i];
46327 tb.add(item.title + ": ");
46330 //optname == used so you can configure the options available..
46331 var opts = item.opts ? item.opts : false;
46332 if (item.optname) {
46333 opts = tbops[item.optname];
46338 // opts == pulldown..
46339 tb.addField( new Roo.form.ComboBox({
46340 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46342 fields: ['val', 'display'],
46345 name : '-roo-edit-' + i,
46347 stylename : item.style ? item.style : false,
46348 displayField: item.displayField ? item.displayField : 'val',
46349 valueField : 'val',
46351 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46353 triggerAction: 'all',
46354 emptyText:'Select',
46355 selectOnFocus:true,
46356 width: item.width ? item.width : 130,
46358 'select': function(c, r, i) {
46360 tb.selectedNode.style[c.stylename] = r.get('val');
46363 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46372 tb.addField( new Roo.form.TextField({
46375 //allowBlank:false,
46380 tb.addField( new Roo.form.TextField({
46381 name: '-roo-edit-' + i,
46388 'change' : function(f, nv, ov) {
46389 tb.selectedNode.setAttribute(f.attrname, nv);
46390 editorcore.syncValue();
46403 text: 'Stylesheets',
46406 click : function ()
46408 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46416 text: 'Remove Tag',
46419 click : function ()
46422 // undo does not work.
46424 var sn = tb.selectedNode;
46426 var pn = sn.parentNode;
46428 var stn = sn.childNodes[0];
46429 var en = sn.childNodes[sn.childNodes.length - 1 ];
46430 while (sn.childNodes.length) {
46431 var node = sn.childNodes[0];
46432 sn.removeChild(node);
46434 pn.insertBefore(node, sn);
46437 pn.removeChild(sn);
46438 var range = editorcore.createRange();
46440 range.setStart(stn,0);
46441 range.setEnd(en,0); //????
46442 //range.selectNode(sel);
46445 var selection = editorcore.getSelection();
46446 selection.removeAllRanges();
46447 selection.addRange(range);
46451 //_this.updateToolbar(null, null, pn);
46452 _this.updateToolbar(null, null, null);
46453 _this.footDisp.dom.innerHTML = '';
46463 tb.el.on('click', function(e){
46464 e.preventDefault(); // what does this do?
46466 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46469 // dont need to disable them... as they will get hidden
46474 buildFooter : function()
46477 var fel = this.editor.wrap.createChild();
46478 this.footer = new Roo.Toolbar(fel);
46479 // toolbar has scrolly on left / right?
46480 var footDisp= new Roo.Toolbar.Fill();
46486 handler : function() {
46487 _t.footDisp.scrollTo('left',0,true)
46491 this.footer.add( footDisp );
46496 handler : function() {
46498 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46502 var fel = Roo.get(footDisp.el);
46503 fel.addClass('x-editor-context');
46504 this.footDispWrap = fel;
46505 this.footDispWrap.overflow = 'hidden';
46507 this.footDisp = fel.createChild();
46508 this.footDispWrap.on('click', this.onContextClick, this)
46512 onContextClick : function (ev,dom)
46514 ev.preventDefault();
46515 var cn = dom.className;
46517 if (!cn.match(/x-ed-loc-/)) {
46520 var n = cn.split('-').pop();
46521 var ans = this.footerEls;
46525 var range = this.editorcore.createRange();
46527 range.selectNodeContents(sel);
46528 //range.selectNode(sel);
46531 var selection = this.editorcore.getSelection();
46532 selection.removeAllRanges();
46533 selection.addRange(range);
46537 this.updateToolbar(null, null, sel);
46554 * Ext JS Library 1.1.1
46555 * Copyright(c) 2006-2007, Ext JS, LLC.
46557 * Originally Released Under LGPL - original licence link has changed is not relivant.
46560 * <script type="text/javascript">
46564 * @class Roo.form.BasicForm
46565 * @extends Roo.util.Observable
46566 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46568 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46569 * @param {Object} config Configuration options
46571 Roo.form.BasicForm = function(el, config){
46572 this.allItems = [];
46573 this.childForms = [];
46574 Roo.apply(this, config);
46576 * The Roo.form.Field items in this form.
46577 * @type MixedCollection
46581 this.items = new Roo.util.MixedCollection(false, function(o){
46582 return o.id || (o.id = Roo.id());
46586 * @event beforeaction
46587 * Fires before any action is performed. Return false to cancel the action.
46588 * @param {Form} this
46589 * @param {Action} action The action to be performed
46591 beforeaction: true,
46593 * @event actionfailed
46594 * Fires when an action fails.
46595 * @param {Form} this
46596 * @param {Action} action The action that failed
46598 actionfailed : true,
46600 * @event actioncomplete
46601 * Fires when an action is completed.
46602 * @param {Form} this
46603 * @param {Action} action The action that completed
46605 actioncomplete : true
46610 Roo.form.BasicForm.superclass.constructor.call(this);
46613 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46615 * @cfg {String} method
46616 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46619 * @cfg {DataReader} reader
46620 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46621 * This is optional as there is built-in support for processing JSON.
46624 * @cfg {DataReader} errorReader
46625 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46626 * This is completely optional as there is built-in support for processing JSON.
46629 * @cfg {String} url
46630 * The URL to use for form actions if one isn't supplied in the action options.
46633 * @cfg {Boolean} fileUpload
46634 * Set to true if this form is a file upload.
46638 * @cfg {Object} baseParams
46639 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46644 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46649 activeAction : null,
46652 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46653 * or setValues() data instead of when the form was first created.
46655 trackResetOnLoad : false,
46659 * childForms - used for multi-tab forms
46662 childForms : false,
46665 * allItems - full list of fields.
46671 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46672 * element by passing it or its id or mask the form itself by passing in true.
46675 waitMsgTarget : false,
46678 initEl : function(el){
46679 this.el = Roo.get(el);
46680 this.id = this.el.id || Roo.id();
46681 this.el.on('submit', this.onSubmit, this);
46682 this.el.addClass('x-form');
46686 onSubmit : function(e){
46691 * Returns true if client-side validation on the form is successful.
46694 isValid : function(){
46696 this.items.each(function(f){
46705 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46708 isDirty : function(){
46710 this.items.each(function(f){
46720 * Returns true if any fields in this form have changed since their original load. (New version)
46724 hasChanged : function()
46727 this.items.each(function(f){
46728 if(f.hasChanged()){
46737 * Resets all hasChanged to 'false' -
46738 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46739 * So hasChanged storage is only to be used for this purpose
46742 resetHasChanged : function()
46744 this.items.each(function(f){
46745 f.resetHasChanged();
46752 * Performs a predefined action (submit or load) or custom actions you define on this form.
46753 * @param {String} actionName The name of the action type
46754 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46755 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46756 * accept other config options):
46758 Property Type Description
46759 ---------------- --------------- ----------------------------------------------------------------------------------
46760 url String The url for the action (defaults to the form's url)
46761 method String The form method to use (defaults to the form's method, or POST if not defined)
46762 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46763 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46764 validate the form on the client (defaults to false)
46766 * @return {BasicForm} this
46768 doAction : function(action, options){
46769 if(typeof action == 'string'){
46770 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46772 if(this.fireEvent('beforeaction', this, action) !== false){
46773 this.beforeAction(action);
46774 action.run.defer(100, action);
46780 * Shortcut to do a submit action.
46781 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46782 * @return {BasicForm} this
46784 submit : function(options){
46785 this.doAction('submit', options);
46790 * Shortcut to do a load action.
46791 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46792 * @return {BasicForm} this
46794 load : function(options){
46795 this.doAction('load', options);
46800 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46801 * @param {Record} record The record to edit
46802 * @return {BasicForm} this
46804 updateRecord : function(record){
46805 record.beginEdit();
46806 var fs = record.fields;
46807 fs.each(function(f){
46808 var field = this.findField(f.name);
46810 record.set(f.name, field.getValue());
46818 * Loads an Roo.data.Record into this form.
46819 * @param {Record} record The record to load
46820 * @return {BasicForm} this
46822 loadRecord : function(record){
46823 this.setValues(record.data);
46828 beforeAction : function(action){
46829 var o = action.options;
46832 if(this.waitMsgTarget === true){
46833 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46834 }else if(this.waitMsgTarget){
46835 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46836 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46838 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46844 afterAction : function(action, success){
46845 this.activeAction = null;
46846 var o = action.options;
46848 if(this.waitMsgTarget === true){
46850 }else if(this.waitMsgTarget){
46851 this.waitMsgTarget.unmask();
46853 Roo.MessageBox.updateProgress(1);
46854 Roo.MessageBox.hide();
46861 Roo.callback(o.success, o.scope, [this, action]);
46862 this.fireEvent('actioncomplete', this, action);
46866 // failure condition..
46867 // we have a scenario where updates need confirming.
46868 // eg. if a locking scenario exists..
46869 // we look for { errors : { needs_confirm : true }} in the response.
46871 (typeof(action.result) != 'undefined') &&
46872 (typeof(action.result.errors) != 'undefined') &&
46873 (typeof(action.result.errors.needs_confirm) != 'undefined')
46876 Roo.MessageBox.confirm(
46877 "Change requires confirmation",
46878 action.result.errorMsg,
46883 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46893 Roo.callback(o.failure, o.scope, [this, action]);
46894 // show an error message if no failed handler is set..
46895 if (!this.hasListener('actionfailed')) {
46896 Roo.MessageBox.alert("Error",
46897 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46898 action.result.errorMsg :
46899 "Saving Failed, please check your entries or try again"
46903 this.fireEvent('actionfailed', this, action);
46909 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46910 * @param {String} id The value to search for
46913 findField : function(id){
46914 var field = this.items.get(id);
46916 this.items.each(function(f){
46917 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46923 return field || null;
46927 * Add a secondary form to this one,
46928 * Used to provide tabbed forms. One form is primary, with hidden values
46929 * which mirror the elements from the other forms.
46931 * @param {Roo.form.Form} form to add.
46934 addForm : function(form)
46937 if (this.childForms.indexOf(form) > -1) {
46941 this.childForms.push(form);
46943 Roo.each(form.allItems, function (fe) {
46945 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46946 if (this.findField(n)) { // already added..
46949 var add = new Roo.form.Hidden({
46952 add.render(this.el);
46959 * Mark fields in this form invalid in bulk.
46960 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46961 * @return {BasicForm} this
46963 markInvalid : function(errors){
46964 if(errors instanceof Array){
46965 for(var i = 0, len = errors.length; i < len; i++){
46966 var fieldError = errors[i];
46967 var f = this.findField(fieldError.id);
46969 f.markInvalid(fieldError.msg);
46975 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46976 field.markInvalid(errors[id]);
46980 Roo.each(this.childForms || [], function (f) {
46981 f.markInvalid(errors);
46988 * Set values for fields in this form in bulk.
46989 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46990 * @return {BasicForm} this
46992 setValues : function(values){
46993 if(values instanceof Array){ // array of objects
46994 for(var i = 0, len = values.length; i < len; i++){
46996 var f = this.findField(v.id);
46998 f.setValue(v.value);
46999 if(this.trackResetOnLoad){
47000 f.originalValue = f.getValue();
47004 }else{ // object hash
47007 if(typeof values[id] != 'function' && (field = this.findField(id))){
47009 if (field.setFromData &&
47010 field.valueField &&
47011 field.displayField &&
47012 // combos' with local stores can
47013 // be queried via setValue()
47014 // to set their value..
47015 (field.store && !field.store.isLocal)
47019 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47020 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47021 field.setFromData(sd);
47024 field.setValue(values[id]);
47028 if(this.trackResetOnLoad){
47029 field.originalValue = field.getValue();
47034 this.resetHasChanged();
47037 Roo.each(this.childForms || [], function (f) {
47038 f.setValues(values);
47039 f.resetHasChanged();
47046 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47047 * they are returned as an array.
47048 * @param {Boolean} asString
47051 getValues : function(asString){
47052 if (this.childForms) {
47053 // copy values from the child forms
47054 Roo.each(this.childForms, function (f) {
47055 this.setValues(f.getValues());
47061 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47062 if(asString === true){
47065 return Roo.urlDecode(fs);
47069 * Returns the fields in this form as an object with key/value pairs.
47070 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47073 getFieldValues : function(with_hidden)
47075 if (this.childForms) {
47076 // copy values from the child forms
47077 // should this call getFieldValues - probably not as we do not currently copy
47078 // hidden fields when we generate..
47079 Roo.each(this.childForms, function (f) {
47080 this.setValues(f.getValues());
47085 this.items.each(function(f){
47086 if (!f.getName()) {
47089 var v = f.getValue();
47090 if (f.inputType =='radio') {
47091 if (typeof(ret[f.getName()]) == 'undefined') {
47092 ret[f.getName()] = ''; // empty..
47095 if (!f.el.dom.checked) {
47099 v = f.el.dom.value;
47103 // not sure if this supported any more..
47104 if ((typeof(v) == 'object') && f.getRawValue) {
47105 v = f.getRawValue() ; // dates..
47107 // combo boxes where name != hiddenName...
47108 if (f.name != f.getName()) {
47109 ret[f.name] = f.getRawValue();
47111 ret[f.getName()] = v;
47118 * Clears all invalid messages in this form.
47119 * @return {BasicForm} this
47121 clearInvalid : function(){
47122 this.items.each(function(f){
47126 Roo.each(this.childForms || [], function (f) {
47135 * Resets this form.
47136 * @return {BasicForm} this
47138 reset : function(){
47139 this.items.each(function(f){
47143 Roo.each(this.childForms || [], function (f) {
47146 this.resetHasChanged();
47152 * Add Roo.form components to this form.
47153 * @param {Field} field1
47154 * @param {Field} field2 (optional)
47155 * @param {Field} etc (optional)
47156 * @return {BasicForm} this
47159 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47165 * Removes a field from the items collection (does NOT remove its markup).
47166 * @param {Field} field
47167 * @return {BasicForm} this
47169 remove : function(field){
47170 this.items.remove(field);
47175 * Looks at the fields in this form, checks them for an id attribute,
47176 * and calls applyTo on the existing dom element with that id.
47177 * @return {BasicForm} this
47179 render : function(){
47180 this.items.each(function(f){
47181 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47189 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47190 * @param {Object} values
47191 * @return {BasicForm} this
47193 applyToFields : function(o){
47194 this.items.each(function(f){
47201 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47202 * @param {Object} values
47203 * @return {BasicForm} this
47205 applyIfToFields : function(o){
47206 this.items.each(function(f){
47214 Roo.BasicForm = Roo.form.BasicForm;/*
47216 * Ext JS Library 1.1.1
47217 * Copyright(c) 2006-2007, Ext JS, LLC.
47219 * Originally Released Under LGPL - original licence link has changed is not relivant.
47222 * <script type="text/javascript">
47226 * @class Roo.form.Form
47227 * @extends Roo.form.BasicForm
47228 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47230 * @param {Object} config Configuration options
47232 Roo.form.Form = function(config){
47234 if (config.items) {
47235 xitems = config.items;
47236 delete config.items;
47240 Roo.form.Form.superclass.constructor.call(this, null, config);
47241 this.url = this.url || this.action;
47243 this.root = new Roo.form.Layout(Roo.applyIf({
47247 this.active = this.root;
47249 * Array of all the buttons that have been added to this form via {@link addButton}
47253 this.allItems = [];
47256 * @event clientvalidation
47257 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47258 * @param {Form} this
47259 * @param {Boolean} valid true if the form has passed client-side validation
47261 clientvalidation: true,
47264 * Fires when the form is rendered
47265 * @param {Roo.form.Form} form
47270 if (this.progressUrl) {
47271 // push a hidden field onto the list of fields..
47275 name : 'UPLOAD_IDENTIFIER'
47280 Roo.each(xitems, this.addxtype, this);
47286 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47288 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47291 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47294 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47296 buttonAlign:'center',
47299 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47304 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47305 * This property cascades to child containers if not set.
47310 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47311 * fires a looping event with that state. This is required to bind buttons to the valid
47312 * state using the config value formBind:true on the button.
47314 monitorValid : false,
47317 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47322 * @cfg {String} progressUrl - Url to return progress data
47325 progressUrl : false,
47328 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47329 * fields are added and the column is closed. If no fields are passed the column remains open
47330 * until end() is called.
47331 * @param {Object} config The config to pass to the column
47332 * @param {Field} field1 (optional)
47333 * @param {Field} field2 (optional)
47334 * @param {Field} etc (optional)
47335 * @return Column The column container object
47337 column : function(c){
47338 var col = new Roo.form.Column(c);
47340 if(arguments.length > 1){ // duplicate code required because of Opera
47341 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47348 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47349 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47350 * until end() is called.
47351 * @param {Object} config The config to pass to the fieldset
47352 * @param {Field} field1 (optional)
47353 * @param {Field} field2 (optional)
47354 * @param {Field} etc (optional)
47355 * @return FieldSet The fieldset container object
47357 fieldset : function(c){
47358 var fs = new Roo.form.FieldSet(c);
47360 if(arguments.length > 1){ // duplicate code required because of Opera
47361 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47368 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47369 * fields are added and the container is closed. If no fields are passed the container remains open
47370 * until end() is called.
47371 * @param {Object} config The config to pass to the Layout
47372 * @param {Field} field1 (optional)
47373 * @param {Field} field2 (optional)
47374 * @param {Field} etc (optional)
47375 * @return Layout The container object
47377 container : function(c){
47378 var l = new Roo.form.Layout(c);
47380 if(arguments.length > 1){ // duplicate code required because of Opera
47381 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47388 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47389 * @param {Object} container A Roo.form.Layout or subclass of Layout
47390 * @return {Form} this
47392 start : function(c){
47393 // cascade label info
47394 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47395 this.active.stack.push(c);
47396 c.ownerCt = this.active;
47402 * Closes the current open container
47403 * @return {Form} this
47406 if(this.active == this.root){
47409 this.active = this.active.ownerCt;
47414 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47415 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47416 * as the label of the field.
47417 * @param {Field} field1
47418 * @param {Field} field2 (optional)
47419 * @param {Field} etc. (optional)
47420 * @return {Form} this
47423 this.active.stack.push.apply(this.active.stack, arguments);
47424 this.allItems.push.apply(this.allItems,arguments);
47426 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47427 if(a[i].isFormField){
47432 Roo.form.Form.superclass.add.apply(this, r);
47442 * Find any element that has been added to a form, using it's ID or name
47443 * This can include framesets, columns etc. along with regular fields..
47444 * @param {String} id - id or name to find.
47446 * @return {Element} e - or false if nothing found.
47448 findbyId : function(id)
47454 Roo.each(this.allItems, function(f){
47455 if (f.id == id || f.name == id ){
47466 * Render this form into the passed container. This should only be called once!
47467 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47468 * @return {Form} this
47470 render : function(ct)
47476 var o = this.autoCreate || {
47478 method : this.method || 'POST',
47479 id : this.id || Roo.id()
47481 this.initEl(ct.createChild(o));
47483 this.root.render(this.el);
47487 this.items.each(function(f){
47488 f.render('x-form-el-'+f.id);
47491 if(this.buttons.length > 0){
47492 // tables are required to maintain order and for correct IE layout
47493 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47494 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47495 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47497 var tr = tb.getElementsByTagName('tr')[0];
47498 for(var i = 0, len = this.buttons.length; i < len; i++) {
47499 var b = this.buttons[i];
47500 var td = document.createElement('td');
47501 td.className = 'x-form-btn-td';
47502 b.render(tr.appendChild(td));
47505 if(this.monitorValid){ // initialize after render
47506 this.startMonitoring();
47508 this.fireEvent('rendered', this);
47513 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47514 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47515 * object or a valid Roo.DomHelper element config
47516 * @param {Function} handler The function called when the button is clicked
47517 * @param {Object} scope (optional) The scope of the handler function
47518 * @return {Roo.Button}
47520 addButton : function(config, handler, scope){
47524 minWidth: this.minButtonWidth,
47527 if(typeof config == "string"){
47530 Roo.apply(bc, config);
47532 var btn = new Roo.Button(null, bc);
47533 this.buttons.push(btn);
47538 * Adds a series of form elements (using the xtype property as the factory method.
47539 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47540 * @param {Object} config
47543 addxtype : function()
47545 var ar = Array.prototype.slice.call(arguments, 0);
47547 for(var i = 0; i < ar.length; i++) {
47549 continue; // skip -- if this happends something invalid got sent, we
47550 // should ignore it, as basically that interface element will not show up
47551 // and that should be pretty obvious!!
47554 if (Roo.form[ar[i].xtype]) {
47556 var fe = Roo.factory(ar[i], Roo.form);
47562 fe.store.form = this;
47567 this.allItems.push(fe);
47568 if (fe.items && fe.addxtype) {
47569 fe.addxtype.apply(fe, fe.items);
47579 // console.log('adding ' + ar[i].xtype);
47581 if (ar[i].xtype == 'Button') {
47582 //console.log('adding button');
47583 //console.log(ar[i]);
47584 this.addButton(ar[i]);
47585 this.allItems.push(fe);
47589 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47590 alert('end is not supported on xtype any more, use items');
47592 // //console.log('adding end');
47600 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47601 * option "monitorValid"
47603 startMonitoring : function(){
47606 Roo.TaskMgr.start({
47607 run : this.bindHandler,
47608 interval : this.monitorPoll || 200,
47615 * Stops monitoring of the valid state of this form
47617 stopMonitoring : function(){
47618 this.bound = false;
47622 bindHandler : function(){
47624 return false; // stops binding
47627 this.items.each(function(f){
47628 if(!f.isValid(true)){
47633 for(var i = 0, len = this.buttons.length; i < len; i++){
47634 var btn = this.buttons[i];
47635 if(btn.formBind === true && btn.disabled === valid){
47636 btn.setDisabled(!valid);
47639 this.fireEvent('clientvalidation', this, valid);
47653 Roo.Form = Roo.form.Form;
47656 * Ext JS Library 1.1.1
47657 * Copyright(c) 2006-2007, Ext JS, LLC.
47659 * Originally Released Under LGPL - original licence link has changed is not relivant.
47662 * <script type="text/javascript">
47665 // as we use this in bootstrap.
47666 Roo.namespace('Roo.form');
47668 * @class Roo.form.Action
47669 * Internal Class used to handle form actions
47671 * @param {Roo.form.BasicForm} el The form element or its id
47672 * @param {Object} config Configuration options
47677 // define the action interface
47678 Roo.form.Action = function(form, options){
47680 this.options = options || {};
47683 * Client Validation Failed
47686 Roo.form.Action.CLIENT_INVALID = 'client';
47688 * Server Validation Failed
47691 Roo.form.Action.SERVER_INVALID = 'server';
47693 * Connect to Server Failed
47696 Roo.form.Action.CONNECT_FAILURE = 'connect';
47698 * Reading Data from Server Failed
47701 Roo.form.Action.LOAD_FAILURE = 'load';
47703 Roo.form.Action.prototype = {
47705 failureType : undefined,
47706 response : undefined,
47707 result : undefined,
47709 // interface method
47710 run : function(options){
47714 // interface method
47715 success : function(response){
47719 // interface method
47720 handleResponse : function(response){
47724 // default connection failure
47725 failure : function(response){
47727 this.response = response;
47728 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47729 this.form.afterAction(this, false);
47732 processResponse : function(response){
47733 this.response = response;
47734 if(!response.responseText){
47737 this.result = this.handleResponse(response);
47738 return this.result;
47741 // utility functions used internally
47742 getUrl : function(appendParams){
47743 var url = this.options.url || this.form.url || this.form.el.dom.action;
47745 var p = this.getParams();
47747 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47753 getMethod : function(){
47754 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47757 getParams : function(){
47758 var bp = this.form.baseParams;
47759 var p = this.options.params;
47761 if(typeof p == "object"){
47762 p = Roo.urlEncode(Roo.applyIf(p, bp));
47763 }else if(typeof p == 'string' && bp){
47764 p += '&' + Roo.urlEncode(bp);
47767 p = Roo.urlEncode(bp);
47772 createCallback : function(){
47774 success: this.success,
47775 failure: this.failure,
47777 timeout: (this.form.timeout*1000),
47778 upload: this.form.fileUpload ? this.success : undefined
47783 Roo.form.Action.Submit = function(form, options){
47784 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47787 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47790 haveProgress : false,
47791 uploadComplete : false,
47793 // uploadProgress indicator.
47794 uploadProgress : function()
47796 if (!this.form.progressUrl) {
47800 if (!this.haveProgress) {
47801 Roo.MessageBox.progress("Uploading", "Uploading");
47803 if (this.uploadComplete) {
47804 Roo.MessageBox.hide();
47808 this.haveProgress = true;
47810 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47812 var c = new Roo.data.Connection();
47814 url : this.form.progressUrl,
47819 success : function(req){
47820 //console.log(data);
47824 rdata = Roo.decode(req.responseText)
47826 Roo.log("Invalid data from server..");
47830 if (!rdata || !rdata.success) {
47832 Roo.MessageBox.alert(Roo.encode(rdata));
47835 var data = rdata.data;
47837 if (this.uploadComplete) {
47838 Roo.MessageBox.hide();
47843 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47844 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47847 this.uploadProgress.defer(2000,this);
47850 failure: function(data) {
47851 Roo.log('progress url failed ');
47862 // run get Values on the form, so it syncs any secondary forms.
47863 this.form.getValues();
47865 var o = this.options;
47866 var method = this.getMethod();
47867 var isPost = method == 'POST';
47868 if(o.clientValidation === false || this.form.isValid()){
47870 if (this.form.progressUrl) {
47871 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47872 (new Date() * 1) + '' + Math.random());
47877 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47878 form:this.form.el.dom,
47879 url:this.getUrl(!isPost),
47881 params:isPost ? this.getParams() : null,
47882 isUpload: this.form.fileUpload
47885 this.uploadProgress();
47887 }else if (o.clientValidation !== false){ // client validation failed
47888 this.failureType = Roo.form.Action.CLIENT_INVALID;
47889 this.form.afterAction(this, false);
47893 success : function(response)
47895 this.uploadComplete= true;
47896 if (this.haveProgress) {
47897 Roo.MessageBox.hide();
47901 var result = this.processResponse(response);
47902 if(result === true || result.success){
47903 this.form.afterAction(this, true);
47907 this.form.markInvalid(result.errors);
47908 this.failureType = Roo.form.Action.SERVER_INVALID;
47910 this.form.afterAction(this, false);
47912 failure : function(response)
47914 this.uploadComplete= true;
47915 if (this.haveProgress) {
47916 Roo.MessageBox.hide();
47919 this.response = response;
47920 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47921 this.form.afterAction(this, false);
47924 handleResponse : function(response){
47925 if(this.form.errorReader){
47926 var rs = this.form.errorReader.read(response);
47929 for(var i = 0, len = rs.records.length; i < len; i++) {
47930 var r = rs.records[i];
47931 errors[i] = r.data;
47934 if(errors.length < 1){
47938 success : rs.success,
47944 ret = Roo.decode(response.responseText);
47948 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47958 Roo.form.Action.Load = function(form, options){
47959 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47960 this.reader = this.form.reader;
47963 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47968 Roo.Ajax.request(Roo.apply(
47969 this.createCallback(), {
47970 method:this.getMethod(),
47971 url:this.getUrl(false),
47972 params:this.getParams()
47976 success : function(response){
47978 var result = this.processResponse(response);
47979 if(result === true || !result.success || !result.data){
47980 this.failureType = Roo.form.Action.LOAD_FAILURE;
47981 this.form.afterAction(this, false);
47984 this.form.clearInvalid();
47985 this.form.setValues(result.data);
47986 this.form.afterAction(this, true);
47989 handleResponse : function(response){
47990 if(this.form.reader){
47991 var rs = this.form.reader.read(response);
47992 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47994 success : rs.success,
47998 return Roo.decode(response.responseText);
48002 Roo.form.Action.ACTION_TYPES = {
48003 'load' : Roo.form.Action.Load,
48004 'submit' : Roo.form.Action.Submit
48007 * Ext JS Library 1.1.1
48008 * Copyright(c) 2006-2007, Ext JS, LLC.
48010 * Originally Released Under LGPL - original licence link has changed is not relivant.
48013 * <script type="text/javascript">
48017 * @class Roo.form.Layout
48018 * @extends Roo.Component
48019 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
48021 * @param {Object} config Configuration options
48023 Roo.form.Layout = function(config){
48025 if (config.items) {
48026 xitems = config.items;
48027 delete config.items;
48029 Roo.form.Layout.superclass.constructor.call(this, config);
48031 Roo.each(xitems, this.addxtype, this);
48035 Roo.extend(Roo.form.Layout, Roo.Component, {
48037 * @cfg {String/Object} autoCreate
48038 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48041 * @cfg {String/Object/Function} style
48042 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48043 * a function which returns such a specification.
48046 * @cfg {String} labelAlign
48047 * Valid values are "left," "top" and "right" (defaults to "left")
48050 * @cfg {Number} labelWidth
48051 * Fixed width in pixels of all field labels (defaults to undefined)
48054 * @cfg {Boolean} clear
48055 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48059 * @cfg {String} labelSeparator
48060 * The separator to use after field labels (defaults to ':')
48062 labelSeparator : ':',
48064 * @cfg {Boolean} hideLabels
48065 * True to suppress the display of field labels in this layout (defaults to false)
48067 hideLabels : false,
48070 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48075 onRender : function(ct, position){
48076 if(this.el){ // from markup
48077 this.el = Roo.get(this.el);
48078 }else { // generate
48079 var cfg = this.getAutoCreate();
48080 this.el = ct.createChild(cfg, position);
48083 this.el.applyStyles(this.style);
48085 if(this.labelAlign){
48086 this.el.addClass('x-form-label-'+this.labelAlign);
48088 if(this.hideLabels){
48089 this.labelStyle = "display:none";
48090 this.elementStyle = "padding-left:0;";
48092 if(typeof this.labelWidth == 'number'){
48093 this.labelStyle = "width:"+this.labelWidth+"px;";
48094 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48096 if(this.labelAlign == 'top'){
48097 this.labelStyle = "width:auto;";
48098 this.elementStyle = "padding-left:0;";
48101 var stack = this.stack;
48102 var slen = stack.length;
48104 if(!this.fieldTpl){
48105 var t = new Roo.Template(
48106 '<div class="x-form-item {5}">',
48107 '<label for="{0}" style="{2}">{1}{4}</label>',
48108 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48110 '</div><div class="x-form-clear-left"></div>'
48112 t.disableFormats = true;
48114 Roo.form.Layout.prototype.fieldTpl = t;
48116 for(var i = 0; i < slen; i++) {
48117 if(stack[i].isFormField){
48118 this.renderField(stack[i]);
48120 this.renderComponent(stack[i]);
48125 this.el.createChild({cls:'x-form-clear'});
48130 renderField : function(f){
48131 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48134 f.labelStyle||this.labelStyle||'', //2
48135 this.elementStyle||'', //3
48136 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48137 f.itemCls||this.itemCls||'' //5
48138 ], true).getPrevSibling());
48142 renderComponent : function(c){
48143 c.render(c.isLayout ? this.el : this.el.createChild());
48146 * Adds a object form elements (using the xtype property as the factory method.)
48147 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48148 * @param {Object} config
48150 addxtype : function(o)
48152 // create the lement.
48153 o.form = this.form;
48154 var fe = Roo.factory(o, Roo.form);
48155 this.form.allItems.push(fe);
48156 this.stack.push(fe);
48158 if (fe.isFormField) {
48159 this.form.items.add(fe);
48167 * @class Roo.form.Column
48168 * @extends Roo.form.Layout
48169 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48171 * @param {Object} config Configuration options
48173 Roo.form.Column = function(config){
48174 Roo.form.Column.superclass.constructor.call(this, config);
48177 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48179 * @cfg {Number/String} width
48180 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48183 * @cfg {String/Object} autoCreate
48184 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48188 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48191 onRender : function(ct, position){
48192 Roo.form.Column.superclass.onRender.call(this, ct, position);
48194 this.el.setWidth(this.width);
48201 * @class Roo.form.Row
48202 * @extends Roo.form.Layout
48203 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48205 * @param {Object} config Configuration options
48209 Roo.form.Row = function(config){
48210 Roo.form.Row.superclass.constructor.call(this, config);
48213 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48215 * @cfg {Number/String} width
48216 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48219 * @cfg {Number/String} height
48220 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48222 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48226 onRender : function(ct, position){
48227 //console.log('row render');
48229 var t = new Roo.Template(
48230 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48231 '<label for="{0}" style="{2}">{1}{4}</label>',
48232 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48236 t.disableFormats = true;
48238 Roo.form.Layout.prototype.rowTpl = t;
48240 this.fieldTpl = this.rowTpl;
48242 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48243 var labelWidth = 100;
48245 if ((this.labelAlign != 'top')) {
48246 if (typeof this.labelWidth == 'number') {
48247 labelWidth = this.labelWidth
48249 this.padWidth = 20 + labelWidth;
48253 Roo.form.Column.superclass.onRender.call(this, ct, position);
48255 this.el.setWidth(this.width);
48258 this.el.setHeight(this.height);
48263 renderField : function(f){
48264 f.fieldEl = this.fieldTpl.append(this.el, [
48265 f.id, f.fieldLabel,
48266 f.labelStyle||this.labelStyle||'',
48267 this.elementStyle||'',
48268 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48269 f.itemCls||this.itemCls||'',
48270 f.width ? f.width + this.padWidth : 160 + this.padWidth
48277 * @class Roo.form.FieldSet
48278 * @extends Roo.form.Layout
48279 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48281 * @param {Object} config Configuration options
48283 Roo.form.FieldSet = function(config){
48284 Roo.form.FieldSet.superclass.constructor.call(this, config);
48287 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48289 * @cfg {String} legend
48290 * The text to display as the legend for the FieldSet (defaults to '')
48293 * @cfg {String/Object} autoCreate
48294 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48298 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48301 onRender : function(ct, position){
48302 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48304 this.setLegend(this.legend);
48309 setLegend : function(text){
48311 this.el.child('legend').update(text);
48316 * Ext JS Library 1.1.1
48317 * Copyright(c) 2006-2007, Ext JS, LLC.
48319 * Originally Released Under LGPL - original licence link has changed is not relivant.
48322 * <script type="text/javascript">
48325 * @class Roo.form.VTypes
48326 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48329 Roo.form.VTypes = function(){
48330 // closure these in so they are only created once.
48331 var alpha = /^[a-zA-Z_]+$/;
48332 var alphanum = /^[a-zA-Z0-9_]+$/;
48333 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48334 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48336 // All these messages and functions are configurable
48339 * The function used to validate email addresses
48340 * @param {String} value The email address
48342 'email' : function(v){
48343 return email.test(v);
48346 * The error text to display when the email validation function returns false
48349 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48351 * The keystroke filter mask to be applied on email input
48354 'emailMask' : /[a-z0-9_\.\-@]/i,
48357 * The function used to validate URLs
48358 * @param {String} value The URL
48360 'url' : function(v){
48361 return url.test(v);
48364 * The error text to display when the url validation function returns false
48367 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48370 * The function used to validate alpha values
48371 * @param {String} value The value
48373 'alpha' : function(v){
48374 return alpha.test(v);
48377 * The error text to display when the alpha validation function returns false
48380 'alphaText' : 'This field should only contain letters and _',
48382 * The keystroke filter mask to be applied on alpha input
48385 'alphaMask' : /[a-z_]/i,
48388 * The function used to validate alphanumeric values
48389 * @param {String} value The value
48391 'alphanum' : function(v){
48392 return alphanum.test(v);
48395 * The error text to display when the alphanumeric validation function returns false
48398 'alphanumText' : 'This field should only contain letters, numbers and _',
48400 * The keystroke filter mask to be applied on alphanumeric input
48403 'alphanumMask' : /[a-z0-9_]/i
48405 }();//<script type="text/javascript">
48408 * @class Roo.form.FCKeditor
48409 * @extends Roo.form.TextArea
48410 * Wrapper around the FCKEditor http://www.fckeditor.net
48412 * Creates a new FCKeditor
48413 * @param {Object} config Configuration options
48415 Roo.form.FCKeditor = function(config){
48416 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48419 * @event editorinit
48420 * Fired when the editor is initialized - you can add extra handlers here..
48421 * @param {FCKeditor} this
48422 * @param {Object} the FCK object.
48429 Roo.form.FCKeditor.editors = { };
48430 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48432 //defaultAutoCreate : {
48433 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48437 * @cfg {Object} fck options - see fck manual for details.
48442 * @cfg {Object} fck toolbar set (Basic or Default)
48444 toolbarSet : 'Basic',
48446 * @cfg {Object} fck BasePath
48448 basePath : '/fckeditor/',
48456 onRender : function(ct, position)
48459 this.defaultAutoCreate = {
48461 style:"width:300px;height:60px;",
48462 autocomplete: "new-password"
48465 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48468 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48469 if(this.preventScrollbars){
48470 this.el.setStyle("overflow", "hidden");
48472 this.el.setHeight(this.growMin);
48475 //console.log('onrender' + this.getId() );
48476 Roo.form.FCKeditor.editors[this.getId()] = this;
48479 this.replaceTextarea() ;
48483 getEditor : function() {
48484 return this.fckEditor;
48487 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48488 * @param {Mixed} value The value to set
48492 setValue : function(value)
48494 //console.log('setValue: ' + value);
48496 if(typeof(value) == 'undefined') { // not sure why this is happending...
48499 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48501 //if(!this.el || !this.getEditor()) {
48502 // this.value = value;
48503 //this.setValue.defer(100,this,[value]);
48507 if(!this.getEditor()) {
48511 this.getEditor().SetData(value);
48518 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48519 * @return {Mixed} value The field value
48521 getValue : function()
48524 if (this.frame && this.frame.dom.style.display == 'none') {
48525 return Roo.form.FCKeditor.superclass.getValue.call(this);
48528 if(!this.el || !this.getEditor()) {
48530 // this.getValue.defer(100,this);
48535 var value=this.getEditor().GetData();
48536 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48537 return Roo.form.FCKeditor.superclass.getValue.call(this);
48543 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48544 * @return {Mixed} value The field value
48546 getRawValue : function()
48548 if (this.frame && this.frame.dom.style.display == 'none') {
48549 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48552 if(!this.el || !this.getEditor()) {
48553 //this.getRawValue.defer(100,this);
48560 var value=this.getEditor().GetData();
48561 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48562 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48566 setSize : function(w,h) {
48570 //if (this.frame && this.frame.dom.style.display == 'none') {
48571 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48574 //if(!this.el || !this.getEditor()) {
48575 // this.setSize.defer(100,this, [w,h]);
48581 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48583 this.frame.dom.setAttribute('width', w);
48584 this.frame.dom.setAttribute('height', h);
48585 this.frame.setSize(w,h);
48589 toggleSourceEdit : function(value) {
48593 this.el.dom.style.display = value ? '' : 'none';
48594 this.frame.dom.style.display = value ? 'none' : '';
48599 focus: function(tag)
48601 if (this.frame.dom.style.display == 'none') {
48602 return Roo.form.FCKeditor.superclass.focus.call(this);
48604 if(!this.el || !this.getEditor()) {
48605 this.focus.defer(100,this, [tag]);
48612 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48613 this.getEditor().Focus();
48615 if (!this.getEditor().Selection.GetSelection()) {
48616 this.focus.defer(100,this, [tag]);
48621 var r = this.getEditor().EditorDocument.createRange();
48622 r.setStart(tgs[0],0);
48623 r.setEnd(tgs[0],0);
48624 this.getEditor().Selection.GetSelection().removeAllRanges();
48625 this.getEditor().Selection.GetSelection().addRange(r);
48626 this.getEditor().Focus();
48633 replaceTextarea : function()
48635 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48638 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48640 // We must check the elements firstly using the Id and then the name.
48641 var oTextarea = document.getElementById( this.getId() );
48643 var colElementsByName = document.getElementsByName( this.getId() ) ;
48645 oTextarea.style.display = 'none' ;
48647 if ( oTextarea.tabIndex ) {
48648 this.TabIndex = oTextarea.tabIndex ;
48651 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48652 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48653 this.frame = Roo.get(this.getId() + '___Frame')
48656 _getConfigHtml : function()
48660 for ( var o in this.fckconfig ) {
48661 sConfig += sConfig.length > 0 ? '&' : '';
48662 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48665 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48669 _getIFrameHtml : function()
48671 var sFile = 'fckeditor.html' ;
48672 /* no idea what this is about..
48675 if ( (/fcksource=true/i).test( window.top.location.search ) )
48676 sFile = 'fckeditor.original.html' ;
48681 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48682 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48685 var html = '<iframe id="' + this.getId() +
48686 '___Frame" src="' + sLink +
48687 '" width="' + this.width +
48688 '" height="' + this.height + '"' +
48689 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48690 ' frameborder="0" scrolling="no"></iframe>' ;
48695 _insertHtmlBefore : function( html, element )
48697 if ( element.insertAdjacentHTML ) {
48699 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48701 var oRange = document.createRange() ;
48702 oRange.setStartBefore( element ) ;
48703 var oFragment = oRange.createContextualFragment( html );
48704 element.parentNode.insertBefore( oFragment, element ) ;
48717 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48719 function FCKeditor_OnComplete(editorInstance){
48720 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48721 f.fckEditor = editorInstance;
48722 //console.log("loaded");
48723 f.fireEvent('editorinit', f, editorInstance);
48743 //<script type="text/javascript">
48745 * @class Roo.form.GridField
48746 * @extends Roo.form.Field
48747 * Embed a grid (or editable grid into a form)
48750 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48752 * xgrid.store = Roo.data.Store
48753 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48754 * xgrid.store.reader = Roo.data.JsonReader
48758 * Creates a new GridField
48759 * @param {Object} config Configuration options
48761 Roo.form.GridField = function(config){
48762 Roo.form.GridField.superclass.constructor.call(this, config);
48766 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48768 * @cfg {Number} width - used to restrict width of grid..
48772 * @cfg {Number} height - used to restrict height of grid..
48776 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48782 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48783 * {tag: "input", type: "checkbox", autocomplete: "off"})
48785 // defaultAutoCreate : { tag: 'div' },
48786 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48788 * @cfg {String} addTitle Text to include for adding a title.
48792 onResize : function(){
48793 Roo.form.Field.superclass.onResize.apply(this, arguments);
48796 initEvents : function(){
48797 // Roo.form.Checkbox.superclass.initEvents.call(this);
48798 // has no events...
48803 getResizeEl : function(){
48807 getPositionEl : function(){
48812 onRender : function(ct, position){
48814 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48815 var style = this.style;
48818 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48819 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48820 this.viewEl = this.wrap.createChild({ tag: 'div' });
48822 this.viewEl.applyStyles(style);
48825 this.viewEl.setWidth(this.width);
48828 this.viewEl.setHeight(this.height);
48830 //if(this.inputValue !== undefined){
48831 //this.setValue(this.value);
48834 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48837 this.grid.render();
48838 this.grid.getDataSource().on('remove', this.refreshValue, this);
48839 this.grid.getDataSource().on('update', this.refreshValue, this);
48840 this.grid.on('afteredit', this.refreshValue, this);
48846 * Sets the value of the item.
48847 * @param {String} either an object or a string..
48849 setValue : function(v){
48851 v = v || []; // empty set..
48852 // this does not seem smart - it really only affects memoryproxy grids..
48853 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48854 var ds = this.grid.getDataSource();
48855 // assumes a json reader..
48857 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48858 ds.loadData( data);
48860 // clear selection so it does not get stale.
48861 if (this.grid.sm) {
48862 this.grid.sm.clearSelections();
48865 Roo.form.GridField.superclass.setValue.call(this, v);
48866 this.refreshValue();
48867 // should load data in the grid really....
48871 refreshValue: function() {
48873 this.grid.getDataSource().each(function(r) {
48876 this.el.dom.value = Roo.encode(val);
48884 * Ext JS Library 1.1.1
48885 * Copyright(c) 2006-2007, Ext JS, LLC.
48887 * Originally Released Under LGPL - original licence link has changed is not relivant.
48890 * <script type="text/javascript">
48893 * @class Roo.form.DisplayField
48894 * @extends Roo.form.Field
48895 * A generic Field to display non-editable data.
48896 * @cfg {Boolean} closable (true|false) default false
48898 * Creates a new Display Field item.
48899 * @param {Object} config Configuration options
48901 Roo.form.DisplayField = function(config){
48902 Roo.form.DisplayField.superclass.constructor.call(this, config);
48907 * Fires after the click the close btn
48908 * @param {Roo.form.DisplayField} this
48914 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48915 inputType: 'hidden',
48921 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48923 focusClass : undefined,
48925 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48927 fieldClass: 'x-form-field',
48930 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48932 valueRenderer: undefined,
48936 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48937 * {tag: "input", type: "checkbox", autocomplete: "off"})
48940 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48944 onResize : function(){
48945 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48949 initEvents : function(){
48950 // Roo.form.Checkbox.superclass.initEvents.call(this);
48951 // has no events...
48954 this.closeEl.on('click', this.onClose, this);
48960 getResizeEl : function(){
48964 getPositionEl : function(){
48969 onRender : function(ct, position){
48971 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48972 //if(this.inputValue !== undefined){
48973 this.wrap = this.el.wrap();
48975 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48978 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48981 if (this.bodyStyle) {
48982 this.viewEl.applyStyles(this.bodyStyle);
48984 //this.viewEl.setStyle('padding', '2px');
48986 this.setValue(this.value);
48991 initValue : Roo.emptyFn,
48996 onClick : function(){
49001 * Sets the checked state of the checkbox.
49002 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
49004 setValue : function(v){
49006 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
49007 // this might be called before we have a dom element..
49008 if (!this.viewEl) {
49011 this.viewEl.dom.innerHTML = html;
49012 Roo.form.DisplayField.superclass.setValue.call(this, v);
49016 onClose : function(e)
49018 e.preventDefault();
49020 this.fireEvent('close', this);
49029 * @class Roo.form.DayPicker
49030 * @extends Roo.form.Field
49031 * A Day picker show [M] [T] [W] ....
49033 * Creates a new Day Picker
49034 * @param {Object} config Configuration options
49036 Roo.form.DayPicker= function(config){
49037 Roo.form.DayPicker.superclass.constructor.call(this, config);
49041 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49043 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49045 focusClass : undefined,
49047 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49049 fieldClass: "x-form-field",
49052 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49053 * {tag: "input", type: "checkbox", autocomplete: "off"})
49055 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49058 actionMode : 'viewEl',
49062 inputType : 'hidden',
49065 inputElement: false, // real input element?
49066 basedOn: false, // ????
49068 isFormField: true, // not sure where this is needed!!!!
49070 onResize : function(){
49071 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49072 if(!this.boxLabel){
49073 this.el.alignTo(this.wrap, 'c-c');
49077 initEvents : function(){
49078 Roo.form.Checkbox.superclass.initEvents.call(this);
49079 this.el.on("click", this.onClick, this);
49080 this.el.on("change", this.onClick, this);
49084 getResizeEl : function(){
49088 getPositionEl : function(){
49094 onRender : function(ct, position){
49095 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49097 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49099 var r1 = '<table><tr>';
49100 var r2 = '<tr class="x-form-daypick-icons">';
49101 for (var i=0; i < 7; i++) {
49102 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49103 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49106 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49107 viewEl.select('img').on('click', this.onClick, this);
49108 this.viewEl = viewEl;
49111 // this will not work on Chrome!!!
49112 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49113 this.el.on('propertychange', this.setFromHidden, this); //ie
49121 initValue : Roo.emptyFn,
49124 * Returns the checked state of the checkbox.
49125 * @return {Boolean} True if checked, else false
49127 getValue : function(){
49128 return this.el.dom.value;
49133 onClick : function(e){
49134 //this.setChecked(!this.checked);
49135 Roo.get(e.target).toggleClass('x-menu-item-checked');
49136 this.refreshValue();
49137 //if(this.el.dom.checked != this.checked){
49138 // this.setValue(this.el.dom.checked);
49143 refreshValue : function()
49146 this.viewEl.select('img',true).each(function(e,i,n) {
49147 val += e.is(".x-menu-item-checked") ? String(n) : '';
49149 this.setValue(val, true);
49153 * Sets the checked state of the checkbox.
49154 * On is always based on a string comparison between inputValue and the param.
49155 * @param {Boolean/String} value - the value to set
49156 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49158 setValue : function(v,suppressEvent){
49159 if (!this.el.dom) {
49162 var old = this.el.dom.value ;
49163 this.el.dom.value = v;
49164 if (suppressEvent) {
49168 // update display..
49169 this.viewEl.select('img',true).each(function(e,i,n) {
49171 var on = e.is(".x-menu-item-checked");
49172 var newv = v.indexOf(String(n)) > -1;
49174 e.toggleClass('x-menu-item-checked');
49180 this.fireEvent('change', this, v, old);
49185 // handle setting of hidden value by some other method!!?!?
49186 setFromHidden: function()
49191 //console.log("SET FROM HIDDEN");
49192 //alert('setFrom hidden');
49193 this.setValue(this.el.dom.value);
49196 onDestroy : function()
49199 Roo.get(this.viewEl).remove();
49202 Roo.form.DayPicker.superclass.onDestroy.call(this);
49206 * RooJS Library 1.1.1
49207 * Copyright(c) 2008-2011 Alan Knowles
49214 * @class Roo.form.ComboCheck
49215 * @extends Roo.form.ComboBox
49216 * A combobox for multiple select items.
49218 * FIXME - could do with a reset button..
49221 * Create a new ComboCheck
49222 * @param {Object} config Configuration options
49224 Roo.form.ComboCheck = function(config){
49225 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49226 // should verify some data...
49228 // hiddenName = required..
49229 // displayField = required
49230 // valudField == required
49231 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49233 Roo.each(req, function(e) {
49234 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49235 throw "Roo.form.ComboCheck : missing value for: " + e;
49242 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49247 selectedClass: 'x-menu-item-checked',
49250 onRender : function(ct, position){
49256 var cls = 'x-combo-list';
49259 this.tpl = new Roo.Template({
49260 html : '<div class="'+cls+'-item x-menu-check-item">' +
49261 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49262 '<span>{' + this.displayField + '}</span>' +
49269 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49270 this.view.singleSelect = false;
49271 this.view.multiSelect = true;
49272 this.view.toggleSelect = true;
49273 this.pageTb.add(new Roo.Toolbar.Fill(), {
49276 handler: function()
49283 onViewOver : function(e, t){
49289 onViewClick : function(doFocus,index){
49293 select: function () {
49294 //Roo.log("SELECT CALLED");
49297 selectByValue : function(xv, scrollIntoView){
49298 var ar = this.getValueArray();
49301 Roo.each(ar, function(v) {
49302 if(v === undefined || v === null){
49305 var r = this.findRecord(this.valueField, v);
49307 sels.push(this.store.indexOf(r))
49311 this.view.select(sels);
49317 onSelect : function(record, index){
49318 // Roo.log("onselect Called");
49319 // this is only called by the clear button now..
49320 this.view.clearSelections();
49321 this.setValue('[]');
49322 if (this.value != this.valueBefore) {
49323 this.fireEvent('change', this, this.value, this.valueBefore);
49324 this.valueBefore = this.value;
49327 getValueArray : function()
49332 //Roo.log(this.value);
49333 if (typeof(this.value) == 'undefined') {
49336 var ar = Roo.decode(this.value);
49337 return ar instanceof Array ? ar : []; //?? valid?
49340 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49345 expand : function ()
49348 Roo.form.ComboCheck.superclass.expand.call(this);
49349 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49350 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49355 collapse : function(){
49356 Roo.form.ComboCheck.superclass.collapse.call(this);
49357 var sl = this.view.getSelectedIndexes();
49358 var st = this.store;
49362 Roo.each(sl, function(i) {
49364 nv.push(r.get(this.valueField));
49366 this.setValue(Roo.encode(nv));
49367 if (this.value != this.valueBefore) {
49369 this.fireEvent('change', this, this.value, this.valueBefore);
49370 this.valueBefore = this.value;
49375 setValue : function(v){
49379 var vals = this.getValueArray();
49381 Roo.each(vals, function(k) {
49382 var r = this.findRecord(this.valueField, k);
49384 tv.push(r.data[this.displayField]);
49385 }else if(this.valueNotFoundText !== undefined){
49386 tv.push( this.valueNotFoundText );
49391 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49392 this.hiddenField.value = v;
49398 * Ext JS Library 1.1.1
49399 * Copyright(c) 2006-2007, Ext JS, LLC.
49401 * Originally Released Under LGPL - original licence link has changed is not relivant.
49404 * <script type="text/javascript">
49408 * @class Roo.form.Signature
49409 * @extends Roo.form.Field
49413 * @param {Object} config Configuration options
49416 Roo.form.Signature = function(config){
49417 Roo.form.Signature.superclass.constructor.call(this, config);
49419 this.addEvents({// not in used??
49422 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49423 * @param {Roo.form.Signature} combo This combo box
49428 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49429 * @param {Roo.form.ComboBox} combo This combo box
49430 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49436 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49438 * @cfg {Object} labels Label to use when rendering a form.
49442 * confirm : "Confirm"
49447 confirm : "Confirm"
49450 * @cfg {Number} width The signature panel width (defaults to 300)
49454 * @cfg {Number} height The signature panel height (defaults to 100)
49458 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49460 allowBlank : false,
49463 // {Object} signPanel The signature SVG panel element (defaults to {})
49465 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49466 isMouseDown : false,
49467 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49468 isConfirmed : false,
49469 // {String} signatureTmp SVG mapping string (defaults to empty string)
49473 defaultAutoCreate : { // modified by initCompnoent..
49479 onRender : function(ct, position){
49481 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49483 this.wrap = this.el.wrap({
49484 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49487 this.createToolbar(this);
49488 this.signPanel = this.wrap.createChild({
49490 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49494 this.svgID = Roo.id();
49495 this.svgEl = this.signPanel.createChild({
49496 xmlns : 'http://www.w3.org/2000/svg',
49498 id : this.svgID + "-svg",
49500 height: this.height,
49501 viewBox: '0 0 '+this.width+' '+this.height,
49505 id: this.svgID + "-svg-r",
49507 height: this.height,
49512 id: this.svgID + "-svg-l",
49514 y1: (this.height*0.8), // start set the line in 80% of height
49515 x2: this.width, // end
49516 y2: (this.height*0.8), // end set the line in 80% of height
49518 'stroke-width': "1",
49519 'stroke-dasharray': "3",
49520 'shape-rendering': "crispEdges",
49521 'pointer-events': "none"
49525 id: this.svgID + "-svg-p",
49527 'stroke-width': "3",
49529 'pointer-events': 'none'
49534 this.svgBox = this.svgEl.dom.getScreenCTM();
49536 createSVG : function(){
49537 var svg = this.signPanel;
49538 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49541 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49542 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49543 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49544 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49545 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49546 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49547 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49550 isTouchEvent : function(e){
49551 return e.type.match(/^touch/);
49553 getCoords : function (e) {
49554 var pt = this.svgEl.dom.createSVGPoint();
49557 if (this.isTouchEvent(e)) {
49558 pt.x = e.targetTouches[0].clientX;
49559 pt.y = e.targetTouches[0].clientY;
49561 var a = this.svgEl.dom.getScreenCTM();
49562 var b = a.inverse();
49563 var mx = pt.matrixTransform(b);
49564 return mx.x + ',' + mx.y;
49566 //mouse event headler
49567 down : function (e) {
49568 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49569 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49571 this.isMouseDown = true;
49573 e.preventDefault();
49575 move : function (e) {
49576 if (this.isMouseDown) {
49577 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49578 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49581 e.preventDefault();
49583 up : function (e) {
49584 this.isMouseDown = false;
49585 var sp = this.signatureTmp.split(' ');
49588 if(!sp[sp.length-2].match(/^L/)){
49592 this.signatureTmp = sp.join(" ");
49595 if(this.getValue() != this.signatureTmp){
49596 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49597 this.isConfirmed = false;
49599 e.preventDefault();
49603 * Protected method that will not generally be called directly. It
49604 * is called when the editor creates its toolbar. Override this method if you need to
49605 * add custom toolbar buttons.
49606 * @param {HtmlEditor} editor
49608 createToolbar : function(editor){
49609 function btn(id, toggle, handler){
49610 var xid = fid + '-'+ id ;
49614 cls : 'x-btn-icon x-edit-'+id,
49615 enableToggle:toggle !== false,
49616 scope: editor, // was editor...
49617 handler:handler||editor.relayBtnCmd,
49618 clickEvent:'mousedown',
49619 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49625 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49629 cls : ' x-signature-btn x-signature-'+id,
49630 scope: editor, // was editor...
49631 handler: this.reset,
49632 clickEvent:'mousedown',
49633 text: this.labels.clear
49640 cls : ' x-signature-btn x-signature-'+id,
49641 scope: editor, // was editor...
49642 handler: this.confirmHandler,
49643 clickEvent:'mousedown',
49644 text: this.labels.confirm
49651 * when user is clicked confirm then show this image.....
49653 * @return {String} Image Data URI
49655 getImageDataURI : function(){
49656 var svg = this.svgEl.dom.parentNode.innerHTML;
49657 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49662 * @return {Boolean} this.isConfirmed
49664 getConfirmed : function(){
49665 return this.isConfirmed;
49669 * @return {Number} this.width
49671 getWidth : function(){
49676 * @return {Number} this.height
49678 getHeight : function(){
49679 return this.height;
49682 getSignature : function(){
49683 return this.signatureTmp;
49686 reset : function(){
49687 this.signatureTmp = '';
49688 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49689 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49690 this.isConfirmed = false;
49691 Roo.form.Signature.superclass.reset.call(this);
49693 setSignature : function(s){
49694 this.signatureTmp = s;
49695 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49696 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49698 this.isConfirmed = false;
49699 Roo.form.Signature.superclass.reset.call(this);
49702 // Roo.log(this.signPanel.dom.contentWindow.up())
49705 setConfirmed : function(){
49709 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49712 confirmHandler : function(){
49713 if(!this.getSignature()){
49717 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49718 this.setValue(this.getSignature());
49719 this.isConfirmed = true;
49721 this.fireEvent('confirm', this);
49724 // Subclasses should provide the validation implementation by overriding this
49725 validateValue : function(value){
49726 if(this.allowBlank){
49730 if(this.isConfirmed){
49737 * Ext JS Library 1.1.1
49738 * Copyright(c) 2006-2007, Ext JS, LLC.
49740 * Originally Released Under LGPL - original licence link has changed is not relivant.
49743 * <script type="text/javascript">
49748 * @class Roo.form.ComboBox
49749 * @extends Roo.form.TriggerField
49750 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49752 * Create a new ComboBox.
49753 * @param {Object} config Configuration options
49755 Roo.form.Select = function(config){
49756 Roo.form.Select.superclass.constructor.call(this, config);
49760 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49762 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49765 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49766 * rendering into an Roo.Editor, defaults to false)
49769 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49770 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49773 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49776 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49777 * the dropdown list (defaults to undefined, with no header element)
49781 * @cfg {String/Roo.Template} tpl The template to use to render the output
49785 defaultAutoCreate : {tag: "select" },
49787 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49789 listWidth: undefined,
49791 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49792 * mode = 'remote' or 'text' if mode = 'local')
49794 displayField: undefined,
49796 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49797 * mode = 'remote' or 'value' if mode = 'local').
49798 * Note: use of a valueField requires the user make a selection
49799 * in order for a value to be mapped.
49801 valueField: undefined,
49805 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49806 * field's data value (defaults to the underlying DOM element's name)
49808 hiddenName: undefined,
49810 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49814 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49816 selectedClass: 'x-combo-selected',
49818 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49819 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49820 * which displays a downward arrow icon).
49822 triggerClass : 'x-form-arrow-trigger',
49824 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49828 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49829 * anchor positions (defaults to 'tl-bl')
49831 listAlign: 'tl-bl?',
49833 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49837 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49838 * query specified by the allQuery config option (defaults to 'query')
49840 triggerAction: 'query',
49842 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49843 * (defaults to 4, does not apply if editable = false)
49847 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49848 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49852 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49853 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49857 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49858 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49862 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49863 * when editable = true (defaults to false)
49865 selectOnFocus:false,
49867 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49869 queryParam: 'query',
49871 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49872 * when mode = 'remote' (defaults to 'Loading...')
49874 loadingText: 'Loading...',
49876 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49880 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49884 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49885 * traditional select (defaults to true)
49889 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49893 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49897 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49898 * listWidth has a higher value)
49902 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49903 * allow the user to set arbitrary text into the field (defaults to false)
49905 forceSelection:false,
49907 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49908 * if typeAhead = true (defaults to 250)
49910 typeAheadDelay : 250,
49912 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49913 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49915 valueNotFoundText : undefined,
49918 * @cfg {String} defaultValue The value displayed after loading the store.
49923 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49925 blockFocus : false,
49928 * @cfg {Boolean} disableClear Disable showing of clear button.
49930 disableClear : false,
49932 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49934 alwaysQuery : false,
49940 // element that contains real text value.. (when hidden is used..)
49943 onRender : function(ct, position){
49944 Roo.form.Field.prototype.onRender.call(this, ct, position);
49947 this.store.on('beforeload', this.onBeforeLoad, this);
49948 this.store.on('load', this.onLoad, this);
49949 this.store.on('loadexception', this.onLoadException, this);
49950 this.store.load({});
49958 initEvents : function(){
49959 //Roo.form.ComboBox.superclass.initEvents.call(this);
49963 onDestroy : function(){
49966 this.store.un('beforeload', this.onBeforeLoad, this);
49967 this.store.un('load', this.onLoad, this);
49968 this.store.un('loadexception', this.onLoadException, this);
49970 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49974 fireKey : function(e){
49975 if(e.isNavKeyPress() && !this.list.isVisible()){
49976 this.fireEvent("specialkey", this, e);
49981 onResize: function(w, h){
49989 * Allow or prevent the user from directly editing the field text. If false is passed,
49990 * the user will only be able to select from the items defined in the dropdown list. This method
49991 * is the runtime equivalent of setting the 'editable' config option at config time.
49992 * @param {Boolean} value True to allow the user to directly edit the field text
49994 setEditable : function(value){
49999 onBeforeLoad : function(){
50001 Roo.log("Select before load");
50004 this.innerList.update(this.loadingText ?
50005 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
50006 //this.restrictHeight();
50007 this.selectedIndex = -1;
50011 onLoad : function(){
50014 var dom = this.el.dom;
50015 dom.innerHTML = '';
50016 var od = dom.ownerDocument;
50018 if (this.emptyText) {
50019 var op = od.createElement('option');
50020 op.setAttribute('value', '');
50021 op.innerHTML = String.format('{0}', this.emptyText);
50022 dom.appendChild(op);
50024 if(this.store.getCount() > 0){
50026 var vf = this.valueField;
50027 var df = this.displayField;
50028 this.store.data.each(function(r) {
50029 // which colmsn to use... testing - cdoe / title..
50030 var op = od.createElement('option');
50031 op.setAttribute('value', r.data[vf]);
50032 op.innerHTML = String.format('{0}', r.data[df]);
50033 dom.appendChild(op);
50035 if (typeof(this.defaultValue != 'undefined')) {
50036 this.setValue(this.defaultValue);
50041 //this.onEmptyResults();
50046 onLoadException : function()
50048 dom.innerHTML = '';
50050 Roo.log("Select on load exception");
50054 Roo.log(this.store.reader.jsonData);
50055 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50056 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50062 onTypeAhead : function(){
50067 onSelect : function(record, index){
50068 Roo.log('on select?');
50070 if(this.fireEvent('beforeselect', this, record, index) !== false){
50071 this.setFromData(index > -1 ? record.data : false);
50073 this.fireEvent('select', this, record, index);
50078 * Returns the currently selected field value or empty string if no value is set.
50079 * @return {String} value The selected value
50081 getValue : function(){
50082 var dom = this.el.dom;
50083 this.value = dom.options[dom.selectedIndex].value;
50089 * Clears any text/value currently set in the field
50091 clearValue : function(){
50093 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50098 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50099 * will be displayed in the field. If the value does not match the data value of an existing item,
50100 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50101 * Otherwise the field will be blank (although the value will still be set).
50102 * @param {String} value The value to match
50104 setValue : function(v){
50105 var d = this.el.dom;
50106 for (var i =0; i < d.options.length;i++) {
50107 if (v == d.options[i].value) {
50108 d.selectedIndex = i;
50116 * @property {Object} the last set data for the element
50121 * Sets the value of the field based on a object which is related to the record format for the store.
50122 * @param {Object} value the value to set as. or false on reset?
50124 setFromData : function(o){
50125 Roo.log('setfrom data?');
50131 reset : function(){
50135 findRecord : function(prop, value){
50140 if(this.store.getCount() > 0){
50141 this.store.each(function(r){
50142 if(r.data[prop] == value){
50152 getName: function()
50154 // returns hidden if it's set..
50155 if (!this.rendered) {return ''};
50156 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50164 onEmptyResults : function(){
50165 Roo.log('empty results');
50170 * Returns true if the dropdown list is expanded, else false.
50172 isExpanded : function(){
50177 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50178 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50179 * @param {String} value The data value of the item to select
50180 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50181 * selected item if it is not currently in view (defaults to true)
50182 * @return {Boolean} True if the value matched an item in the list, else false
50184 selectByValue : function(v, scrollIntoView){
50185 Roo.log('select By Value');
50188 if(v !== undefined && v !== null){
50189 var r = this.findRecord(this.valueField || this.displayField, v);
50191 this.select(this.store.indexOf(r), scrollIntoView);
50199 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50200 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50201 * @param {Number} index The zero-based index of the list item to select
50202 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50203 * selected item if it is not currently in view (defaults to true)
50205 select : function(index, scrollIntoView){
50206 Roo.log('select ');
50209 this.selectedIndex = index;
50210 this.view.select(index);
50211 if(scrollIntoView !== false){
50212 var el = this.view.getNode(index);
50214 this.innerList.scrollChildIntoView(el, false);
50222 validateBlur : function(){
50229 initQuery : function(){
50230 this.doQuery(this.getRawValue());
50234 doForce : function(){
50235 if(this.el.dom.value.length > 0){
50236 this.el.dom.value =
50237 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50243 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50244 * query allowing the query action to be canceled if needed.
50245 * @param {String} query The SQL query to execute
50246 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50247 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50248 * saved in the current store (defaults to false)
50250 doQuery : function(q, forceAll){
50252 Roo.log('doQuery?');
50253 if(q === undefined || q === null){
50258 forceAll: forceAll,
50262 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50266 forceAll = qe.forceAll;
50267 if(forceAll === true || (q.length >= this.minChars)){
50268 if(this.lastQuery != q || this.alwaysQuery){
50269 this.lastQuery = q;
50270 if(this.mode == 'local'){
50271 this.selectedIndex = -1;
50273 this.store.clearFilter();
50275 this.store.filter(this.displayField, q);
50279 this.store.baseParams[this.queryParam] = q;
50281 params: this.getParams(q)
50286 this.selectedIndex = -1;
50293 getParams : function(q){
50295 //p[this.queryParam] = q;
50298 p.limit = this.pageSize;
50304 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50306 collapse : function(){
50311 collapseIf : function(e){
50316 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50318 expand : function(){
50326 * @cfg {Boolean} grow
50330 * @cfg {Number} growMin
50334 * @cfg {Number} growMax
50342 setWidth : function()
50346 getResizeEl : function(){
50349 });//<script type="text/javasscript">
50353 * @class Roo.DDView
50354 * A DnD enabled version of Roo.View.
50355 * @param {Element/String} container The Element in which to create the View.
50356 * @param {String} tpl The template string used to create the markup for each element of the View
50357 * @param {Object} config The configuration properties. These include all the config options of
50358 * {@link Roo.View} plus some specific to this class.<br>
50360 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50361 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50363 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50364 .x-view-drag-insert-above {
50365 border-top:1px dotted #3366cc;
50367 .x-view-drag-insert-below {
50368 border-bottom:1px dotted #3366cc;
50374 Roo.DDView = function(container, tpl, config) {
50375 Roo.DDView.superclass.constructor.apply(this, arguments);
50376 this.getEl().setStyle("outline", "0px none");
50377 this.getEl().unselectable();
50378 if (this.dragGroup) {
50379 this.setDraggable(this.dragGroup.split(","));
50381 if (this.dropGroup) {
50382 this.setDroppable(this.dropGroup.split(","));
50384 if (this.deletable) {
50385 this.setDeletable();
50387 this.isDirtyFlag = false;
50393 Roo.extend(Roo.DDView, Roo.View, {
50394 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50395 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50396 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50397 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50401 reset: Roo.emptyFn,
50403 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50405 validate: function() {
50409 destroy: function() {
50410 this.purgeListeners();
50411 this.getEl.removeAllListeners();
50412 this.getEl().remove();
50413 if (this.dragZone) {
50414 if (this.dragZone.destroy) {
50415 this.dragZone.destroy();
50418 if (this.dropZone) {
50419 if (this.dropZone.destroy) {
50420 this.dropZone.destroy();
50425 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50426 getName: function() {
50430 /** Loads the View from a JSON string representing the Records to put into the Store. */
50431 setValue: function(v) {
50433 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50436 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50437 this.store.proxy = new Roo.data.MemoryProxy(data);
50441 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50442 getValue: function() {
50444 this.store.each(function(rec) {
50445 result += rec.id + ',';
50447 return result.substr(0, result.length - 1) + ')';
50450 getIds: function() {
50451 var i = 0, result = new Array(this.store.getCount());
50452 this.store.each(function(rec) {
50453 result[i++] = rec.id;
50458 isDirty: function() {
50459 return this.isDirtyFlag;
50463 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50464 * whole Element becomes the target, and this causes the drop gesture to append.
50466 getTargetFromEvent : function(e) {
50467 var target = e.getTarget();
50468 while ((target !== null) && (target.parentNode != this.el.dom)) {
50469 target = target.parentNode;
50472 target = this.el.dom.lastChild || this.el.dom;
50478 * Create the drag data which consists of an object which has the property "ddel" as
50479 * the drag proxy element.
50481 getDragData : function(e) {
50482 var target = this.findItemFromChild(e.getTarget());
50484 this.handleSelection(e);
50485 var selNodes = this.getSelectedNodes();
50488 copy: this.copy || (this.allowCopy && e.ctrlKey),
50492 var selectedIndices = this.getSelectedIndexes();
50493 for (var i = 0; i < selectedIndices.length; i++) {
50494 dragData.records.push(this.store.getAt(selectedIndices[i]));
50496 if (selNodes.length == 1) {
50497 dragData.ddel = target.cloneNode(true); // the div element
50499 var div = document.createElement('div'); // create the multi element drag "ghost"
50500 div.className = 'multi-proxy';
50501 for (var i = 0, len = selNodes.length; i < len; i++) {
50502 div.appendChild(selNodes[i].cloneNode(true));
50504 dragData.ddel = div;
50506 //console.log(dragData)
50507 //console.log(dragData.ddel.innerHTML)
50510 //console.log('nodragData')
50514 /** Specify to which ddGroup items in this DDView may be dragged. */
50515 setDraggable: function(ddGroup) {
50516 if (ddGroup instanceof Array) {
50517 Roo.each(ddGroup, this.setDraggable, this);
50520 if (this.dragZone) {
50521 this.dragZone.addToGroup(ddGroup);
50523 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50524 containerScroll: true,
50528 // Draggability implies selection. DragZone's mousedown selects the element.
50529 if (!this.multiSelect) { this.singleSelect = true; }
50531 // Wire the DragZone's handlers up to methods in *this*
50532 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50536 /** Specify from which ddGroup this DDView accepts drops. */
50537 setDroppable: function(ddGroup) {
50538 if (ddGroup instanceof Array) {
50539 Roo.each(ddGroup, this.setDroppable, this);
50542 if (this.dropZone) {
50543 this.dropZone.addToGroup(ddGroup);
50545 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50546 containerScroll: true,
50550 // Wire the DropZone's handlers up to methods in *this*
50551 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50552 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50553 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50554 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50555 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50559 /** Decide whether to drop above or below a View node. */
50560 getDropPoint : function(e, n, dd){
50561 if (n == this.el.dom) { return "above"; }
50562 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50563 var c = t + (b - t) / 2;
50564 var y = Roo.lib.Event.getPageY(e);
50572 onNodeEnter : function(n, dd, e, data){
50576 onNodeOver : function(n, dd, e, data){
50577 var pt = this.getDropPoint(e, n, dd);
50578 // set the insert point style on the target node
50579 var dragElClass = this.dropNotAllowed;
50582 if (pt == "above"){
50583 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50584 targetElClass = "x-view-drag-insert-above";
50586 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50587 targetElClass = "x-view-drag-insert-below";
50589 if (this.lastInsertClass != targetElClass){
50590 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50591 this.lastInsertClass = targetElClass;
50594 return dragElClass;
50597 onNodeOut : function(n, dd, e, data){
50598 this.removeDropIndicators(n);
50601 onNodeDrop : function(n, dd, e, data){
50602 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50605 var pt = this.getDropPoint(e, n, dd);
50606 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50607 if (pt == "below") { insertAt++; }
50608 for (var i = 0; i < data.records.length; i++) {
50609 var r = data.records[i];
50610 var dup = this.store.getById(r.id);
50611 if (dup && (dd != this.dragZone)) {
50612 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50615 this.store.insert(insertAt++, r.copy());
50617 data.source.isDirtyFlag = true;
50619 this.store.insert(insertAt++, r);
50621 this.isDirtyFlag = true;
50624 this.dragZone.cachedTarget = null;
50628 removeDropIndicators : function(n){
50630 Roo.fly(n).removeClass([
50631 "x-view-drag-insert-above",
50632 "x-view-drag-insert-below"]);
50633 this.lastInsertClass = "_noclass";
50638 * Utility method. Add a delete option to the DDView's context menu.
50639 * @param {String} imageUrl The URL of the "delete" icon image.
50641 setDeletable: function(imageUrl) {
50642 if (!this.singleSelect && !this.multiSelect) {
50643 this.singleSelect = true;
50645 var c = this.getContextMenu();
50646 this.contextMenu.on("itemclick", function(item) {
50649 this.remove(this.getSelectedIndexes());
50653 this.contextMenu.add({
50660 /** Return the context menu for this DDView. */
50661 getContextMenu: function() {
50662 if (!this.contextMenu) {
50663 // Create the View's context menu
50664 this.contextMenu = new Roo.menu.Menu({
50665 id: this.id + "-contextmenu"
50667 this.el.on("contextmenu", this.showContextMenu, this);
50669 return this.contextMenu;
50672 disableContextMenu: function() {
50673 if (this.contextMenu) {
50674 this.el.un("contextmenu", this.showContextMenu, this);
50678 showContextMenu: function(e, item) {
50679 item = this.findItemFromChild(e.getTarget());
50682 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50683 this.contextMenu.showAt(e.getXY());
50688 * Remove {@link Roo.data.Record}s at the specified indices.
50689 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50691 remove: function(selectedIndices) {
50692 selectedIndices = [].concat(selectedIndices);
50693 for (var i = 0; i < selectedIndices.length; i++) {
50694 var rec = this.store.getAt(selectedIndices[i]);
50695 this.store.remove(rec);
50700 * Double click fires the event, but also, if this is draggable, and there is only one other
50701 * related DropZone, it transfers the selected node.
50703 onDblClick : function(e){
50704 var item = this.findItemFromChild(e.getTarget());
50706 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50709 if (this.dragGroup) {
50710 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50711 while (targets.indexOf(this.dropZone) > -1) {
50712 targets.remove(this.dropZone);
50714 if (targets.length == 1) {
50715 this.dragZone.cachedTarget = null;
50716 var el = Roo.get(targets[0].getEl());
50717 var box = el.getBox(true);
50718 targets[0].onNodeDrop(el.dom, {
50720 xy: [box.x, box.y + box.height - 1]
50721 }, null, this.getDragData(e));
50727 handleSelection: function(e) {
50728 this.dragZone.cachedTarget = null;
50729 var item = this.findItemFromChild(e.getTarget());
50731 this.clearSelections(true);
50734 if (item && (this.multiSelect || this.singleSelect)){
50735 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50736 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50737 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50738 this.unselect(item);
50740 this.select(item, this.multiSelect && e.ctrlKey);
50741 this.lastSelection = item;
50746 onItemClick : function(item, index, e){
50747 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50753 unselect : function(nodeInfo, suppressEvent){
50754 var node = this.getNode(nodeInfo);
50755 if(node && this.isSelected(node)){
50756 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50757 Roo.fly(node).removeClass(this.selectedClass);
50758 this.selections.remove(node);
50759 if(!suppressEvent){
50760 this.fireEvent("selectionchange", this, this.selections);
50768 * Ext JS Library 1.1.1
50769 * Copyright(c) 2006-2007, Ext JS, LLC.
50771 * Originally Released Under LGPL - original licence link has changed is not relivant.
50774 * <script type="text/javascript">
50778 * @class Roo.LayoutManager
50779 * @extends Roo.util.Observable
50780 * Base class for layout managers.
50782 Roo.LayoutManager = function(container, config){
50783 Roo.LayoutManager.superclass.constructor.call(this);
50784 this.el = Roo.get(container);
50785 // ie scrollbar fix
50786 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50787 document.body.scroll = "no";
50788 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50789 this.el.position('relative');
50791 this.id = this.el.id;
50792 this.el.addClass("x-layout-container");
50793 /** false to disable window resize monitoring @type Boolean */
50794 this.monitorWindowResize = true;
50799 * Fires when a layout is performed.
50800 * @param {Roo.LayoutManager} this
50804 * @event regionresized
50805 * Fires when the user resizes a region.
50806 * @param {Roo.LayoutRegion} region The resized region
50807 * @param {Number} newSize The new size (width for east/west, height for north/south)
50809 "regionresized" : true,
50811 * @event regioncollapsed
50812 * Fires when a region is collapsed.
50813 * @param {Roo.LayoutRegion} region The collapsed region
50815 "regioncollapsed" : true,
50817 * @event regionexpanded
50818 * Fires when a region is expanded.
50819 * @param {Roo.LayoutRegion} region The expanded region
50821 "regionexpanded" : true
50823 this.updating = false;
50824 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50827 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50829 * Returns true if this layout is currently being updated
50830 * @return {Boolean}
50832 isUpdating : function(){
50833 return this.updating;
50837 * Suspend the LayoutManager from doing auto-layouts while
50838 * making multiple add or remove calls
50840 beginUpdate : function(){
50841 this.updating = true;
50845 * Restore auto-layouts and optionally disable the manager from performing a layout
50846 * @param {Boolean} noLayout true to disable a layout update
50848 endUpdate : function(noLayout){
50849 this.updating = false;
50855 layout: function(){
50859 onRegionResized : function(region, newSize){
50860 this.fireEvent("regionresized", region, newSize);
50864 onRegionCollapsed : function(region){
50865 this.fireEvent("regioncollapsed", region);
50868 onRegionExpanded : function(region){
50869 this.fireEvent("regionexpanded", region);
50873 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50874 * performs box-model adjustments.
50875 * @return {Object} The size as an object {width: (the width), height: (the height)}
50877 getViewSize : function(){
50879 if(this.el.dom != document.body){
50880 size = this.el.getSize();
50882 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50884 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50885 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50890 * Returns the Element this layout is bound to.
50891 * @return {Roo.Element}
50893 getEl : function(){
50898 * Returns the specified region.
50899 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50900 * @return {Roo.LayoutRegion}
50902 getRegion : function(target){
50903 return this.regions[target.toLowerCase()];
50906 onWindowResize : function(){
50907 if(this.monitorWindowResize){
50913 * Ext JS Library 1.1.1
50914 * Copyright(c) 2006-2007, Ext JS, LLC.
50916 * Originally Released Under LGPL - original licence link has changed is not relivant.
50919 * <script type="text/javascript">
50922 * @class Roo.BorderLayout
50923 * @extends Roo.LayoutManager
50924 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50925 * please see: <br><br>
50926 * <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>
50927 * <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>
50930 var layout = new Roo.BorderLayout(document.body, {
50964 preferredTabWidth: 150
50969 var CP = Roo.ContentPanel;
50971 layout.beginUpdate();
50972 layout.add("north", new CP("north", "North"));
50973 layout.add("south", new CP("south", {title: "South", closable: true}));
50974 layout.add("west", new CP("west", {title: "West"}));
50975 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50976 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50977 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50978 layout.getRegion("center").showPanel("center1");
50979 layout.endUpdate();
50982 <b>The container the layout is rendered into can be either the body element or any other element.
50983 If it is not the body element, the container needs to either be an absolute positioned element,
50984 or you will need to add "position:relative" to the css of the container. You will also need to specify
50985 the container size if it is not the body element.</b>
50988 * Create a new BorderLayout
50989 * @param {String/HTMLElement/Element} container The container this layout is bound to
50990 * @param {Object} config Configuration options
50992 Roo.BorderLayout = function(container, config){
50993 config = config || {};
50994 Roo.BorderLayout.superclass.constructor.call(this, container, config);
50995 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
50996 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
50997 var target = this.factory.validRegions[i];
50998 if(config[target]){
50999 this.addRegion(target, config[target]);
51004 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
51006 * Creates and adds a new region if it doesn't already exist.
51007 * @param {String} target The target region key (north, south, east, west or center).
51008 * @param {Object} config The regions config object
51009 * @return {BorderLayoutRegion} The new region
51011 addRegion : function(target, config){
51012 if(!this.regions[target]){
51013 var r = this.factory.create(target, this, config);
51014 this.bindRegion(target, r);
51016 return this.regions[target];
51020 bindRegion : function(name, r){
51021 this.regions[name] = r;
51022 r.on("visibilitychange", this.layout, this);
51023 r.on("paneladded", this.layout, this);
51024 r.on("panelremoved", this.layout, this);
51025 r.on("invalidated", this.layout, this);
51026 r.on("resized", this.onRegionResized, this);
51027 r.on("collapsed", this.onRegionCollapsed, this);
51028 r.on("expanded", this.onRegionExpanded, this);
51032 * Performs a layout update.
51034 layout : function(){
51035 if(this.updating) {
51038 var size = this.getViewSize();
51039 var w = size.width;
51040 var h = size.height;
51045 //var x = 0, y = 0;
51047 var rs = this.regions;
51048 var north = rs["north"];
51049 var south = rs["south"];
51050 var west = rs["west"];
51051 var east = rs["east"];
51052 var center = rs["center"];
51053 //if(this.hideOnLayout){ // not supported anymore
51054 //c.el.setStyle("display", "none");
51056 if(north && north.isVisible()){
51057 var b = north.getBox();
51058 var m = north.getMargins();
51059 b.width = w - (m.left+m.right);
51062 centerY = b.height + b.y + m.bottom;
51063 centerH -= centerY;
51064 north.updateBox(this.safeBox(b));
51066 if(south && south.isVisible()){
51067 var b = south.getBox();
51068 var m = south.getMargins();
51069 b.width = w - (m.left+m.right);
51071 var totalHeight = (b.height + m.top + m.bottom);
51072 b.y = h - totalHeight + m.top;
51073 centerH -= totalHeight;
51074 south.updateBox(this.safeBox(b));
51076 if(west && west.isVisible()){
51077 var b = west.getBox();
51078 var m = west.getMargins();
51079 b.height = centerH - (m.top+m.bottom);
51081 b.y = centerY + m.top;
51082 var totalWidth = (b.width + m.left + m.right);
51083 centerX += totalWidth;
51084 centerW -= totalWidth;
51085 west.updateBox(this.safeBox(b));
51087 if(east && east.isVisible()){
51088 var b = east.getBox();
51089 var m = east.getMargins();
51090 b.height = centerH - (m.top+m.bottom);
51091 var totalWidth = (b.width + m.left + m.right);
51092 b.x = w - totalWidth + m.left;
51093 b.y = centerY + m.top;
51094 centerW -= totalWidth;
51095 east.updateBox(this.safeBox(b));
51098 var m = center.getMargins();
51100 x: centerX + m.left,
51101 y: centerY + m.top,
51102 width: centerW - (m.left+m.right),
51103 height: centerH - (m.top+m.bottom)
51105 //if(this.hideOnLayout){
51106 //center.el.setStyle("display", "block");
51108 center.updateBox(this.safeBox(centerBox));
51111 this.fireEvent("layout", this);
51115 safeBox : function(box){
51116 box.width = Math.max(0, box.width);
51117 box.height = Math.max(0, box.height);
51122 * Adds a ContentPanel (or subclass) to this layout.
51123 * @param {String} target The target region key (north, south, east, west or center).
51124 * @param {Roo.ContentPanel} panel The panel to add
51125 * @return {Roo.ContentPanel} The added panel
51127 add : function(target, panel){
51129 target = target.toLowerCase();
51130 return this.regions[target].add(panel);
51134 * Remove a ContentPanel (or subclass) to this layout.
51135 * @param {String} target The target region key (north, south, east, west or center).
51136 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51137 * @return {Roo.ContentPanel} The removed panel
51139 remove : function(target, panel){
51140 target = target.toLowerCase();
51141 return this.regions[target].remove(panel);
51145 * Searches all regions for a panel with the specified id
51146 * @param {String} panelId
51147 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51149 findPanel : function(panelId){
51150 var rs = this.regions;
51151 for(var target in rs){
51152 if(typeof rs[target] != "function"){
51153 var p = rs[target].getPanel(panelId);
51163 * Searches all regions for a panel with the specified id and activates (shows) it.
51164 * @param {String/ContentPanel} panelId The panels id or the panel itself
51165 * @return {Roo.ContentPanel} The shown panel or null
51167 showPanel : function(panelId) {
51168 var rs = this.regions;
51169 for(var target in rs){
51170 var r = rs[target];
51171 if(typeof r != "function"){
51172 if(r.hasPanel(panelId)){
51173 return r.showPanel(panelId);
51181 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51182 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51184 restoreState : function(provider){
51186 provider = Roo.state.Manager;
51188 var sm = new Roo.LayoutStateManager();
51189 sm.init(this, provider);
51193 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51194 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51195 * a valid ContentPanel config object. Example:
51197 // Create the main layout
51198 var layout = new Roo.BorderLayout('main-ct', {
51209 // Create and add multiple ContentPanels at once via configs
51212 id: 'source-files',
51214 title:'Ext Source Files',
51227 * @param {Object} regions An object containing ContentPanel configs by region name
51229 batchAdd : function(regions){
51230 this.beginUpdate();
51231 for(var rname in regions){
51232 var lr = this.regions[rname];
51234 this.addTypedPanels(lr, regions[rname]);
51241 addTypedPanels : function(lr, ps){
51242 if(typeof ps == 'string'){
51243 lr.add(new Roo.ContentPanel(ps));
51245 else if(ps instanceof Array){
51246 for(var i =0, len = ps.length; i < len; i++){
51247 this.addTypedPanels(lr, ps[i]);
51250 else if(!ps.events){ // raw config?
51252 delete ps.el; // prevent conflict
51253 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51255 else { // panel object assumed!
51260 * Adds a xtype elements to the layout.
51264 xtype : 'ContentPanel',
51271 xtype : 'NestedLayoutPanel',
51277 items : [ ... list of content panels or nested layout panels.. ]
51281 * @param {Object} cfg Xtype definition of item to add.
51283 addxtype : function(cfg)
51285 // basically accepts a pannel...
51286 // can accept a layout region..!?!?
51287 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51289 if (!cfg.xtype.match(/Panel$/)) {
51294 if (typeof(cfg.region) == 'undefined') {
51295 Roo.log("Failed to add Panel, region was not set");
51299 var region = cfg.region;
51305 xitems = cfg.items;
51312 case 'ContentPanel': // ContentPanel (el, cfg)
51313 case 'ScrollPanel': // ContentPanel (el, cfg)
51315 if(cfg.autoCreate) {
51316 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51318 var el = this.el.createChild();
51319 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51322 this.add(region, ret);
51326 case 'TreePanel': // our new panel!
51327 cfg.el = this.el.createChild();
51328 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51329 this.add(region, ret);
51332 case 'NestedLayoutPanel':
51333 // create a new Layout (which is a Border Layout...
51334 var el = this.el.createChild();
51335 var clayout = cfg.layout;
51337 clayout.items = clayout.items || [];
51338 // replace this exitems with the clayout ones..
51339 xitems = clayout.items;
51342 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51343 cfg.background = false;
51345 var layout = new Roo.BorderLayout(el, clayout);
51347 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51348 //console.log('adding nested layout panel ' + cfg.toSource());
51349 this.add(region, ret);
51350 nb = {}; /// find first...
51355 // needs grid and region
51357 //var el = this.getRegion(region).el.createChild();
51358 var el = this.el.createChild();
51359 // create the grid first...
51361 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51363 if (region == 'center' && this.active ) {
51364 cfg.background = false;
51366 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51368 this.add(region, ret);
51369 if (cfg.background) {
51370 ret.on('activate', function(gp) {
51371 if (!gp.grid.rendered) {
51386 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51388 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51389 this.add(region, ret);
51392 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51396 // GridPanel (grid, cfg)
51399 this.beginUpdate();
51403 Roo.each(xitems, function(i) {
51404 region = nb && i.region ? i.region : false;
51406 var add = ret.addxtype(i);
51409 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51410 if (!i.background) {
51411 abn[region] = nb[region] ;
51418 // make the last non-background panel active..
51419 //if (nb) { Roo.log(abn); }
51422 for(var r in abn) {
51423 region = this.getRegion(r);
51425 // tried using nb[r], but it does not work..
51427 region.showPanel(abn[r]);
51438 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51439 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51440 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51441 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51444 var CP = Roo.ContentPanel;
51446 var layout = Roo.BorderLayout.create({
51450 panels: [new CP("north", "North")]
51459 panels: [new CP("west", {title: "West"})]
51468 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51477 panels: [new CP("south", {title: "South", closable: true})]
51484 preferredTabWidth: 150,
51486 new CP("center1", {title: "Close Me", closable: true}),
51487 new CP("center2", {title: "Center Panel", closable: false})
51492 layout.getRegion("center").showPanel("center1");
51497 Roo.BorderLayout.create = function(config, targetEl){
51498 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51499 layout.beginUpdate();
51500 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51501 for(var j = 0, jlen = regions.length; j < jlen; j++){
51502 var lr = regions[j];
51503 if(layout.regions[lr] && config[lr].panels){
51504 var r = layout.regions[lr];
51505 var ps = config[lr].panels;
51506 layout.addTypedPanels(r, ps);
51509 layout.endUpdate();
51514 Roo.BorderLayout.RegionFactory = {
51516 validRegions : ["north","south","east","west","center"],
51519 create : function(target, mgr, config){
51520 target = target.toLowerCase();
51521 if(config.lightweight || config.basic){
51522 return new Roo.BasicLayoutRegion(mgr, config, target);
51526 return new Roo.NorthLayoutRegion(mgr, config);
51528 return new Roo.SouthLayoutRegion(mgr, config);
51530 return new Roo.EastLayoutRegion(mgr, config);
51532 return new Roo.WestLayoutRegion(mgr, config);
51534 return new Roo.CenterLayoutRegion(mgr, config);
51536 throw 'Layout region "'+target+'" not supported.';
51540 * Ext JS Library 1.1.1
51541 * Copyright(c) 2006-2007, Ext JS, LLC.
51543 * Originally Released Under LGPL - original licence link has changed is not relivant.
51546 * <script type="text/javascript">
51550 * @class Roo.BasicLayoutRegion
51551 * @extends Roo.util.Observable
51552 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51553 * and does not have a titlebar, tabs or any other features. All it does is size and position
51554 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51556 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51558 this.position = pos;
51561 * @scope Roo.BasicLayoutRegion
51565 * @event beforeremove
51566 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51567 * @param {Roo.LayoutRegion} this
51568 * @param {Roo.ContentPanel} panel The panel
51569 * @param {Object} e The cancel event object
51571 "beforeremove" : true,
51573 * @event invalidated
51574 * Fires when the layout for this region is changed.
51575 * @param {Roo.LayoutRegion} this
51577 "invalidated" : true,
51579 * @event visibilitychange
51580 * Fires when this region is shown or hidden
51581 * @param {Roo.LayoutRegion} this
51582 * @param {Boolean} visibility true or false
51584 "visibilitychange" : true,
51586 * @event paneladded
51587 * Fires when a panel is added.
51588 * @param {Roo.LayoutRegion} this
51589 * @param {Roo.ContentPanel} panel The panel
51591 "paneladded" : true,
51593 * @event panelremoved
51594 * Fires when a panel is removed.
51595 * @param {Roo.LayoutRegion} this
51596 * @param {Roo.ContentPanel} panel The panel
51598 "panelremoved" : true,
51600 * @event beforecollapse
51601 * Fires when this region before collapse.
51602 * @param {Roo.LayoutRegion} this
51604 "beforecollapse" : true,
51607 * Fires when this region is collapsed.
51608 * @param {Roo.LayoutRegion} this
51610 "collapsed" : true,
51613 * Fires when this region is expanded.
51614 * @param {Roo.LayoutRegion} this
51619 * Fires when this region is slid into view.
51620 * @param {Roo.LayoutRegion} this
51622 "slideshow" : true,
51625 * Fires when this region slides out of view.
51626 * @param {Roo.LayoutRegion} this
51628 "slidehide" : true,
51630 * @event panelactivated
51631 * Fires when a panel is activated.
51632 * @param {Roo.LayoutRegion} this
51633 * @param {Roo.ContentPanel} panel The activated panel
51635 "panelactivated" : true,
51638 * Fires when the user resizes this region.
51639 * @param {Roo.LayoutRegion} this
51640 * @param {Number} newSize The new size (width for east/west, height for north/south)
51644 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51645 this.panels = new Roo.util.MixedCollection();
51646 this.panels.getKey = this.getPanelId.createDelegate(this);
51648 this.activePanel = null;
51649 // ensure listeners are added...
51651 if (config.listeners || config.events) {
51652 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51653 listeners : config.listeners || {},
51654 events : config.events || {}
51658 if(skipConfig !== true){
51659 this.applyConfig(config);
51663 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51664 getPanelId : function(p){
51668 applyConfig : function(config){
51669 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51670 this.config = config;
51675 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51676 * the width, for horizontal (north, south) the height.
51677 * @param {Number} newSize The new width or height
51679 resizeTo : function(newSize){
51680 var el = this.el ? this.el :
51681 (this.activePanel ? this.activePanel.getEl() : null);
51683 switch(this.position){
51686 el.setWidth(newSize);
51687 this.fireEvent("resized", this, newSize);
51691 el.setHeight(newSize);
51692 this.fireEvent("resized", this, newSize);
51698 getBox : function(){
51699 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51702 getMargins : function(){
51703 return this.margins;
51706 updateBox : function(box){
51708 var el = this.activePanel.getEl();
51709 el.dom.style.left = box.x + "px";
51710 el.dom.style.top = box.y + "px";
51711 this.activePanel.setSize(box.width, box.height);
51715 * Returns the container element for this region.
51716 * @return {Roo.Element}
51718 getEl : function(){
51719 return this.activePanel;
51723 * Returns true if this region is currently visible.
51724 * @return {Boolean}
51726 isVisible : function(){
51727 return this.activePanel ? true : false;
51730 setActivePanel : function(panel){
51731 panel = this.getPanel(panel);
51732 if(this.activePanel && this.activePanel != panel){
51733 this.activePanel.setActiveState(false);
51734 this.activePanel.getEl().setLeftTop(-10000,-10000);
51736 this.activePanel = panel;
51737 panel.setActiveState(true);
51739 panel.setSize(this.box.width, this.box.height);
51741 this.fireEvent("panelactivated", this, panel);
51742 this.fireEvent("invalidated");
51746 * Show the specified panel.
51747 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51748 * @return {Roo.ContentPanel} The shown panel or null
51750 showPanel : function(panel){
51751 if(panel = this.getPanel(panel)){
51752 this.setActivePanel(panel);
51758 * Get the active panel for this region.
51759 * @return {Roo.ContentPanel} The active panel or null
51761 getActivePanel : function(){
51762 return this.activePanel;
51766 * Add the passed ContentPanel(s)
51767 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51768 * @return {Roo.ContentPanel} The panel added (if only one was added)
51770 add : function(panel){
51771 if(arguments.length > 1){
51772 for(var i = 0, len = arguments.length; i < len; i++) {
51773 this.add(arguments[i]);
51777 if(this.hasPanel(panel)){
51778 this.showPanel(panel);
51781 var el = panel.getEl();
51782 if(el.dom.parentNode != this.mgr.el.dom){
51783 this.mgr.el.dom.appendChild(el.dom);
51785 if(panel.setRegion){
51786 panel.setRegion(this);
51788 this.panels.add(panel);
51789 el.setStyle("position", "absolute");
51790 if(!panel.background){
51791 this.setActivePanel(panel);
51792 if(this.config.initialSize && this.panels.getCount()==1){
51793 this.resizeTo(this.config.initialSize);
51796 this.fireEvent("paneladded", this, panel);
51801 * Returns true if the panel is in this region.
51802 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51803 * @return {Boolean}
51805 hasPanel : function(panel){
51806 if(typeof panel == "object"){ // must be panel obj
51807 panel = panel.getId();
51809 return this.getPanel(panel) ? true : false;
51813 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51814 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51815 * @param {Boolean} preservePanel Overrides the config preservePanel option
51816 * @return {Roo.ContentPanel} The panel that was removed
51818 remove : function(panel, preservePanel){
51819 panel = this.getPanel(panel);
51824 this.fireEvent("beforeremove", this, panel, e);
51825 if(e.cancel === true){
51828 var panelId = panel.getId();
51829 this.panels.removeKey(panelId);
51834 * Returns the panel specified or null if it's not in this region.
51835 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51836 * @return {Roo.ContentPanel}
51838 getPanel : function(id){
51839 if(typeof id == "object"){ // must be panel obj
51842 return this.panels.get(id);
51846 * Returns this regions position (north/south/east/west/center).
51849 getPosition: function(){
51850 return this.position;
51854 * Ext JS Library 1.1.1
51855 * Copyright(c) 2006-2007, Ext JS, LLC.
51857 * Originally Released Under LGPL - original licence link has changed is not relivant.
51860 * <script type="text/javascript">
51864 * @class Roo.LayoutRegion
51865 * @extends Roo.BasicLayoutRegion
51866 * This class represents a region in a layout manager.
51867 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51868 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51869 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51870 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51871 * @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})
51872 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51873 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51874 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51875 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51876 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51877 * @cfg {String} title The title for the region (overrides panel titles)
51878 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51879 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51880 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51881 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51882 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51883 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51884 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51885 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51886 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51887 * @cfg {Boolean} showPin True to show a pin button
51888 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51889 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51890 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51891 * @cfg {Number} width For East/West panels
51892 * @cfg {Number} height For North/South panels
51893 * @cfg {Boolean} split To show the splitter
51894 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51896 Roo.LayoutRegion = function(mgr, config, pos){
51897 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51898 var dh = Roo.DomHelper;
51899 /** This region's container element
51900 * @type Roo.Element */
51901 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51902 /** This region's title element
51903 * @type Roo.Element */
51905 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51906 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51907 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51909 this.titleEl.enableDisplayMode();
51910 /** This region's title text element
51911 * @type HTMLElement */
51912 this.titleTextEl = this.titleEl.dom.firstChild;
51913 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51914 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51915 this.closeBtn.enableDisplayMode();
51916 this.closeBtn.on("click", this.closeClicked, this);
51917 this.closeBtn.hide();
51919 this.createBody(config);
51920 this.visible = true;
51921 this.collapsed = false;
51923 if(config.hideWhenEmpty){
51925 this.on("paneladded", this.validateVisibility, this);
51926 this.on("panelremoved", this.validateVisibility, this);
51928 this.applyConfig(config);
51931 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51933 createBody : function(){
51934 /** This region's body element
51935 * @type Roo.Element */
51936 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51939 applyConfig : function(c){
51940 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51941 var dh = Roo.DomHelper;
51942 if(c.titlebar !== false){
51943 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51944 this.collapseBtn.on("click", this.collapse, this);
51945 this.collapseBtn.enableDisplayMode();
51947 if(c.showPin === true || this.showPin){
51948 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51949 this.stickBtn.enableDisplayMode();
51950 this.stickBtn.on("click", this.expand, this);
51951 this.stickBtn.hide();
51954 /** This region's collapsed element
51955 * @type Roo.Element */
51956 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51957 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51959 if(c.floatable !== false){
51960 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51961 this.collapsedEl.on("click", this.collapseClick, this);
51964 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51965 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51966 id: "message", unselectable: "on", style:{"float":"left"}});
51967 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51969 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51970 this.expandBtn.on("click", this.expand, this);
51972 if(this.collapseBtn){
51973 this.collapseBtn.setVisible(c.collapsible == true);
51975 this.cmargins = c.cmargins || this.cmargins ||
51976 (this.position == "west" || this.position == "east" ?
51977 {top: 0, left: 2, right:2, bottom: 0} :
51978 {top: 2, left: 0, right:0, bottom: 2});
51979 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51980 this.bottomTabs = c.tabPosition != "top";
51981 this.autoScroll = c.autoScroll || false;
51982 if(this.autoScroll){
51983 this.bodyEl.setStyle("overflow", "auto");
51985 this.bodyEl.setStyle("overflow", "hidden");
51987 //if(c.titlebar !== false){
51988 if((!c.titlebar && !c.title) || c.titlebar === false){
51989 this.titleEl.hide();
51991 this.titleEl.show();
51993 this.titleTextEl.innerHTML = c.title;
51997 this.duration = c.duration || .30;
51998 this.slideDuration = c.slideDuration || .45;
52001 this.collapse(true);
52008 * Returns true if this region is currently visible.
52009 * @return {Boolean}
52011 isVisible : function(){
52012 return this.visible;
52016 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
52017 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
52019 setCollapsedTitle : function(title){
52020 title = title || " ";
52021 if(this.collapsedTitleTextEl){
52022 this.collapsedTitleTextEl.innerHTML = title;
52026 getBox : function(){
52028 if(!this.collapsed){
52029 b = this.el.getBox(false, true);
52031 b = this.collapsedEl.getBox(false, true);
52036 getMargins : function(){
52037 return this.collapsed ? this.cmargins : this.margins;
52040 highlight : function(){
52041 this.el.addClass("x-layout-panel-dragover");
52044 unhighlight : function(){
52045 this.el.removeClass("x-layout-panel-dragover");
52048 updateBox : function(box){
52050 if(!this.collapsed){
52051 this.el.dom.style.left = box.x + "px";
52052 this.el.dom.style.top = box.y + "px";
52053 this.updateBody(box.width, box.height);
52055 this.collapsedEl.dom.style.left = box.x + "px";
52056 this.collapsedEl.dom.style.top = box.y + "px";
52057 this.collapsedEl.setSize(box.width, box.height);
52060 this.tabs.autoSizeTabs();
52064 updateBody : function(w, h){
52066 this.el.setWidth(w);
52067 w -= this.el.getBorderWidth("rl");
52068 if(this.config.adjustments){
52069 w += this.config.adjustments[0];
52073 this.el.setHeight(h);
52074 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52075 h -= this.el.getBorderWidth("tb");
52076 if(this.config.adjustments){
52077 h += this.config.adjustments[1];
52079 this.bodyEl.setHeight(h);
52081 h = this.tabs.syncHeight(h);
52084 if(this.panelSize){
52085 w = w !== null ? w : this.panelSize.width;
52086 h = h !== null ? h : this.panelSize.height;
52088 if(this.activePanel){
52089 var el = this.activePanel.getEl();
52090 w = w !== null ? w : el.getWidth();
52091 h = h !== null ? h : el.getHeight();
52092 this.panelSize = {width: w, height: h};
52093 this.activePanel.setSize(w, h);
52095 if(Roo.isIE && this.tabs){
52096 this.tabs.el.repaint();
52101 * Returns the container element for this region.
52102 * @return {Roo.Element}
52104 getEl : function(){
52109 * Hides this region.
52112 if(!this.collapsed){
52113 this.el.dom.style.left = "-2000px";
52116 this.collapsedEl.dom.style.left = "-2000px";
52117 this.collapsedEl.hide();
52119 this.visible = false;
52120 this.fireEvent("visibilitychange", this, false);
52124 * Shows this region if it was previously hidden.
52127 if(!this.collapsed){
52130 this.collapsedEl.show();
52132 this.visible = true;
52133 this.fireEvent("visibilitychange", this, true);
52136 closeClicked : function(){
52137 if(this.activePanel){
52138 this.remove(this.activePanel);
52142 collapseClick : function(e){
52144 e.stopPropagation();
52147 e.stopPropagation();
52153 * Collapses this region.
52154 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52156 collapse : function(skipAnim, skipCheck = false){
52157 if(this.collapsed) {
52161 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52163 this.collapsed = true;
52165 this.split.el.hide();
52167 if(this.config.animate && skipAnim !== true){
52168 this.fireEvent("invalidated", this);
52169 this.animateCollapse();
52171 this.el.setLocation(-20000,-20000);
52173 this.collapsedEl.show();
52174 this.fireEvent("collapsed", this);
52175 this.fireEvent("invalidated", this);
52181 animateCollapse : function(){
52186 * Expands this region if it was previously collapsed.
52187 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52188 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52190 expand : function(e, skipAnim){
52192 e.stopPropagation();
52194 if(!this.collapsed || this.el.hasActiveFx()) {
52198 this.afterSlideIn();
52201 this.collapsed = false;
52202 if(this.config.animate && skipAnim !== true){
52203 this.animateExpand();
52207 this.split.el.show();
52209 this.collapsedEl.setLocation(-2000,-2000);
52210 this.collapsedEl.hide();
52211 this.fireEvent("invalidated", this);
52212 this.fireEvent("expanded", this);
52216 animateExpand : function(){
52220 initTabs : function()
52222 this.bodyEl.setStyle("overflow", "hidden");
52223 var ts = new Roo.TabPanel(
52226 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52227 disableTooltips: this.config.disableTabTips,
52228 toolbar : this.config.toolbar
52231 if(this.config.hideTabs){
52232 ts.stripWrap.setDisplayed(false);
52235 ts.resizeTabs = this.config.resizeTabs === true;
52236 ts.minTabWidth = this.config.minTabWidth || 40;
52237 ts.maxTabWidth = this.config.maxTabWidth || 250;
52238 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52239 ts.monitorResize = false;
52240 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52241 ts.bodyEl.addClass('x-layout-tabs-body');
52242 this.panels.each(this.initPanelAsTab, this);
52245 initPanelAsTab : function(panel){
52246 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52247 this.config.closeOnTab && panel.isClosable());
52248 if(panel.tabTip !== undefined){
52249 ti.setTooltip(panel.tabTip);
52251 ti.on("activate", function(){
52252 this.setActivePanel(panel);
52254 if(this.config.closeOnTab){
52255 ti.on("beforeclose", function(t, e){
52257 this.remove(panel);
52263 updatePanelTitle : function(panel, title){
52264 if(this.activePanel == panel){
52265 this.updateTitle(title);
52268 var ti = this.tabs.getTab(panel.getEl().id);
52270 if(panel.tabTip !== undefined){
52271 ti.setTooltip(panel.tabTip);
52276 updateTitle : function(title){
52277 if(this.titleTextEl && !this.config.title){
52278 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52282 setActivePanel : function(panel){
52283 panel = this.getPanel(panel);
52284 if(this.activePanel && this.activePanel != panel){
52285 this.activePanel.setActiveState(false);
52287 this.activePanel = panel;
52288 panel.setActiveState(true);
52289 if(this.panelSize){
52290 panel.setSize(this.panelSize.width, this.panelSize.height);
52293 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52295 this.updateTitle(panel.getTitle());
52297 this.fireEvent("invalidated", this);
52299 this.fireEvent("panelactivated", this, panel);
52303 * Shows the specified panel.
52304 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52305 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52307 showPanel : function(panel)
52309 panel = this.getPanel(panel);
52312 var tab = this.tabs.getTab(panel.getEl().id);
52313 if(tab.isHidden()){
52314 this.tabs.unhideTab(tab.id);
52318 this.setActivePanel(panel);
52325 * Get the active panel for this region.
52326 * @return {Roo.ContentPanel} The active panel or null
52328 getActivePanel : function(){
52329 return this.activePanel;
52332 validateVisibility : function(){
52333 if(this.panels.getCount() < 1){
52334 this.updateTitle(" ");
52335 this.closeBtn.hide();
52338 if(!this.isVisible()){
52345 * Adds the passed ContentPanel(s) to this region.
52346 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52347 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52349 add : function(panel){
52350 if(arguments.length > 1){
52351 for(var i = 0, len = arguments.length; i < len; i++) {
52352 this.add(arguments[i]);
52356 if(this.hasPanel(panel)){
52357 this.showPanel(panel);
52360 panel.setRegion(this);
52361 this.panels.add(panel);
52362 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52363 this.bodyEl.dom.appendChild(panel.getEl().dom);
52364 if(panel.background !== true){
52365 this.setActivePanel(panel);
52367 this.fireEvent("paneladded", this, panel);
52373 this.initPanelAsTab(panel);
52375 if(panel.background !== true){
52376 this.tabs.activate(panel.getEl().id);
52378 this.fireEvent("paneladded", this, panel);
52383 * Hides the tab for the specified panel.
52384 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52386 hidePanel : function(panel){
52387 if(this.tabs && (panel = this.getPanel(panel))){
52388 this.tabs.hideTab(panel.getEl().id);
52393 * Unhides the tab for a previously hidden panel.
52394 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52396 unhidePanel : function(panel){
52397 if(this.tabs && (panel = this.getPanel(panel))){
52398 this.tabs.unhideTab(panel.getEl().id);
52402 clearPanels : function(){
52403 while(this.panels.getCount() > 0){
52404 this.remove(this.panels.first());
52409 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52410 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52411 * @param {Boolean} preservePanel Overrides the config preservePanel option
52412 * @return {Roo.ContentPanel} The panel that was removed
52414 remove : function(panel, preservePanel){
52415 panel = this.getPanel(panel);
52420 this.fireEvent("beforeremove", this, panel, e);
52421 if(e.cancel === true){
52424 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52425 var panelId = panel.getId();
52426 this.panels.removeKey(panelId);
52428 document.body.appendChild(panel.getEl().dom);
52431 this.tabs.removeTab(panel.getEl().id);
52432 }else if (!preservePanel){
52433 this.bodyEl.dom.removeChild(panel.getEl().dom);
52435 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52436 var p = this.panels.first();
52437 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52438 tempEl.appendChild(p.getEl().dom);
52439 this.bodyEl.update("");
52440 this.bodyEl.dom.appendChild(p.getEl().dom);
52442 this.updateTitle(p.getTitle());
52444 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52445 this.setActivePanel(p);
52447 panel.setRegion(null);
52448 if(this.activePanel == panel){
52449 this.activePanel = null;
52451 if(this.config.autoDestroy !== false && preservePanel !== true){
52452 try{panel.destroy();}catch(e){}
52454 this.fireEvent("panelremoved", this, panel);
52459 * Returns the TabPanel component used by this region
52460 * @return {Roo.TabPanel}
52462 getTabs : function(){
52466 createTool : function(parentEl, className){
52467 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52468 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52469 btn.addClassOnOver("x-layout-tools-button-over");
52474 * Ext JS Library 1.1.1
52475 * Copyright(c) 2006-2007, Ext JS, LLC.
52477 * Originally Released Under LGPL - original licence link has changed is not relivant.
52480 * <script type="text/javascript">
52486 * @class Roo.SplitLayoutRegion
52487 * @extends Roo.LayoutRegion
52488 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52490 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52491 this.cursor = cursor;
52492 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52495 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52496 splitTip : "Drag to resize.",
52497 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52498 useSplitTips : false,
52500 applyConfig : function(config){
52501 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52504 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52505 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52506 /** The SplitBar for this region
52507 * @type Roo.SplitBar */
52508 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52509 this.split.on("moved", this.onSplitMove, this);
52510 this.split.useShim = config.useShim === true;
52511 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52512 if(this.useSplitTips){
52513 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52515 if(config.collapsible){
52516 this.split.el.on("dblclick", this.collapse, this);
52519 if(typeof config.minSize != "undefined"){
52520 this.split.minSize = config.minSize;
52522 if(typeof config.maxSize != "undefined"){
52523 this.split.maxSize = config.maxSize;
52525 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52526 this.hideSplitter();
52531 getHMaxSize : function(){
52532 var cmax = this.config.maxSize || 10000;
52533 var center = this.mgr.getRegion("center");
52534 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52537 getVMaxSize : function(){
52538 var cmax = this.config.maxSize || 10000;
52539 var center = this.mgr.getRegion("center");
52540 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52543 onSplitMove : function(split, newSize){
52544 this.fireEvent("resized", this, newSize);
52548 * Returns the {@link Roo.SplitBar} for this region.
52549 * @return {Roo.SplitBar}
52551 getSplitBar : function(){
52556 this.hideSplitter();
52557 Roo.SplitLayoutRegion.superclass.hide.call(this);
52560 hideSplitter : function(){
52562 this.split.el.setLocation(-2000,-2000);
52563 this.split.el.hide();
52569 this.split.el.show();
52571 Roo.SplitLayoutRegion.superclass.show.call(this);
52574 beforeSlide: function(){
52575 if(Roo.isGecko){// firefox overflow auto bug workaround
52576 this.bodyEl.clip();
52578 this.tabs.bodyEl.clip();
52580 if(this.activePanel){
52581 this.activePanel.getEl().clip();
52583 if(this.activePanel.beforeSlide){
52584 this.activePanel.beforeSlide();
52590 afterSlide : function(){
52591 if(Roo.isGecko){// firefox overflow auto bug workaround
52592 this.bodyEl.unclip();
52594 this.tabs.bodyEl.unclip();
52596 if(this.activePanel){
52597 this.activePanel.getEl().unclip();
52598 if(this.activePanel.afterSlide){
52599 this.activePanel.afterSlide();
52605 initAutoHide : function(){
52606 if(this.autoHide !== false){
52607 if(!this.autoHideHd){
52608 var st = new Roo.util.DelayedTask(this.slideIn, this);
52609 this.autoHideHd = {
52610 "mouseout": function(e){
52611 if(!e.within(this.el, true)){
52615 "mouseover" : function(e){
52621 this.el.on(this.autoHideHd);
52625 clearAutoHide : function(){
52626 if(this.autoHide !== false){
52627 this.el.un("mouseout", this.autoHideHd.mouseout);
52628 this.el.un("mouseover", this.autoHideHd.mouseover);
52632 clearMonitor : function(){
52633 Roo.get(document).un("click", this.slideInIf, this);
52636 // these names are backwards but not changed for compat
52637 slideOut : function(){
52638 if(this.isSlid || this.el.hasActiveFx()){
52641 this.isSlid = true;
52642 if(this.collapseBtn){
52643 this.collapseBtn.hide();
52645 this.closeBtnState = this.closeBtn.getStyle('display');
52646 this.closeBtn.hide();
52648 this.stickBtn.show();
52651 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52652 this.beforeSlide();
52653 this.el.setStyle("z-index", 10001);
52654 this.el.slideIn(this.getSlideAnchor(), {
52655 callback: function(){
52657 this.initAutoHide();
52658 Roo.get(document).on("click", this.slideInIf, this);
52659 this.fireEvent("slideshow", this);
52666 afterSlideIn : function(){
52667 this.clearAutoHide();
52668 this.isSlid = false;
52669 this.clearMonitor();
52670 this.el.setStyle("z-index", "");
52671 if(this.collapseBtn){
52672 this.collapseBtn.show();
52674 this.closeBtn.setStyle('display', this.closeBtnState);
52676 this.stickBtn.hide();
52678 this.fireEvent("slidehide", this);
52681 slideIn : function(cb){
52682 if(!this.isSlid || this.el.hasActiveFx()){
52686 this.isSlid = false;
52687 this.beforeSlide();
52688 this.el.slideOut(this.getSlideAnchor(), {
52689 callback: function(){
52690 this.el.setLeftTop(-10000, -10000);
52692 this.afterSlideIn();
52700 slideInIf : function(e){
52701 if(!e.within(this.el)){
52706 animateCollapse : function(){
52707 this.beforeSlide();
52708 this.el.setStyle("z-index", 20000);
52709 var anchor = this.getSlideAnchor();
52710 this.el.slideOut(anchor, {
52711 callback : function(){
52712 this.el.setStyle("z-index", "");
52713 this.collapsedEl.slideIn(anchor, {duration:.3});
52715 this.el.setLocation(-10000,-10000);
52717 this.fireEvent("collapsed", this);
52724 animateExpand : function(){
52725 this.beforeSlide();
52726 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52727 this.el.setStyle("z-index", 20000);
52728 this.collapsedEl.hide({
52731 this.el.slideIn(this.getSlideAnchor(), {
52732 callback : function(){
52733 this.el.setStyle("z-index", "");
52736 this.split.el.show();
52738 this.fireEvent("invalidated", this);
52739 this.fireEvent("expanded", this);
52767 getAnchor : function(){
52768 return this.anchors[this.position];
52771 getCollapseAnchor : function(){
52772 return this.canchors[this.position];
52775 getSlideAnchor : function(){
52776 return this.sanchors[this.position];
52779 getAlignAdj : function(){
52780 var cm = this.cmargins;
52781 switch(this.position){
52797 getExpandAdj : function(){
52798 var c = this.collapsedEl, cm = this.cmargins;
52799 switch(this.position){
52801 return [-(cm.right+c.getWidth()+cm.left), 0];
52804 return [cm.right+c.getWidth()+cm.left, 0];
52807 return [0, -(cm.top+cm.bottom+c.getHeight())];
52810 return [0, cm.top+cm.bottom+c.getHeight()];
52816 * Ext JS Library 1.1.1
52817 * Copyright(c) 2006-2007, Ext JS, LLC.
52819 * Originally Released Under LGPL - original licence link has changed is not relivant.
52822 * <script type="text/javascript">
52825 * These classes are private internal classes
52827 Roo.CenterLayoutRegion = function(mgr, config){
52828 Roo.LayoutRegion.call(this, mgr, config, "center");
52829 this.visible = true;
52830 this.minWidth = config.minWidth || 20;
52831 this.minHeight = config.minHeight || 20;
52834 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52836 // center panel can't be hidden
52840 // center panel can't be hidden
52843 getMinWidth: function(){
52844 return this.minWidth;
52847 getMinHeight: function(){
52848 return this.minHeight;
52853 Roo.NorthLayoutRegion = function(mgr, config){
52854 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52856 this.split.placement = Roo.SplitBar.TOP;
52857 this.split.orientation = Roo.SplitBar.VERTICAL;
52858 this.split.el.addClass("x-layout-split-v");
52860 var size = config.initialSize || config.height;
52861 if(typeof size != "undefined"){
52862 this.el.setHeight(size);
52865 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52866 orientation: Roo.SplitBar.VERTICAL,
52867 getBox : function(){
52868 if(this.collapsed){
52869 return this.collapsedEl.getBox();
52871 var box = this.el.getBox();
52873 box.height += this.split.el.getHeight();
52878 updateBox : function(box){
52879 if(this.split && !this.collapsed){
52880 box.height -= this.split.el.getHeight();
52881 this.split.el.setLeft(box.x);
52882 this.split.el.setTop(box.y+box.height);
52883 this.split.el.setWidth(box.width);
52885 if(this.collapsed){
52886 this.updateBody(box.width, null);
52888 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52892 Roo.SouthLayoutRegion = function(mgr, config){
52893 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52895 this.split.placement = Roo.SplitBar.BOTTOM;
52896 this.split.orientation = Roo.SplitBar.VERTICAL;
52897 this.split.el.addClass("x-layout-split-v");
52899 var size = config.initialSize || config.height;
52900 if(typeof size != "undefined"){
52901 this.el.setHeight(size);
52904 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52905 orientation: Roo.SplitBar.VERTICAL,
52906 getBox : function(){
52907 if(this.collapsed){
52908 return this.collapsedEl.getBox();
52910 var box = this.el.getBox();
52912 var sh = this.split.el.getHeight();
52919 updateBox : function(box){
52920 if(this.split && !this.collapsed){
52921 var sh = this.split.el.getHeight();
52924 this.split.el.setLeft(box.x);
52925 this.split.el.setTop(box.y-sh);
52926 this.split.el.setWidth(box.width);
52928 if(this.collapsed){
52929 this.updateBody(box.width, null);
52931 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52935 Roo.EastLayoutRegion = function(mgr, config){
52936 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52938 this.split.placement = Roo.SplitBar.RIGHT;
52939 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52940 this.split.el.addClass("x-layout-split-h");
52942 var size = config.initialSize || config.width;
52943 if(typeof size != "undefined"){
52944 this.el.setWidth(size);
52947 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52948 orientation: Roo.SplitBar.HORIZONTAL,
52949 getBox : function(){
52950 if(this.collapsed){
52951 return this.collapsedEl.getBox();
52953 var box = this.el.getBox();
52955 var sw = this.split.el.getWidth();
52962 updateBox : function(box){
52963 if(this.split && !this.collapsed){
52964 var sw = this.split.el.getWidth();
52966 this.split.el.setLeft(box.x);
52967 this.split.el.setTop(box.y);
52968 this.split.el.setHeight(box.height);
52971 if(this.collapsed){
52972 this.updateBody(null, box.height);
52974 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52978 Roo.WestLayoutRegion = function(mgr, config){
52979 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52981 this.split.placement = Roo.SplitBar.LEFT;
52982 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52983 this.split.el.addClass("x-layout-split-h");
52985 var size = config.initialSize || config.width;
52986 if(typeof size != "undefined"){
52987 this.el.setWidth(size);
52990 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52991 orientation: Roo.SplitBar.HORIZONTAL,
52992 getBox : function(){
52993 if(this.collapsed){
52994 return this.collapsedEl.getBox();
52996 var box = this.el.getBox();
52998 box.width += this.split.el.getWidth();
53003 updateBox : function(box){
53004 if(this.split && !this.collapsed){
53005 var sw = this.split.el.getWidth();
53007 this.split.el.setLeft(box.x+box.width);
53008 this.split.el.setTop(box.y);
53009 this.split.el.setHeight(box.height);
53011 if(this.collapsed){
53012 this.updateBody(null, box.height);
53014 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53019 * Ext JS Library 1.1.1
53020 * Copyright(c) 2006-2007, Ext JS, LLC.
53022 * Originally Released Under LGPL - original licence link has changed is not relivant.
53025 * <script type="text/javascript">
53030 * Private internal class for reading and applying state
53032 Roo.LayoutStateManager = function(layout){
53033 // default empty state
53042 Roo.LayoutStateManager.prototype = {
53043 init : function(layout, provider){
53044 this.provider = provider;
53045 var state = provider.get(layout.id+"-layout-state");
53047 var wasUpdating = layout.isUpdating();
53049 layout.beginUpdate();
53051 for(var key in state){
53052 if(typeof state[key] != "function"){
53053 var rstate = state[key];
53054 var r = layout.getRegion(key);
53057 r.resizeTo(rstate.size);
53059 if(rstate.collapsed == true){
53062 r.expand(null, true);
53068 layout.endUpdate();
53070 this.state = state;
53072 this.layout = layout;
53073 layout.on("regionresized", this.onRegionResized, this);
53074 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53075 layout.on("regionexpanded", this.onRegionExpanded, this);
53078 storeState : function(){
53079 this.provider.set(this.layout.id+"-layout-state", this.state);
53082 onRegionResized : function(region, newSize){
53083 this.state[region.getPosition()].size = newSize;
53087 onRegionCollapsed : function(region){
53088 this.state[region.getPosition()].collapsed = true;
53092 onRegionExpanded : function(region){
53093 this.state[region.getPosition()].collapsed = false;
53098 * Ext JS Library 1.1.1
53099 * Copyright(c) 2006-2007, Ext JS, LLC.
53101 * Originally Released Under LGPL - original licence link has changed is not relivant.
53104 * <script type="text/javascript">
53107 * @class Roo.ContentPanel
53108 * @extends Roo.util.Observable
53109 * A basic ContentPanel element.
53110 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53111 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53112 * @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
53113 * @cfg {Boolean} closable True if the panel can be closed/removed
53114 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53115 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53116 * @cfg {Toolbar} toolbar A toolbar for this panel
53117 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53118 * @cfg {String} title The title for this panel
53119 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53120 * @cfg {String} url Calls {@link #setUrl} with this value
53121 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53122 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53123 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53124 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53127 * Create a new ContentPanel.
53128 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53129 * @param {String/Object} config A string to set only the title or a config object
53130 * @param {String} content (optional) Set the HTML content for this panel
53131 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53133 Roo.ContentPanel = function(el, config, content){
53137 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53141 if (config && config.parentLayout) {
53142 el = config.parentLayout.el.createChild();
53145 if(el.autoCreate){ // xtype is available if this is called from factory
53149 this.el = Roo.get(el);
53150 if(!this.el && config && config.autoCreate){
53151 if(typeof config.autoCreate == "object"){
53152 if(!config.autoCreate.id){
53153 config.autoCreate.id = config.id||el;
53155 this.el = Roo.DomHelper.append(document.body,
53156 config.autoCreate, true);
53158 this.el = Roo.DomHelper.append(document.body,
53159 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53162 this.closable = false;
53163 this.loaded = false;
53164 this.active = false;
53165 if(typeof config == "string"){
53166 this.title = config;
53168 Roo.apply(this, config);
53171 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53172 this.wrapEl = this.el.wrap();
53173 this.toolbar.container = this.el.insertSibling(false, 'before');
53174 this.toolbar = new Roo.Toolbar(this.toolbar);
53177 // xtype created footer. - not sure if will work as we normally have to render first..
53178 if (this.footer && !this.footer.el && this.footer.xtype) {
53179 if (!this.wrapEl) {
53180 this.wrapEl = this.el.wrap();
53183 this.footer.container = this.wrapEl.createChild();
53185 this.footer = Roo.factory(this.footer, Roo);
53190 this.resizeEl = Roo.get(this.resizeEl, true);
53192 this.resizeEl = this.el;
53194 // handle view.xtype
53202 * Fires when this panel is activated.
53203 * @param {Roo.ContentPanel} this
53207 * @event deactivate
53208 * Fires when this panel is activated.
53209 * @param {Roo.ContentPanel} this
53211 "deactivate" : true,
53215 * Fires when this panel is resized if fitToFrame is true.
53216 * @param {Roo.ContentPanel} this
53217 * @param {Number} width The width after any component adjustments
53218 * @param {Number} height The height after any component adjustments
53224 * Fires when this tab is created
53225 * @param {Roo.ContentPanel} this
53236 if(this.autoScroll){
53237 this.resizeEl.setStyle("overflow", "auto");
53239 // fix randome scrolling
53240 this.el.on('scroll', function() {
53241 Roo.log('fix random scolling');
53242 this.scrollTo('top',0);
53245 content = content || this.content;
53247 this.setContent(content);
53249 if(config && config.url){
53250 this.setUrl(this.url, this.params, this.loadOnce);
53255 Roo.ContentPanel.superclass.constructor.call(this);
53257 if (this.view && typeof(this.view.xtype) != 'undefined') {
53258 this.view.el = this.el.appendChild(document.createElement("div"));
53259 this.view = Roo.factory(this.view);
53260 this.view.render && this.view.render(false, '');
53264 this.fireEvent('render', this);
53267 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53269 setRegion : function(region){
53270 this.region = region;
53272 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53274 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53279 * Returns the toolbar for this Panel if one was configured.
53280 * @return {Roo.Toolbar}
53282 getToolbar : function(){
53283 return this.toolbar;
53286 setActiveState : function(active){
53287 this.active = active;
53289 this.fireEvent("deactivate", this);
53291 this.fireEvent("activate", this);
53295 * Updates this panel's element
53296 * @param {String} content The new content
53297 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53299 setContent : function(content, loadScripts){
53300 this.el.update(content, loadScripts);
53303 ignoreResize : function(w, h){
53304 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53307 this.lastSize = {width: w, height: h};
53312 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53313 * @return {Roo.UpdateManager} The UpdateManager
53315 getUpdateManager : function(){
53316 return this.el.getUpdateManager();
53319 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53320 * @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:
53323 url: "your-url.php",
53324 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53325 callback: yourFunction,
53326 scope: yourObject, //(optional scope)
53329 text: "Loading...",
53334 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53335 * 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.
53336 * @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}
53337 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53338 * @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.
53339 * @return {Roo.ContentPanel} this
53342 var um = this.el.getUpdateManager();
53343 um.update.apply(um, arguments);
53349 * 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.
53350 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53351 * @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)
53352 * @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)
53353 * @return {Roo.UpdateManager} The UpdateManager
53355 setUrl : function(url, params, loadOnce){
53356 if(this.refreshDelegate){
53357 this.removeListener("activate", this.refreshDelegate);
53359 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53360 this.on("activate", this.refreshDelegate);
53361 return this.el.getUpdateManager();
53364 _handleRefresh : function(url, params, loadOnce){
53365 if(!loadOnce || !this.loaded){
53366 var updater = this.el.getUpdateManager();
53367 updater.update(url, params, this._setLoaded.createDelegate(this));
53371 _setLoaded : function(){
53372 this.loaded = true;
53376 * Returns this panel's id
53379 getId : function(){
53384 * Returns this panel's element - used by regiosn to add.
53385 * @return {Roo.Element}
53387 getEl : function(){
53388 return this.wrapEl || this.el;
53391 adjustForComponents : function(width, height)
53393 //Roo.log('adjustForComponents ');
53394 if(this.resizeEl != this.el){
53395 width -= this.el.getFrameWidth('lr');
53396 height -= this.el.getFrameWidth('tb');
53399 var te = this.toolbar.getEl();
53400 height -= te.getHeight();
53401 te.setWidth(width);
53404 var te = this.footer.getEl();
53405 Roo.log("footer:" + te.getHeight());
53407 height -= te.getHeight();
53408 te.setWidth(width);
53412 if(this.adjustments){
53413 width += this.adjustments[0];
53414 height += this.adjustments[1];
53416 return {"width": width, "height": height};
53419 setSize : function(width, height){
53420 if(this.fitToFrame && !this.ignoreResize(width, height)){
53421 if(this.fitContainer && this.resizeEl != this.el){
53422 this.el.setSize(width, height);
53424 var size = this.adjustForComponents(width, height);
53425 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53426 this.fireEvent('resize', this, size.width, size.height);
53431 * Returns this panel's title
53434 getTitle : function(){
53439 * Set this panel's title
53440 * @param {String} title
53442 setTitle : function(title){
53443 this.title = title;
53445 this.region.updatePanelTitle(this, title);
53450 * Returns true is this panel was configured to be closable
53451 * @return {Boolean}
53453 isClosable : function(){
53454 return this.closable;
53457 beforeSlide : function(){
53459 this.resizeEl.clip();
53462 afterSlide : function(){
53464 this.resizeEl.unclip();
53468 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53469 * Will fail silently if the {@link #setUrl} method has not been called.
53470 * This does not activate the panel, just updates its content.
53472 refresh : function(){
53473 if(this.refreshDelegate){
53474 this.loaded = false;
53475 this.refreshDelegate();
53480 * Destroys this panel
53482 destroy : function(){
53483 this.el.removeAllListeners();
53484 var tempEl = document.createElement("span");
53485 tempEl.appendChild(this.el.dom);
53486 tempEl.innerHTML = "";
53492 * form - if the content panel contains a form - this is a reference to it.
53493 * @type {Roo.form.Form}
53497 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53498 * This contains a reference to it.
53504 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53514 * @param {Object} cfg Xtype definition of item to add.
53517 addxtype : function(cfg) {
53519 if (cfg.xtype.match(/^Form$/)) {
53522 //if (this.footer) {
53523 // el = this.footer.container.insertSibling(false, 'before');
53525 el = this.el.createChild();
53528 this.form = new Roo.form.Form(cfg);
53531 if ( this.form.allItems.length) {
53532 this.form.render(el.dom);
53536 // should only have one of theses..
53537 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53538 // views.. should not be just added - used named prop 'view''
53540 cfg.el = this.el.appendChild(document.createElement("div"));
53543 var ret = new Roo.factory(cfg);
53545 ret.render && ret.render(false, ''); // render blank..
53554 * @class Roo.GridPanel
53555 * @extends Roo.ContentPanel
53557 * Create a new GridPanel.
53558 * @param {Roo.grid.Grid} grid The grid for this panel
53559 * @param {String/Object} config A string to set only the panel's title, or a config object
53561 Roo.GridPanel = function(grid, config){
53564 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53565 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53567 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53569 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53572 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53574 // xtype created footer. - not sure if will work as we normally have to render first..
53575 if (this.footer && !this.footer.el && this.footer.xtype) {
53577 this.footer.container = this.grid.getView().getFooterPanel(true);
53578 this.footer.dataSource = this.grid.dataSource;
53579 this.footer = Roo.factory(this.footer, Roo);
53583 grid.monitorWindowResize = false; // turn off autosizing
53584 grid.autoHeight = false;
53585 grid.autoWidth = false;
53587 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53590 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53591 getId : function(){
53592 return this.grid.id;
53596 * Returns the grid for this panel
53597 * @return {Roo.grid.Grid}
53599 getGrid : function(){
53603 setSize : function(width, height){
53604 if(!this.ignoreResize(width, height)){
53605 var grid = this.grid;
53606 var size = this.adjustForComponents(width, height);
53607 grid.getGridEl().setSize(size.width, size.height);
53612 beforeSlide : function(){
53613 this.grid.getView().scroller.clip();
53616 afterSlide : function(){
53617 this.grid.getView().scroller.unclip();
53620 destroy : function(){
53621 this.grid.destroy();
53623 Roo.GridPanel.superclass.destroy.call(this);
53629 * @class Roo.NestedLayoutPanel
53630 * @extends Roo.ContentPanel
53632 * Create a new NestedLayoutPanel.
53635 * @param {Roo.BorderLayout} layout The layout for this panel
53636 * @param {String/Object} config A string to set only the title or a config object
53638 Roo.NestedLayoutPanel = function(layout, config)
53640 // construct with only one argument..
53641 /* FIXME - implement nicer consturctors
53642 if (layout.layout) {
53644 layout = config.layout;
53645 delete config.layout;
53647 if (layout.xtype && !layout.getEl) {
53648 // then layout needs constructing..
53649 layout = Roo.factory(layout, Roo);
53654 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53656 layout.monitorWindowResize = false; // turn off autosizing
53657 this.layout = layout;
53658 this.layout.getEl().addClass("x-layout-nested-layout");
53665 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53667 setSize : function(width, height){
53668 if(!this.ignoreResize(width, height)){
53669 var size = this.adjustForComponents(width, height);
53670 var el = this.layout.getEl();
53671 el.setSize(size.width, size.height);
53672 var touch = el.dom.offsetWidth;
53673 this.layout.layout();
53674 // ie requires a double layout on the first pass
53675 if(Roo.isIE && !this.initialized){
53676 this.initialized = true;
53677 this.layout.layout();
53682 // activate all subpanels if not currently active..
53684 setActiveState : function(active){
53685 this.active = active;
53687 this.fireEvent("deactivate", this);
53691 this.fireEvent("activate", this);
53692 // not sure if this should happen before or after..
53693 if (!this.layout) {
53694 return; // should not happen..
53697 for (var r in this.layout.regions) {
53698 reg = this.layout.getRegion(r);
53699 if (reg.getActivePanel()) {
53700 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53701 reg.setActivePanel(reg.getActivePanel());
53704 if (!reg.panels.length) {
53707 reg.showPanel(reg.getPanel(0));
53716 * Returns the nested BorderLayout for this panel
53717 * @return {Roo.BorderLayout}
53719 getLayout : function(){
53720 return this.layout;
53724 * Adds a xtype elements to the layout of the nested panel
53728 xtype : 'ContentPanel',
53735 xtype : 'NestedLayoutPanel',
53741 items : [ ... list of content panels or nested layout panels.. ]
53745 * @param {Object} cfg Xtype definition of item to add.
53747 addxtype : function(cfg) {
53748 return this.layout.addxtype(cfg);
53753 Roo.ScrollPanel = function(el, config, content){
53754 config = config || {};
53755 config.fitToFrame = true;
53756 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53758 this.el.dom.style.overflow = "hidden";
53759 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53760 this.el.removeClass("x-layout-inactive-content");
53761 this.el.on("mousewheel", this.onWheel, this);
53763 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53764 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53765 up.unselectable(); down.unselectable();
53766 up.on("click", this.scrollUp, this);
53767 down.on("click", this.scrollDown, this);
53768 up.addClassOnOver("x-scroller-btn-over");
53769 down.addClassOnOver("x-scroller-btn-over");
53770 up.addClassOnClick("x-scroller-btn-click");
53771 down.addClassOnClick("x-scroller-btn-click");
53772 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53774 this.resizeEl = this.el;
53775 this.el = wrap; this.up = up; this.down = down;
53778 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53780 wheelIncrement : 5,
53781 scrollUp : function(){
53782 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53785 scrollDown : function(){
53786 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53789 afterScroll : function(){
53790 var el = this.resizeEl;
53791 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53792 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53793 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53796 setSize : function(){
53797 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53798 this.afterScroll();
53801 onWheel : function(e){
53802 var d = e.getWheelDelta();
53803 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53804 this.afterScroll();
53808 setContent : function(content, loadScripts){
53809 this.resizeEl.update(content, loadScripts);
53823 * @class Roo.TreePanel
53824 * @extends Roo.ContentPanel
53826 * Create a new TreePanel. - defaults to fit/scoll contents.
53827 * @param {String/Object} config A string to set only the panel's title, or a config object
53828 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53830 Roo.TreePanel = function(config){
53831 var el = config.el;
53832 var tree = config.tree;
53833 delete config.tree;
53834 delete config.el; // hopefull!
53836 // wrapper for IE7 strict & safari scroll issue
53838 var treeEl = el.createChild();
53839 config.resizeEl = treeEl;
53843 Roo.TreePanel.superclass.constructor.call(this, el, config);
53846 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53847 //console.log(tree);
53848 this.on('activate', function()
53850 if (this.tree.rendered) {
53853 //console.log('render tree');
53854 this.tree.render();
53856 // this should not be needed.. - it's actually the 'el' that resizes?
53857 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53859 //this.on('resize', function (cp, w, h) {
53860 // this.tree.innerCt.setWidth(w);
53861 // this.tree.innerCt.setHeight(h);
53862 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53869 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53886 * Ext JS Library 1.1.1
53887 * Copyright(c) 2006-2007, Ext JS, LLC.
53889 * Originally Released Under LGPL - original licence link has changed is not relivant.
53892 * <script type="text/javascript">
53897 * @class Roo.ReaderLayout
53898 * @extends Roo.BorderLayout
53899 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53900 * center region containing two nested regions (a top one for a list view and one for item preview below),
53901 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53902 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53903 * expedites the setup of the overall layout and regions for this common application style.
53906 var reader = new Roo.ReaderLayout();
53907 var CP = Roo.ContentPanel; // shortcut for adding
53909 reader.beginUpdate();
53910 reader.add("north", new CP("north", "North"));
53911 reader.add("west", new CP("west", {title: "West"}));
53912 reader.add("east", new CP("east", {title: "East"}));
53914 reader.regions.listView.add(new CP("listView", "List"));
53915 reader.regions.preview.add(new CP("preview", "Preview"));
53916 reader.endUpdate();
53919 * Create a new ReaderLayout
53920 * @param {Object} config Configuration options
53921 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53922 * document.body if omitted)
53924 Roo.ReaderLayout = function(config, renderTo){
53925 var c = config || {size:{}};
53926 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53927 north: c.north !== false ? Roo.apply({
53931 }, c.north) : false,
53932 west: c.west !== false ? Roo.apply({
53940 margins:{left:5,right:0,bottom:5,top:5},
53941 cmargins:{left:5,right:5,bottom:5,top:5}
53942 }, c.west) : false,
53943 east: c.east !== false ? Roo.apply({
53951 margins:{left:0,right:5,bottom:5,top:5},
53952 cmargins:{left:5,right:5,bottom:5,top:5}
53953 }, c.east) : false,
53954 center: Roo.apply({
53955 tabPosition: 'top',
53959 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53963 this.el.addClass('x-reader');
53965 this.beginUpdate();
53967 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53968 south: c.preview !== false ? Roo.apply({
53975 cmargins:{top:5,left:0, right:0, bottom:0}
53976 }, c.preview) : false,
53977 center: Roo.apply({
53983 this.add('center', new Roo.NestedLayoutPanel(inner,
53984 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53988 this.regions.preview = inner.getRegion('south');
53989 this.regions.listView = inner.getRegion('center');
53992 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53994 * Ext JS Library 1.1.1
53995 * Copyright(c) 2006-2007, Ext JS, LLC.
53997 * Originally Released Under LGPL - original licence link has changed is not relivant.
54000 * <script type="text/javascript">
54004 * @class Roo.grid.Grid
54005 * @extends Roo.util.Observable
54006 * This class represents the primary interface of a component based grid control.
54007 * <br><br>Usage:<pre><code>
54008 var grid = new Roo.grid.Grid("my-container-id", {
54011 selModel: mySelectionModel,
54012 autoSizeColumns: true,
54013 monitorWindowResize: false,
54014 trackMouseOver: true
54019 * <b>Common Problems:</b><br/>
54020 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
54021 * element will correct this<br/>
54022 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
54023 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
54024 * are unpredictable.<br/>
54025 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
54026 * grid to calculate dimensions/offsets.<br/>
54028 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54029 * The container MUST have some type of size defined for the grid to fill. The container will be
54030 * automatically set to position relative if it isn't already.
54031 * @param {Object} config A config object that sets properties on this grid.
54033 Roo.grid.Grid = function(container, config){
54034 // initialize the container
54035 this.container = Roo.get(container);
54036 this.container.update("");
54037 this.container.setStyle("overflow", "hidden");
54038 this.container.addClass('x-grid-container');
54040 this.id = this.container.id;
54042 Roo.apply(this, config);
54043 // check and correct shorthanded configs
54045 this.dataSource = this.ds;
54049 this.colModel = this.cm;
54053 this.selModel = this.sm;
54057 if (this.selModel) {
54058 this.selModel = Roo.factory(this.selModel, Roo.grid);
54059 this.sm = this.selModel;
54060 this.sm.xmodule = this.xmodule || false;
54062 if (typeof(this.colModel.config) == 'undefined') {
54063 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54064 this.cm = this.colModel;
54065 this.cm.xmodule = this.xmodule || false;
54067 if (this.dataSource) {
54068 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54069 this.ds = this.dataSource;
54070 this.ds.xmodule = this.xmodule || false;
54077 this.container.setWidth(this.width);
54081 this.container.setHeight(this.height);
54088 * The raw click event for the entire grid.
54089 * @param {Roo.EventObject} e
54094 * The raw dblclick event for the entire grid.
54095 * @param {Roo.EventObject} e
54099 * @event contextmenu
54100 * The raw contextmenu event for the entire grid.
54101 * @param {Roo.EventObject} e
54103 "contextmenu" : true,
54106 * The raw mousedown event for the entire grid.
54107 * @param {Roo.EventObject} e
54109 "mousedown" : true,
54112 * The raw mouseup event for the entire grid.
54113 * @param {Roo.EventObject} e
54118 * The raw mouseover event for the entire grid.
54119 * @param {Roo.EventObject} e
54121 "mouseover" : true,
54124 * The raw mouseout event for the entire grid.
54125 * @param {Roo.EventObject} e
54130 * The raw keypress event for the entire grid.
54131 * @param {Roo.EventObject} e
54136 * The raw keydown event for the entire grid.
54137 * @param {Roo.EventObject} e
54145 * Fires when a cell is clicked
54146 * @param {Grid} this
54147 * @param {Number} rowIndex
54148 * @param {Number} columnIndex
54149 * @param {Roo.EventObject} e
54151 "cellclick" : true,
54153 * @event celldblclick
54154 * Fires when a cell is double clicked
54155 * @param {Grid} this
54156 * @param {Number} rowIndex
54157 * @param {Number} columnIndex
54158 * @param {Roo.EventObject} e
54160 "celldblclick" : true,
54163 * Fires when a row is clicked
54164 * @param {Grid} this
54165 * @param {Number} rowIndex
54166 * @param {Roo.EventObject} e
54170 * @event rowdblclick
54171 * Fires when a row is double clicked
54172 * @param {Grid} this
54173 * @param {Number} rowIndex
54174 * @param {Roo.EventObject} e
54176 "rowdblclick" : true,
54178 * @event headerclick
54179 * Fires when a header is clicked
54180 * @param {Grid} this
54181 * @param {Number} columnIndex
54182 * @param {Roo.EventObject} e
54184 "headerclick" : true,
54186 * @event headerdblclick
54187 * Fires when a header cell is double clicked
54188 * @param {Grid} this
54189 * @param {Number} columnIndex
54190 * @param {Roo.EventObject} e
54192 "headerdblclick" : true,
54194 * @event rowcontextmenu
54195 * Fires when a row is right clicked
54196 * @param {Grid} this
54197 * @param {Number} rowIndex
54198 * @param {Roo.EventObject} e
54200 "rowcontextmenu" : true,
54202 * @event cellcontextmenu
54203 * Fires when a cell is right clicked
54204 * @param {Grid} this
54205 * @param {Number} rowIndex
54206 * @param {Number} cellIndex
54207 * @param {Roo.EventObject} e
54209 "cellcontextmenu" : true,
54211 * @event headercontextmenu
54212 * Fires when a header is right clicked
54213 * @param {Grid} this
54214 * @param {Number} columnIndex
54215 * @param {Roo.EventObject} e
54217 "headercontextmenu" : true,
54219 * @event bodyscroll
54220 * Fires when the body element is scrolled
54221 * @param {Number} scrollLeft
54222 * @param {Number} scrollTop
54224 "bodyscroll" : true,
54226 * @event columnresize
54227 * Fires when the user resizes a column
54228 * @param {Number} columnIndex
54229 * @param {Number} newSize
54231 "columnresize" : true,
54233 * @event columnmove
54234 * Fires when the user moves a column
54235 * @param {Number} oldIndex
54236 * @param {Number} newIndex
54238 "columnmove" : true,
54241 * Fires when row(s) start being dragged
54242 * @param {Grid} this
54243 * @param {Roo.GridDD} dd The drag drop object
54244 * @param {event} e The raw browser event
54246 "startdrag" : true,
54249 * Fires when a drag operation is complete
54250 * @param {Grid} this
54251 * @param {Roo.GridDD} dd The drag drop object
54252 * @param {event} e The raw browser event
54257 * Fires when dragged row(s) are dropped on a valid DD target
54258 * @param {Grid} this
54259 * @param {Roo.GridDD} dd The drag drop object
54260 * @param {String} targetId The target drag drop object
54261 * @param {event} e The raw browser event
54266 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54267 * @param {Grid} this
54268 * @param {Roo.GridDD} dd The drag drop object
54269 * @param {String} targetId The target drag drop object
54270 * @param {event} e The raw browser event
54275 * Fires when the dragged row(s) first cross another DD target while being dragged
54276 * @param {Grid} this
54277 * @param {Roo.GridDD} dd The drag drop object
54278 * @param {String} targetId The target drag drop object
54279 * @param {event} e The raw browser event
54281 "dragenter" : true,
54284 * Fires when the dragged row(s) leave another DD target while being dragged
54285 * @param {Grid} this
54286 * @param {Roo.GridDD} dd The drag drop object
54287 * @param {String} targetId The target drag drop object
54288 * @param {event} e The raw browser event
54293 * Fires when a row is rendered, so you can change add a style to it.
54294 * @param {GridView} gridview The grid view
54295 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54301 * Fires when the grid is rendered
54302 * @param {Grid} grid
54307 Roo.grid.Grid.superclass.constructor.call(this);
54309 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54312 * @cfg {String} ddGroup - drag drop group.
54316 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54318 minColumnWidth : 25,
54321 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54322 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54323 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54325 autoSizeColumns : false,
54328 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54330 autoSizeHeaders : true,
54333 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54335 monitorWindowResize : true,
54338 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54339 * rows measured to get a columns size. Default is 0 (all rows).
54341 maxRowsToMeasure : 0,
54344 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54346 trackMouseOver : true,
54349 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54353 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54355 enableDragDrop : false,
54358 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54360 enableColumnMove : true,
54363 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54365 enableColumnHide : true,
54368 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54370 enableRowHeightSync : false,
54373 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54378 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54380 autoHeight : false,
54383 * @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.
54385 autoExpandColumn : false,
54388 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54391 autoExpandMin : 50,
54394 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54396 autoExpandMax : 1000,
54399 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54404 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54408 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54418 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54419 * of a fixed width. Default is false.
54422 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54425 * Called once after all setup has been completed and the grid is ready to be rendered.
54426 * @return {Roo.grid.Grid} this
54428 render : function()
54430 var c = this.container;
54431 // try to detect autoHeight/width mode
54432 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54433 this.autoHeight = true;
54435 var view = this.getView();
54438 c.on("click", this.onClick, this);
54439 c.on("dblclick", this.onDblClick, this);
54440 c.on("contextmenu", this.onContextMenu, this);
54441 c.on("keydown", this.onKeyDown, this);
54443 c.on("touchstart", this.onTouchStart, this);
54446 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54448 this.getSelectionModel().init(this);
54453 this.loadMask = new Roo.LoadMask(this.container,
54454 Roo.apply({store:this.dataSource}, this.loadMask));
54458 if (this.toolbar && this.toolbar.xtype) {
54459 this.toolbar.container = this.getView().getHeaderPanel(true);
54460 this.toolbar = new Roo.Toolbar(this.toolbar);
54462 if (this.footer && this.footer.xtype) {
54463 this.footer.dataSource = this.getDataSource();
54464 this.footer.container = this.getView().getFooterPanel(true);
54465 this.footer = Roo.factory(this.footer, Roo);
54467 if (this.dropTarget && this.dropTarget.xtype) {
54468 delete this.dropTarget.xtype;
54469 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54473 this.rendered = true;
54474 this.fireEvent('render', this);
54479 * Reconfigures the grid to use a different Store and Column Model.
54480 * The View will be bound to the new objects and refreshed.
54481 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54482 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54484 reconfigure : function(dataSource, colModel){
54486 this.loadMask.destroy();
54487 this.loadMask = new Roo.LoadMask(this.container,
54488 Roo.apply({store:dataSource}, this.loadMask));
54490 this.view.bind(dataSource, colModel);
54491 this.dataSource = dataSource;
54492 this.colModel = colModel;
54493 this.view.refresh(true);
54497 onKeyDown : function(e){
54498 this.fireEvent("keydown", e);
54502 * Destroy this grid.
54503 * @param {Boolean} removeEl True to remove the element
54505 destroy : function(removeEl, keepListeners){
54507 this.loadMask.destroy();
54509 var c = this.container;
54510 c.removeAllListeners();
54511 this.view.destroy();
54512 this.colModel.purgeListeners();
54513 if(!keepListeners){
54514 this.purgeListeners();
54517 if(removeEl === true){
54523 processEvent : function(name, e){
54524 // does this fire select???
54525 //Roo.log('grid:processEvent ' + name);
54527 if (name != 'touchstart' ) {
54528 this.fireEvent(name, e);
54531 var t = e.getTarget();
54533 var header = v.findHeaderIndex(t);
54534 if(header !== false){
54535 var ename = name == 'touchstart' ? 'click' : name;
54537 this.fireEvent("header" + ename, this, header, e);
54539 var row = v.findRowIndex(t);
54540 var cell = v.findCellIndex(t);
54541 if (name == 'touchstart') {
54542 // first touch is always a click.
54543 // hopefull this happens after selection is updated.?
54546 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54547 var cs = this.selModel.getSelectedCell();
54548 if (row == cs[0] && cell == cs[1]){
54552 if (typeof(this.selModel.getSelections) != 'undefined') {
54553 var cs = this.selModel.getSelections();
54554 var ds = this.dataSource;
54555 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54566 this.fireEvent("row" + name, this, row, e);
54567 if(cell !== false){
54568 this.fireEvent("cell" + name, this, row, cell, e);
54575 onClick : function(e){
54576 this.processEvent("click", e);
54579 onTouchStart : function(e){
54580 this.processEvent("touchstart", e);
54584 onContextMenu : function(e, t){
54585 this.processEvent("contextmenu", e);
54589 onDblClick : function(e){
54590 this.processEvent("dblclick", e);
54594 walkCells : function(row, col, step, fn, scope){
54595 var cm = this.colModel, clen = cm.getColumnCount();
54596 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54608 if(fn.call(scope || this, row, col, cm) === true){
54626 if(fn.call(scope || this, row, col, cm) === true){
54638 getSelections : function(){
54639 return this.selModel.getSelections();
54643 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54644 * but if manual update is required this method will initiate it.
54646 autoSize : function(){
54648 this.view.layout();
54649 if(this.view.adjustForScroll){
54650 this.view.adjustForScroll();
54656 * Returns the grid's underlying element.
54657 * @return {Element} The element
54659 getGridEl : function(){
54660 return this.container;
54663 // private for compatibility, overridden by editor grid
54664 stopEditing : function(){},
54667 * Returns the grid's SelectionModel.
54668 * @return {SelectionModel}
54670 getSelectionModel : function(){
54671 if(!this.selModel){
54672 this.selModel = new Roo.grid.RowSelectionModel();
54674 return this.selModel;
54678 * Returns the grid's DataSource.
54679 * @return {DataSource}
54681 getDataSource : function(){
54682 return this.dataSource;
54686 * Returns the grid's ColumnModel.
54687 * @return {ColumnModel}
54689 getColumnModel : function(){
54690 return this.colModel;
54694 * Returns the grid's GridView object.
54695 * @return {GridView}
54697 getView : function(){
54699 this.view = new Roo.grid.GridView(this.viewConfig);
54704 * Called to get grid's drag proxy text, by default returns this.ddText.
54707 getDragDropText : function(){
54708 var count = this.selModel.getCount();
54709 return String.format(this.ddText, count, count == 1 ? '' : 's');
54713 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54714 * %0 is replaced with the number of selected rows.
54717 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54719 * Ext JS Library 1.1.1
54720 * Copyright(c) 2006-2007, Ext JS, LLC.
54722 * Originally Released Under LGPL - original licence link has changed is not relivant.
54725 * <script type="text/javascript">
54728 Roo.grid.AbstractGridView = function(){
54732 "beforerowremoved" : true,
54733 "beforerowsinserted" : true,
54734 "beforerefresh" : true,
54735 "rowremoved" : true,
54736 "rowsinserted" : true,
54737 "rowupdated" : true,
54740 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54743 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54744 rowClass : "x-grid-row",
54745 cellClass : "x-grid-cell",
54746 tdClass : "x-grid-td",
54747 hdClass : "x-grid-hd",
54748 splitClass : "x-grid-hd-split",
54750 init: function(grid){
54752 var cid = this.grid.getGridEl().id;
54753 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54754 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54755 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54756 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54759 getColumnRenderers : function(){
54760 var renderers = [];
54761 var cm = this.grid.colModel;
54762 var colCount = cm.getColumnCount();
54763 for(var i = 0; i < colCount; i++){
54764 renderers[i] = cm.getRenderer(i);
54769 getColumnIds : function(){
54771 var cm = this.grid.colModel;
54772 var colCount = cm.getColumnCount();
54773 for(var i = 0; i < colCount; i++){
54774 ids[i] = cm.getColumnId(i);
54779 getDataIndexes : function(){
54780 if(!this.indexMap){
54781 this.indexMap = this.buildIndexMap();
54783 return this.indexMap.colToData;
54786 getColumnIndexByDataIndex : function(dataIndex){
54787 if(!this.indexMap){
54788 this.indexMap = this.buildIndexMap();
54790 return this.indexMap.dataToCol[dataIndex];
54794 * Set a css style for a column dynamically.
54795 * @param {Number} colIndex The index of the column
54796 * @param {String} name The css property name
54797 * @param {String} value The css value
54799 setCSSStyle : function(colIndex, name, value){
54800 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54801 Roo.util.CSS.updateRule(selector, name, value);
54804 generateRules : function(cm){
54805 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54806 Roo.util.CSS.removeStyleSheet(rulesId);
54807 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54808 var cid = cm.getColumnId(i);
54809 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54810 this.tdSelector, cid, " {\n}\n",
54811 this.hdSelector, cid, " {\n}\n",
54812 this.splitSelector, cid, " {\n}\n");
54814 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54818 * Ext JS Library 1.1.1
54819 * Copyright(c) 2006-2007, Ext JS, LLC.
54821 * Originally Released Under LGPL - original licence link has changed is not relivant.
54824 * <script type="text/javascript">
54828 // This is a support class used internally by the Grid components
54829 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54831 this.view = grid.getView();
54832 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54833 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54835 this.setHandleElId(Roo.id(hd));
54836 this.setOuterHandleElId(Roo.id(hd2));
54838 this.scroll = false;
54840 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54842 getDragData : function(e){
54843 var t = Roo.lib.Event.getTarget(e);
54844 var h = this.view.findHeaderCell(t);
54846 return {ddel: h.firstChild, header:h};
54851 onInitDrag : function(e){
54852 this.view.headersDisabled = true;
54853 var clone = this.dragData.ddel.cloneNode(true);
54854 clone.id = Roo.id();
54855 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54856 this.proxy.update(clone);
54860 afterValidDrop : function(){
54862 setTimeout(function(){
54863 v.headersDisabled = false;
54867 afterInvalidDrop : function(){
54869 setTimeout(function(){
54870 v.headersDisabled = false;
54876 * Ext JS Library 1.1.1
54877 * Copyright(c) 2006-2007, Ext JS, LLC.
54879 * Originally Released Under LGPL - original licence link has changed is not relivant.
54882 * <script type="text/javascript">
54885 // This is a support class used internally by the Grid components
54886 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54888 this.view = grid.getView();
54889 // split the proxies so they don't interfere with mouse events
54890 this.proxyTop = Roo.DomHelper.append(document.body, {
54891 cls:"col-move-top", html:" "
54893 this.proxyBottom = Roo.DomHelper.append(document.body, {
54894 cls:"col-move-bottom", html:" "
54896 this.proxyTop.hide = this.proxyBottom.hide = function(){
54897 this.setLeftTop(-100,-100);
54898 this.setStyle("visibility", "hidden");
54900 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54901 // temporarily disabled
54902 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54903 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54905 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54906 proxyOffsets : [-4, -9],
54907 fly: Roo.Element.fly,
54909 getTargetFromEvent : function(e){
54910 var t = Roo.lib.Event.getTarget(e);
54911 var cindex = this.view.findCellIndex(t);
54912 if(cindex !== false){
54913 return this.view.getHeaderCell(cindex);
54918 nextVisible : function(h){
54919 var v = this.view, cm = this.grid.colModel;
54922 if(!cm.isHidden(v.getCellIndex(h))){
54930 prevVisible : function(h){
54931 var v = this.view, cm = this.grid.colModel;
54934 if(!cm.isHidden(v.getCellIndex(h))){
54942 positionIndicator : function(h, n, e){
54943 var x = Roo.lib.Event.getPageX(e);
54944 var r = Roo.lib.Dom.getRegion(n.firstChild);
54945 var px, pt, py = r.top + this.proxyOffsets[1];
54946 if((r.right - x) <= (r.right-r.left)/2){
54947 px = r.right+this.view.borderWidth;
54953 var oldIndex = this.view.getCellIndex(h);
54954 var newIndex = this.view.getCellIndex(n);
54956 if(this.grid.colModel.isFixed(newIndex)){
54960 var locked = this.grid.colModel.isLocked(newIndex);
54965 if(oldIndex < newIndex){
54968 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54971 px += this.proxyOffsets[0];
54972 this.proxyTop.setLeftTop(px, py);
54973 this.proxyTop.show();
54974 if(!this.bottomOffset){
54975 this.bottomOffset = this.view.mainHd.getHeight();
54977 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54978 this.proxyBottom.show();
54982 onNodeEnter : function(n, dd, e, data){
54983 if(data.header != n){
54984 this.positionIndicator(data.header, n, e);
54988 onNodeOver : function(n, dd, e, data){
54989 var result = false;
54990 if(data.header != n){
54991 result = this.positionIndicator(data.header, n, e);
54994 this.proxyTop.hide();
54995 this.proxyBottom.hide();
54997 return result ? this.dropAllowed : this.dropNotAllowed;
55000 onNodeOut : function(n, dd, e, data){
55001 this.proxyTop.hide();
55002 this.proxyBottom.hide();
55005 onNodeDrop : function(n, dd, e, data){
55006 var h = data.header;
55008 var cm = this.grid.colModel;
55009 var x = Roo.lib.Event.getPageX(e);
55010 var r = Roo.lib.Dom.getRegion(n.firstChild);
55011 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
55012 var oldIndex = this.view.getCellIndex(h);
55013 var newIndex = this.view.getCellIndex(n);
55014 var locked = cm.isLocked(newIndex);
55018 if(oldIndex < newIndex){
55021 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
55024 cm.setLocked(oldIndex, locked, true);
55025 cm.moveColumn(oldIndex, newIndex);
55026 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55034 * Ext JS Library 1.1.1
55035 * Copyright(c) 2006-2007, Ext JS, LLC.
55037 * Originally Released Under LGPL - original licence link has changed is not relivant.
55040 * <script type="text/javascript">
55044 * @class Roo.grid.GridView
55045 * @extends Roo.util.Observable
55048 * @param {Object} config
55050 Roo.grid.GridView = function(config){
55051 Roo.grid.GridView.superclass.constructor.call(this);
55054 Roo.apply(this, config);
55057 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55059 unselectable : 'unselectable="on"',
55060 unselectableCls : 'x-unselectable',
55063 rowClass : "x-grid-row",
55065 cellClass : "x-grid-col",
55067 tdClass : "x-grid-td",
55069 hdClass : "x-grid-hd",
55071 splitClass : "x-grid-split",
55073 sortClasses : ["sort-asc", "sort-desc"],
55075 enableMoveAnim : false,
55079 dh : Roo.DomHelper,
55081 fly : Roo.Element.fly,
55083 css : Roo.util.CSS,
55089 scrollIncrement : 22,
55091 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55093 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55095 bind : function(ds, cm){
55097 this.ds.un("load", this.onLoad, this);
55098 this.ds.un("datachanged", this.onDataChange, this);
55099 this.ds.un("add", this.onAdd, this);
55100 this.ds.un("remove", this.onRemove, this);
55101 this.ds.un("update", this.onUpdate, this);
55102 this.ds.un("clear", this.onClear, this);
55105 ds.on("load", this.onLoad, this);
55106 ds.on("datachanged", this.onDataChange, this);
55107 ds.on("add", this.onAdd, this);
55108 ds.on("remove", this.onRemove, this);
55109 ds.on("update", this.onUpdate, this);
55110 ds.on("clear", this.onClear, this);
55115 this.cm.un("widthchange", this.onColWidthChange, this);
55116 this.cm.un("headerchange", this.onHeaderChange, this);
55117 this.cm.un("hiddenchange", this.onHiddenChange, this);
55118 this.cm.un("columnmoved", this.onColumnMove, this);
55119 this.cm.un("columnlockchange", this.onColumnLock, this);
55122 this.generateRules(cm);
55123 cm.on("widthchange", this.onColWidthChange, this);
55124 cm.on("headerchange", this.onHeaderChange, this);
55125 cm.on("hiddenchange", this.onHiddenChange, this);
55126 cm.on("columnmoved", this.onColumnMove, this);
55127 cm.on("columnlockchange", this.onColumnLock, this);
55132 init: function(grid){
55133 Roo.grid.GridView.superclass.init.call(this, grid);
55135 this.bind(grid.dataSource, grid.colModel);
55137 grid.on("headerclick", this.handleHeaderClick, this);
55139 if(grid.trackMouseOver){
55140 grid.on("mouseover", this.onRowOver, this);
55141 grid.on("mouseout", this.onRowOut, this);
55143 grid.cancelTextSelection = function(){};
55144 this.gridId = grid.id;
55146 var tpls = this.templates || {};
55149 tpls.master = new Roo.Template(
55150 '<div class="x-grid" hidefocus="true">',
55151 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55152 '<div class="x-grid-topbar"></div>',
55153 '<div class="x-grid-scroller"><div></div></div>',
55154 '<div class="x-grid-locked">',
55155 '<div class="x-grid-header">{lockedHeader}</div>',
55156 '<div class="x-grid-body">{lockedBody}</div>',
55158 '<div class="x-grid-viewport">',
55159 '<div class="x-grid-header">{header}</div>',
55160 '<div class="x-grid-body">{body}</div>',
55162 '<div class="x-grid-bottombar"></div>',
55164 '<div class="x-grid-resize-proxy"> </div>',
55167 tpls.master.disableformats = true;
55171 tpls.header = new Roo.Template(
55172 '<table border="0" cellspacing="0" cellpadding="0">',
55173 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55176 tpls.header.disableformats = true;
55178 tpls.header.compile();
55181 tpls.hcell = new Roo.Template(
55182 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55183 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55186 tpls.hcell.disableFormats = true;
55188 tpls.hcell.compile();
55191 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55192 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55193 tpls.hsplit.disableFormats = true;
55195 tpls.hsplit.compile();
55198 tpls.body = new Roo.Template(
55199 '<table border="0" cellspacing="0" cellpadding="0">',
55200 "<tbody>{rows}</tbody>",
55203 tpls.body.disableFormats = true;
55205 tpls.body.compile();
55208 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55209 tpls.row.disableFormats = true;
55211 tpls.row.compile();
55214 tpls.cell = new Roo.Template(
55215 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55216 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55217 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55220 tpls.cell.disableFormats = true;
55222 tpls.cell.compile();
55224 this.templates = tpls;
55227 // remap these for backwards compat
55228 onColWidthChange : function(){
55229 this.updateColumns.apply(this, arguments);
55231 onHeaderChange : function(){
55232 this.updateHeaders.apply(this, arguments);
55234 onHiddenChange : function(){
55235 this.handleHiddenChange.apply(this, arguments);
55237 onColumnMove : function(){
55238 this.handleColumnMove.apply(this, arguments);
55240 onColumnLock : function(){
55241 this.handleLockChange.apply(this, arguments);
55244 onDataChange : function(){
55246 this.updateHeaderSortState();
55249 onClear : function(){
55253 onUpdate : function(ds, record){
55254 this.refreshRow(record);
55257 refreshRow : function(record){
55258 var ds = this.ds, index;
55259 if(typeof record == 'number'){
55261 record = ds.getAt(index);
55263 index = ds.indexOf(record);
55265 this.insertRows(ds, index, index, true);
55266 this.onRemove(ds, record, index+1, true);
55267 this.syncRowHeights(index, index);
55269 this.fireEvent("rowupdated", this, index, record);
55272 onAdd : function(ds, records, index){
55273 this.insertRows(ds, index, index + (records.length-1));
55276 onRemove : function(ds, record, index, isUpdate){
55277 if(isUpdate !== true){
55278 this.fireEvent("beforerowremoved", this, index, record);
55280 var bt = this.getBodyTable(), lt = this.getLockedTable();
55281 if(bt.rows[index]){
55282 bt.firstChild.removeChild(bt.rows[index]);
55284 if(lt.rows[index]){
55285 lt.firstChild.removeChild(lt.rows[index]);
55287 if(isUpdate !== true){
55288 this.stripeRows(index);
55289 this.syncRowHeights(index, index);
55291 this.fireEvent("rowremoved", this, index, record);
55295 onLoad : function(){
55296 this.scrollToTop();
55300 * Scrolls the grid to the top
55302 scrollToTop : function(){
55304 this.scroller.dom.scrollTop = 0;
55310 * Gets a panel in the header of the grid that can be used for toolbars etc.
55311 * After modifying the contents of this panel a call to grid.autoSize() may be
55312 * required to register any changes in size.
55313 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55314 * @return Roo.Element
55316 getHeaderPanel : function(doShow){
55318 this.headerPanel.show();
55320 return this.headerPanel;
55324 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55325 * After modifying the contents of this panel a call to grid.autoSize() may be
55326 * required to register any changes in size.
55327 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55328 * @return Roo.Element
55330 getFooterPanel : function(doShow){
55332 this.footerPanel.show();
55334 return this.footerPanel;
55337 initElements : function(){
55338 var E = Roo.Element;
55339 var el = this.grid.getGridEl().dom.firstChild;
55340 var cs = el.childNodes;
55342 this.el = new E(el);
55344 this.focusEl = new E(el.firstChild);
55345 this.focusEl.swallowEvent("click", true);
55347 this.headerPanel = new E(cs[1]);
55348 this.headerPanel.enableDisplayMode("block");
55350 this.scroller = new E(cs[2]);
55351 this.scrollSizer = new E(this.scroller.dom.firstChild);
55353 this.lockedWrap = new E(cs[3]);
55354 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55355 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55357 this.mainWrap = new E(cs[4]);
55358 this.mainHd = new E(this.mainWrap.dom.firstChild);
55359 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55361 this.footerPanel = new E(cs[5]);
55362 this.footerPanel.enableDisplayMode("block");
55364 this.resizeProxy = new E(cs[6]);
55366 this.headerSelector = String.format(
55367 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55368 this.lockedHd.id, this.mainHd.id
55371 this.splitterSelector = String.format(
55372 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55373 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55376 idToCssName : function(s)
55378 return s.replace(/[^a-z0-9]+/ig, '-');
55381 getHeaderCell : function(index){
55382 return Roo.DomQuery.select(this.headerSelector)[index];
55385 getHeaderCellMeasure : function(index){
55386 return this.getHeaderCell(index).firstChild;
55389 getHeaderCellText : function(index){
55390 return this.getHeaderCell(index).firstChild.firstChild;
55393 getLockedTable : function(){
55394 return this.lockedBody.dom.firstChild;
55397 getBodyTable : function(){
55398 return this.mainBody.dom.firstChild;
55401 getLockedRow : function(index){
55402 return this.getLockedTable().rows[index];
55405 getRow : function(index){
55406 return this.getBodyTable().rows[index];
55409 getRowComposite : function(index){
55411 this.rowEl = new Roo.CompositeElementLite();
55413 var els = [], lrow, mrow;
55414 if(lrow = this.getLockedRow(index)){
55417 if(mrow = this.getRow(index)){
55420 this.rowEl.elements = els;
55424 * Gets the 'td' of the cell
55426 * @param {Integer} rowIndex row to select
55427 * @param {Integer} colIndex column to select
55431 getCell : function(rowIndex, colIndex){
55432 var locked = this.cm.getLockedCount();
55434 if(colIndex < locked){
55435 source = this.lockedBody.dom.firstChild;
55437 source = this.mainBody.dom.firstChild;
55438 colIndex -= locked;
55440 return source.rows[rowIndex].childNodes[colIndex];
55443 getCellText : function(rowIndex, colIndex){
55444 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55447 getCellBox : function(cell){
55448 var b = this.fly(cell).getBox();
55449 if(Roo.isOpera){ // opera fails to report the Y
55450 b.y = cell.offsetTop + this.mainBody.getY();
55455 getCellIndex : function(cell){
55456 var id = String(cell.className).match(this.cellRE);
55458 return parseInt(id[1], 10);
55463 findHeaderIndex : function(n){
55464 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55465 return r ? this.getCellIndex(r) : false;
55468 findHeaderCell : function(n){
55469 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55470 return r ? r : false;
55473 findRowIndex : function(n){
55477 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55478 return r ? r.rowIndex : false;
55481 findCellIndex : function(node){
55482 var stop = this.el.dom;
55483 while(node && node != stop){
55484 if(this.findRE.test(node.className)){
55485 return this.getCellIndex(node);
55487 node = node.parentNode;
55492 getColumnId : function(index){
55493 return this.cm.getColumnId(index);
55496 getSplitters : function()
55498 if(this.splitterSelector){
55499 return Roo.DomQuery.select(this.splitterSelector);
55505 getSplitter : function(index){
55506 return this.getSplitters()[index];
55509 onRowOver : function(e, t){
55511 if((row = this.findRowIndex(t)) !== false){
55512 this.getRowComposite(row).addClass("x-grid-row-over");
55516 onRowOut : function(e, t){
55518 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55519 this.getRowComposite(row).removeClass("x-grid-row-over");
55523 renderHeaders : function(){
55525 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55526 var cb = [], lb = [], sb = [], lsb = [], p = {};
55527 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55528 p.cellId = "x-grid-hd-0-" + i;
55529 p.splitId = "x-grid-csplit-0-" + i;
55530 p.id = cm.getColumnId(i);
55531 p.value = cm.getColumnHeader(i) || "";
55532 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55533 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55534 if(!cm.isLocked(i)){
55535 cb[cb.length] = ct.apply(p);
55536 sb[sb.length] = st.apply(p);
55538 lb[lb.length] = ct.apply(p);
55539 lsb[lsb.length] = st.apply(p);
55542 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55543 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55546 updateHeaders : function(){
55547 var html = this.renderHeaders();
55548 this.lockedHd.update(html[0]);
55549 this.mainHd.update(html[1]);
55553 * Focuses the specified row.
55554 * @param {Number} row The row index
55556 focusRow : function(row)
55558 //Roo.log('GridView.focusRow');
55559 var x = this.scroller.dom.scrollLeft;
55560 this.focusCell(row, 0, false);
55561 this.scroller.dom.scrollLeft = x;
55565 * Focuses the specified cell.
55566 * @param {Number} row The row index
55567 * @param {Number} col The column index
55568 * @param {Boolean} hscroll false to disable horizontal scrolling
55570 focusCell : function(row, col, hscroll)
55572 //Roo.log('GridView.focusCell');
55573 var el = this.ensureVisible(row, col, hscroll);
55574 this.focusEl.alignTo(el, "tl-tl");
55576 this.focusEl.focus();
55578 this.focusEl.focus.defer(1, this.focusEl);
55583 * Scrolls the specified cell into view
55584 * @param {Number} row The row index
55585 * @param {Number} col The column index
55586 * @param {Boolean} hscroll false to disable horizontal scrolling
55588 ensureVisible : function(row, col, hscroll)
55590 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55591 //return null; //disable for testing.
55592 if(typeof row != "number"){
55593 row = row.rowIndex;
55595 if(row < 0 && row >= this.ds.getCount()){
55598 col = (col !== undefined ? col : 0);
55599 var cm = this.grid.colModel;
55600 while(cm.isHidden(col)){
55604 var el = this.getCell(row, col);
55608 var c = this.scroller.dom;
55610 var ctop = parseInt(el.offsetTop, 10);
55611 var cleft = parseInt(el.offsetLeft, 10);
55612 var cbot = ctop + el.offsetHeight;
55613 var cright = cleft + el.offsetWidth;
55615 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55616 var stop = parseInt(c.scrollTop, 10);
55617 var sleft = parseInt(c.scrollLeft, 10);
55618 var sbot = stop + ch;
55619 var sright = sleft + c.clientWidth;
55621 Roo.log('GridView.ensureVisible:' +
55623 ' c.clientHeight:' + c.clientHeight +
55624 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55632 c.scrollTop = ctop;
55633 //Roo.log("set scrolltop to ctop DISABLE?");
55634 }else if(cbot > sbot){
55635 //Roo.log("set scrolltop to cbot-ch");
55636 c.scrollTop = cbot-ch;
55639 if(hscroll !== false){
55641 c.scrollLeft = cleft;
55642 }else if(cright > sright){
55643 c.scrollLeft = cright-c.clientWidth;
55650 updateColumns : function(){
55651 this.grid.stopEditing();
55652 var cm = this.grid.colModel, colIds = this.getColumnIds();
55653 //var totalWidth = cm.getTotalWidth();
55655 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55656 //if(cm.isHidden(i)) continue;
55657 var w = cm.getColumnWidth(i);
55658 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55659 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55661 this.updateSplitters();
55664 generateRules : function(cm){
55665 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55666 Roo.util.CSS.removeStyleSheet(rulesId);
55667 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55668 var cid = cm.getColumnId(i);
55670 if(cm.config[i].align){
55671 align = 'text-align:'+cm.config[i].align+';';
55674 if(cm.isHidden(i)){
55675 hidden = 'display:none;';
55677 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55679 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55680 this.hdSelector, cid, " {\n", align, width, "}\n",
55681 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55682 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55684 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55687 updateSplitters : function(){
55688 var cm = this.cm, s = this.getSplitters();
55689 if(s){ // splitters not created yet
55690 var pos = 0, locked = true;
55691 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55692 if(cm.isHidden(i)) {
55695 var w = cm.getColumnWidth(i); // make sure it's a number
55696 if(!cm.isLocked(i) && locked){
55701 s[i].style.left = (pos-this.splitOffset) + "px";
55706 handleHiddenChange : function(colModel, colIndex, hidden){
55708 this.hideColumn(colIndex);
55710 this.unhideColumn(colIndex);
55714 hideColumn : function(colIndex){
55715 var cid = this.getColumnId(colIndex);
55716 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55717 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55719 this.updateHeaders();
55721 this.updateSplitters();
55725 unhideColumn : function(colIndex){
55726 var cid = this.getColumnId(colIndex);
55727 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55728 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55731 this.updateHeaders();
55733 this.updateSplitters();
55737 insertRows : function(dm, firstRow, lastRow, isUpdate){
55738 if(firstRow == 0 && lastRow == dm.getCount()-1){
55742 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55744 var s = this.getScrollState();
55745 var markup = this.renderRows(firstRow, lastRow);
55746 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55747 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55748 this.restoreScroll(s);
55750 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55751 this.syncRowHeights(firstRow, lastRow);
55752 this.stripeRows(firstRow);
55758 bufferRows : function(markup, target, index){
55759 var before = null, trows = target.rows, tbody = target.tBodies[0];
55760 if(index < trows.length){
55761 before = trows[index];
55763 var b = document.createElement("div");
55764 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55765 var rows = b.firstChild.rows;
55766 for(var i = 0, len = rows.length; i < len; i++){
55768 tbody.insertBefore(rows[0], before);
55770 tbody.appendChild(rows[0]);
55777 deleteRows : function(dm, firstRow, lastRow){
55778 if(dm.getRowCount()<1){
55779 this.fireEvent("beforerefresh", this);
55780 this.mainBody.update("");
55781 this.lockedBody.update("");
55782 this.fireEvent("refresh", this);
55784 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55785 var bt = this.getBodyTable();
55786 var tbody = bt.firstChild;
55787 var rows = bt.rows;
55788 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55789 tbody.removeChild(rows[firstRow]);
55791 this.stripeRows(firstRow);
55792 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55796 updateRows : function(dataSource, firstRow, lastRow){
55797 var s = this.getScrollState();
55799 this.restoreScroll(s);
55802 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55806 this.updateHeaderSortState();
55809 getScrollState : function(){
55811 var sb = this.scroller.dom;
55812 return {left: sb.scrollLeft, top: sb.scrollTop};
55815 stripeRows : function(startRow){
55816 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55819 startRow = startRow || 0;
55820 var rows = this.getBodyTable().rows;
55821 var lrows = this.getLockedTable().rows;
55822 var cls = ' x-grid-row-alt ';
55823 for(var i = startRow, len = rows.length; i < len; i++){
55824 var row = rows[i], lrow = lrows[i];
55825 var isAlt = ((i+1) % 2 == 0);
55826 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55827 if(isAlt == hasAlt){
55831 row.className += " x-grid-row-alt";
55833 row.className = row.className.replace("x-grid-row-alt", "");
55836 lrow.className = row.className;
55841 restoreScroll : function(state){
55842 //Roo.log('GridView.restoreScroll');
55843 var sb = this.scroller.dom;
55844 sb.scrollLeft = state.left;
55845 sb.scrollTop = state.top;
55849 syncScroll : function(){
55850 //Roo.log('GridView.syncScroll');
55851 var sb = this.scroller.dom;
55852 var sh = this.mainHd.dom;
55853 var bs = this.mainBody.dom;
55854 var lv = this.lockedBody.dom;
55855 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55856 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55859 handleScroll : function(e){
55861 var sb = this.scroller.dom;
55862 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55866 handleWheel : function(e){
55867 var d = e.getWheelDelta();
55868 this.scroller.dom.scrollTop -= d*22;
55869 // set this here to prevent jumpy scrolling on large tables
55870 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55874 renderRows : function(startRow, endRow){
55875 // pull in all the crap needed to render rows
55876 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55877 var colCount = cm.getColumnCount();
55879 if(ds.getCount() < 1){
55883 // build a map for all the columns
55885 for(var i = 0; i < colCount; i++){
55886 var name = cm.getDataIndex(i);
55888 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55889 renderer : cm.getRenderer(i),
55890 id : cm.getColumnId(i),
55891 locked : cm.isLocked(i),
55892 has_editor : cm.isCellEditable(i)
55896 startRow = startRow || 0;
55897 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55899 // records to render
55900 var rs = ds.getRange(startRow, endRow);
55902 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55905 // As much as I hate to duplicate code, this was branched because FireFox really hates
55906 // [].join("") on strings. The performance difference was substantial enough to
55907 // branch this function
55908 doRender : Roo.isGecko ?
55909 function(cs, rs, ds, startRow, colCount, stripe){
55910 var ts = this.templates, ct = ts.cell, rt = ts.row;
55912 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55914 var hasListener = this.grid.hasListener('rowclass');
55916 for(var j = 0, len = rs.length; j < len; j++){
55917 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55918 for(var i = 0; i < colCount; i++){
55920 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55922 p.css = p.attr = "";
55923 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55924 if(p.value == undefined || p.value === "") {
55925 p.value = " ";
55928 p.css += ' x-grid-editable-cell';
55930 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55931 p.css += ' x-grid-dirty-cell';
55933 var markup = ct.apply(p);
55941 if(stripe && ((rowIndex+1) % 2 == 0)){
55942 alt.push("x-grid-row-alt")
55945 alt.push( " x-grid-dirty-row");
55948 if(this.getRowClass){
55949 alt.push(this.getRowClass(r, rowIndex));
55955 rowIndex : rowIndex,
55958 this.grid.fireEvent('rowclass', this, rowcfg);
55959 alt.push(rowcfg.rowClass);
55961 rp.alt = alt.join(" ");
55962 lbuf+= rt.apply(rp);
55964 buf+= rt.apply(rp);
55966 return [lbuf, buf];
55968 function(cs, rs, ds, startRow, colCount, stripe){
55969 var ts = this.templates, ct = ts.cell, rt = ts.row;
55971 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55972 var hasListener = this.grid.hasListener('rowclass');
55975 for(var j = 0, len = rs.length; j < len; j++){
55976 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55977 for(var i = 0; i < colCount; i++){
55979 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55981 p.css = p.attr = "";
55982 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55983 if(p.value == undefined || p.value === "") {
55984 p.value = " ";
55988 p.css += ' x-grid-editable-cell';
55990 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55991 p.css += ' x-grid-dirty-cell'
55994 var markup = ct.apply(p);
55996 cb[cb.length] = markup;
55998 lcb[lcb.length] = markup;
56002 if(stripe && ((rowIndex+1) % 2 == 0)){
56003 alt.push( "x-grid-row-alt");
56006 alt.push(" x-grid-dirty-row");
56009 if(this.getRowClass){
56010 alt.push( this.getRowClass(r, rowIndex));
56016 rowIndex : rowIndex,
56019 this.grid.fireEvent('rowclass', this, rowcfg);
56020 alt.push(rowcfg.rowClass);
56023 rp.alt = alt.join(" ");
56024 rp.cells = lcb.join("");
56025 lbuf[lbuf.length] = rt.apply(rp);
56026 rp.cells = cb.join("");
56027 buf[buf.length] = rt.apply(rp);
56029 return [lbuf.join(""), buf.join("")];
56032 renderBody : function(){
56033 var markup = this.renderRows();
56034 var bt = this.templates.body;
56035 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56039 * Refreshes the grid
56040 * @param {Boolean} headersToo
56042 refresh : function(headersToo){
56043 this.fireEvent("beforerefresh", this);
56044 this.grid.stopEditing();
56045 var result = this.renderBody();
56046 this.lockedBody.update(result[0]);
56047 this.mainBody.update(result[1]);
56048 if(headersToo === true){
56049 this.updateHeaders();
56050 this.updateColumns();
56051 this.updateSplitters();
56052 this.updateHeaderSortState();
56054 this.syncRowHeights();
56056 this.fireEvent("refresh", this);
56059 handleColumnMove : function(cm, oldIndex, newIndex){
56060 this.indexMap = null;
56061 var s = this.getScrollState();
56062 this.refresh(true);
56063 this.restoreScroll(s);
56064 this.afterMove(newIndex);
56067 afterMove : function(colIndex){
56068 if(this.enableMoveAnim && Roo.enableFx){
56069 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56071 // if multisort - fix sortOrder, and reload..
56072 if (this.grid.dataSource.multiSort) {
56073 // the we can call sort again..
56074 var dm = this.grid.dataSource;
56075 var cm = this.grid.colModel;
56077 for(var i = 0; i < cm.config.length; i++ ) {
56079 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56080 continue; // dont' bother, it's not in sort list or being set.
56083 so.push(cm.config[i].dataIndex);
56086 dm.load(dm.lastOptions);
56093 updateCell : function(dm, rowIndex, dataIndex){
56094 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56095 if(typeof colIndex == "undefined"){ // not present in grid
56098 var cm = this.grid.colModel;
56099 var cell = this.getCell(rowIndex, colIndex);
56100 var cellText = this.getCellText(rowIndex, colIndex);
56103 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56104 id : cm.getColumnId(colIndex),
56105 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56107 var renderer = cm.getRenderer(colIndex);
56108 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56109 if(typeof val == "undefined" || val === "") {
56112 cellText.innerHTML = val;
56113 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56114 this.syncRowHeights(rowIndex, rowIndex);
56117 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56119 if(this.grid.autoSizeHeaders){
56120 var h = this.getHeaderCellMeasure(colIndex);
56121 maxWidth = Math.max(maxWidth, h.scrollWidth);
56124 if(this.cm.isLocked(colIndex)){
56125 tb = this.getLockedTable();
56128 tb = this.getBodyTable();
56129 index = colIndex - this.cm.getLockedCount();
56132 var rows = tb.rows;
56133 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56134 for(var i = 0; i < stopIndex; i++){
56135 var cell = rows[i].childNodes[index].firstChild;
56136 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56139 return maxWidth + /*margin for error in IE*/ 5;
56142 * Autofit a column to its content.
56143 * @param {Number} colIndex
56144 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56146 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56147 if(this.cm.isHidden(colIndex)){
56148 return; // can't calc a hidden column
56151 var cid = this.cm.getColumnId(colIndex);
56152 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56153 if(this.grid.autoSizeHeaders){
56154 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56157 var newWidth = this.calcColumnWidth(colIndex);
56158 this.cm.setColumnWidth(colIndex,
56159 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56160 if(!suppressEvent){
56161 this.grid.fireEvent("columnresize", colIndex, newWidth);
56166 * Autofits all columns to their content and then expands to fit any extra space in the grid
56168 autoSizeColumns : function(){
56169 var cm = this.grid.colModel;
56170 var colCount = cm.getColumnCount();
56171 for(var i = 0; i < colCount; i++){
56172 this.autoSizeColumn(i, true, true);
56174 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56177 this.updateColumns();
56183 * Autofits all columns to the grid's width proportionate with their current size
56184 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56186 fitColumns : function(reserveScrollSpace){
56187 var cm = this.grid.colModel;
56188 var colCount = cm.getColumnCount();
56192 for (i = 0; i < colCount; i++){
56193 if(!cm.isHidden(i) && !cm.isFixed(i)){
56194 w = cm.getColumnWidth(i);
56200 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56201 if(reserveScrollSpace){
56204 var frac = (avail - cm.getTotalWidth())/width;
56205 while (cols.length){
56208 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56210 this.updateColumns();
56214 onRowSelect : function(rowIndex){
56215 var row = this.getRowComposite(rowIndex);
56216 row.addClass("x-grid-row-selected");
56219 onRowDeselect : function(rowIndex){
56220 var row = this.getRowComposite(rowIndex);
56221 row.removeClass("x-grid-row-selected");
56224 onCellSelect : function(row, col){
56225 var cell = this.getCell(row, col);
56227 Roo.fly(cell).addClass("x-grid-cell-selected");
56231 onCellDeselect : function(row, col){
56232 var cell = this.getCell(row, col);
56234 Roo.fly(cell).removeClass("x-grid-cell-selected");
56238 updateHeaderSortState : function(){
56240 // sort state can be single { field: xxx, direction : yyy}
56241 // or { xxx=>ASC , yyy : DESC ..... }
56244 if (!this.ds.multiSort) {
56245 var state = this.ds.getSortState();
56249 mstate[state.field] = state.direction;
56250 // FIXME... - this is not used here.. but might be elsewhere..
56251 this.sortState = state;
56254 mstate = this.ds.sortToggle;
56256 //remove existing sort classes..
56258 var sc = this.sortClasses;
56259 var hds = this.el.select(this.headerSelector).removeClass(sc);
56261 for(var f in mstate) {
56263 var sortColumn = this.cm.findColumnIndex(f);
56265 if(sortColumn != -1){
56266 var sortDir = mstate[f];
56267 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56276 handleHeaderClick : function(g, index,e){
56278 Roo.log("header click");
56281 // touch events on header are handled by context
56282 this.handleHdCtx(g,index,e);
56287 if(this.headersDisabled){
56290 var dm = g.dataSource, cm = g.colModel;
56291 if(!cm.isSortable(index)){
56296 if (dm.multiSort) {
56297 // update the sortOrder
56299 for(var i = 0; i < cm.config.length; i++ ) {
56301 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56302 continue; // dont' bother, it's not in sort list or being set.
56305 so.push(cm.config[i].dataIndex);
56311 dm.sort(cm.getDataIndex(index));
56315 destroy : function(){
56317 this.colMenu.removeAll();
56318 Roo.menu.MenuMgr.unregister(this.colMenu);
56319 this.colMenu.getEl().remove();
56320 delete this.colMenu;
56323 this.hmenu.removeAll();
56324 Roo.menu.MenuMgr.unregister(this.hmenu);
56325 this.hmenu.getEl().remove();
56328 if(this.grid.enableColumnMove){
56329 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56331 for(var dd in dds){
56332 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56333 var elid = dds[dd].dragElId;
56335 Roo.get(elid).remove();
56336 } else if(dds[dd].config.isTarget){
56337 dds[dd].proxyTop.remove();
56338 dds[dd].proxyBottom.remove();
56341 if(Roo.dd.DDM.locationCache[dd]){
56342 delete Roo.dd.DDM.locationCache[dd];
56345 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56348 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56349 this.bind(null, null);
56350 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56353 handleLockChange : function(){
56354 this.refresh(true);
56357 onDenyColumnLock : function(){
56361 onDenyColumnHide : function(){
56365 handleHdMenuClick : function(item){
56366 var index = this.hdCtxIndex;
56367 var cm = this.cm, ds = this.ds;
56370 ds.sort(cm.getDataIndex(index), "ASC");
56373 ds.sort(cm.getDataIndex(index), "DESC");
56376 var lc = cm.getLockedCount();
56377 if(cm.getColumnCount(true) <= lc+1){
56378 this.onDenyColumnLock();
56382 cm.setLocked(index, true, true);
56383 cm.moveColumn(index, lc);
56384 this.grid.fireEvent("columnmove", index, lc);
56386 cm.setLocked(index, true);
56390 var lc = cm.getLockedCount();
56391 if((lc-1) != index){
56392 cm.setLocked(index, false, true);
56393 cm.moveColumn(index, lc-1);
56394 this.grid.fireEvent("columnmove", index, lc-1);
56396 cm.setLocked(index, false);
56399 case 'wider': // used to expand cols on touch..
56401 var cw = cm.getColumnWidth(index);
56402 cw += (item.id == 'wider' ? 1 : -1) * 50;
56403 cw = Math.max(0, cw);
56404 cw = Math.min(cw,4000);
56405 cm.setColumnWidth(index, cw);
56409 index = cm.getIndexById(item.id.substr(4));
56411 if(item.checked && cm.getColumnCount(true) <= 1){
56412 this.onDenyColumnHide();
56415 cm.setHidden(index, item.checked);
56421 beforeColMenuShow : function(){
56422 var cm = this.cm, colCount = cm.getColumnCount();
56423 this.colMenu.removeAll();
56424 for(var i = 0; i < colCount; i++){
56425 this.colMenu.add(new Roo.menu.CheckItem({
56426 id: "col-"+cm.getColumnId(i),
56427 text: cm.getColumnHeader(i),
56428 checked: !cm.isHidden(i),
56434 handleHdCtx : function(g, index, e){
56436 var hd = this.getHeaderCell(index);
56437 this.hdCtxIndex = index;
56438 var ms = this.hmenu.items, cm = this.cm;
56439 ms.get("asc").setDisabled(!cm.isSortable(index));
56440 ms.get("desc").setDisabled(!cm.isSortable(index));
56441 if(this.grid.enableColLock !== false){
56442 ms.get("lock").setDisabled(cm.isLocked(index));
56443 ms.get("unlock").setDisabled(!cm.isLocked(index));
56445 this.hmenu.show(hd, "tl-bl");
56448 handleHdOver : function(e){
56449 var hd = this.findHeaderCell(e.getTarget());
56450 if(hd && !this.headersDisabled){
56451 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56452 this.fly(hd).addClass("x-grid-hd-over");
56457 handleHdOut : function(e){
56458 var hd = this.findHeaderCell(e.getTarget());
56460 this.fly(hd).removeClass("x-grid-hd-over");
56464 handleSplitDblClick : function(e, t){
56465 var i = this.getCellIndex(t);
56466 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56467 this.autoSizeColumn(i, true);
56472 render : function(){
56475 var colCount = cm.getColumnCount();
56477 if(this.grid.monitorWindowResize === true){
56478 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56480 var header = this.renderHeaders();
56481 var body = this.templates.body.apply({rows:""});
56482 var html = this.templates.master.apply({
56485 lockedHeader: header[0],
56489 //this.updateColumns();
56491 this.grid.getGridEl().dom.innerHTML = html;
56493 this.initElements();
56495 // a kludge to fix the random scolling effect in webkit
56496 this.el.on("scroll", function() {
56497 this.el.dom.scrollTop=0; // hopefully not recursive..
56500 this.scroller.on("scroll", this.handleScroll, this);
56501 this.lockedBody.on("mousewheel", this.handleWheel, this);
56502 this.mainBody.on("mousewheel", this.handleWheel, this);
56504 this.mainHd.on("mouseover", this.handleHdOver, this);
56505 this.mainHd.on("mouseout", this.handleHdOut, this);
56506 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56507 {delegate: "."+this.splitClass});
56509 this.lockedHd.on("mouseover", this.handleHdOver, this);
56510 this.lockedHd.on("mouseout", this.handleHdOut, this);
56511 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56512 {delegate: "."+this.splitClass});
56514 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56515 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56518 this.updateSplitters();
56520 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56521 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56522 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56525 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56526 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56528 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56529 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56531 if(this.grid.enableColLock !== false){
56532 this.hmenu.add('-',
56533 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56534 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56538 this.hmenu.add('-',
56539 {id:"wider", text: this.columnsWiderText},
56540 {id:"narrow", text: this.columnsNarrowText }
56546 if(this.grid.enableColumnHide !== false){
56548 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56549 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56550 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56552 this.hmenu.add('-',
56553 {id:"columns", text: this.columnsText, menu: this.colMenu}
56556 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56558 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56561 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56562 this.dd = new Roo.grid.GridDragZone(this.grid, {
56563 ddGroup : this.grid.ddGroup || 'GridDD'
56569 for(var i = 0; i < colCount; i++){
56570 if(cm.isHidden(i)){
56571 this.hideColumn(i);
56573 if(cm.config[i].align){
56574 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56575 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56579 this.updateHeaderSortState();
56581 this.beforeInitialResize();
56584 // two part rendering gives faster view to the user
56585 this.renderPhase2.defer(1, this);
56588 renderPhase2 : function(){
56589 // render the rows now
56591 if(this.grid.autoSizeColumns){
56592 this.autoSizeColumns();
56596 beforeInitialResize : function(){
56600 onColumnSplitterMoved : function(i, w){
56601 this.userResized = true;
56602 var cm = this.grid.colModel;
56603 cm.setColumnWidth(i, w, true);
56604 var cid = cm.getColumnId(i);
56605 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56606 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56607 this.updateSplitters();
56609 this.grid.fireEvent("columnresize", i, w);
56612 syncRowHeights : function(startIndex, endIndex){
56613 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56614 startIndex = startIndex || 0;
56615 var mrows = this.getBodyTable().rows;
56616 var lrows = this.getLockedTable().rows;
56617 var len = mrows.length-1;
56618 endIndex = Math.min(endIndex || len, len);
56619 for(var i = startIndex; i <= endIndex; i++){
56620 var m = mrows[i], l = lrows[i];
56621 var h = Math.max(m.offsetHeight, l.offsetHeight);
56622 m.style.height = l.style.height = h + "px";
56627 layout : function(initialRender, is2ndPass){
56629 var auto = g.autoHeight;
56630 var scrollOffset = 16;
56631 var c = g.getGridEl(), cm = this.cm,
56632 expandCol = g.autoExpandColumn,
56634 //c.beginMeasure();
56636 if(!c.dom.offsetWidth){ // display:none?
56638 this.lockedWrap.show();
56639 this.mainWrap.show();
56644 var hasLock = this.cm.isLocked(0);
56646 var tbh = this.headerPanel.getHeight();
56647 var bbh = this.footerPanel.getHeight();
56650 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56651 var newHeight = ch + c.getBorderWidth("tb");
56653 newHeight = Math.min(g.maxHeight, newHeight);
56655 c.setHeight(newHeight);
56659 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56662 var s = this.scroller;
56664 var csize = c.getSize(true);
56666 this.el.setSize(csize.width, csize.height);
56668 this.headerPanel.setWidth(csize.width);
56669 this.footerPanel.setWidth(csize.width);
56671 var hdHeight = this.mainHd.getHeight();
56672 var vw = csize.width;
56673 var vh = csize.height - (tbh + bbh);
56677 var bt = this.getBodyTable();
56679 if(cm.getLockedCount() == cm.config.length){
56680 bt = this.getLockedTable();
56683 var ltWidth = hasLock ?
56684 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56686 var scrollHeight = bt.offsetHeight;
56687 var scrollWidth = ltWidth + bt.offsetWidth;
56688 var vscroll = false, hscroll = false;
56690 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56692 var lw = this.lockedWrap, mw = this.mainWrap;
56693 var lb = this.lockedBody, mb = this.mainBody;
56695 setTimeout(function(){
56696 var t = s.dom.offsetTop;
56697 var w = s.dom.clientWidth,
56698 h = s.dom.clientHeight;
56701 lw.setSize(ltWidth, h);
56703 mw.setLeftTop(ltWidth, t);
56704 mw.setSize(w-ltWidth, h);
56706 lb.setHeight(h-hdHeight);
56707 mb.setHeight(h-hdHeight);
56709 if(is2ndPass !== true && !gv.userResized && expandCol){
56710 // high speed resize without full column calculation
56712 var ci = cm.getIndexById(expandCol);
56714 ci = cm.findColumnIndex(expandCol);
56716 ci = Math.max(0, ci); // make sure it's got at least the first col.
56717 var expandId = cm.getColumnId(ci);
56718 var tw = cm.getTotalWidth(false);
56719 var currentWidth = cm.getColumnWidth(ci);
56720 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56721 if(currentWidth != cw){
56722 cm.setColumnWidth(ci, cw, true);
56723 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56724 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56725 gv.updateSplitters();
56726 gv.layout(false, true);
56738 onWindowResize : function(){
56739 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56745 appendFooter : function(parentEl){
56749 sortAscText : "Sort Ascending",
56750 sortDescText : "Sort Descending",
56751 lockText : "Lock Column",
56752 unlockText : "Unlock Column",
56753 columnsText : "Columns",
56755 columnsWiderText : "Wider",
56756 columnsNarrowText : "Thinner"
56760 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56761 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56762 this.proxy.el.addClass('x-grid3-col-dd');
56765 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56766 handleMouseDown : function(e){
56770 callHandleMouseDown : function(e){
56771 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56776 * Ext JS Library 1.1.1
56777 * Copyright(c) 2006-2007, Ext JS, LLC.
56779 * Originally Released Under LGPL - original licence link has changed is not relivant.
56782 * <script type="text/javascript">
56786 // This is a support class used internally by the Grid components
56787 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56789 this.view = grid.getView();
56790 this.proxy = this.view.resizeProxy;
56791 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56792 "gridSplitters" + this.grid.getGridEl().id, {
56793 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56795 this.setHandleElId(Roo.id(hd));
56796 this.setOuterHandleElId(Roo.id(hd2));
56797 this.scroll = false;
56799 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56800 fly: Roo.Element.fly,
56802 b4StartDrag : function(x, y){
56803 this.view.headersDisabled = true;
56804 this.proxy.setHeight(this.view.mainWrap.getHeight());
56805 var w = this.cm.getColumnWidth(this.cellIndex);
56806 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56807 this.resetConstraints();
56808 this.setXConstraint(minw, 1000);
56809 this.setYConstraint(0, 0);
56810 this.minX = x - minw;
56811 this.maxX = x + 1000;
56813 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56817 handleMouseDown : function(e){
56818 ev = Roo.EventObject.setEvent(e);
56819 var t = this.fly(ev.getTarget());
56820 if(t.hasClass("x-grid-split")){
56821 this.cellIndex = this.view.getCellIndex(t.dom);
56822 this.split = t.dom;
56823 this.cm = this.grid.colModel;
56824 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56825 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56830 endDrag : function(e){
56831 this.view.headersDisabled = false;
56832 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56833 var diff = endX - this.startPos;
56834 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56837 autoOffset : function(){
56838 this.setDelta(0,0);
56842 * Ext JS Library 1.1.1
56843 * Copyright(c) 2006-2007, Ext JS, LLC.
56845 * Originally Released Under LGPL - original licence link has changed is not relivant.
56848 * <script type="text/javascript">
56852 // This is a support class used internally by the Grid components
56853 Roo.grid.GridDragZone = function(grid, config){
56854 this.view = grid.getView();
56855 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56856 if(this.view.lockedBody){
56857 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56858 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56860 this.scroll = false;
56862 this.ddel = document.createElement('div');
56863 this.ddel.className = 'x-grid-dd-wrap';
56866 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56867 ddGroup : "GridDD",
56869 getDragData : function(e){
56870 var t = Roo.lib.Event.getTarget(e);
56871 var rowIndex = this.view.findRowIndex(t);
56872 var sm = this.grid.selModel;
56874 //Roo.log(rowIndex);
56876 if (sm.getSelectedCell) {
56877 // cell selection..
56878 if (!sm.getSelectedCell()) {
56881 if (rowIndex != sm.getSelectedCell()[0]) {
56887 if(rowIndex !== false){
56892 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56894 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56897 if (e.hasModifier()){
56898 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56901 Roo.log("getDragData");
56906 rowIndex: rowIndex,
56907 selections:sm.getSelections ? sm.getSelections() : (
56908 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56915 onInitDrag : function(e){
56916 var data = this.dragData;
56917 this.ddel.innerHTML = this.grid.getDragDropText();
56918 this.proxy.update(this.ddel);
56919 // fire start drag?
56922 afterRepair : function(){
56923 this.dragging = false;
56926 getRepairXY : function(e, data){
56930 onEndDrag : function(data, e){
56934 onValidDrop : function(dd, e, id){
56939 beforeInvalidDrop : function(e, id){
56944 * Ext JS Library 1.1.1
56945 * Copyright(c) 2006-2007, Ext JS, LLC.
56947 * Originally Released Under LGPL - original licence link has changed is not relivant.
56950 * <script type="text/javascript">
56955 * @class Roo.grid.ColumnModel
56956 * @extends Roo.util.Observable
56957 * This is the default implementation of a ColumnModel used by the Grid. It defines
56958 * the columns in the grid.
56961 var colModel = new Roo.grid.ColumnModel([
56962 {header: "Ticker", width: 60, sortable: true, locked: true},
56963 {header: "Company Name", width: 150, sortable: true},
56964 {header: "Market Cap.", width: 100, sortable: true},
56965 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56966 {header: "Employees", width: 100, sortable: true, resizable: false}
56971 * The config options listed for this class are options which may appear in each
56972 * individual column definition.
56973 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56975 * @param {Object} config An Array of column config objects. See this class's
56976 * config objects for details.
56978 Roo.grid.ColumnModel = function(config){
56980 * The config passed into the constructor
56982 this.config = config;
56985 // if no id, create one
56986 // if the column does not have a dataIndex mapping,
56987 // map it to the order it is in the config
56988 for(var i = 0, len = config.length; i < len; i++){
56990 if(typeof c.dataIndex == "undefined"){
56993 if(typeof c.renderer == "string"){
56994 c.renderer = Roo.util.Format[c.renderer];
56996 if(typeof c.id == "undefined"){
56999 if(c.editor && c.editor.xtype){
57000 c.editor = Roo.factory(c.editor, Roo.grid);
57002 if(c.editor && c.editor.isFormField){
57003 c.editor = new Roo.grid.GridEditor(c.editor);
57005 this.lookup[c.id] = c;
57009 * The width of columns which have no width specified (defaults to 100)
57012 this.defaultWidth = 100;
57015 * Default sortable of columns which have no sortable specified (defaults to false)
57018 this.defaultSortable = false;
57022 * @event widthchange
57023 * Fires when the width of a column changes.
57024 * @param {ColumnModel} this
57025 * @param {Number} columnIndex The column index
57026 * @param {Number} newWidth The new width
57028 "widthchange": true,
57030 * @event headerchange
57031 * Fires when the text of a header changes.
57032 * @param {ColumnModel} this
57033 * @param {Number} columnIndex The column index
57034 * @param {Number} newText The new header text
57036 "headerchange": true,
57038 * @event hiddenchange
57039 * Fires when a column is hidden or "unhidden".
57040 * @param {ColumnModel} this
57041 * @param {Number} columnIndex The column index
57042 * @param {Boolean} hidden true if hidden, false otherwise
57044 "hiddenchange": true,
57046 * @event columnmoved
57047 * Fires when a column is moved.
57048 * @param {ColumnModel} this
57049 * @param {Number} oldIndex
57050 * @param {Number} newIndex
57052 "columnmoved" : true,
57054 * @event columlockchange
57055 * Fires when a column's locked state is changed
57056 * @param {ColumnModel} this
57057 * @param {Number} colIndex
57058 * @param {Boolean} locked true if locked
57060 "columnlockchange" : true
57062 Roo.grid.ColumnModel.superclass.constructor.call(this);
57064 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57066 * @cfg {String} header The header text to display in the Grid view.
57069 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57070 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57071 * specified, the column's index is used as an index into the Record's data Array.
57074 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57075 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57078 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57079 * Defaults to the value of the {@link #defaultSortable} property.
57080 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57083 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57086 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57089 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57092 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57095 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57096 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57097 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57098 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57101 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57104 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57107 * @cfg {String} cursor (Optional)
57110 * @cfg {String} tooltip (Optional)
57113 * @cfg {Number} xs (Optional)
57116 * @cfg {Number} sm (Optional)
57119 * @cfg {Number} md (Optional)
57122 * @cfg {Number} lg (Optional)
57125 * Returns the id of the column at the specified index.
57126 * @param {Number} index The column index
57127 * @return {String} the id
57129 getColumnId : function(index){
57130 return this.config[index].id;
57134 * Returns the column for a specified id.
57135 * @param {String} id The column id
57136 * @return {Object} the column
57138 getColumnById : function(id){
57139 return this.lookup[id];
57144 * Returns the column for a specified dataIndex.
57145 * @param {String} dataIndex The column dataIndex
57146 * @return {Object|Boolean} the column or false if not found
57148 getColumnByDataIndex: function(dataIndex){
57149 var index = this.findColumnIndex(dataIndex);
57150 return index > -1 ? this.config[index] : false;
57154 * Returns the index for a specified column id.
57155 * @param {String} id The column id
57156 * @return {Number} the index, or -1 if not found
57158 getIndexById : function(id){
57159 for(var i = 0, len = this.config.length; i < len; i++){
57160 if(this.config[i].id == id){
57168 * Returns the index for a specified column dataIndex.
57169 * @param {String} dataIndex The column dataIndex
57170 * @return {Number} the index, or -1 if not found
57173 findColumnIndex : function(dataIndex){
57174 for(var i = 0, len = this.config.length; i < len; i++){
57175 if(this.config[i].dataIndex == dataIndex){
57183 moveColumn : function(oldIndex, newIndex){
57184 var c = this.config[oldIndex];
57185 this.config.splice(oldIndex, 1);
57186 this.config.splice(newIndex, 0, c);
57187 this.dataMap = null;
57188 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57191 isLocked : function(colIndex){
57192 return this.config[colIndex].locked === true;
57195 setLocked : function(colIndex, value, suppressEvent){
57196 if(this.isLocked(colIndex) == value){
57199 this.config[colIndex].locked = value;
57200 if(!suppressEvent){
57201 this.fireEvent("columnlockchange", this, colIndex, value);
57205 getTotalLockedWidth : function(){
57206 var totalWidth = 0;
57207 for(var i = 0; i < this.config.length; i++){
57208 if(this.isLocked(i) && !this.isHidden(i)){
57209 this.totalWidth += this.getColumnWidth(i);
57215 getLockedCount : function(){
57216 for(var i = 0, len = this.config.length; i < len; i++){
57217 if(!this.isLocked(i)){
57222 return this.config.length;
57226 * Returns the number of columns.
57229 getColumnCount : function(visibleOnly){
57230 if(visibleOnly === true){
57232 for(var i = 0, len = this.config.length; i < len; i++){
57233 if(!this.isHidden(i)){
57239 return this.config.length;
57243 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57244 * @param {Function} fn
57245 * @param {Object} scope (optional)
57246 * @return {Array} result
57248 getColumnsBy : function(fn, scope){
57250 for(var i = 0, len = this.config.length; i < len; i++){
57251 var c = this.config[i];
57252 if(fn.call(scope||this, c, i) === true){
57260 * Returns true if the specified column is sortable.
57261 * @param {Number} col The column index
57262 * @return {Boolean}
57264 isSortable : function(col){
57265 if(typeof this.config[col].sortable == "undefined"){
57266 return this.defaultSortable;
57268 return this.config[col].sortable;
57272 * Returns the rendering (formatting) function defined for the column.
57273 * @param {Number} col The column index.
57274 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57276 getRenderer : function(col){
57277 if(!this.config[col].renderer){
57278 return Roo.grid.ColumnModel.defaultRenderer;
57280 return this.config[col].renderer;
57284 * Sets the rendering (formatting) function for a column.
57285 * @param {Number} col The column index
57286 * @param {Function} fn The function to use to process the cell's raw data
57287 * to return HTML markup for the grid view. The render function is called with
57288 * the following parameters:<ul>
57289 * <li>Data value.</li>
57290 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57291 * <li>css A CSS style string to apply to the table cell.</li>
57292 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57293 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57294 * <li>Row index</li>
57295 * <li>Column index</li>
57296 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57298 setRenderer : function(col, fn){
57299 this.config[col].renderer = fn;
57303 * Returns the width for the specified column.
57304 * @param {Number} col The column index
57307 getColumnWidth : function(col){
57308 return this.config[col].width * 1 || this.defaultWidth;
57312 * Sets the width for a column.
57313 * @param {Number} col The column index
57314 * @param {Number} width The new width
57316 setColumnWidth : function(col, width, suppressEvent){
57317 this.config[col].width = width;
57318 this.totalWidth = null;
57319 if(!suppressEvent){
57320 this.fireEvent("widthchange", this, col, width);
57325 * Returns the total width of all columns.
57326 * @param {Boolean} includeHidden True to include hidden column widths
57329 getTotalWidth : function(includeHidden){
57330 if(!this.totalWidth){
57331 this.totalWidth = 0;
57332 for(var i = 0, len = this.config.length; i < len; i++){
57333 if(includeHidden || !this.isHidden(i)){
57334 this.totalWidth += this.getColumnWidth(i);
57338 return this.totalWidth;
57342 * Returns the header for the specified column.
57343 * @param {Number} col The column index
57346 getColumnHeader : function(col){
57347 return this.config[col].header;
57351 * Sets the header for a column.
57352 * @param {Number} col The column index
57353 * @param {String} header The new header
57355 setColumnHeader : function(col, header){
57356 this.config[col].header = header;
57357 this.fireEvent("headerchange", this, col, header);
57361 * Returns the tooltip for the specified column.
57362 * @param {Number} col The column index
57365 getColumnTooltip : function(col){
57366 return this.config[col].tooltip;
57369 * Sets the tooltip for a column.
57370 * @param {Number} col The column index
57371 * @param {String} tooltip The new tooltip
57373 setColumnTooltip : function(col, tooltip){
57374 this.config[col].tooltip = tooltip;
57378 * Returns the dataIndex for the specified column.
57379 * @param {Number} col The column index
57382 getDataIndex : function(col){
57383 return this.config[col].dataIndex;
57387 * Sets the dataIndex for a column.
57388 * @param {Number} col The column index
57389 * @param {Number} dataIndex The new dataIndex
57391 setDataIndex : function(col, dataIndex){
57392 this.config[col].dataIndex = dataIndex;
57398 * Returns true if the cell is editable.
57399 * @param {Number} colIndex The column index
57400 * @param {Number} rowIndex The row index - this is nto actually used..?
57401 * @return {Boolean}
57403 isCellEditable : function(colIndex, rowIndex){
57404 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57408 * Returns the editor defined for the cell/column.
57409 * return false or null to disable editing.
57410 * @param {Number} colIndex The column index
57411 * @param {Number} rowIndex The row index
57414 getCellEditor : function(colIndex, rowIndex){
57415 return this.config[colIndex].editor;
57419 * Sets if a column is editable.
57420 * @param {Number} col The column index
57421 * @param {Boolean} editable True if the column is editable
57423 setEditable : function(col, editable){
57424 this.config[col].editable = editable;
57429 * Returns true if the column is hidden.
57430 * @param {Number} colIndex The column index
57431 * @return {Boolean}
57433 isHidden : function(colIndex){
57434 return this.config[colIndex].hidden;
57439 * Returns true if the column width cannot be changed
57441 isFixed : function(colIndex){
57442 return this.config[colIndex].fixed;
57446 * Returns true if the column can be resized
57447 * @return {Boolean}
57449 isResizable : function(colIndex){
57450 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57453 * Sets if a column is hidden.
57454 * @param {Number} colIndex The column index
57455 * @param {Boolean} hidden True if the column is hidden
57457 setHidden : function(colIndex, hidden){
57458 this.config[colIndex].hidden = hidden;
57459 this.totalWidth = null;
57460 this.fireEvent("hiddenchange", this, colIndex, hidden);
57464 * Sets the editor for a column.
57465 * @param {Number} col The column index
57466 * @param {Object} editor The editor object
57468 setEditor : function(col, editor){
57469 this.config[col].editor = editor;
57473 Roo.grid.ColumnModel.defaultRenderer = function(value)
57475 if(typeof value == "object") {
57478 if(typeof value == "string" && value.length < 1){
57482 return String.format("{0}", value);
57485 // Alias for backwards compatibility
57486 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57489 * Ext JS Library 1.1.1
57490 * Copyright(c) 2006-2007, Ext JS, LLC.
57492 * Originally Released Under LGPL - original licence link has changed is not relivant.
57495 * <script type="text/javascript">
57499 * @class Roo.grid.AbstractSelectionModel
57500 * @extends Roo.util.Observable
57501 * Abstract base class for grid SelectionModels. It provides the interface that should be
57502 * implemented by descendant classes. This class should not be directly instantiated.
57505 Roo.grid.AbstractSelectionModel = function(){
57506 this.locked = false;
57507 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57510 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57511 /** @ignore Called by the grid automatically. Do not call directly. */
57512 init : function(grid){
57518 * Locks the selections.
57521 this.locked = true;
57525 * Unlocks the selections.
57527 unlock : function(){
57528 this.locked = false;
57532 * Returns true if the selections are locked.
57533 * @return {Boolean}
57535 isLocked : function(){
57536 return this.locked;
57540 * Ext JS Library 1.1.1
57541 * Copyright(c) 2006-2007, Ext JS, LLC.
57543 * Originally Released Under LGPL - original licence link has changed is not relivant.
57546 * <script type="text/javascript">
57549 * @extends Roo.grid.AbstractSelectionModel
57550 * @class Roo.grid.RowSelectionModel
57551 * The default SelectionModel used by {@link Roo.grid.Grid}.
57552 * It supports multiple selections and keyboard selection/navigation.
57554 * @param {Object} config
57556 Roo.grid.RowSelectionModel = function(config){
57557 Roo.apply(this, config);
57558 this.selections = new Roo.util.MixedCollection(false, function(o){
57563 this.lastActive = false;
57567 * @event selectionchange
57568 * Fires when the selection changes
57569 * @param {SelectionModel} this
57571 "selectionchange" : true,
57573 * @event afterselectionchange
57574 * Fires after the selection changes (eg. by key press or clicking)
57575 * @param {SelectionModel} this
57577 "afterselectionchange" : true,
57579 * @event beforerowselect
57580 * Fires when a row is selected being selected, return false to cancel.
57581 * @param {SelectionModel} this
57582 * @param {Number} rowIndex The selected index
57583 * @param {Boolean} keepExisting False if other selections will be cleared
57585 "beforerowselect" : true,
57588 * Fires when a row is selected.
57589 * @param {SelectionModel} this
57590 * @param {Number} rowIndex The selected index
57591 * @param {Roo.data.Record} r The record
57593 "rowselect" : true,
57595 * @event rowdeselect
57596 * Fires when a row is deselected.
57597 * @param {SelectionModel} this
57598 * @param {Number} rowIndex The selected index
57600 "rowdeselect" : true
57602 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57603 this.locked = false;
57606 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57608 * @cfg {Boolean} singleSelect
57609 * True to allow selection of only one row at a time (defaults to false)
57611 singleSelect : false,
57614 initEvents : function(){
57616 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57617 this.grid.on("mousedown", this.handleMouseDown, this);
57618 }else{ // allow click to work like normal
57619 this.grid.on("rowclick", this.handleDragableRowClick, this);
57622 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57623 "up" : function(e){
57625 this.selectPrevious(e.shiftKey);
57626 }else if(this.last !== false && this.lastActive !== false){
57627 var last = this.last;
57628 this.selectRange(this.last, this.lastActive-1);
57629 this.grid.getView().focusRow(this.lastActive);
57630 if(last !== false){
57634 this.selectFirstRow();
57636 this.fireEvent("afterselectionchange", this);
57638 "down" : function(e){
57640 this.selectNext(e.shiftKey);
57641 }else if(this.last !== false && this.lastActive !== false){
57642 var last = this.last;
57643 this.selectRange(this.last, this.lastActive+1);
57644 this.grid.getView().focusRow(this.lastActive);
57645 if(last !== false){
57649 this.selectFirstRow();
57651 this.fireEvent("afterselectionchange", this);
57656 var view = this.grid.view;
57657 view.on("refresh", this.onRefresh, this);
57658 view.on("rowupdated", this.onRowUpdated, this);
57659 view.on("rowremoved", this.onRemove, this);
57663 onRefresh : function(){
57664 var ds = this.grid.dataSource, i, v = this.grid.view;
57665 var s = this.selections;
57666 s.each(function(r){
57667 if((i = ds.indexOfId(r.id)) != -1){
57669 s.add(ds.getAt(i)); // updating the selection relate data
57677 onRemove : function(v, index, r){
57678 this.selections.remove(r);
57682 onRowUpdated : function(v, index, r){
57683 if(this.isSelected(r)){
57684 v.onRowSelect(index);
57690 * @param {Array} records The records to select
57691 * @param {Boolean} keepExisting (optional) True to keep existing selections
57693 selectRecords : function(records, keepExisting){
57695 this.clearSelections();
57697 var ds = this.grid.dataSource;
57698 for(var i = 0, len = records.length; i < len; i++){
57699 this.selectRow(ds.indexOf(records[i]), true);
57704 * Gets the number of selected rows.
57707 getCount : function(){
57708 return this.selections.length;
57712 * Selects the first row in the grid.
57714 selectFirstRow : function(){
57719 * Select the last row.
57720 * @param {Boolean} keepExisting (optional) True to keep existing selections
57722 selectLastRow : function(keepExisting){
57723 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57727 * Selects the row immediately following the last selected row.
57728 * @param {Boolean} keepExisting (optional) True to keep existing selections
57730 selectNext : function(keepExisting){
57731 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57732 this.selectRow(this.last+1, keepExisting);
57733 this.grid.getView().focusRow(this.last);
57738 * Selects the row that precedes the last selected row.
57739 * @param {Boolean} keepExisting (optional) True to keep existing selections
57741 selectPrevious : function(keepExisting){
57743 this.selectRow(this.last-1, keepExisting);
57744 this.grid.getView().focusRow(this.last);
57749 * Returns the selected records
57750 * @return {Array} Array of selected records
57752 getSelections : function(){
57753 return [].concat(this.selections.items);
57757 * Returns the first selected record.
57760 getSelected : function(){
57761 return this.selections.itemAt(0);
57766 * Clears all selections.
57768 clearSelections : function(fast){
57773 var ds = this.grid.dataSource;
57774 var s = this.selections;
57775 s.each(function(r){
57776 this.deselectRow(ds.indexOfId(r.id));
57780 this.selections.clear();
57787 * Selects all rows.
57789 selectAll : function(){
57793 this.selections.clear();
57794 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57795 this.selectRow(i, true);
57800 * Returns True if there is a selection.
57801 * @return {Boolean}
57803 hasSelection : function(){
57804 return this.selections.length > 0;
57808 * Returns True if the specified row is selected.
57809 * @param {Number/Record} record The record or index of the record to check
57810 * @return {Boolean}
57812 isSelected : function(index){
57813 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57814 return (r && this.selections.key(r.id) ? true : false);
57818 * Returns True if the specified record id is selected.
57819 * @param {String} id The id of record to check
57820 * @return {Boolean}
57822 isIdSelected : function(id){
57823 return (this.selections.key(id) ? true : false);
57827 handleMouseDown : function(e, t){
57828 var view = this.grid.getView(), rowIndex;
57829 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57832 if(e.shiftKey && this.last !== false){
57833 var last = this.last;
57834 this.selectRange(last, rowIndex, e.ctrlKey);
57835 this.last = last; // reset the last
57836 view.focusRow(rowIndex);
57838 var isSelected = this.isSelected(rowIndex);
57839 if(e.button !== 0 && isSelected){
57840 view.focusRow(rowIndex);
57841 }else if(e.ctrlKey && isSelected){
57842 this.deselectRow(rowIndex);
57843 }else if(!isSelected){
57844 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57845 view.focusRow(rowIndex);
57848 this.fireEvent("afterselectionchange", this);
57851 handleDragableRowClick : function(grid, rowIndex, e)
57853 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57854 this.selectRow(rowIndex, false);
57855 grid.view.focusRow(rowIndex);
57856 this.fireEvent("afterselectionchange", this);
57861 * Selects multiple rows.
57862 * @param {Array} rows Array of the indexes of the row to select
57863 * @param {Boolean} keepExisting (optional) True to keep existing selections
57865 selectRows : function(rows, keepExisting){
57867 this.clearSelections();
57869 for(var i = 0, len = rows.length; i < len; i++){
57870 this.selectRow(rows[i], true);
57875 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57876 * @param {Number} startRow The index of the first row in the range
57877 * @param {Number} endRow The index of the last row in the range
57878 * @param {Boolean} keepExisting (optional) True to retain existing selections
57880 selectRange : function(startRow, endRow, keepExisting){
57885 this.clearSelections();
57887 if(startRow <= endRow){
57888 for(var i = startRow; i <= endRow; i++){
57889 this.selectRow(i, true);
57892 for(var i = startRow; i >= endRow; i--){
57893 this.selectRow(i, true);
57899 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57900 * @param {Number} startRow The index of the first row in the range
57901 * @param {Number} endRow The index of the last row in the range
57903 deselectRange : function(startRow, endRow, preventViewNotify){
57907 for(var i = startRow; i <= endRow; i++){
57908 this.deselectRow(i, preventViewNotify);
57914 * @param {Number} row The index of the row to select
57915 * @param {Boolean} keepExisting (optional) True to keep existing selections
57917 selectRow : function(index, keepExisting, preventViewNotify){
57918 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57921 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57922 if(!keepExisting || this.singleSelect){
57923 this.clearSelections();
57925 var r = this.grid.dataSource.getAt(index);
57926 this.selections.add(r);
57927 this.last = this.lastActive = index;
57928 if(!preventViewNotify){
57929 this.grid.getView().onRowSelect(index);
57931 this.fireEvent("rowselect", this, index, r);
57932 this.fireEvent("selectionchange", this);
57938 * @param {Number} row The index of the row to deselect
57940 deselectRow : function(index, preventViewNotify){
57944 if(this.last == index){
57947 if(this.lastActive == index){
57948 this.lastActive = false;
57950 var r = this.grid.dataSource.getAt(index);
57951 this.selections.remove(r);
57952 if(!preventViewNotify){
57953 this.grid.getView().onRowDeselect(index);
57955 this.fireEvent("rowdeselect", this, index);
57956 this.fireEvent("selectionchange", this);
57960 restoreLast : function(){
57962 this.last = this._last;
57967 acceptsNav : function(row, col, cm){
57968 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57972 onEditorKey : function(field, e){
57973 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57978 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57980 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57982 }else if(k == e.ENTER && !e.ctrlKey){
57986 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57988 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57990 }else if(k == e.ESC){
57994 g.startEditing(newCell[0], newCell[1]);
57999 * Ext JS Library 1.1.1
58000 * Copyright(c) 2006-2007, Ext JS, LLC.
58002 * Originally Released Under LGPL - original licence link has changed is not relivant.
58005 * <script type="text/javascript">
58008 * @class Roo.grid.CellSelectionModel
58009 * @extends Roo.grid.AbstractSelectionModel
58010 * This class provides the basic implementation for cell selection in a grid.
58012 * @param {Object} config The object containing the configuration of this model.
58013 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
58015 Roo.grid.CellSelectionModel = function(config){
58016 Roo.apply(this, config);
58018 this.selection = null;
58022 * @event beforerowselect
58023 * Fires before a cell is selected.
58024 * @param {SelectionModel} this
58025 * @param {Number} rowIndex The selected row index
58026 * @param {Number} colIndex The selected cell index
58028 "beforecellselect" : true,
58030 * @event cellselect
58031 * Fires when a cell is selected.
58032 * @param {SelectionModel} this
58033 * @param {Number} rowIndex The selected row index
58034 * @param {Number} colIndex The selected cell index
58036 "cellselect" : true,
58038 * @event selectionchange
58039 * Fires when the active selection changes.
58040 * @param {SelectionModel} this
58041 * @param {Object} selection null for no selection or an object (o) with two properties
58043 <li>o.record: the record object for the row the selection is in</li>
58044 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58047 "selectionchange" : true,
58050 * Fires when the tab (or enter) was pressed on the last editable cell
58051 * You can use this to trigger add new row.
58052 * @param {SelectionModel} this
58056 * @event beforeeditnext
58057 * Fires before the next editable sell is made active
58058 * You can use this to skip to another cell or fire the tabend
58059 * if you set cell to false
58060 * @param {Object} eventdata object : { cell : [ row, col ] }
58062 "beforeeditnext" : true
58064 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58067 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58069 enter_is_tab: false,
58072 initEvents : function(){
58073 this.grid.on("mousedown", this.handleMouseDown, this);
58074 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58075 var view = this.grid.view;
58076 view.on("refresh", this.onViewChange, this);
58077 view.on("rowupdated", this.onRowUpdated, this);
58078 view.on("beforerowremoved", this.clearSelections, this);
58079 view.on("beforerowsinserted", this.clearSelections, this);
58080 if(this.grid.isEditor){
58081 this.grid.on("beforeedit", this.beforeEdit, this);
58086 beforeEdit : function(e){
58087 this.select(e.row, e.column, false, true, e.record);
58091 onRowUpdated : function(v, index, r){
58092 if(this.selection && this.selection.record == r){
58093 v.onCellSelect(index, this.selection.cell[1]);
58098 onViewChange : function(){
58099 this.clearSelections(true);
58103 * Returns the currently selected cell,.
58104 * @return {Array} The selected cell (row, column) or null if none selected.
58106 getSelectedCell : function(){
58107 return this.selection ? this.selection.cell : null;
58111 * Clears all selections.
58112 * @param {Boolean} true to prevent the gridview from being notified about the change.
58114 clearSelections : function(preventNotify){
58115 var s = this.selection;
58117 if(preventNotify !== true){
58118 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58120 this.selection = null;
58121 this.fireEvent("selectionchange", this, null);
58126 * Returns true if there is a selection.
58127 * @return {Boolean}
58129 hasSelection : function(){
58130 return this.selection ? true : false;
58134 handleMouseDown : function(e, t){
58135 var v = this.grid.getView();
58136 if(this.isLocked()){
58139 var row = v.findRowIndex(t);
58140 var cell = v.findCellIndex(t);
58141 if(row !== false && cell !== false){
58142 this.select(row, cell);
58148 * @param {Number} rowIndex
58149 * @param {Number} collIndex
58151 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58152 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58153 this.clearSelections();
58154 r = r || this.grid.dataSource.getAt(rowIndex);
58157 cell : [rowIndex, colIndex]
58159 if(!preventViewNotify){
58160 var v = this.grid.getView();
58161 v.onCellSelect(rowIndex, colIndex);
58162 if(preventFocus !== true){
58163 v.focusCell(rowIndex, colIndex);
58166 this.fireEvent("cellselect", this, rowIndex, colIndex);
58167 this.fireEvent("selectionchange", this, this.selection);
58172 isSelectable : function(rowIndex, colIndex, cm){
58173 return !cm.isHidden(colIndex);
58177 handleKeyDown : function(e){
58178 //Roo.log('Cell Sel Model handleKeyDown');
58179 if(!e.isNavKeyPress()){
58182 var g = this.grid, s = this.selection;
58185 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58187 this.select(cell[0], cell[1]);
58192 var walk = function(row, col, step){
58193 return g.walkCells(row, col, step, sm.isSelectable, sm);
58195 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58202 // handled by onEditorKey
58203 if (g.isEditor && g.editing) {
58207 newCell = walk(r, c-1, -1);
58209 newCell = walk(r, c+1, 1);
58214 newCell = walk(r+1, c, 1);
58218 newCell = walk(r-1, c, -1);
58222 newCell = walk(r, c+1, 1);
58226 newCell = walk(r, c-1, -1);
58231 if(g.isEditor && !g.editing){
58232 g.startEditing(r, c);
58241 this.select(newCell[0], newCell[1]);
58247 acceptsNav : function(row, col, cm){
58248 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58252 * @param {Number} field (not used) - as it's normally used as a listener
58253 * @param {Number} e - event - fake it by using
58255 * var e = Roo.EventObjectImpl.prototype;
58256 * e.keyCode = e.TAB
58260 onEditorKey : function(field, e){
58262 var k = e.getKey(),
58265 ed = g.activeEditor,
58267 ///Roo.log('onEditorKey' + k);
58270 if (this.enter_is_tab && k == e.ENTER) {
58276 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58278 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58284 } else if(k == e.ENTER && !e.ctrlKey){
58287 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58289 } else if(k == e.ESC){
58294 var ecall = { cell : newCell, forward : forward };
58295 this.fireEvent('beforeeditnext', ecall );
58296 newCell = ecall.cell;
58297 forward = ecall.forward;
58301 //Roo.log('next cell after edit');
58302 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58303 } else if (forward) {
58304 // tabbed past last
58305 this.fireEvent.defer(100, this, ['tabend',this]);
58310 * Ext JS Library 1.1.1
58311 * Copyright(c) 2006-2007, Ext JS, LLC.
58313 * Originally Released Under LGPL - original licence link has changed is not relivant.
58316 * <script type="text/javascript">
58320 * @class Roo.grid.EditorGrid
58321 * @extends Roo.grid.Grid
58322 * Class for creating and editable grid.
58323 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58324 * The container MUST have some type of size defined for the grid to fill. The container will be
58325 * automatically set to position relative if it isn't already.
58326 * @param {Object} dataSource The data model to bind to
58327 * @param {Object} colModel The column model with info about this grid's columns
58329 Roo.grid.EditorGrid = function(container, config){
58330 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58331 this.getGridEl().addClass("xedit-grid");
58333 if(!this.selModel){
58334 this.selModel = new Roo.grid.CellSelectionModel();
58337 this.activeEditor = null;
58341 * @event beforeedit
58342 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58343 * <ul style="padding:5px;padding-left:16px;">
58344 * <li>grid - This grid</li>
58345 * <li>record - The record being edited</li>
58346 * <li>field - The field name being edited</li>
58347 * <li>value - The value for the field being edited.</li>
58348 * <li>row - The grid row index</li>
58349 * <li>column - The grid column index</li>
58350 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58352 * @param {Object} e An edit event (see above for description)
58354 "beforeedit" : true,
58357 * Fires after a cell is edited. <br />
58358 * <ul style="padding:5px;padding-left:16px;">
58359 * <li>grid - This grid</li>
58360 * <li>record - The record being edited</li>
58361 * <li>field - The field name being edited</li>
58362 * <li>value - The value being set</li>
58363 * <li>originalValue - The original value for the field, before the edit.</li>
58364 * <li>row - The grid row index</li>
58365 * <li>column - The grid column index</li>
58367 * @param {Object} e An edit event (see above for description)
58369 "afteredit" : true,
58371 * @event validateedit
58372 * Fires after a cell is edited, but before the value is set in the record.
58373 * You can use this to modify the value being set in the field, Return false
58374 * to cancel the change. The edit event object has the following properties <br />
58375 * <ul style="padding:5px;padding-left:16px;">
58376 * <li>editor - This editor</li>
58377 * <li>grid - This grid</li>
58378 * <li>record - The record being edited</li>
58379 * <li>field - The field name being edited</li>
58380 * <li>value - The value being set</li>
58381 * <li>originalValue - The original value for the field, before the edit.</li>
58382 * <li>row - The grid row index</li>
58383 * <li>column - The grid column index</li>
58384 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58386 * @param {Object} e An edit event (see above for description)
58388 "validateedit" : true
58390 this.on("bodyscroll", this.stopEditing, this);
58391 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58394 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58396 * @cfg {Number} clicksToEdit
58397 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58404 trackMouseOver: false, // causes very odd FF errors
58406 onCellDblClick : function(g, row, col){
58407 this.startEditing(row, col);
58410 onEditComplete : function(ed, value, startValue){
58411 this.editing = false;
58412 this.activeEditor = null;
58413 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58415 var field = this.colModel.getDataIndex(ed.col);
58420 originalValue: startValue,
58427 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58430 if(String(value) !== String(startValue)){
58432 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58433 r.set(field, e.value);
58434 // if we are dealing with a combo box..
58435 // then we also set the 'name' colum to be the displayField
58436 if (ed.field.displayField && ed.field.name) {
58437 r.set(ed.field.name, ed.field.el.dom.value);
58440 delete e.cancel; //?? why!!!
58441 this.fireEvent("afteredit", e);
58444 this.fireEvent("afteredit", e); // always fire it!
58446 this.view.focusCell(ed.row, ed.col);
58450 * Starts editing the specified for the specified row/column
58451 * @param {Number} rowIndex
58452 * @param {Number} colIndex
58454 startEditing : function(row, col){
58455 this.stopEditing();
58456 if(this.colModel.isCellEditable(col, row)){
58457 this.view.ensureVisible(row, col, true);
58459 var r = this.dataSource.getAt(row);
58460 var field = this.colModel.getDataIndex(col);
58461 var cell = Roo.get(this.view.getCell(row,col));
58466 value: r.data[field],
58471 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58472 this.editing = true;
58473 var ed = this.colModel.getCellEditor(col, row);
58479 ed.render(ed.parentEl || document.body);
58485 (function(){ // complex but required for focus issues in safari, ie and opera
58489 ed.on("complete", this.onEditComplete, this, {single: true});
58490 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58491 this.activeEditor = ed;
58492 var v = r.data[field];
58493 ed.startEdit(this.view.getCell(row, col), v);
58494 // combo's with 'displayField and name set
58495 if (ed.field.displayField && ed.field.name) {
58496 ed.field.el.dom.value = r.data[ed.field.name];
58500 }).defer(50, this);
58506 * Stops any active editing
58508 stopEditing : function(){
58509 if(this.activeEditor){
58510 this.activeEditor.completeEdit();
58512 this.activeEditor = null;
58516 * Called to get grid's drag proxy text, by default returns this.ddText.
58519 getDragDropText : function(){
58520 var count = this.selModel.getSelectedCell() ? 1 : 0;
58521 return String.format(this.ddText, count, count == 1 ? '' : 's');
58526 * Ext JS Library 1.1.1
58527 * Copyright(c) 2006-2007, Ext JS, LLC.
58529 * Originally Released Under LGPL - original licence link has changed is not relivant.
58532 * <script type="text/javascript">
58535 // private - not really -- you end up using it !
58536 // This is a support class used internally by the Grid components
58539 * @class Roo.grid.GridEditor
58540 * @extends Roo.Editor
58541 * Class for creating and editable grid elements.
58542 * @param {Object} config any settings (must include field)
58544 Roo.grid.GridEditor = function(field, config){
58545 if (!config && field.field) {
58547 field = Roo.factory(config.field, Roo.form);
58549 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58550 field.monitorTab = false;
58553 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58556 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58559 alignment: "tl-tl",
58562 cls: "x-small-editor x-grid-editor",
58567 * Ext JS Library 1.1.1
58568 * Copyright(c) 2006-2007, Ext JS, LLC.
58570 * Originally Released Under LGPL - original licence link has changed is not relivant.
58573 * <script type="text/javascript">
58578 Roo.grid.PropertyRecord = Roo.data.Record.create([
58579 {name:'name',type:'string'}, 'value'
58583 Roo.grid.PropertyStore = function(grid, source){
58585 this.store = new Roo.data.Store({
58586 recordType : Roo.grid.PropertyRecord
58588 this.store.on('update', this.onUpdate, this);
58590 this.setSource(source);
58592 Roo.grid.PropertyStore.superclass.constructor.call(this);
58597 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58598 setSource : function(o){
58600 this.store.removeAll();
58603 if(this.isEditableValue(o[k])){
58604 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58607 this.store.loadRecords({records: data}, {}, true);
58610 onUpdate : function(ds, record, type){
58611 if(type == Roo.data.Record.EDIT){
58612 var v = record.data['value'];
58613 var oldValue = record.modified['value'];
58614 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58615 this.source[record.id] = v;
58617 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58624 getProperty : function(row){
58625 return this.store.getAt(row);
58628 isEditableValue: function(val){
58629 if(val && val instanceof Date){
58631 }else if(typeof val == 'object' || typeof val == 'function'){
58637 setValue : function(prop, value){
58638 this.source[prop] = value;
58639 this.store.getById(prop).set('value', value);
58642 getSource : function(){
58643 return this.source;
58647 Roo.grid.PropertyColumnModel = function(grid, store){
58650 g.PropertyColumnModel.superclass.constructor.call(this, [
58651 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58652 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58654 this.store = store;
58655 this.bselect = Roo.DomHelper.append(document.body, {
58656 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58657 {tag: 'option', value: 'true', html: 'true'},
58658 {tag: 'option', value: 'false', html: 'false'}
58661 Roo.id(this.bselect);
58664 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58665 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58666 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58667 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58668 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58670 this.renderCellDelegate = this.renderCell.createDelegate(this);
58671 this.renderPropDelegate = this.renderProp.createDelegate(this);
58674 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58678 valueText : 'Value',
58680 dateFormat : 'm/j/Y',
58683 renderDate : function(dateVal){
58684 return dateVal.dateFormat(this.dateFormat);
58687 renderBool : function(bVal){
58688 return bVal ? 'true' : 'false';
58691 isCellEditable : function(colIndex, rowIndex){
58692 return colIndex == 1;
58695 getRenderer : function(col){
58697 this.renderCellDelegate : this.renderPropDelegate;
58700 renderProp : function(v){
58701 return this.getPropertyName(v);
58704 renderCell : function(val){
58706 if(val instanceof Date){
58707 rv = this.renderDate(val);
58708 }else if(typeof val == 'boolean'){
58709 rv = this.renderBool(val);
58711 return Roo.util.Format.htmlEncode(rv);
58714 getPropertyName : function(name){
58715 var pn = this.grid.propertyNames;
58716 return pn && pn[name] ? pn[name] : name;
58719 getCellEditor : function(colIndex, rowIndex){
58720 var p = this.store.getProperty(rowIndex);
58721 var n = p.data['name'], val = p.data['value'];
58723 if(typeof(this.grid.customEditors[n]) == 'string'){
58724 return this.editors[this.grid.customEditors[n]];
58726 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58727 return this.grid.customEditors[n];
58729 if(val instanceof Date){
58730 return this.editors['date'];
58731 }else if(typeof val == 'number'){
58732 return this.editors['number'];
58733 }else if(typeof val == 'boolean'){
58734 return this.editors['boolean'];
58736 return this.editors['string'];
58742 * @class Roo.grid.PropertyGrid
58743 * @extends Roo.grid.EditorGrid
58744 * This class represents the interface of a component based property grid control.
58745 * <br><br>Usage:<pre><code>
58746 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58754 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58755 * The container MUST have some type of size defined for the grid to fill. The container will be
58756 * automatically set to position relative if it isn't already.
58757 * @param {Object} config A config object that sets properties on this grid.
58759 Roo.grid.PropertyGrid = function(container, config){
58760 config = config || {};
58761 var store = new Roo.grid.PropertyStore(this);
58762 this.store = store;
58763 var cm = new Roo.grid.PropertyColumnModel(this, store);
58764 store.store.sort('name', 'ASC');
58765 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58768 enableColLock:false,
58769 enableColumnMove:false,
58771 trackMouseOver: false,
58774 this.getGridEl().addClass('x-props-grid');
58775 this.lastEditRow = null;
58776 this.on('columnresize', this.onColumnResize, this);
58779 * @event beforepropertychange
58780 * Fires before a property changes (return false to stop?)
58781 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58782 * @param {String} id Record Id
58783 * @param {String} newval New Value
58784 * @param {String} oldval Old Value
58786 "beforepropertychange": true,
58788 * @event propertychange
58789 * Fires after a property changes
58790 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58791 * @param {String} id Record Id
58792 * @param {String} newval New Value
58793 * @param {String} oldval Old Value
58795 "propertychange": true
58797 this.customEditors = this.customEditors || {};
58799 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58802 * @cfg {Object} customEditors map of colnames=> custom editors.
58803 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58804 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58805 * false disables editing of the field.
58809 * @cfg {Object} propertyNames map of property Names to their displayed value
58812 render : function(){
58813 Roo.grid.PropertyGrid.superclass.render.call(this);
58814 this.autoSize.defer(100, this);
58817 autoSize : function(){
58818 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58820 this.view.fitColumns();
58824 onColumnResize : function(){
58825 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58829 * Sets the data for the Grid
58830 * accepts a Key => Value object of all the elements avaiable.
58831 * @param {Object} data to appear in grid.
58833 setSource : function(source){
58834 this.store.setSource(source);
58838 * Gets all the data from the grid.
58839 * @return {Object} data data stored in grid
58841 getSource : function(){
58842 return this.store.getSource();
58851 * @class Roo.grid.Calendar
58852 * @extends Roo.util.Grid
58853 * This class extends the Grid to provide a calendar widget
58854 * <br><br>Usage:<pre><code>
58855 var grid = new Roo.grid.Calendar("my-container-id", {
58858 selModel: mySelectionModel,
58859 autoSizeColumns: true,
58860 monitorWindowResize: false,
58861 trackMouseOver: true
58862 eventstore : real data store..
58868 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58869 * The container MUST have some type of size defined for the grid to fill. The container will be
58870 * automatically set to position relative if it isn't already.
58871 * @param {Object} config A config object that sets properties on this grid.
58873 Roo.grid.Calendar = function(container, config){
58874 // initialize the container
58875 this.container = Roo.get(container);
58876 this.container.update("");
58877 this.container.setStyle("overflow", "hidden");
58878 this.container.addClass('x-grid-container');
58880 this.id = this.container.id;
58882 Roo.apply(this, config);
58883 // check and correct shorthanded configs
58887 for (var r = 0;r < 6;r++) {
58890 for (var c =0;c < 7;c++) {
58894 if (this.eventStore) {
58895 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58896 this.eventStore.on('load',this.onLoad, this);
58897 this.eventStore.on('beforeload',this.clearEvents, this);
58901 this.dataSource = new Roo.data.Store({
58902 proxy: new Roo.data.MemoryProxy(rows),
58903 reader: new Roo.data.ArrayReader({}, [
58904 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58907 this.dataSource.load();
58908 this.ds = this.dataSource;
58909 this.ds.xmodule = this.xmodule || false;
58912 var cellRender = function(v,x,r)
58914 return String.format(
58915 '<div class="fc-day fc-widget-content"><div>' +
58916 '<div class="fc-event-container"></div>' +
58917 '<div class="fc-day-number">{0}</div>'+
58919 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58920 '</div></div>', v);
58925 this.colModel = new Roo.grid.ColumnModel( [
58927 xtype: 'ColumnModel',
58929 dataIndex : 'weekday0',
58931 renderer : cellRender
58934 xtype: 'ColumnModel',
58936 dataIndex : 'weekday1',
58938 renderer : cellRender
58941 xtype: 'ColumnModel',
58943 dataIndex : 'weekday2',
58944 header : 'Tuesday',
58945 renderer : cellRender
58948 xtype: 'ColumnModel',
58950 dataIndex : 'weekday3',
58951 header : 'Wednesday',
58952 renderer : cellRender
58955 xtype: 'ColumnModel',
58957 dataIndex : 'weekday4',
58958 header : 'Thursday',
58959 renderer : cellRender
58962 xtype: 'ColumnModel',
58964 dataIndex : 'weekday5',
58966 renderer : cellRender
58969 xtype: 'ColumnModel',
58971 dataIndex : 'weekday6',
58972 header : 'Saturday',
58973 renderer : cellRender
58976 this.cm = this.colModel;
58977 this.cm.xmodule = this.xmodule || false;
58981 //this.selModel = new Roo.grid.CellSelectionModel();
58982 //this.sm = this.selModel;
58983 //this.selModel.init(this);
58987 this.container.setWidth(this.width);
58991 this.container.setHeight(this.height);
58998 * The raw click event for the entire grid.
58999 * @param {Roo.EventObject} e
59004 * The raw dblclick event for the entire grid.
59005 * @param {Roo.EventObject} e
59009 * @event contextmenu
59010 * The raw contextmenu event for the entire grid.
59011 * @param {Roo.EventObject} e
59013 "contextmenu" : true,
59016 * The raw mousedown event for the entire grid.
59017 * @param {Roo.EventObject} e
59019 "mousedown" : true,
59022 * The raw mouseup event for the entire grid.
59023 * @param {Roo.EventObject} e
59028 * The raw mouseover event for the entire grid.
59029 * @param {Roo.EventObject} e
59031 "mouseover" : true,
59034 * The raw mouseout event for the entire grid.
59035 * @param {Roo.EventObject} e
59040 * The raw keypress event for the entire grid.
59041 * @param {Roo.EventObject} e
59046 * The raw keydown event for the entire grid.
59047 * @param {Roo.EventObject} e
59055 * Fires when a cell is clicked
59056 * @param {Grid} this
59057 * @param {Number} rowIndex
59058 * @param {Number} columnIndex
59059 * @param {Roo.EventObject} e
59061 "cellclick" : true,
59063 * @event celldblclick
59064 * Fires when a cell is double clicked
59065 * @param {Grid} this
59066 * @param {Number} rowIndex
59067 * @param {Number} columnIndex
59068 * @param {Roo.EventObject} e
59070 "celldblclick" : true,
59073 * Fires when a row is clicked
59074 * @param {Grid} this
59075 * @param {Number} rowIndex
59076 * @param {Roo.EventObject} e
59080 * @event rowdblclick
59081 * Fires when a row is double clicked
59082 * @param {Grid} this
59083 * @param {Number} rowIndex
59084 * @param {Roo.EventObject} e
59086 "rowdblclick" : true,
59088 * @event headerclick
59089 * Fires when a header is clicked
59090 * @param {Grid} this
59091 * @param {Number} columnIndex
59092 * @param {Roo.EventObject} e
59094 "headerclick" : true,
59096 * @event headerdblclick
59097 * Fires when a header cell is double clicked
59098 * @param {Grid} this
59099 * @param {Number} columnIndex
59100 * @param {Roo.EventObject} e
59102 "headerdblclick" : true,
59104 * @event rowcontextmenu
59105 * Fires when a row is right clicked
59106 * @param {Grid} this
59107 * @param {Number} rowIndex
59108 * @param {Roo.EventObject} e
59110 "rowcontextmenu" : true,
59112 * @event cellcontextmenu
59113 * Fires when a cell is right clicked
59114 * @param {Grid} this
59115 * @param {Number} rowIndex
59116 * @param {Number} cellIndex
59117 * @param {Roo.EventObject} e
59119 "cellcontextmenu" : true,
59121 * @event headercontextmenu
59122 * Fires when a header is right clicked
59123 * @param {Grid} this
59124 * @param {Number} columnIndex
59125 * @param {Roo.EventObject} e
59127 "headercontextmenu" : true,
59129 * @event bodyscroll
59130 * Fires when the body element is scrolled
59131 * @param {Number} scrollLeft
59132 * @param {Number} scrollTop
59134 "bodyscroll" : true,
59136 * @event columnresize
59137 * Fires when the user resizes a column
59138 * @param {Number} columnIndex
59139 * @param {Number} newSize
59141 "columnresize" : true,
59143 * @event columnmove
59144 * Fires when the user moves a column
59145 * @param {Number} oldIndex
59146 * @param {Number} newIndex
59148 "columnmove" : true,
59151 * Fires when row(s) start being dragged
59152 * @param {Grid} this
59153 * @param {Roo.GridDD} dd The drag drop object
59154 * @param {event} e The raw browser event
59156 "startdrag" : true,
59159 * Fires when a drag operation is complete
59160 * @param {Grid} this
59161 * @param {Roo.GridDD} dd The drag drop object
59162 * @param {event} e The raw browser event
59167 * Fires when dragged row(s) are dropped on a valid DD target
59168 * @param {Grid} this
59169 * @param {Roo.GridDD} dd The drag drop object
59170 * @param {String} targetId The target drag drop object
59171 * @param {event} e The raw browser event
59176 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59177 * @param {Grid} this
59178 * @param {Roo.GridDD} dd The drag drop object
59179 * @param {String} targetId The target drag drop object
59180 * @param {event} e The raw browser event
59185 * Fires when the dragged row(s) first cross another DD target while being dragged
59186 * @param {Grid} this
59187 * @param {Roo.GridDD} dd The drag drop object
59188 * @param {String} targetId The target drag drop object
59189 * @param {event} e The raw browser event
59191 "dragenter" : true,
59194 * Fires when the dragged row(s) leave another DD target while being dragged
59195 * @param {Grid} this
59196 * @param {Roo.GridDD} dd The drag drop object
59197 * @param {String} targetId The target drag drop object
59198 * @param {event} e The raw browser event
59203 * Fires when a row is rendered, so you can change add a style to it.
59204 * @param {GridView} gridview The grid view
59205 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59211 * Fires when the grid is rendered
59212 * @param {Grid} grid
59217 * Fires when a date is selected
59218 * @param {DatePicker} this
59219 * @param {Date} date The selected date
59223 * @event monthchange
59224 * Fires when the displayed month changes
59225 * @param {DatePicker} this
59226 * @param {Date} date The selected month
59228 'monthchange': true,
59230 * @event evententer
59231 * Fires when mouse over an event
59232 * @param {Calendar} this
59233 * @param {event} Event
59235 'evententer': true,
59237 * @event eventleave
59238 * Fires when the mouse leaves an
59239 * @param {Calendar} this
59242 'eventleave': true,
59244 * @event eventclick
59245 * Fires when the mouse click an
59246 * @param {Calendar} this
59249 'eventclick': true,
59251 * @event eventrender
59252 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59253 * @param {Calendar} this
59254 * @param {data} data to be modified
59256 'eventrender': true
59260 Roo.grid.Grid.superclass.constructor.call(this);
59261 this.on('render', function() {
59262 this.view.el.addClass('x-grid-cal');
59264 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59268 if (!Roo.grid.Calendar.style) {
59269 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59272 '.x-grid-cal .x-grid-col' : {
59273 height: 'auto !important',
59274 'vertical-align': 'top'
59276 '.x-grid-cal .fc-event-hori' : {
59287 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59289 * @cfg {Store} eventStore The store that loads events.
59294 activeDate : false,
59297 monitorWindowResize : false,
59300 resizeColumns : function() {
59301 var col = (this.view.el.getWidth() / 7) - 3;
59302 // loop through cols, and setWidth
59303 for(var i =0 ; i < 7 ; i++){
59304 this.cm.setColumnWidth(i, col);
59307 setDate :function(date) {
59309 Roo.log('setDate?');
59311 this.resizeColumns();
59312 var vd = this.activeDate;
59313 this.activeDate = date;
59314 // if(vd && this.el){
59315 // var t = date.getTime();
59316 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59317 // Roo.log('using add remove');
59319 // this.fireEvent('monthchange', this, date);
59321 // this.cells.removeClass("fc-state-highlight");
59322 // this.cells.each(function(c){
59323 // if(c.dateValue == t){
59324 // c.addClass("fc-state-highlight");
59325 // setTimeout(function(){
59326 // try{c.dom.firstChild.focus();}catch(e){}
59336 var days = date.getDaysInMonth();
59338 var firstOfMonth = date.getFirstDateOfMonth();
59339 var startingPos = firstOfMonth.getDay()-this.startDay;
59341 if(startingPos < this.startDay){
59345 var pm = date.add(Date.MONTH, -1);
59346 var prevStart = pm.getDaysInMonth()-startingPos;
59350 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59352 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59353 //this.cells.addClassOnOver('fc-state-hover');
59355 var cells = this.cells.elements;
59356 var textEls = this.textNodes;
59358 //Roo.each(cells, function(cell){
59359 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59362 days += startingPos;
59364 // convert everything to numbers so it's fast
59365 var day = 86400000;
59366 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59369 //Roo.log(prevStart);
59371 var today = new Date().clearTime().getTime();
59372 var sel = date.clearTime().getTime();
59373 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59374 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59375 var ddMatch = this.disabledDatesRE;
59376 var ddText = this.disabledDatesText;
59377 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59378 var ddaysText = this.disabledDaysText;
59379 var format = this.format;
59381 var setCellClass = function(cal, cell){
59383 //Roo.log('set Cell Class');
59385 var t = d.getTime();
59390 cell.dateValue = t;
59392 cell.className += " fc-today";
59393 cell.className += " fc-state-highlight";
59394 cell.title = cal.todayText;
59397 // disable highlight in other month..
59398 cell.className += " fc-state-highlight";
59403 //cell.className = " fc-state-disabled";
59404 cell.title = cal.minText;
59408 //cell.className = " fc-state-disabled";
59409 cell.title = cal.maxText;
59413 if(ddays.indexOf(d.getDay()) != -1){
59414 // cell.title = ddaysText;
59415 // cell.className = " fc-state-disabled";
59418 if(ddMatch && format){
59419 var fvalue = d.dateFormat(format);
59420 if(ddMatch.test(fvalue)){
59421 cell.title = ddText.replace("%0", fvalue);
59422 cell.className = " fc-state-disabled";
59426 if (!cell.initialClassName) {
59427 cell.initialClassName = cell.dom.className;
59430 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59435 for(; i < startingPos; i++) {
59436 cells[i].dayName = (++prevStart);
59437 Roo.log(textEls[i]);
59438 d.setDate(d.getDate()+1);
59440 //cells[i].className = "fc-past fc-other-month";
59441 setCellClass(this, cells[i]);
59446 for(; i < days; i++){
59447 intDay = i - startingPos + 1;
59448 cells[i].dayName = (intDay);
59449 d.setDate(d.getDate()+1);
59451 cells[i].className = ''; // "x-date-active";
59452 setCellClass(this, cells[i]);
59456 for(; i < 42; i++) {
59457 //textEls[i].innerHTML = (++extraDays);
59459 d.setDate(d.getDate()+1);
59460 cells[i].dayName = (++extraDays);
59461 cells[i].className = "fc-future fc-other-month";
59462 setCellClass(this, cells[i]);
59465 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59467 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59469 // this will cause all the cells to mis
59472 for (var r = 0;r < 6;r++) {
59473 for (var c =0;c < 7;c++) {
59474 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59478 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59479 for(i=0;i<cells.length;i++) {
59481 this.cells.elements[i].dayName = cells[i].dayName ;
59482 this.cells.elements[i].className = cells[i].className;
59483 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59484 this.cells.elements[i].title = cells[i].title ;
59485 this.cells.elements[i].dateValue = cells[i].dateValue ;
59491 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59492 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59494 ////if(totalRows != 6){
59495 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59496 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59499 this.fireEvent('monthchange', this, date);
59504 * Returns the grid's SelectionModel.
59505 * @return {SelectionModel}
59507 getSelectionModel : function(){
59508 if(!this.selModel){
59509 this.selModel = new Roo.grid.CellSelectionModel();
59511 return this.selModel;
59515 this.eventStore.load()
59521 findCell : function(dt) {
59522 dt = dt.clearTime().getTime();
59524 this.cells.each(function(c){
59525 //Roo.log("check " +c.dateValue + '?=' + dt);
59526 if(c.dateValue == dt){
59536 findCells : function(rec) {
59537 var s = rec.data.start_dt.clone().clearTime().getTime();
59539 var e= rec.data.end_dt.clone().clearTime().getTime();
59542 this.cells.each(function(c){
59543 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59545 if(c.dateValue > e){
59548 if(c.dateValue < s){
59557 findBestRow: function(cells)
59561 for (var i =0 ; i < cells.length;i++) {
59562 ret = Math.max(cells[i].rows || 0,ret);
59569 addItem : function(rec)
59571 // look for vertical location slot in
59572 var cells = this.findCells(rec);
59574 rec.row = this.findBestRow(cells);
59576 // work out the location.
59580 for(var i =0; i < cells.length; i++) {
59588 if (crow.start.getY() == cells[i].getY()) {
59590 crow.end = cells[i];
59606 for (var i = 0; i < cells.length;i++) {
59607 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59614 clearEvents: function() {
59616 if (!this.eventStore.getCount()) {
59619 // reset number of rows in cells.
59620 Roo.each(this.cells.elements, function(c){
59624 this.eventStore.each(function(e) {
59625 this.clearEvent(e);
59630 clearEvent : function(ev)
59633 Roo.each(ev.els, function(el) {
59634 el.un('mouseenter' ,this.onEventEnter, this);
59635 el.un('mouseleave' ,this.onEventLeave, this);
59643 renderEvent : function(ev,ctr) {
59645 ctr = this.view.el.select('.fc-event-container',true).first();
59649 this.clearEvent(ev);
59655 var cells = ev.cells;
59656 var rows = ev.rows;
59657 this.fireEvent('eventrender', this, ev);
59659 for(var i =0; i < rows.length; i++) {
59663 cls += ' fc-event-start';
59665 if ((i+1) == rows.length) {
59666 cls += ' fc-event-end';
59669 //Roo.log(ev.data);
59670 // how many rows should it span..
59671 var cg = this.eventTmpl.append(ctr,Roo.apply({
59674 }, ev.data) , true);
59677 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59678 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59679 cg.on('click', this.onEventClick, this, ev);
59683 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59684 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59687 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59688 cg.setWidth(ebox.right - sbox.x -2);
59692 renderEvents: function()
59694 // first make sure there is enough space..
59696 if (!this.eventTmpl) {
59697 this.eventTmpl = new Roo.Template(
59698 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59699 '<div class="fc-event-inner">' +
59700 '<span class="fc-event-time">{time}</span>' +
59701 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59703 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59711 this.cells.each(function(c) {
59712 //Roo.log(c.select('.fc-day-content div',true).first());
59713 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59716 var ctr = this.view.el.select('.fc-event-container',true).first();
59719 this.eventStore.each(function(ev){
59721 this.renderEvent(ev);
59725 this.view.layout();
59729 onEventEnter: function (e, el,event,d) {
59730 this.fireEvent('evententer', this, el, event);
59733 onEventLeave: function (e, el,event,d) {
59734 this.fireEvent('eventleave', this, el, event);
59737 onEventClick: function (e, el,event,d) {
59738 this.fireEvent('eventclick', this, el, event);
59741 onMonthChange: function () {
59745 onLoad: function () {
59747 //Roo.log('calendar onload');
59749 if(this.eventStore.getCount() > 0){
59753 this.eventStore.each(function(d){
59758 if (typeof(add.end_dt) == 'undefined') {
59759 Roo.log("Missing End time in calendar data: ");
59763 if (typeof(add.start_dt) == 'undefined') {
59764 Roo.log("Missing Start time in calendar data: ");
59768 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59769 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59770 add.id = add.id || d.id;
59771 add.title = add.title || '??';
59779 this.renderEvents();
59789 render : function ()
59793 if (!this.view.el.hasClass('course-timesheet')) {
59794 this.view.el.addClass('course-timesheet');
59796 if (this.tsStyle) {
59801 Roo.log(_this.grid.view.el.getWidth());
59804 this.tsStyle = Roo.util.CSS.createStyleSheet({
59805 '.course-timesheet .x-grid-row' : {
59808 '.x-grid-row td' : {
59809 'vertical-align' : 0
59811 '.course-edit-link' : {
59813 'text-overflow' : 'ellipsis',
59814 'overflow' : 'hidden',
59815 'white-space' : 'nowrap',
59816 'cursor' : 'pointer'
59821 '.de-act-sup-link' : {
59822 'color' : 'purple',
59823 'text-decoration' : 'line-through'
59827 'text-decoration' : 'line-through'
59829 '.course-timesheet .course-highlight' : {
59830 'border-top-style': 'dashed !important',
59831 'border-bottom-bottom': 'dashed !important'
59833 '.course-timesheet .course-item' : {
59834 'font-family' : 'tahoma, arial, helvetica',
59835 'font-size' : '11px',
59836 'overflow' : 'hidden',
59837 'padding-left' : '10px',
59838 'padding-right' : '10px',
59839 'padding-top' : '10px'
59847 monitorWindowResize : false,
59848 cellrenderer : function(v,x,r)
59853 xtype: 'CellSelectionModel',
59860 beforeload : function (_self, options)
59862 options.params = options.params || {};
59863 options.params._month = _this.monthField.getValue();
59864 options.params.limit = 9999;
59865 options.params['sort'] = 'when_dt';
59866 options.params['dir'] = 'ASC';
59867 this.proxy.loadResponse = this.loadResponse;
59869 //this.addColumns();
59871 load : function (_self, records, options)
59873 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59874 // if you click on the translation.. you can edit it...
59875 var el = Roo.get(this);
59876 var id = el.dom.getAttribute('data-id');
59877 var d = el.dom.getAttribute('data-date');
59878 var t = el.dom.getAttribute('data-time');
59879 //var id = this.child('span').dom.textContent;
59882 Pman.Dialog.CourseCalendar.show({
59886 productitem_active : id ? 1 : 0
59888 _this.grid.ds.load({});
59893 _this.panel.fireEvent('resize', [ '', '' ]);
59896 loadResponse : function(o, success, response){
59897 // this is overridden on before load..
59899 Roo.log("our code?");
59900 //Roo.log(success);
59901 //Roo.log(response)
59902 delete this.activeRequest;
59904 this.fireEvent("loadexception", this, o, response);
59905 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59910 result = o.reader.read(response);
59912 Roo.log("load exception?");
59913 this.fireEvent("loadexception", this, o, response, e);
59914 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59917 Roo.log("ready...");
59918 // loop through result.records;
59919 // and set this.tdate[date] = [] << array of records..
59921 Roo.each(result.records, function(r){
59923 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59924 _this.tdata[r.data.when_dt.format('j')] = [];
59926 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59929 //Roo.log(_this.tdata);
59931 result.records = [];
59932 result.totalRecords = 6;
59934 // let's generate some duumy records for the rows.
59935 //var st = _this.dateField.getValue();
59937 // work out monday..
59938 //st = st.add(Date.DAY, -1 * st.format('w'));
59940 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59942 var firstOfMonth = date.getFirstDayOfMonth();
59943 var days = date.getDaysInMonth();
59945 var firstAdded = false;
59946 for (var i = 0; i < result.totalRecords ; i++) {
59947 //var d= st.add(Date.DAY, i);
59950 for(var w = 0 ; w < 7 ; w++){
59951 if(!firstAdded && firstOfMonth != w){
59958 var dd = (d > 0 && d < 10) ? "0"+d : d;
59959 row['weekday'+w] = String.format(
59960 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59961 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59963 date.format('Y-m-')+dd
59966 if(typeof(_this.tdata[d]) != 'undefined'){
59967 Roo.each(_this.tdata[d], function(r){
59971 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59972 if(r.parent_id*1>0){
59973 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59976 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59977 deactive = 'de-act-link';
59980 row['weekday'+w] += String.format(
59981 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59983 r.product_id_name, //1
59984 r.when_dt.format('h:ia'), //2
59994 // only do this if something added..
59996 result.records.push(_this.grid.dataSource.reader.newRow(row));
60000 // push it twice. (second one with an hour..
60004 this.fireEvent("load", this, o, o.request.arg);
60005 o.request.callback.call(o.request.scope, result, o.request.arg, true);
60007 sortInfo : {field: 'when_dt', direction : 'ASC' },
60009 xtype: 'HttpProxy',
60012 url : baseURL + '/Roo/Shop_course.php'
60015 xtype: 'JsonReader',
60032 'name': 'parent_id',
60036 'name': 'product_id',
60040 'name': 'productitem_id',
60058 click : function (_self, e)
60060 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60061 sd.setMonth(sd.getMonth()-1);
60062 _this.monthField.setValue(sd.format('Y-m-d'));
60063 _this.grid.ds.load({});
60069 xtype: 'Separator',
60073 xtype: 'MonthField',
60076 render : function (_self)
60078 _this.monthField = _self;
60079 // _this.monthField.set today
60081 select : function (combo, date)
60083 _this.grid.ds.load({});
60086 value : (function() { return new Date(); })()
60089 xtype: 'Separator',
60095 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60105 click : function (_self, e)
60107 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60108 sd.setMonth(sd.getMonth()+1);
60109 _this.monthField.setValue(sd.format('Y-m-d'));
60110 _this.grid.ds.load({});
60123 * Ext JS Library 1.1.1
60124 * Copyright(c) 2006-2007, Ext JS, LLC.
60126 * Originally Released Under LGPL - original licence link has changed is not relivant.
60129 * <script type="text/javascript">
60133 * @class Roo.LoadMask
60134 * A simple utility class for generically masking elements while loading data. If the element being masked has
60135 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60136 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60137 * element's UpdateManager load indicator and will be destroyed after the initial load.
60139 * Create a new LoadMask
60140 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60141 * @param {Object} config The config object
60143 Roo.LoadMask = function(el, config){
60144 this.el = Roo.get(el);
60145 Roo.apply(this, config);
60147 this.store.on('beforeload', this.onBeforeLoad, this);
60148 this.store.on('load', this.onLoad, this);
60149 this.store.on('loadexception', this.onLoadException, this);
60150 this.removeMask = false;
60152 var um = this.el.getUpdateManager();
60153 um.showLoadIndicator = false; // disable the default indicator
60154 um.on('beforeupdate', this.onBeforeLoad, this);
60155 um.on('update', this.onLoad, this);
60156 um.on('failure', this.onLoad, this);
60157 this.removeMask = true;
60161 Roo.LoadMask.prototype = {
60163 * @cfg {Boolean} removeMask
60164 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60165 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60168 * @cfg {String} msg
60169 * The text to display in a centered loading message box (defaults to 'Loading...')
60171 msg : 'Loading...',
60173 * @cfg {String} msgCls
60174 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60176 msgCls : 'x-mask-loading',
60179 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60185 * Disables the mask to prevent it from being displayed
60187 disable : function(){
60188 this.disabled = true;
60192 * Enables the mask so that it can be displayed
60194 enable : function(){
60195 this.disabled = false;
60198 onLoadException : function()
60200 Roo.log(arguments);
60202 if (typeof(arguments[3]) != 'undefined') {
60203 Roo.MessageBox.alert("Error loading",arguments[3]);
60207 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60208 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60215 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60218 onLoad : function()
60220 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60224 onBeforeLoad : function(){
60225 if(!this.disabled){
60226 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
60231 destroy : function(){
60233 this.store.un('beforeload', this.onBeforeLoad, this);
60234 this.store.un('load', this.onLoad, this);
60235 this.store.un('loadexception', this.onLoadException, this);
60237 var um = this.el.getUpdateManager();
60238 um.un('beforeupdate', this.onBeforeLoad, this);
60239 um.un('update', this.onLoad, this);
60240 um.un('failure', this.onLoad, this);
60245 * Ext JS Library 1.1.1
60246 * Copyright(c) 2006-2007, Ext JS, LLC.
60248 * Originally Released Under LGPL - original licence link has changed is not relivant.
60251 * <script type="text/javascript">
60256 * @class Roo.XTemplate
60257 * @extends Roo.Template
60258 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60260 var t = new Roo.XTemplate(
60261 '<select name="{name}">',
60262 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60266 // then append, applying the master template values
60269 * Supported features:
60274 {a_variable} - output encoded.
60275 {a_variable.format:("Y-m-d")} - call a method on the variable
60276 {a_variable:raw} - unencoded output
60277 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60278 {a_variable:this.method_on_template(...)} - call a method on the template object.
60283 <tpl for="a_variable or condition.."></tpl>
60284 <tpl if="a_variable or condition"></tpl>
60285 <tpl exec="some javascript"></tpl>
60286 <tpl name="named_template"></tpl> (experimental)
60288 <tpl for="."></tpl> - just iterate the property..
60289 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60293 Roo.XTemplate = function()
60295 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60302 Roo.extend(Roo.XTemplate, Roo.Template, {
60305 * The various sub templates
60310 * basic tag replacing syntax
60313 * // you can fake an object call by doing this
60317 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60320 * compile the template
60322 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60325 compile: function()
60329 s = ['<tpl>', s, '</tpl>'].join('');
60331 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60332 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60333 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60334 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60335 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60340 while(true == !!(m = s.match(re))){
60341 var forMatch = m[0].match(nameRe),
60342 ifMatch = m[0].match(ifRe),
60343 execMatch = m[0].match(execRe),
60344 namedMatch = m[0].match(namedRe),
60349 name = forMatch && forMatch[1] ? forMatch[1] : '';
60352 // if - puts fn into test..
60353 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60355 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60360 // exec - calls a function... returns empty if true is returned.
60361 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60363 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60371 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60372 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60373 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60376 var uid = namedMatch ? namedMatch[1] : id;
60380 id: namedMatch ? namedMatch[1] : id,
60387 s = s.replace(m[0], '');
60389 s = s.replace(m[0], '{xtpl'+ id + '}');
60394 for(var i = tpls.length-1; i >= 0; --i){
60395 this.compileTpl(tpls[i]);
60396 this.tpls[tpls[i].id] = tpls[i];
60398 this.master = tpls[tpls.length-1];
60402 * same as applyTemplate, except it's done to one of the subTemplates
60403 * when using named templates, you can do:
60405 * var str = pl.applySubTemplate('your-name', values);
60408 * @param {Number} id of the template
60409 * @param {Object} values to apply to template
60410 * @param {Object} parent (normaly the instance of this object)
60412 applySubTemplate : function(id, values, parent)
60416 var t = this.tpls[id];
60420 if(t.test && !t.test.call(this, values, parent)){
60424 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60425 Roo.log(e.toString());
60431 if(t.exec && t.exec.call(this, values, parent)){
60435 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60436 Roo.log(e.toString());
60441 var vs = t.target ? t.target.call(this, values, parent) : values;
60442 parent = t.target ? values : parent;
60443 if(t.target && vs instanceof Array){
60445 for(var i = 0, len = vs.length; i < len; i++){
60446 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60448 return buf.join('');
60450 return t.compiled.call(this, vs, parent);
60452 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60453 Roo.log(e.toString());
60454 Roo.log(t.compiled);
60459 compileTpl : function(tpl)
60461 var fm = Roo.util.Format;
60462 var useF = this.disableFormats !== true;
60463 var sep = Roo.isGecko ? "+" : ",";
60464 var undef = function(str) {
60465 Roo.log("Property not found :" + str);
60469 var fn = function(m, name, format, args)
60471 //Roo.log(arguments);
60472 args = args ? args.replace(/\\'/g,"'") : args;
60473 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60474 if (typeof(format) == 'undefined') {
60475 format= 'htmlEncode';
60477 if (format == 'raw' ) {
60481 if(name.substr(0, 4) == 'xtpl'){
60482 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60485 // build an array of options to determine if value is undefined..
60487 // basically get 'xxxx.yyyy' then do
60488 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60489 // (function () { Roo.log("Property not found"); return ''; })() :
60494 Roo.each(name.split('.'), function(st) {
60495 lookfor += (lookfor.length ? '.': '') + st;
60496 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60499 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60502 if(format && useF){
60504 args = args ? ',' + args : "";
60506 if(format.substr(0, 5) != "this."){
60507 format = "fm." + format + '(';
60509 format = 'this.call("'+ format.substr(5) + '", ';
60513 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60517 // called with xxyx.yuu:(test,test)
60519 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60521 // raw.. - :raw modifier..
60522 return "'"+ sep + udef_st + name + ")"+sep+"'";
60526 // branched to use + in gecko and [].join() in others
60528 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60529 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60532 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60533 body.push(tpl.body.replace(/(\r\n|\n)/g,
60534 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60535 body.push("'].join('');};};");
60536 body = body.join('');
60539 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60541 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60547 applyTemplate : function(values){
60548 return this.master.compiled.call(this, values, {});
60549 //var s = this.subs;
60552 apply : function(){
60553 return this.applyTemplate.apply(this, arguments);
60558 Roo.XTemplate.from = function(el){
60559 el = Roo.getDom(el);
60560 return new Roo.XTemplate(el.value || el.innerHTML);