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 } ' +
42856 var cls = 'roo-htmleditor-body';
42858 if(this.bodyCls.length){
42859 cls += ' ' + this.bodyCls;
42862 return '<html><head>' + st +
42863 //<style type="text/css">' +
42864 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
42866 ' </head><body class="' + cls + '"></body></html>';
42870 onRender : function(ct, position)
42873 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
42874 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
42877 this.el.dom.style.border = '0 none';
42878 this.el.dom.setAttribute('tabIndex', -1);
42879 this.el.addClass('x-hidden hide');
42883 if(Roo.isIE){ // fix IE 1px bogus margin
42884 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
42888 this.frameId = Roo.id();
42892 var iframe = this.owner.wrap.createChild({
42894 cls: 'form-control', // bootstrap..
42896 name: this.frameId,
42897 frameBorder : 'no',
42898 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
42903 this.iframe = iframe.dom;
42905 this.assignDocWin();
42907 this.doc.designMode = 'on';
42910 this.doc.write(this.getDocMarkup());
42914 var task = { // must defer to wait for browser to be ready
42916 //console.log("run task?" + this.doc.readyState);
42917 this.assignDocWin();
42918 if(this.doc.body || this.doc.readyState == 'complete'){
42920 this.doc.designMode="on";
42924 Roo.TaskMgr.stop(task);
42925 this.initEditor.defer(10, this);
42932 Roo.TaskMgr.start(task);
42937 onResize : function(w, h)
42939 Roo.log('resize: ' +w + ',' + h );
42940 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
42944 if(typeof w == 'number'){
42946 this.iframe.style.width = w + 'px';
42948 if(typeof h == 'number'){
42950 this.iframe.style.height = h + 'px';
42952 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
42959 * Toggles the editor between standard and source edit mode.
42960 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
42962 toggleSourceEdit : function(sourceEditMode){
42964 this.sourceEditMode = sourceEditMode === true;
42966 if(this.sourceEditMode){
42968 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
42971 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
42972 //this.iframe.className = '';
42975 //this.setSize(this.owner.wrap.getSize());
42976 //this.fireEvent('editmodechange', this, this.sourceEditMode);
42983 * Protected method that will not generally be called directly. If you need/want
42984 * custom HTML cleanup, this is the method you should override.
42985 * @param {String} html The HTML to be cleaned
42986 * return {String} The cleaned HTML
42988 cleanHtml : function(html){
42989 html = String(html);
42990 if(html.length > 5){
42991 if(Roo.isSafari){ // strip safari nonsense
42992 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
42995 if(html == ' '){
43002 * HTML Editor -> Textarea
43003 * Protected method that will not generally be called directly. Syncs the contents
43004 * of the editor iframe with the textarea.
43006 syncValue : function(){
43007 if(this.initialized){
43008 var bd = (this.doc.body || this.doc.documentElement);
43009 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43010 var html = bd.innerHTML;
43012 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43013 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43015 html = '<div style="'+m[0]+'">' + html + '</div>';
43018 html = this.cleanHtml(html);
43019 // fix up the special chars.. normaly like back quotes in word...
43020 // however we do not want to do this with chinese..
43021 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
43022 var cc = b.charCodeAt();
43024 (cc >= 0x4E00 && cc < 0xA000 ) ||
43025 (cc >= 0x3400 && cc < 0x4E00 ) ||
43026 (cc >= 0xf900 && cc < 0xfb00 )
43032 if(this.owner.fireEvent('beforesync', this, html) !== false){
43033 this.el.dom.value = html;
43034 this.owner.fireEvent('sync', this, html);
43040 * Protected method that will not generally be called directly. Pushes the value of the textarea
43041 * into the iframe editor.
43043 pushValue : function(){
43044 if(this.initialized){
43045 var v = this.el.dom.value.trim();
43047 // if(v.length < 1){
43051 if(this.owner.fireEvent('beforepush', this, v) !== false){
43052 var d = (this.doc.body || this.doc.documentElement);
43054 this.cleanUpPaste();
43055 this.el.dom.value = d.innerHTML;
43056 this.owner.fireEvent('push', this, v);
43062 deferFocus : function(){
43063 this.focus.defer(10, this);
43067 focus : function(){
43068 if(this.win && !this.sourceEditMode){
43075 assignDocWin: function()
43077 var iframe = this.iframe;
43080 this.doc = iframe.contentWindow.document;
43081 this.win = iframe.contentWindow;
43083 // if (!Roo.get(this.frameId)) {
43086 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43087 // this.win = Roo.get(this.frameId).dom.contentWindow;
43089 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
43093 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
43094 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
43099 initEditor : function(){
43100 //console.log("INIT EDITOR");
43101 this.assignDocWin();
43105 this.doc.designMode="on";
43107 this.doc.write(this.getDocMarkup());
43110 var dbody = (this.doc.body || this.doc.documentElement);
43111 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
43112 // this copies styles from the containing element into thsi one..
43113 // not sure why we need all of this..
43114 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
43116 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
43117 //ss['background-attachment'] = 'fixed'; // w3c
43118 dbody.bgProperties = 'fixed'; // ie
43119 //Roo.DomHelper.applyStyles(dbody, ss);
43120 Roo.EventManager.on(this.doc, {
43121 //'mousedown': this.onEditorEvent,
43122 'mouseup': this.onEditorEvent,
43123 'dblclick': this.onEditorEvent,
43124 'click': this.onEditorEvent,
43125 'keyup': this.onEditorEvent,
43130 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
43132 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
43133 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
43135 this.initialized = true;
43137 this.owner.fireEvent('initialize', this);
43142 onDestroy : function(){
43148 //for (var i =0; i < this.toolbars.length;i++) {
43149 // // fixme - ask toolbars for heights?
43150 // this.toolbars[i].onDestroy();
43153 //this.wrap.dom.innerHTML = '';
43154 //this.wrap.remove();
43159 onFirstFocus : function(){
43161 this.assignDocWin();
43164 this.activated = true;
43167 if(Roo.isGecko){ // prevent silly gecko errors
43169 var s = this.win.getSelection();
43170 if(!s.focusNode || s.focusNode.nodeType != 3){
43171 var r = s.getRangeAt(0);
43172 r.selectNodeContents((this.doc.body || this.doc.documentElement));
43177 this.execCmd('useCSS', true);
43178 this.execCmd('styleWithCSS', false);
43181 this.owner.fireEvent('activate', this);
43185 adjustFont: function(btn){
43186 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
43187 //if(Roo.isSafari){ // safari
43190 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
43191 if(Roo.isSafari){ // safari
43192 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
43193 v = (v < 10) ? 10 : v;
43194 v = (v > 48) ? 48 : v;
43195 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
43200 v = Math.max(1, v+adjust);
43202 this.execCmd('FontSize', v );
43205 onEditorEvent : function(e)
43207 this.owner.fireEvent('editorevent', this, e);
43208 // this.updateToolbar();
43209 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
43212 insertTag : function(tg)
43214 // could be a bit smarter... -> wrap the current selected tRoo..
43215 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
43217 range = this.createRange(this.getSelection());
43218 var wrappingNode = this.doc.createElement(tg.toLowerCase());
43219 wrappingNode.appendChild(range.extractContents());
43220 range.insertNode(wrappingNode);
43227 this.execCmd("formatblock", tg);
43231 insertText : function(txt)
43235 var range = this.createRange();
43236 range.deleteContents();
43237 //alert(Sender.getAttribute('label'));
43239 range.insertNode(this.doc.createTextNode(txt));
43245 * Executes a Midas editor command on the editor document and performs necessary focus and
43246 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
43247 * @param {String} cmd The Midas command
43248 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43250 relayCmd : function(cmd, value){
43252 this.execCmd(cmd, value);
43253 this.owner.fireEvent('editorevent', this);
43254 //this.updateToolbar();
43255 this.owner.deferFocus();
43259 * Executes a Midas editor command directly on the editor document.
43260 * For visual commands, you should use {@link #relayCmd} instead.
43261 * <b>This should only be called after the editor is initialized.</b>
43262 * @param {String} cmd The Midas command
43263 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
43265 execCmd : function(cmd, value){
43266 this.doc.execCommand(cmd, false, value === undefined ? null : value);
43273 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
43275 * @param {String} text | dom node..
43277 insertAtCursor : function(text)
43280 if(!this.activated){
43286 var r = this.doc.selection.createRange();
43297 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
43301 // from jquery ui (MIT licenced)
43303 var win = this.win;
43305 if (win.getSelection && win.getSelection().getRangeAt) {
43306 range = win.getSelection().getRangeAt(0);
43307 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
43308 range.insertNode(node);
43309 } else if (win.document.selection && win.document.selection.createRange) {
43310 // no firefox support
43311 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43312 win.document.selection.createRange().pasteHTML(txt);
43314 // no firefox support
43315 var txt = typeof(text) == 'string' ? text : text.outerHTML;
43316 this.execCmd('InsertHTML', txt);
43325 mozKeyPress : function(e){
43327 var c = e.getCharCode(), cmd;
43330 c = String.fromCharCode(c).toLowerCase();
43344 this.cleanUpPaste.defer(100, this);
43352 e.preventDefault();
43360 fixKeys : function(){ // load time branching for fastest keydown performance
43362 return function(e){
43363 var k = e.getKey(), r;
43366 r = this.doc.selection.createRange();
43369 r.pasteHTML('    ');
43376 r = this.doc.selection.createRange();
43378 var target = r.parentElement();
43379 if(!target || target.tagName.toLowerCase() != 'li'){
43381 r.pasteHTML('<br />');
43387 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43388 this.cleanUpPaste.defer(100, this);
43394 }else if(Roo.isOpera){
43395 return function(e){
43396 var k = e.getKey();
43400 this.execCmd('InsertHTML','    ');
43403 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43404 this.cleanUpPaste.defer(100, this);
43409 }else if(Roo.isSafari){
43410 return function(e){
43411 var k = e.getKey();
43415 this.execCmd('InsertText','\t');
43419 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
43420 this.cleanUpPaste.defer(100, this);
43428 getAllAncestors: function()
43430 var p = this.getSelectedNode();
43433 a.push(p); // push blank onto stack..
43434 p = this.getParentElement();
43438 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
43442 a.push(this.doc.body);
43446 lastSelNode : false,
43449 getSelection : function()
43451 this.assignDocWin();
43452 return Roo.isIE ? this.doc.selection : this.win.getSelection();
43455 getSelectedNode: function()
43457 // this may only work on Gecko!!!
43459 // should we cache this!!!!
43464 var range = this.createRange(this.getSelection()).cloneRange();
43467 var parent = range.parentElement();
43469 var testRange = range.duplicate();
43470 testRange.moveToElementText(parent);
43471 if (testRange.inRange(range)) {
43474 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
43477 parent = parent.parentElement;
43482 // is ancestor a text element.
43483 var ac = range.commonAncestorContainer;
43484 if (ac.nodeType == 3) {
43485 ac = ac.parentNode;
43488 var ar = ac.childNodes;
43491 var other_nodes = [];
43492 var has_other_nodes = false;
43493 for (var i=0;i<ar.length;i++) {
43494 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
43497 // fullly contained node.
43499 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
43504 // probably selected..
43505 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
43506 other_nodes.push(ar[i]);
43510 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
43515 has_other_nodes = true;
43517 if (!nodes.length && other_nodes.length) {
43518 nodes= other_nodes;
43520 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
43526 createRange: function(sel)
43528 // this has strange effects when using with
43529 // top toolbar - not sure if it's a great idea.
43530 //this.editor.contentWindow.focus();
43531 if (typeof sel != "undefined") {
43533 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
43535 return this.doc.createRange();
43538 return this.doc.createRange();
43541 getParentElement: function()
43544 this.assignDocWin();
43545 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
43547 var range = this.createRange(sel);
43550 var p = range.commonAncestorContainer;
43551 while (p.nodeType == 3) { // text node
43562 * Range intersection.. the hard stuff...
43566 * [ -- selected range --- ]
43570 * if end is before start or hits it. fail.
43571 * if start is after end or hits it fail.
43573 * if either hits (but other is outside. - then it's not
43579 // @see http://www.thismuchiknow.co.uk/?p=64.
43580 rangeIntersectsNode : function(range, node)
43582 var nodeRange = node.ownerDocument.createRange();
43584 nodeRange.selectNode(node);
43586 nodeRange.selectNodeContents(node);
43589 var rangeStartRange = range.cloneRange();
43590 rangeStartRange.collapse(true);
43592 var rangeEndRange = range.cloneRange();
43593 rangeEndRange.collapse(false);
43595 var nodeStartRange = nodeRange.cloneRange();
43596 nodeStartRange.collapse(true);
43598 var nodeEndRange = nodeRange.cloneRange();
43599 nodeEndRange.collapse(false);
43601 return rangeStartRange.compareBoundaryPoints(
43602 Range.START_TO_START, nodeEndRange) == -1 &&
43603 rangeEndRange.compareBoundaryPoints(
43604 Range.START_TO_START, nodeStartRange) == 1;
43608 rangeCompareNode : function(range, node)
43610 var nodeRange = node.ownerDocument.createRange();
43612 nodeRange.selectNode(node);
43614 nodeRange.selectNodeContents(node);
43618 range.collapse(true);
43620 nodeRange.collapse(true);
43622 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
43623 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
43625 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
43627 var nodeIsBefore = ss == 1;
43628 var nodeIsAfter = ee == -1;
43630 if (nodeIsBefore && nodeIsAfter) {
43633 if (!nodeIsBefore && nodeIsAfter) {
43634 return 1; //right trailed.
43637 if (nodeIsBefore && !nodeIsAfter) {
43638 return 2; // left trailed.
43644 // private? - in a new class?
43645 cleanUpPaste : function()
43647 // cleans up the whole document..
43648 Roo.log('cleanuppaste');
43650 this.cleanUpChildren(this.doc.body);
43651 var clean = this.cleanWordChars(this.doc.body.innerHTML);
43652 if (clean != this.doc.body.innerHTML) {
43653 this.doc.body.innerHTML = clean;
43658 cleanWordChars : function(input) {// change the chars to hex code
43659 var he = Roo.HtmlEditorCore;
43661 var output = input;
43662 Roo.each(he.swapCodes, function(sw) {
43663 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
43665 output = output.replace(swapper, sw[1]);
43672 cleanUpChildren : function (n)
43674 if (!n.childNodes.length) {
43677 for (var i = n.childNodes.length-1; i > -1 ; i--) {
43678 this.cleanUpChild(n.childNodes[i]);
43685 cleanUpChild : function (node)
43688 //console.log(node);
43689 if (node.nodeName == "#text") {
43690 // clean up silly Windows -- stuff?
43693 if (node.nodeName == "#comment") {
43694 node.parentNode.removeChild(node);
43695 // clean up silly Windows -- stuff?
43698 var lcname = node.tagName.toLowerCase();
43699 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
43700 // whitelist of tags..
43702 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
43704 node.parentNode.removeChild(node);
43709 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
43711 // remove <a name=....> as rendering on yahoo mailer is borked with this.
43712 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
43714 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
43715 // remove_keep_children = true;
43718 if (remove_keep_children) {
43719 this.cleanUpChildren(node);
43720 // inserts everything just before this node...
43721 while (node.childNodes.length) {
43722 var cn = node.childNodes[0];
43723 node.removeChild(cn);
43724 node.parentNode.insertBefore(cn, node);
43726 node.parentNode.removeChild(node);
43730 if (!node.attributes || !node.attributes.length) {
43731 this.cleanUpChildren(node);
43735 function cleanAttr(n,v)
43738 if (v.match(/^\./) || v.match(/^\//)) {
43741 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
43744 if (v.match(/^#/)) {
43747 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
43748 node.removeAttribute(n);
43752 var cwhite = this.cwhite;
43753 var cblack = this.cblack;
43755 function cleanStyle(n,v)
43757 if (v.match(/expression/)) { //XSS?? should we even bother..
43758 node.removeAttribute(n);
43762 var parts = v.split(/;/);
43765 Roo.each(parts, function(p) {
43766 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
43770 var l = p.split(':').shift().replace(/\s+/g,'');
43771 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
43773 if ( cwhite.length && cblack.indexOf(l) > -1) {
43774 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43775 //node.removeAttribute(n);
43779 // only allow 'c whitelisted system attributes'
43780 if ( cwhite.length && cwhite.indexOf(l) < 0) {
43781 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
43782 //node.removeAttribute(n);
43792 if (clean.length) {
43793 node.setAttribute(n, clean.join(';'));
43795 node.removeAttribute(n);
43801 for (var i = node.attributes.length-1; i > -1 ; i--) {
43802 var a = node.attributes[i];
43805 if (a.name.toLowerCase().substr(0,2)=='on') {
43806 node.removeAttribute(a.name);
43809 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
43810 node.removeAttribute(a.name);
43813 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
43814 cleanAttr(a.name,a.value); // fixme..
43817 if (a.name == 'style') {
43818 cleanStyle(a.name,a.value);
43821 /// clean up MS crap..
43822 // tecnically this should be a list of valid class'es..
43825 if (a.name == 'class') {
43826 if (a.value.match(/^Mso/)) {
43827 node.className = '';
43830 if (a.value.match(/^body$/)) {
43831 node.className = '';
43842 this.cleanUpChildren(node);
43848 * Clean up MS wordisms...
43850 cleanWord : function(node)
43855 this.cleanWord(this.doc.body);
43858 if (node.nodeName == "#text") {
43859 // clean up silly Windows -- stuff?
43862 if (node.nodeName == "#comment") {
43863 node.parentNode.removeChild(node);
43864 // clean up silly Windows -- stuff?
43868 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
43869 node.parentNode.removeChild(node);
43873 // remove - but keep children..
43874 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|font)/)) {
43875 while (node.childNodes.length) {
43876 var cn = node.childNodes[0];
43877 node.removeChild(cn);
43878 node.parentNode.insertBefore(cn, node);
43880 node.parentNode.removeChild(node);
43881 this.iterateChildren(node, this.cleanWord);
43885 if (node.className.length) {
43887 var cn = node.className.split(/\W+/);
43889 Roo.each(cn, function(cls) {
43890 if (cls.match(/Mso[a-zA-Z]+/)) {
43895 node.className = cna.length ? cna.join(' ') : '';
43897 node.removeAttribute("class");
43901 if (node.hasAttribute("lang")) {
43902 node.removeAttribute("lang");
43905 if (node.hasAttribute("style")) {
43907 var styles = node.getAttribute("style").split(";");
43909 Roo.each(styles, function(s) {
43910 if (!s.match(/:/)) {
43913 var kv = s.split(":");
43914 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
43917 // what ever is left... we allow.
43920 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43921 if (!nstyle.length) {
43922 node.removeAttribute('style');
43925 this.iterateChildren(node, this.cleanWord);
43931 * iterateChildren of a Node, calling fn each time, using this as the scole..
43932 * @param {DomNode} node node to iterate children of.
43933 * @param {Function} fn method of this class to call on each item.
43935 iterateChildren : function(node, fn)
43937 if (!node.childNodes.length) {
43940 for (var i = node.childNodes.length-1; i > -1 ; i--) {
43941 fn.call(this, node.childNodes[i])
43947 * cleanTableWidths.
43949 * Quite often pasting from word etc.. results in tables with column and widths.
43950 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
43953 cleanTableWidths : function(node)
43958 this.cleanTableWidths(this.doc.body);
43963 if (node.nodeName == "#text" || node.nodeName == "#comment") {
43966 Roo.log(node.tagName);
43967 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
43968 this.iterateChildren(node, this.cleanTableWidths);
43971 if (node.hasAttribute('width')) {
43972 node.removeAttribute('width');
43976 if (node.hasAttribute("style")) {
43979 var styles = node.getAttribute("style").split(";");
43981 Roo.each(styles, function(s) {
43982 if (!s.match(/:/)) {
43985 var kv = s.split(":");
43986 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
43989 // what ever is left... we allow.
43992 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
43993 if (!nstyle.length) {
43994 node.removeAttribute('style');
43998 this.iterateChildren(node, this.cleanTableWidths);
44006 domToHTML : function(currentElement, depth, nopadtext) {
44008 depth = depth || 0;
44009 nopadtext = nopadtext || false;
44011 if (!currentElement) {
44012 return this.domToHTML(this.doc.body);
44015 //Roo.log(currentElement);
44017 var allText = false;
44018 var nodeName = currentElement.nodeName;
44019 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
44021 if (nodeName == '#text') {
44023 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
44028 if (nodeName != 'BODY') {
44031 // Prints the node tagName, such as <A>, <IMG>, etc
44034 for(i = 0; i < currentElement.attributes.length;i++) {
44036 var aname = currentElement.attributes.item(i).name;
44037 if (!currentElement.attributes.item(i).value.length) {
44040 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
44043 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
44052 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
44055 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
44060 // Traverse the tree
44062 var currentElementChild = currentElement.childNodes.item(i);
44063 var allText = true;
44064 var innerHTML = '';
44066 while (currentElementChild) {
44067 // Formatting code (indent the tree so it looks nice on the screen)
44068 var nopad = nopadtext;
44069 if (lastnode == 'SPAN') {
44073 if (currentElementChild.nodeName == '#text') {
44074 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
44075 toadd = nopadtext ? toadd : toadd.trim();
44076 if (!nopad && toadd.length > 80) {
44077 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
44079 innerHTML += toadd;
44082 currentElementChild = currentElement.childNodes.item(i);
44088 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
44090 // Recursively traverse the tree structure of the child node
44091 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
44092 lastnode = currentElementChild.nodeName;
44094 currentElementChild=currentElement.childNodes.item(i);
44100 // The remaining code is mostly for formatting the tree
44101 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
44106 ret+= "</"+tagName+">";
44112 applyBlacklists : function()
44114 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
44115 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
44119 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
44120 if (b.indexOf(tag) > -1) {
44123 this.white.push(tag);
44127 Roo.each(w, function(tag) {
44128 if (b.indexOf(tag) > -1) {
44131 if (this.white.indexOf(tag) > -1) {
44134 this.white.push(tag);
44139 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
44140 if (w.indexOf(tag) > -1) {
44143 this.black.push(tag);
44147 Roo.each(b, function(tag) {
44148 if (w.indexOf(tag) > -1) {
44151 if (this.black.indexOf(tag) > -1) {
44154 this.black.push(tag);
44159 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
44160 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
44164 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
44165 if (b.indexOf(tag) > -1) {
44168 this.cwhite.push(tag);
44172 Roo.each(w, function(tag) {
44173 if (b.indexOf(tag) > -1) {
44176 if (this.cwhite.indexOf(tag) > -1) {
44179 this.cwhite.push(tag);
44184 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
44185 if (w.indexOf(tag) > -1) {
44188 this.cblack.push(tag);
44192 Roo.each(b, function(tag) {
44193 if (w.indexOf(tag) > -1) {
44196 if (this.cblack.indexOf(tag) > -1) {
44199 this.cblack.push(tag);
44204 setStylesheets : function(stylesheets)
44206 if(typeof(stylesheets) == 'string'){
44207 Roo.get(this.iframe.contentDocument.head).createChild({
44209 rel : 'stylesheet',
44218 Roo.each(stylesheets, function(s) {
44223 Roo.get(_this.iframe.contentDocument.head).createChild({
44225 rel : 'stylesheet',
44234 removeStylesheets : function()
44238 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
44243 setStyle : function(style)
44245 Roo.get(this.iframe.contentDocument.head).createChild({
44254 // hide stuff that is not compatible
44268 * @event specialkey
44272 * @cfg {String} fieldClass @hide
44275 * @cfg {String} focusClass @hide
44278 * @cfg {String} autoCreate @hide
44281 * @cfg {String} inputType @hide
44284 * @cfg {String} invalidClass @hide
44287 * @cfg {String} invalidText @hide
44290 * @cfg {String} msgFx @hide
44293 * @cfg {String} validateOnBlur @hide
44297 Roo.HtmlEditorCore.white = [
44298 'area', 'br', 'img', 'input', 'hr', 'wbr',
44300 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
44301 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
44302 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
44303 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
44304 'table', 'ul', 'xmp',
44306 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
44309 'dir', 'menu', 'ol', 'ul', 'dl',
44315 Roo.HtmlEditorCore.black = [
44316 // 'embed', 'object', // enable - backend responsiblity to clean thiese
44318 'base', 'basefont', 'bgsound', 'blink', 'body',
44319 'frame', 'frameset', 'head', 'html', 'ilayer',
44320 'iframe', 'layer', 'link', 'meta', 'object',
44321 'script', 'style' ,'title', 'xml' // clean later..
44323 Roo.HtmlEditorCore.clean = [
44324 'script', 'style', 'title', 'xml'
44326 Roo.HtmlEditorCore.remove = [
44331 Roo.HtmlEditorCore.ablack = [
44335 Roo.HtmlEditorCore.aclean = [
44336 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
44340 Roo.HtmlEditorCore.pwhite= [
44341 'http', 'https', 'mailto'
44344 // white listed style attributes.
44345 Roo.HtmlEditorCore.cwhite= [
44346 // 'text-align', /// default is to allow most things..
44352 // black listed style attributes.
44353 Roo.HtmlEditorCore.cblack= [
44354 // 'font-size' -- this can be set by the project
44358 Roo.HtmlEditorCore.swapCodes =[
44369 //<script type="text/javascript">
44372 * Ext JS Library 1.1.1
44373 * Copyright(c) 2006-2007, Ext JS, LLC.
44379 Roo.form.HtmlEditor = function(config){
44383 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
44385 if (!this.toolbars) {
44386 this.toolbars = [];
44388 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
44394 * @class Roo.form.HtmlEditor
44395 * @extends Roo.form.Field
44396 * Provides a lightweight HTML Editor component.
44398 * This has been tested on Fireforx / Chrome.. IE may not be so great..
44400 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
44401 * supported by this editor.</b><br/><br/>
44402 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
44403 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
44405 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
44407 * @cfg {Boolean} clearUp
44411 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
44416 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
44421 * @cfg {Number} height (in pixels)
44425 * @cfg {Number} width (in pixels)
44430 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
44433 stylesheets: false,
44437 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
44442 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
44448 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
44453 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
44461 // private properties
44462 validationEvent : false,
44464 initialized : false,
44467 onFocus : Roo.emptyFn,
44469 hideMode:'offsets',
44471 actionMode : 'container', // defaults to hiding it...
44473 defaultAutoCreate : { // modified by initCompnoent..
44475 style:"width:500px;height:300px;",
44476 autocomplete: "new-password"
44480 initComponent : function(){
44483 * @event initialize
44484 * Fires when the editor is fully initialized (including the iframe)
44485 * @param {HtmlEditor} this
44490 * Fires when the editor is first receives the focus. Any insertion must wait
44491 * until after this event.
44492 * @param {HtmlEditor} this
44496 * @event beforesync
44497 * Fires before the textarea is updated with content from the editor iframe. Return false
44498 * to cancel the sync.
44499 * @param {HtmlEditor} this
44500 * @param {String} html
44504 * @event beforepush
44505 * Fires before the iframe editor is updated with content from the textarea. Return false
44506 * to cancel the push.
44507 * @param {HtmlEditor} this
44508 * @param {String} html
44513 * Fires when the textarea is updated with content from the editor iframe.
44514 * @param {HtmlEditor} this
44515 * @param {String} html
44520 * Fires when the iframe editor is updated with content from the textarea.
44521 * @param {HtmlEditor} this
44522 * @param {String} html
44526 * @event editmodechange
44527 * Fires when the editor switches edit modes
44528 * @param {HtmlEditor} this
44529 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
44531 editmodechange: true,
44533 * @event editorevent
44534 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
44535 * @param {HtmlEditor} this
44539 * @event firstfocus
44540 * Fires when on first focus - needed by toolbars..
44541 * @param {HtmlEditor} this
44546 * Auto save the htmlEditor value as a file into Events
44547 * @param {HtmlEditor} this
44551 * @event savedpreview
44552 * preview the saved version of htmlEditor
44553 * @param {HtmlEditor} this
44555 savedpreview: true,
44558 * @event stylesheetsclick
44559 * Fires when press the Sytlesheets button
44560 * @param {Roo.HtmlEditorCore} this
44562 stylesheetsclick: true
44564 this.defaultAutoCreate = {
44566 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
44567 autocomplete: "new-password"
44572 * Protected method that will not generally be called directly. It
44573 * is called when the editor creates its toolbar. Override this method if you need to
44574 * add custom toolbar buttons.
44575 * @param {HtmlEditor} editor
44577 createToolbar : function(editor){
44578 Roo.log("create toolbars");
44579 if (!editor.toolbars || !editor.toolbars.length) {
44580 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
44583 for (var i =0 ; i < editor.toolbars.length;i++) {
44584 editor.toolbars[i] = Roo.factory(
44585 typeof(editor.toolbars[i]) == 'string' ?
44586 { xtype: editor.toolbars[i]} : editor.toolbars[i],
44587 Roo.form.HtmlEditor);
44588 editor.toolbars[i].init(editor);
44596 onRender : function(ct, position)
44599 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
44601 this.wrap = this.el.wrap({
44602 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
44605 this.editorcore.onRender(ct, position);
44607 if (this.resizable) {
44608 this.resizeEl = new Roo.Resizable(this.wrap, {
44612 minHeight : this.height,
44613 height: this.height,
44614 handles : this.resizable,
44617 resize : function(r, w, h) {
44618 _t.onResize(w,h); // -something
44624 this.createToolbar(this);
44628 this.setSize(this.wrap.getSize());
44630 if (this.resizeEl) {
44631 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
44632 // should trigger onReize..
44635 this.keyNav = new Roo.KeyNav(this.el, {
44637 "tab" : function(e){
44638 e.preventDefault();
44640 var value = this.getValue();
44642 var start = this.el.dom.selectionStart;
44643 var end = this.el.dom.selectionEnd;
44647 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
44648 this.el.dom.setSelectionRange(end + 1, end + 1);
44652 var f = value.substring(0, start).split("\t");
44654 if(f.pop().length != 0){
44658 this.setValue(f.join("\t") + value.substring(end));
44659 this.el.dom.setSelectionRange(start - 1, start - 1);
44663 "home" : function(e){
44664 e.preventDefault();
44666 var curr = this.el.dom.selectionStart;
44667 var lines = this.getValue().split("\n");
44674 this.el.dom.setSelectionRange(0, 0);
44680 for (var i = 0; i < lines.length;i++) {
44681 pos += lines[i].length;
44691 pos -= lines[i].length;
44697 this.el.dom.setSelectionRange(pos, pos);
44701 this.el.dom.selectionStart = pos;
44702 this.el.dom.selectionEnd = curr;
44705 "end" : function(e){
44706 e.preventDefault();
44708 var curr = this.el.dom.selectionStart;
44709 var lines = this.getValue().split("\n");
44716 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
44722 for (var i = 0; i < lines.length;i++) {
44724 pos += lines[i].length;
44738 this.el.dom.setSelectionRange(pos, pos);
44742 this.el.dom.selectionStart = curr;
44743 this.el.dom.selectionEnd = pos;
44748 doRelay : function(foo, bar, hname){
44749 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
44755 // if(this.autosave && this.w){
44756 // this.autoSaveFn = setInterval(this.autosave, 1000);
44761 onResize : function(w, h)
44763 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
44768 if(typeof w == 'number'){
44769 var aw = w - this.wrap.getFrameWidth('lr');
44770 this.el.setWidth(this.adjustWidth('textarea', aw));
44773 if(typeof h == 'number'){
44775 for (var i =0; i < this.toolbars.length;i++) {
44776 // fixme - ask toolbars for heights?
44777 tbh += this.toolbars[i].tb.el.getHeight();
44778 if (this.toolbars[i].footer) {
44779 tbh += this.toolbars[i].footer.el.getHeight();
44786 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
44787 ah -= 5; // knock a few pixes off for look..
44789 this.el.setHeight(this.adjustWidth('textarea', ah));
44793 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
44794 this.editorcore.onResize(ew,eh);
44799 * Toggles the editor between standard and source edit mode.
44800 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
44802 toggleSourceEdit : function(sourceEditMode)
44804 this.editorcore.toggleSourceEdit(sourceEditMode);
44806 if(this.editorcore.sourceEditMode){
44807 Roo.log('editor - showing textarea');
44810 // Roo.log(this.syncValue());
44811 this.editorcore.syncValue();
44812 this.el.removeClass('x-hidden');
44813 this.el.dom.removeAttribute('tabIndex');
44816 for (var i = 0; i < this.toolbars.length; i++) {
44817 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44818 this.toolbars[i].tb.hide();
44819 this.toolbars[i].footer.hide();
44824 Roo.log('editor - hiding textarea');
44826 // Roo.log(this.pushValue());
44827 this.editorcore.pushValue();
44829 this.el.addClass('x-hidden');
44830 this.el.dom.setAttribute('tabIndex', -1);
44832 for (var i = 0; i < this.toolbars.length; i++) {
44833 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
44834 this.toolbars[i].tb.show();
44835 this.toolbars[i].footer.show();
44839 //this.deferFocus();
44842 this.setSize(this.wrap.getSize());
44843 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
44845 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
44848 // private (for BoxComponent)
44849 adjustSize : Roo.BoxComponent.prototype.adjustSize,
44851 // private (for BoxComponent)
44852 getResizeEl : function(){
44856 // private (for BoxComponent)
44857 getPositionEl : function(){
44862 initEvents : function(){
44863 this.originalValue = this.getValue();
44867 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44870 markInvalid : Roo.emptyFn,
44872 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
44875 clearInvalid : Roo.emptyFn,
44877 setValue : function(v){
44878 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
44879 this.editorcore.pushValue();
44884 deferFocus : function(){
44885 this.focus.defer(10, this);
44889 focus : function(){
44890 this.editorcore.focus();
44896 onDestroy : function(){
44902 for (var i =0; i < this.toolbars.length;i++) {
44903 // fixme - ask toolbars for heights?
44904 this.toolbars[i].onDestroy();
44907 this.wrap.dom.innerHTML = '';
44908 this.wrap.remove();
44913 onFirstFocus : function(){
44914 //Roo.log("onFirstFocus");
44915 this.editorcore.onFirstFocus();
44916 for (var i =0; i < this.toolbars.length;i++) {
44917 this.toolbars[i].onFirstFocus();
44923 syncValue : function()
44925 this.editorcore.syncValue();
44928 pushValue : function()
44930 this.editorcore.pushValue();
44933 setStylesheets : function(stylesheets)
44935 this.editorcore.setStylesheets(stylesheets);
44938 removeStylesheets : function()
44940 this.editorcore.removeStylesheets();
44944 // hide stuff that is not compatible
44958 * @event specialkey
44962 * @cfg {String} fieldClass @hide
44965 * @cfg {String} focusClass @hide
44968 * @cfg {String} autoCreate @hide
44971 * @cfg {String} inputType @hide
44974 * @cfg {String} invalidClass @hide
44977 * @cfg {String} invalidText @hide
44980 * @cfg {String} msgFx @hide
44983 * @cfg {String} validateOnBlur @hide
44987 // <script type="text/javascript">
44990 * Ext JS Library 1.1.1
44991 * Copyright(c) 2006-2007, Ext JS, LLC.
44997 * @class Roo.form.HtmlEditorToolbar1
45002 new Roo.form.HtmlEditor({
45005 new Roo.form.HtmlEditorToolbar1({
45006 disable : { fonts: 1 , format: 1, ..., ... , ...],
45012 * @cfg {Object} disable List of elements to disable..
45013 * @cfg {Array} btns List of additional buttons.
45017 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
45020 Roo.form.HtmlEditor.ToolbarStandard = function(config)
45023 Roo.apply(this, config);
45025 // default disabled, based on 'good practice'..
45026 this.disable = this.disable || {};
45027 Roo.applyIf(this.disable, {
45030 specialElements : true
45034 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45035 // dont call parent... till later.
45038 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
45045 editorcore : false,
45047 * @cfg {Object} disable List of toolbar elements to disable
45054 * @cfg {String} createLinkText The default text for the create link prompt
45056 createLinkText : 'Please enter the URL for the link:',
45058 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
45060 defaultLinkValue : 'http:/'+'/',
45064 * @cfg {Array} fontFamilies An array of available font families
45082 // "á" , ?? a acute?
45087 "°" // , // degrees
45089 // "é" , // e ecute
45090 // "ú" , // u ecute?
45093 specialElements : [
45095 text: "Insert Table",
45098 ihtml : '<table><tr><td>Cell</td></tr></table>'
45102 text: "Insert Image",
45105 ihtml : '<img src="about:blank"/>'
45114 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
45115 "input:submit", "input:button", "select", "textarea", "label" ],
45118 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
45120 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
45128 * @cfg {String} defaultFont default font to use.
45130 defaultFont: 'tahoma',
45132 fontSelect : false,
45135 formatCombo : false,
45137 init : function(editor)
45139 this.editor = editor;
45140 this.editorcore = editor.editorcore ? editor.editorcore : editor;
45141 var editorcore = this.editorcore;
45145 var fid = editorcore.frameId;
45147 function btn(id, toggle, handler){
45148 var xid = fid + '-'+ id ;
45152 cls : 'x-btn-icon x-edit-'+id,
45153 enableToggle:toggle !== false,
45154 scope: _t, // was editor...
45155 handler:handler||_t.relayBtnCmd,
45156 clickEvent:'mousedown',
45157 tooltip: etb.buttonTips[id] || undefined, ///tips ???
45164 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
45166 // stop form submits
45167 tb.el.on('click', function(e){
45168 e.preventDefault(); // what does this do?
45171 if(!this.disable.font) { // && !Roo.isSafari){
45172 /* why no safari for fonts
45173 editor.fontSelect = tb.el.createChild({
45176 cls:'x-font-select',
45177 html: this.createFontOptions()
45180 editor.fontSelect.on('change', function(){
45181 var font = editor.fontSelect.dom.value;
45182 editor.relayCmd('fontname', font);
45183 editor.deferFocus();
45187 editor.fontSelect.dom,
45193 if(!this.disable.formats){
45194 this.formatCombo = new Roo.form.ComboBox({
45195 store: new Roo.data.SimpleStore({
45198 data : this.formats // from states.js
45202 //autoCreate : {tag: "div", size: "20"},
45203 displayField:'tag',
45207 triggerAction: 'all',
45208 emptyText:'Add tag',
45209 selectOnFocus:true,
45212 'select': function(c, r, i) {
45213 editorcore.insertTag(r.get('tag'));
45219 tb.addField(this.formatCombo);
45223 if(!this.disable.format){
45228 btn('strikethrough')
45231 if(!this.disable.fontSize){
45236 btn('increasefontsize', false, editorcore.adjustFont),
45237 btn('decreasefontsize', false, editorcore.adjustFont)
45242 if(!this.disable.colors){
45245 id:editorcore.frameId +'-forecolor',
45246 cls:'x-btn-icon x-edit-forecolor',
45247 clickEvent:'mousedown',
45248 tooltip: this.buttonTips['forecolor'] || undefined,
45250 menu : new Roo.menu.ColorMenu({
45251 allowReselect: true,
45252 focus: Roo.emptyFn,
45255 selectHandler: function(cp, color){
45256 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
45257 editor.deferFocus();
45260 clickEvent:'mousedown'
45263 id:editorcore.frameId +'backcolor',
45264 cls:'x-btn-icon x-edit-backcolor',
45265 clickEvent:'mousedown',
45266 tooltip: this.buttonTips['backcolor'] || undefined,
45268 menu : new Roo.menu.ColorMenu({
45269 focus: Roo.emptyFn,
45272 allowReselect: true,
45273 selectHandler: function(cp, color){
45275 editorcore.execCmd('useCSS', false);
45276 editorcore.execCmd('hilitecolor', color);
45277 editorcore.execCmd('useCSS', true);
45278 editor.deferFocus();
45280 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
45281 Roo.isSafari || Roo.isIE ? '#'+color : color);
45282 editor.deferFocus();
45286 clickEvent:'mousedown'
45291 // now add all the items...
45294 if(!this.disable.alignments){
45297 btn('justifyleft'),
45298 btn('justifycenter'),
45299 btn('justifyright')
45303 //if(!Roo.isSafari){
45304 if(!this.disable.links){
45307 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
45311 if(!this.disable.lists){
45314 btn('insertorderedlist'),
45315 btn('insertunorderedlist')
45318 if(!this.disable.sourceEdit){
45321 btn('sourceedit', true, function(btn){
45322 this.toggleSourceEdit(btn.pressed);
45329 // special menu.. - needs to be tidied up..
45330 if (!this.disable.special) {
45333 cls: 'x-edit-none',
45339 for (var i =0; i < this.specialChars.length; i++) {
45340 smenu.menu.items.push({
45342 html: this.specialChars[i],
45343 handler: function(a,b) {
45344 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
45345 //editor.insertAtCursor(a.html);
45359 if (!this.disable.cleanStyles) {
45361 cls: 'x-btn-icon x-btn-clear',
45367 for (var i =0; i < this.cleanStyles.length; i++) {
45368 cmenu.menu.items.push({
45369 actiontype : this.cleanStyles[i],
45370 html: 'Remove ' + this.cleanStyles[i],
45371 handler: function(a,b) {
45374 var c = Roo.get(editorcore.doc.body);
45375 c.select('[style]').each(function(s) {
45376 s.dom.style.removeProperty(a.actiontype);
45378 editorcore.syncValue();
45383 cmenu.menu.items.push({
45384 actiontype : 'tablewidths',
45385 html: 'Remove Table Widths',
45386 handler: function(a,b) {
45387 editorcore.cleanTableWidths();
45388 editorcore.syncValue();
45392 cmenu.menu.items.push({
45393 actiontype : 'word',
45394 html: 'Remove MS Word Formating',
45395 handler: function(a,b) {
45396 editorcore.cleanWord();
45397 editorcore.syncValue();
45402 cmenu.menu.items.push({
45403 actiontype : 'all',
45404 html: 'Remove All Styles',
45405 handler: function(a,b) {
45407 var c = Roo.get(editorcore.doc.body);
45408 c.select('[style]').each(function(s) {
45409 s.dom.removeAttribute('style');
45411 editorcore.syncValue();
45416 cmenu.menu.items.push({
45417 actiontype : 'all',
45418 html: 'Remove All CSS Classes',
45419 handler: function(a,b) {
45421 var c = Roo.get(editorcore.doc.body);
45422 c.select('[class]').each(function(s) {
45423 s.dom.className = '';
45425 editorcore.syncValue();
45430 cmenu.menu.items.push({
45431 actiontype : 'tidy',
45432 html: 'Tidy HTML Source',
45433 handler: function(a,b) {
45434 editorcore.doc.body.innerHTML = editorcore.domToHTML();
45435 editorcore.syncValue();
45444 if (!this.disable.specialElements) {
45447 cls: 'x-edit-none',
45452 for (var i =0; i < this.specialElements.length; i++) {
45453 semenu.menu.items.push(
45455 handler: function(a,b) {
45456 editor.insertAtCursor(this.ihtml);
45458 }, this.specialElements[i])
45470 for(var i =0; i< this.btns.length;i++) {
45471 var b = Roo.factory(this.btns[i],Roo.form);
45472 b.cls = 'x-edit-none';
45474 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
45475 b.cls += ' x-init-enable';
45478 b.scope = editorcore;
45486 // disable everything...
45488 this.tb.items.each(function(item){
45491 item.id != editorcore.frameId+ '-sourceedit' &&
45492 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
45498 this.rendered = true;
45500 // the all the btns;
45501 editor.on('editorevent', this.updateToolbar, this);
45502 // other toolbars need to implement this..
45503 //editor.on('editmodechange', this.updateToolbar, this);
45507 relayBtnCmd : function(btn) {
45508 this.editorcore.relayCmd(btn.cmd);
45510 // private used internally
45511 createLink : function(){
45512 Roo.log("create link?");
45513 var url = prompt(this.createLinkText, this.defaultLinkValue);
45514 if(url && url != 'http:/'+'/'){
45515 this.editorcore.relayCmd('createlink', url);
45521 * Protected method that will not generally be called directly. It triggers
45522 * a toolbar update by reading the markup state of the current selection in the editor.
45524 updateToolbar: function(){
45526 if(!this.editorcore.activated){
45527 this.editor.onFirstFocus();
45531 var btns = this.tb.items.map,
45532 doc = this.editorcore.doc,
45533 frameId = this.editorcore.frameId;
45535 if(!this.disable.font && !Roo.isSafari){
45537 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
45538 if(name != this.fontSelect.dom.value){
45539 this.fontSelect.dom.value = name;
45543 if(!this.disable.format){
45544 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
45545 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
45546 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
45547 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
45549 if(!this.disable.alignments){
45550 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
45551 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
45552 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
45554 if(!Roo.isSafari && !this.disable.lists){
45555 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
45556 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
45559 var ans = this.editorcore.getAllAncestors();
45560 if (this.formatCombo) {
45563 var store = this.formatCombo.store;
45564 this.formatCombo.setValue("");
45565 for (var i =0; i < ans.length;i++) {
45566 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
45568 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
45576 // hides menus... - so this cant be on a menu...
45577 Roo.menu.MenuMgr.hideAll();
45579 //this.editorsyncValue();
45583 createFontOptions : function(){
45584 var buf = [], fs = this.fontFamilies, ff, lc;
45588 for(var i = 0, len = fs.length; i< len; i++){
45590 lc = ff.toLowerCase();
45592 '<option value="',lc,'" style="font-family:',ff,';"',
45593 (this.defaultFont == lc ? ' selected="true">' : '>'),
45598 return buf.join('');
45601 toggleSourceEdit : function(sourceEditMode){
45603 Roo.log("toolbar toogle");
45604 if(sourceEditMode === undefined){
45605 sourceEditMode = !this.sourceEditMode;
45607 this.sourceEditMode = sourceEditMode === true;
45608 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
45609 // just toggle the button?
45610 if(btn.pressed !== this.sourceEditMode){
45611 btn.toggle(this.sourceEditMode);
45615 if(sourceEditMode){
45616 Roo.log("disabling buttons");
45617 this.tb.items.each(function(item){
45618 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
45624 Roo.log("enabling buttons");
45625 if(this.editorcore.initialized){
45626 this.tb.items.each(function(item){
45632 Roo.log("calling toggole on editor");
45633 // tell the editor that it's been pressed..
45634 this.editor.toggleSourceEdit(sourceEditMode);
45638 * Object collection of toolbar tooltips for the buttons in the editor. The key
45639 * is the command id associated with that button and the value is a valid QuickTips object.
45644 title: 'Bold (Ctrl+B)',
45645 text: 'Make the selected text bold.',
45646 cls: 'x-html-editor-tip'
45649 title: 'Italic (Ctrl+I)',
45650 text: 'Make the selected text italic.',
45651 cls: 'x-html-editor-tip'
45659 title: 'Bold (Ctrl+B)',
45660 text: 'Make the selected text bold.',
45661 cls: 'x-html-editor-tip'
45664 title: 'Italic (Ctrl+I)',
45665 text: 'Make the selected text italic.',
45666 cls: 'x-html-editor-tip'
45669 title: 'Underline (Ctrl+U)',
45670 text: 'Underline the selected text.',
45671 cls: 'x-html-editor-tip'
45674 title: 'Strikethrough',
45675 text: 'Strikethrough the selected text.',
45676 cls: 'x-html-editor-tip'
45678 increasefontsize : {
45679 title: 'Grow Text',
45680 text: 'Increase the font size.',
45681 cls: 'x-html-editor-tip'
45683 decreasefontsize : {
45684 title: 'Shrink Text',
45685 text: 'Decrease the font size.',
45686 cls: 'x-html-editor-tip'
45689 title: 'Text Highlight Color',
45690 text: 'Change the background color of the selected text.',
45691 cls: 'x-html-editor-tip'
45694 title: 'Font Color',
45695 text: 'Change the color of the selected text.',
45696 cls: 'x-html-editor-tip'
45699 title: 'Align Text Left',
45700 text: 'Align text to the left.',
45701 cls: 'x-html-editor-tip'
45704 title: 'Center Text',
45705 text: 'Center text in the editor.',
45706 cls: 'x-html-editor-tip'
45709 title: 'Align Text Right',
45710 text: 'Align text to the right.',
45711 cls: 'x-html-editor-tip'
45713 insertunorderedlist : {
45714 title: 'Bullet List',
45715 text: 'Start a bulleted list.',
45716 cls: 'x-html-editor-tip'
45718 insertorderedlist : {
45719 title: 'Numbered List',
45720 text: 'Start a numbered list.',
45721 cls: 'x-html-editor-tip'
45724 title: 'Hyperlink',
45725 text: 'Make the selected text a hyperlink.',
45726 cls: 'x-html-editor-tip'
45729 title: 'Source Edit',
45730 text: 'Switch to source editing mode.',
45731 cls: 'x-html-editor-tip'
45735 onDestroy : function(){
45738 this.tb.items.each(function(item){
45740 item.menu.removeAll();
45742 item.menu.el.destroy();
45750 onFirstFocus: function() {
45751 this.tb.items.each(function(item){
45760 // <script type="text/javascript">
45763 * Ext JS Library 1.1.1
45764 * Copyright(c) 2006-2007, Ext JS, LLC.
45771 * @class Roo.form.HtmlEditor.ToolbarContext
45776 new Roo.form.HtmlEditor({
45779 { xtype: 'ToolbarStandard', styles : {} }
45780 { xtype: 'ToolbarContext', disable : {} }
45786 * @config : {Object} disable List of elements to disable.. (not done yet.)
45787 * @config : {Object} styles Map of styles available.
45791 Roo.form.HtmlEditor.ToolbarContext = function(config)
45794 Roo.apply(this, config);
45795 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
45796 // dont call parent... till later.
45797 this.styles = this.styles || {};
45802 Roo.form.HtmlEditor.ToolbarContext.types = {
45814 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
45880 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
45885 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
45895 style : 'fontFamily',
45896 displayField: 'display',
45897 optname : 'font-family',
45946 // should we really allow this??
45947 // should this just be
45958 style : 'fontFamily',
45959 displayField: 'display',
45960 optname : 'font-family',
45967 style : 'fontFamily',
45968 displayField: 'display',
45969 optname : 'font-family',
45976 style : 'fontFamily',
45977 displayField: 'display',
45978 optname : 'font-family',
45989 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
45990 Roo.form.HtmlEditor.ToolbarContext.stores = false;
45992 Roo.form.HtmlEditor.ToolbarContext.options = {
45994 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
45995 [ 'Courier New', 'Courier New'],
45996 [ 'Tahoma', 'Tahoma'],
45997 [ 'Times New Roman,serif', 'Times'],
45998 [ 'Verdana','Verdana' ]
46002 // fixme - these need to be configurable..
46005 //Roo.form.HtmlEditor.ToolbarContext.types
46008 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
46015 editorcore : false,
46017 * @cfg {Object} disable List of toolbar elements to disable
46022 * @cfg {Object} styles List of styles
46023 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
46025 * These must be defined in the page, so they get rendered correctly..
46036 init : function(editor)
46038 this.editor = editor;
46039 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46040 var editorcore = this.editorcore;
46042 var fid = editorcore.frameId;
46044 function btn(id, toggle, handler){
46045 var xid = fid + '-'+ id ;
46049 cls : 'x-btn-icon x-edit-'+id,
46050 enableToggle:toggle !== false,
46051 scope: editorcore, // was editor...
46052 handler:handler||editorcore.relayBtnCmd,
46053 clickEvent:'mousedown',
46054 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46058 // create a new element.
46059 var wdiv = editor.wrap.createChild({
46061 }, editor.wrap.dom.firstChild.nextSibling, true);
46063 // can we do this more than once??
46065 // stop form submits
46068 // disable everything...
46069 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46070 this.toolbars = {};
46072 for (var i in ty) {
46074 this.toolbars[i] = this.buildToolbar(ty[i],i);
46076 this.tb = this.toolbars.BODY;
46078 this.buildFooter();
46079 this.footer.show();
46080 editor.on('hide', function( ) { this.footer.hide() }, this);
46081 editor.on('show', function( ) { this.footer.show() }, this);
46084 this.rendered = true;
46086 // the all the btns;
46087 editor.on('editorevent', this.updateToolbar, this);
46088 // other toolbars need to implement this..
46089 //editor.on('editmodechange', this.updateToolbar, this);
46095 * Protected method that will not generally be called directly. It triggers
46096 * a toolbar update by reading the markup state of the current selection in the editor.
46098 * Note you can force an update by calling on('editorevent', scope, false)
46100 updateToolbar: function(editor,ev,sel){
46103 // capture mouse up - this is handy for selecting images..
46104 // perhaps should go somewhere else...
46105 if(!this.editorcore.activated){
46106 this.editor.onFirstFocus();
46112 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
46113 // selectNode - might want to handle IE?
46115 (ev.type == 'mouseup' || ev.type == 'click' ) &&
46116 ev.target && ev.target.tagName == 'IMG') {
46117 // they have click on an image...
46118 // let's see if we can change the selection...
46121 var nodeRange = sel.ownerDocument.createRange();
46123 nodeRange.selectNode(sel);
46125 nodeRange.selectNodeContents(sel);
46127 //nodeRange.collapse(true);
46128 var s = this.editorcore.win.getSelection();
46129 s.removeAllRanges();
46130 s.addRange(nodeRange);
46134 var updateFooter = sel ? false : true;
46137 var ans = this.editorcore.getAllAncestors();
46140 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
46143 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
46144 sel = sel ? sel : this.editorcore.doc.body;
46145 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
46148 // pick a menu that exists..
46149 var tn = sel.tagName.toUpperCase();
46150 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
46152 tn = sel.tagName.toUpperCase();
46154 var lastSel = this.tb.selectedNode;
46156 this.tb.selectedNode = sel;
46158 // if current menu does not match..
46160 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
46163 ///console.log("show: " + tn);
46164 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
46167 this.tb.items.first().el.innerHTML = tn + ': ';
46170 // update attributes
46171 if (this.tb.fields) {
46172 this.tb.fields.each(function(e) {
46174 e.setValue(sel.style[e.stylename]);
46177 e.setValue(sel.getAttribute(e.attrname));
46181 var hasStyles = false;
46182 for(var i in this.styles) {
46189 var st = this.tb.fields.item(0);
46191 st.store.removeAll();
46194 var cn = sel.className.split(/\s+/);
46197 if (this.styles['*']) {
46199 Roo.each(this.styles['*'], function(v) {
46200 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46203 if (this.styles[tn]) {
46204 Roo.each(this.styles[tn], function(v) {
46205 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
46209 st.store.loadData(avs);
46213 // flag our selected Node.
46214 this.tb.selectedNode = sel;
46217 Roo.menu.MenuMgr.hideAll();
46221 if (!updateFooter) {
46222 //this.footDisp.dom.innerHTML = '';
46225 // update the footer
46229 this.footerEls = ans.reverse();
46230 Roo.each(this.footerEls, function(a,i) {
46231 if (!a) { return; }
46232 html += html.length ? ' > ' : '';
46234 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
46239 var sz = this.footDisp.up('td').getSize();
46240 this.footDisp.dom.style.width = (sz.width -10) + 'px';
46241 this.footDisp.dom.style.marginLeft = '5px';
46243 this.footDisp.dom.style.overflow = 'hidden';
46245 this.footDisp.dom.innerHTML = html;
46247 //this.editorsyncValue();
46254 onDestroy : function(){
46257 this.tb.items.each(function(item){
46259 item.menu.removeAll();
46261 item.menu.el.destroy();
46269 onFirstFocus: function() {
46270 // need to do this for all the toolbars..
46271 this.tb.items.each(function(item){
46275 buildToolbar: function(tlist, nm)
46277 var editor = this.editor;
46278 var editorcore = this.editorcore;
46279 // create a new element.
46280 var wdiv = editor.wrap.createChild({
46282 }, editor.wrap.dom.firstChild.nextSibling, true);
46285 var tb = new Roo.Toolbar(wdiv);
46288 tb.add(nm+ ": ");
46291 for(var i in this.styles) {
46296 if (styles && styles.length) {
46298 // this needs a multi-select checkbox...
46299 tb.addField( new Roo.form.ComboBox({
46300 store: new Roo.data.SimpleStore({
46302 fields: ['val', 'selected'],
46305 name : '-roo-edit-className',
46306 attrname : 'className',
46307 displayField: 'val',
46311 triggerAction: 'all',
46312 emptyText:'Select Style',
46313 selectOnFocus:true,
46316 'select': function(c, r, i) {
46317 // initial support only for on class per el..
46318 tb.selectedNode.className = r ? r.get('val') : '';
46319 editorcore.syncValue();
46326 var tbc = Roo.form.HtmlEditor.ToolbarContext;
46327 var tbops = tbc.options;
46329 for (var i in tlist) {
46331 var item = tlist[i];
46332 tb.add(item.title + ": ");
46335 //optname == used so you can configure the options available..
46336 var opts = item.opts ? item.opts : false;
46337 if (item.optname) {
46338 opts = tbops[item.optname];
46343 // opts == pulldown..
46344 tb.addField( new Roo.form.ComboBox({
46345 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
46347 fields: ['val', 'display'],
46350 name : '-roo-edit-' + i,
46352 stylename : item.style ? item.style : false,
46353 displayField: item.displayField ? item.displayField : 'val',
46354 valueField : 'val',
46356 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
46358 triggerAction: 'all',
46359 emptyText:'Select',
46360 selectOnFocus:true,
46361 width: item.width ? item.width : 130,
46363 'select': function(c, r, i) {
46365 tb.selectedNode.style[c.stylename] = r.get('val');
46368 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
46377 tb.addField( new Roo.form.TextField({
46380 //allowBlank:false,
46385 tb.addField( new Roo.form.TextField({
46386 name: '-roo-edit-' + i,
46393 'change' : function(f, nv, ov) {
46394 tb.selectedNode.setAttribute(f.attrname, nv);
46395 editorcore.syncValue();
46408 text: 'Stylesheets',
46411 click : function ()
46413 _this.editor.fireEvent('stylesheetsclick', _this.editor);
46421 text: 'Remove Tag',
46424 click : function ()
46427 // undo does not work.
46429 var sn = tb.selectedNode;
46431 var pn = sn.parentNode;
46433 var stn = sn.childNodes[0];
46434 var en = sn.childNodes[sn.childNodes.length - 1 ];
46435 while (sn.childNodes.length) {
46436 var node = sn.childNodes[0];
46437 sn.removeChild(node);
46439 pn.insertBefore(node, sn);
46442 pn.removeChild(sn);
46443 var range = editorcore.createRange();
46445 range.setStart(stn,0);
46446 range.setEnd(en,0); //????
46447 //range.selectNode(sel);
46450 var selection = editorcore.getSelection();
46451 selection.removeAllRanges();
46452 selection.addRange(range);
46456 //_this.updateToolbar(null, null, pn);
46457 _this.updateToolbar(null, null, null);
46458 _this.footDisp.dom.innerHTML = '';
46468 tb.el.on('click', function(e){
46469 e.preventDefault(); // what does this do?
46471 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
46474 // dont need to disable them... as they will get hidden
46479 buildFooter : function()
46482 var fel = this.editor.wrap.createChild();
46483 this.footer = new Roo.Toolbar(fel);
46484 // toolbar has scrolly on left / right?
46485 var footDisp= new Roo.Toolbar.Fill();
46491 handler : function() {
46492 _t.footDisp.scrollTo('left',0,true)
46496 this.footer.add( footDisp );
46501 handler : function() {
46503 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
46507 var fel = Roo.get(footDisp.el);
46508 fel.addClass('x-editor-context');
46509 this.footDispWrap = fel;
46510 this.footDispWrap.overflow = 'hidden';
46512 this.footDisp = fel.createChild();
46513 this.footDispWrap.on('click', this.onContextClick, this)
46517 onContextClick : function (ev,dom)
46519 ev.preventDefault();
46520 var cn = dom.className;
46522 if (!cn.match(/x-ed-loc-/)) {
46525 var n = cn.split('-').pop();
46526 var ans = this.footerEls;
46530 var range = this.editorcore.createRange();
46532 range.selectNodeContents(sel);
46533 //range.selectNode(sel);
46536 var selection = this.editorcore.getSelection();
46537 selection.removeAllRanges();
46538 selection.addRange(range);
46542 this.updateToolbar(null, null, sel);
46559 * Ext JS Library 1.1.1
46560 * Copyright(c) 2006-2007, Ext JS, LLC.
46562 * Originally Released Under LGPL - original licence link has changed is not relivant.
46565 * <script type="text/javascript">
46569 * @class Roo.form.BasicForm
46570 * @extends Roo.util.Observable
46571 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
46573 * @param {String/HTMLElement/Roo.Element} el The form element or its id
46574 * @param {Object} config Configuration options
46576 Roo.form.BasicForm = function(el, config){
46577 this.allItems = [];
46578 this.childForms = [];
46579 Roo.apply(this, config);
46581 * The Roo.form.Field items in this form.
46582 * @type MixedCollection
46586 this.items = new Roo.util.MixedCollection(false, function(o){
46587 return o.id || (o.id = Roo.id());
46591 * @event beforeaction
46592 * Fires before any action is performed. Return false to cancel the action.
46593 * @param {Form} this
46594 * @param {Action} action The action to be performed
46596 beforeaction: true,
46598 * @event actionfailed
46599 * Fires when an action fails.
46600 * @param {Form} this
46601 * @param {Action} action The action that failed
46603 actionfailed : true,
46605 * @event actioncomplete
46606 * Fires when an action is completed.
46607 * @param {Form} this
46608 * @param {Action} action The action that completed
46610 actioncomplete : true
46615 Roo.form.BasicForm.superclass.constructor.call(this);
46618 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
46620 * @cfg {String} method
46621 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
46624 * @cfg {DataReader} reader
46625 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
46626 * This is optional as there is built-in support for processing JSON.
46629 * @cfg {DataReader} errorReader
46630 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
46631 * This is completely optional as there is built-in support for processing JSON.
46634 * @cfg {String} url
46635 * The URL to use for form actions if one isn't supplied in the action options.
46638 * @cfg {Boolean} fileUpload
46639 * Set to true if this form is a file upload.
46643 * @cfg {Object} baseParams
46644 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
46649 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
46654 activeAction : null,
46657 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
46658 * or setValues() data instead of when the form was first created.
46660 trackResetOnLoad : false,
46664 * childForms - used for multi-tab forms
46667 childForms : false,
46670 * allItems - full list of fields.
46676 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
46677 * element by passing it or its id or mask the form itself by passing in true.
46680 waitMsgTarget : false,
46683 initEl : function(el){
46684 this.el = Roo.get(el);
46685 this.id = this.el.id || Roo.id();
46686 this.el.on('submit', this.onSubmit, this);
46687 this.el.addClass('x-form');
46691 onSubmit : function(e){
46696 * Returns true if client-side validation on the form is successful.
46699 isValid : function(){
46701 this.items.each(function(f){
46710 * DEPRICATED Returns true if any fields in this form have changed since their original load.
46713 isDirty : function(){
46715 this.items.each(function(f){
46725 * Returns true if any fields in this form have changed since their original load. (New version)
46729 hasChanged : function()
46732 this.items.each(function(f){
46733 if(f.hasChanged()){
46742 * Resets all hasChanged to 'false' -
46743 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
46744 * So hasChanged storage is only to be used for this purpose
46747 resetHasChanged : function()
46749 this.items.each(function(f){
46750 f.resetHasChanged();
46757 * Performs a predefined action (submit or load) or custom actions you define on this form.
46758 * @param {String} actionName The name of the action type
46759 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
46760 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
46761 * accept other config options):
46763 Property Type Description
46764 ---------------- --------------- ----------------------------------------------------------------------------------
46765 url String The url for the action (defaults to the form's url)
46766 method String The form method to use (defaults to the form's method, or POST if not defined)
46767 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
46768 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
46769 validate the form on the client (defaults to false)
46771 * @return {BasicForm} this
46773 doAction : function(action, options){
46774 if(typeof action == 'string'){
46775 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
46777 if(this.fireEvent('beforeaction', this, action) !== false){
46778 this.beforeAction(action);
46779 action.run.defer(100, action);
46785 * Shortcut to do a submit action.
46786 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46787 * @return {BasicForm} this
46789 submit : function(options){
46790 this.doAction('submit', options);
46795 * Shortcut to do a load action.
46796 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
46797 * @return {BasicForm} this
46799 load : function(options){
46800 this.doAction('load', options);
46805 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
46806 * @param {Record} record The record to edit
46807 * @return {BasicForm} this
46809 updateRecord : function(record){
46810 record.beginEdit();
46811 var fs = record.fields;
46812 fs.each(function(f){
46813 var field = this.findField(f.name);
46815 record.set(f.name, field.getValue());
46823 * Loads an Roo.data.Record into this form.
46824 * @param {Record} record The record to load
46825 * @return {BasicForm} this
46827 loadRecord : function(record){
46828 this.setValues(record.data);
46833 beforeAction : function(action){
46834 var o = action.options;
46837 if(this.waitMsgTarget === true){
46838 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
46839 }else if(this.waitMsgTarget){
46840 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
46841 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
46843 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
46849 afterAction : function(action, success){
46850 this.activeAction = null;
46851 var o = action.options;
46853 if(this.waitMsgTarget === true){
46855 }else if(this.waitMsgTarget){
46856 this.waitMsgTarget.unmask();
46858 Roo.MessageBox.updateProgress(1);
46859 Roo.MessageBox.hide();
46866 Roo.callback(o.success, o.scope, [this, action]);
46867 this.fireEvent('actioncomplete', this, action);
46871 // failure condition..
46872 // we have a scenario where updates need confirming.
46873 // eg. if a locking scenario exists..
46874 // we look for { errors : { needs_confirm : true }} in the response.
46876 (typeof(action.result) != 'undefined') &&
46877 (typeof(action.result.errors) != 'undefined') &&
46878 (typeof(action.result.errors.needs_confirm) != 'undefined')
46881 Roo.MessageBox.confirm(
46882 "Change requires confirmation",
46883 action.result.errorMsg,
46888 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
46898 Roo.callback(o.failure, o.scope, [this, action]);
46899 // show an error message if no failed handler is set..
46900 if (!this.hasListener('actionfailed')) {
46901 Roo.MessageBox.alert("Error",
46902 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
46903 action.result.errorMsg :
46904 "Saving Failed, please check your entries or try again"
46908 this.fireEvent('actionfailed', this, action);
46914 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
46915 * @param {String} id The value to search for
46918 findField : function(id){
46919 var field = this.items.get(id);
46921 this.items.each(function(f){
46922 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
46928 return field || null;
46932 * Add a secondary form to this one,
46933 * Used to provide tabbed forms. One form is primary, with hidden values
46934 * which mirror the elements from the other forms.
46936 * @param {Roo.form.Form} form to add.
46939 addForm : function(form)
46942 if (this.childForms.indexOf(form) > -1) {
46946 this.childForms.push(form);
46948 Roo.each(form.allItems, function (fe) {
46950 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
46951 if (this.findField(n)) { // already added..
46954 var add = new Roo.form.Hidden({
46957 add.render(this.el);
46964 * Mark fields in this form invalid in bulk.
46965 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
46966 * @return {BasicForm} this
46968 markInvalid : function(errors){
46969 if(errors instanceof Array){
46970 for(var i = 0, len = errors.length; i < len; i++){
46971 var fieldError = errors[i];
46972 var f = this.findField(fieldError.id);
46974 f.markInvalid(fieldError.msg);
46980 if(typeof errors[id] != 'function' && (field = this.findField(id))){
46981 field.markInvalid(errors[id]);
46985 Roo.each(this.childForms || [], function (f) {
46986 f.markInvalid(errors);
46993 * Set values for fields in this form in bulk.
46994 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
46995 * @return {BasicForm} this
46997 setValues : function(values){
46998 if(values instanceof Array){ // array of objects
46999 for(var i = 0, len = values.length; i < len; i++){
47001 var f = this.findField(v.id);
47003 f.setValue(v.value);
47004 if(this.trackResetOnLoad){
47005 f.originalValue = f.getValue();
47009 }else{ // object hash
47012 if(typeof values[id] != 'function' && (field = this.findField(id))){
47014 if (field.setFromData &&
47015 field.valueField &&
47016 field.displayField &&
47017 // combos' with local stores can
47018 // be queried via setValue()
47019 // to set their value..
47020 (field.store && !field.store.isLocal)
47024 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
47025 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
47026 field.setFromData(sd);
47029 field.setValue(values[id]);
47033 if(this.trackResetOnLoad){
47034 field.originalValue = field.getValue();
47039 this.resetHasChanged();
47042 Roo.each(this.childForms || [], function (f) {
47043 f.setValues(values);
47044 f.resetHasChanged();
47051 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
47052 * they are returned as an array.
47053 * @param {Boolean} asString
47056 getValues : function(asString){
47057 if (this.childForms) {
47058 // copy values from the child forms
47059 Roo.each(this.childForms, function (f) {
47060 this.setValues(f.getValues());
47066 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
47067 if(asString === true){
47070 return Roo.urlDecode(fs);
47074 * Returns the fields in this form as an object with key/value pairs.
47075 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
47078 getFieldValues : function(with_hidden)
47080 if (this.childForms) {
47081 // copy values from the child forms
47082 // should this call getFieldValues - probably not as we do not currently copy
47083 // hidden fields when we generate..
47084 Roo.each(this.childForms, function (f) {
47085 this.setValues(f.getValues());
47090 this.items.each(function(f){
47091 if (!f.getName()) {
47094 var v = f.getValue();
47095 if (f.inputType =='radio') {
47096 if (typeof(ret[f.getName()]) == 'undefined') {
47097 ret[f.getName()] = ''; // empty..
47100 if (!f.el.dom.checked) {
47104 v = f.el.dom.value;
47108 // not sure if this supported any more..
47109 if ((typeof(v) == 'object') && f.getRawValue) {
47110 v = f.getRawValue() ; // dates..
47112 // combo boxes where name != hiddenName...
47113 if (f.name != f.getName()) {
47114 ret[f.name] = f.getRawValue();
47116 ret[f.getName()] = v;
47123 * Clears all invalid messages in this form.
47124 * @return {BasicForm} this
47126 clearInvalid : function(){
47127 this.items.each(function(f){
47131 Roo.each(this.childForms || [], function (f) {
47140 * Resets this form.
47141 * @return {BasicForm} this
47143 reset : function(){
47144 this.items.each(function(f){
47148 Roo.each(this.childForms || [], function (f) {
47151 this.resetHasChanged();
47157 * Add Roo.form components to this form.
47158 * @param {Field} field1
47159 * @param {Field} field2 (optional)
47160 * @param {Field} etc (optional)
47161 * @return {BasicForm} this
47164 this.items.addAll(Array.prototype.slice.call(arguments, 0));
47170 * Removes a field from the items collection (does NOT remove its markup).
47171 * @param {Field} field
47172 * @return {BasicForm} this
47174 remove : function(field){
47175 this.items.remove(field);
47180 * Looks at the fields in this form, checks them for an id attribute,
47181 * and calls applyTo on the existing dom element with that id.
47182 * @return {BasicForm} this
47184 render : function(){
47185 this.items.each(function(f){
47186 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
47194 * Calls {@link Ext#apply} for all fields in this form with the passed object.
47195 * @param {Object} values
47196 * @return {BasicForm} this
47198 applyToFields : function(o){
47199 this.items.each(function(f){
47206 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
47207 * @param {Object} values
47208 * @return {BasicForm} this
47210 applyIfToFields : function(o){
47211 this.items.each(function(f){
47219 Roo.BasicForm = Roo.form.BasicForm;/*
47221 * Ext JS Library 1.1.1
47222 * Copyright(c) 2006-2007, Ext JS, LLC.
47224 * Originally Released Under LGPL - original licence link has changed is not relivant.
47227 * <script type="text/javascript">
47231 * @class Roo.form.Form
47232 * @extends Roo.form.BasicForm
47233 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
47235 * @param {Object} config Configuration options
47237 Roo.form.Form = function(config){
47239 if (config.items) {
47240 xitems = config.items;
47241 delete config.items;
47245 Roo.form.Form.superclass.constructor.call(this, null, config);
47246 this.url = this.url || this.action;
47248 this.root = new Roo.form.Layout(Roo.applyIf({
47252 this.active = this.root;
47254 * Array of all the buttons that have been added to this form via {@link addButton}
47258 this.allItems = [];
47261 * @event clientvalidation
47262 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
47263 * @param {Form} this
47264 * @param {Boolean} valid true if the form has passed client-side validation
47266 clientvalidation: true,
47269 * Fires when the form is rendered
47270 * @param {Roo.form.Form} form
47275 if (this.progressUrl) {
47276 // push a hidden field onto the list of fields..
47280 name : 'UPLOAD_IDENTIFIER'
47285 Roo.each(xitems, this.addxtype, this);
47291 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
47293 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
47296 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
47299 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
47301 buttonAlign:'center',
47304 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
47309 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
47310 * This property cascades to child containers if not set.
47315 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
47316 * fires a looping event with that state. This is required to bind buttons to the valid
47317 * state using the config value formBind:true on the button.
47319 monitorValid : false,
47322 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
47327 * @cfg {String} progressUrl - Url to return progress data
47330 progressUrl : false,
47333 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
47334 * fields are added and the column is closed. If no fields are passed the column remains open
47335 * until end() is called.
47336 * @param {Object} config The config to pass to the column
47337 * @param {Field} field1 (optional)
47338 * @param {Field} field2 (optional)
47339 * @param {Field} etc (optional)
47340 * @return Column The column container object
47342 column : function(c){
47343 var col = new Roo.form.Column(c);
47345 if(arguments.length > 1){ // duplicate code required because of Opera
47346 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47353 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
47354 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
47355 * until end() is called.
47356 * @param {Object} config The config to pass to the fieldset
47357 * @param {Field} field1 (optional)
47358 * @param {Field} field2 (optional)
47359 * @param {Field} etc (optional)
47360 * @return FieldSet The fieldset container object
47362 fieldset : function(c){
47363 var fs = new Roo.form.FieldSet(c);
47365 if(arguments.length > 1){ // duplicate code required because of Opera
47366 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47373 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
47374 * fields are added and the container is closed. If no fields are passed the container remains open
47375 * until end() is called.
47376 * @param {Object} config The config to pass to the Layout
47377 * @param {Field} field1 (optional)
47378 * @param {Field} field2 (optional)
47379 * @param {Field} etc (optional)
47380 * @return Layout The container object
47382 container : function(c){
47383 var l = new Roo.form.Layout(c);
47385 if(arguments.length > 1){ // duplicate code required because of Opera
47386 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
47393 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
47394 * @param {Object} container A Roo.form.Layout or subclass of Layout
47395 * @return {Form} this
47397 start : function(c){
47398 // cascade label info
47399 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
47400 this.active.stack.push(c);
47401 c.ownerCt = this.active;
47407 * Closes the current open container
47408 * @return {Form} this
47411 if(this.active == this.root){
47414 this.active = this.active.ownerCt;
47419 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
47420 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
47421 * as the label of the field.
47422 * @param {Field} field1
47423 * @param {Field} field2 (optional)
47424 * @param {Field} etc. (optional)
47425 * @return {Form} this
47428 this.active.stack.push.apply(this.active.stack, arguments);
47429 this.allItems.push.apply(this.allItems,arguments);
47431 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
47432 if(a[i].isFormField){
47437 Roo.form.Form.superclass.add.apply(this, r);
47447 * Find any element that has been added to a form, using it's ID or name
47448 * This can include framesets, columns etc. along with regular fields..
47449 * @param {String} id - id or name to find.
47451 * @return {Element} e - or false if nothing found.
47453 findbyId : function(id)
47459 Roo.each(this.allItems, function(f){
47460 if (f.id == id || f.name == id ){
47471 * Render this form into the passed container. This should only be called once!
47472 * @param {String/HTMLElement/Element} container The element this component should be rendered into
47473 * @return {Form} this
47475 render : function(ct)
47481 var o = this.autoCreate || {
47483 method : this.method || 'POST',
47484 id : this.id || Roo.id()
47486 this.initEl(ct.createChild(o));
47488 this.root.render(this.el);
47492 this.items.each(function(f){
47493 f.render('x-form-el-'+f.id);
47496 if(this.buttons.length > 0){
47497 // tables are required to maintain order and for correct IE layout
47498 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
47499 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
47500 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
47502 var tr = tb.getElementsByTagName('tr')[0];
47503 for(var i = 0, len = this.buttons.length; i < len; i++) {
47504 var b = this.buttons[i];
47505 var td = document.createElement('td');
47506 td.className = 'x-form-btn-td';
47507 b.render(tr.appendChild(td));
47510 if(this.monitorValid){ // initialize after render
47511 this.startMonitoring();
47513 this.fireEvent('rendered', this);
47518 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
47519 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
47520 * object or a valid Roo.DomHelper element config
47521 * @param {Function} handler The function called when the button is clicked
47522 * @param {Object} scope (optional) The scope of the handler function
47523 * @return {Roo.Button}
47525 addButton : function(config, handler, scope){
47529 minWidth: this.minButtonWidth,
47532 if(typeof config == "string"){
47535 Roo.apply(bc, config);
47537 var btn = new Roo.Button(null, bc);
47538 this.buttons.push(btn);
47543 * Adds a series of form elements (using the xtype property as the factory method.
47544 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
47545 * @param {Object} config
47548 addxtype : function()
47550 var ar = Array.prototype.slice.call(arguments, 0);
47552 for(var i = 0; i < ar.length; i++) {
47554 continue; // skip -- if this happends something invalid got sent, we
47555 // should ignore it, as basically that interface element will not show up
47556 // and that should be pretty obvious!!
47559 if (Roo.form[ar[i].xtype]) {
47561 var fe = Roo.factory(ar[i], Roo.form);
47567 fe.store.form = this;
47572 this.allItems.push(fe);
47573 if (fe.items && fe.addxtype) {
47574 fe.addxtype.apply(fe, fe.items);
47584 // console.log('adding ' + ar[i].xtype);
47586 if (ar[i].xtype == 'Button') {
47587 //console.log('adding button');
47588 //console.log(ar[i]);
47589 this.addButton(ar[i]);
47590 this.allItems.push(fe);
47594 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
47595 alert('end is not supported on xtype any more, use items');
47597 // //console.log('adding end');
47605 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
47606 * option "monitorValid"
47608 startMonitoring : function(){
47611 Roo.TaskMgr.start({
47612 run : this.bindHandler,
47613 interval : this.monitorPoll || 200,
47620 * Stops monitoring of the valid state of this form
47622 stopMonitoring : function(){
47623 this.bound = false;
47627 bindHandler : function(){
47629 return false; // stops binding
47632 this.items.each(function(f){
47633 if(!f.isValid(true)){
47638 for(var i = 0, len = this.buttons.length; i < len; i++){
47639 var btn = this.buttons[i];
47640 if(btn.formBind === true && btn.disabled === valid){
47641 btn.setDisabled(!valid);
47644 this.fireEvent('clientvalidation', this, valid);
47658 Roo.Form = Roo.form.Form;
47661 * Ext JS Library 1.1.1
47662 * Copyright(c) 2006-2007, Ext JS, LLC.
47664 * Originally Released Under LGPL - original licence link has changed is not relivant.
47667 * <script type="text/javascript">
47670 // as we use this in bootstrap.
47671 Roo.namespace('Roo.form');
47673 * @class Roo.form.Action
47674 * Internal Class used to handle form actions
47676 * @param {Roo.form.BasicForm} el The form element or its id
47677 * @param {Object} config Configuration options
47682 // define the action interface
47683 Roo.form.Action = function(form, options){
47685 this.options = options || {};
47688 * Client Validation Failed
47691 Roo.form.Action.CLIENT_INVALID = 'client';
47693 * Server Validation Failed
47696 Roo.form.Action.SERVER_INVALID = 'server';
47698 * Connect to Server Failed
47701 Roo.form.Action.CONNECT_FAILURE = 'connect';
47703 * Reading Data from Server Failed
47706 Roo.form.Action.LOAD_FAILURE = 'load';
47708 Roo.form.Action.prototype = {
47710 failureType : undefined,
47711 response : undefined,
47712 result : undefined,
47714 // interface method
47715 run : function(options){
47719 // interface method
47720 success : function(response){
47724 // interface method
47725 handleResponse : function(response){
47729 // default connection failure
47730 failure : function(response){
47732 this.response = response;
47733 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47734 this.form.afterAction(this, false);
47737 processResponse : function(response){
47738 this.response = response;
47739 if(!response.responseText){
47742 this.result = this.handleResponse(response);
47743 return this.result;
47746 // utility functions used internally
47747 getUrl : function(appendParams){
47748 var url = this.options.url || this.form.url || this.form.el.dom.action;
47750 var p = this.getParams();
47752 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
47758 getMethod : function(){
47759 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
47762 getParams : function(){
47763 var bp = this.form.baseParams;
47764 var p = this.options.params;
47766 if(typeof p == "object"){
47767 p = Roo.urlEncode(Roo.applyIf(p, bp));
47768 }else if(typeof p == 'string' && bp){
47769 p += '&' + Roo.urlEncode(bp);
47772 p = Roo.urlEncode(bp);
47777 createCallback : function(){
47779 success: this.success,
47780 failure: this.failure,
47782 timeout: (this.form.timeout*1000),
47783 upload: this.form.fileUpload ? this.success : undefined
47788 Roo.form.Action.Submit = function(form, options){
47789 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
47792 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
47795 haveProgress : false,
47796 uploadComplete : false,
47798 // uploadProgress indicator.
47799 uploadProgress : function()
47801 if (!this.form.progressUrl) {
47805 if (!this.haveProgress) {
47806 Roo.MessageBox.progress("Uploading", "Uploading");
47808 if (this.uploadComplete) {
47809 Roo.MessageBox.hide();
47813 this.haveProgress = true;
47815 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
47817 var c = new Roo.data.Connection();
47819 url : this.form.progressUrl,
47824 success : function(req){
47825 //console.log(data);
47829 rdata = Roo.decode(req.responseText)
47831 Roo.log("Invalid data from server..");
47835 if (!rdata || !rdata.success) {
47837 Roo.MessageBox.alert(Roo.encode(rdata));
47840 var data = rdata.data;
47842 if (this.uploadComplete) {
47843 Roo.MessageBox.hide();
47848 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
47849 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
47852 this.uploadProgress.defer(2000,this);
47855 failure: function(data) {
47856 Roo.log('progress url failed ');
47867 // run get Values on the form, so it syncs any secondary forms.
47868 this.form.getValues();
47870 var o = this.options;
47871 var method = this.getMethod();
47872 var isPost = method == 'POST';
47873 if(o.clientValidation === false || this.form.isValid()){
47875 if (this.form.progressUrl) {
47876 this.form.findField('UPLOAD_IDENTIFIER').setValue(
47877 (new Date() * 1) + '' + Math.random());
47882 Roo.Ajax.request(Roo.apply(this.createCallback(), {
47883 form:this.form.el.dom,
47884 url:this.getUrl(!isPost),
47886 params:isPost ? this.getParams() : null,
47887 isUpload: this.form.fileUpload
47890 this.uploadProgress();
47892 }else if (o.clientValidation !== false){ // client validation failed
47893 this.failureType = Roo.form.Action.CLIENT_INVALID;
47894 this.form.afterAction(this, false);
47898 success : function(response)
47900 this.uploadComplete= true;
47901 if (this.haveProgress) {
47902 Roo.MessageBox.hide();
47906 var result = this.processResponse(response);
47907 if(result === true || result.success){
47908 this.form.afterAction(this, true);
47912 this.form.markInvalid(result.errors);
47913 this.failureType = Roo.form.Action.SERVER_INVALID;
47915 this.form.afterAction(this, false);
47917 failure : function(response)
47919 this.uploadComplete= true;
47920 if (this.haveProgress) {
47921 Roo.MessageBox.hide();
47924 this.response = response;
47925 this.failureType = Roo.form.Action.CONNECT_FAILURE;
47926 this.form.afterAction(this, false);
47929 handleResponse : function(response){
47930 if(this.form.errorReader){
47931 var rs = this.form.errorReader.read(response);
47934 for(var i = 0, len = rs.records.length; i < len; i++) {
47935 var r = rs.records[i];
47936 errors[i] = r.data;
47939 if(errors.length < 1){
47943 success : rs.success,
47949 ret = Roo.decode(response.responseText);
47953 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
47963 Roo.form.Action.Load = function(form, options){
47964 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
47965 this.reader = this.form.reader;
47968 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
47973 Roo.Ajax.request(Roo.apply(
47974 this.createCallback(), {
47975 method:this.getMethod(),
47976 url:this.getUrl(false),
47977 params:this.getParams()
47981 success : function(response){
47983 var result = this.processResponse(response);
47984 if(result === true || !result.success || !result.data){
47985 this.failureType = Roo.form.Action.LOAD_FAILURE;
47986 this.form.afterAction(this, false);
47989 this.form.clearInvalid();
47990 this.form.setValues(result.data);
47991 this.form.afterAction(this, true);
47994 handleResponse : function(response){
47995 if(this.form.reader){
47996 var rs = this.form.reader.read(response);
47997 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
47999 success : rs.success,
48003 return Roo.decode(response.responseText);
48007 Roo.form.Action.ACTION_TYPES = {
48008 'load' : Roo.form.Action.Load,
48009 'submit' : Roo.form.Action.Submit
48012 * Ext JS Library 1.1.1
48013 * Copyright(c) 2006-2007, Ext JS, LLC.
48015 * Originally Released Under LGPL - original licence link has changed is not relivant.
48018 * <script type="text/javascript">
48022 * @class Roo.form.Layout
48023 * @extends Roo.Component
48024 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
48026 * @param {Object} config Configuration options
48028 Roo.form.Layout = function(config){
48030 if (config.items) {
48031 xitems = config.items;
48032 delete config.items;
48034 Roo.form.Layout.superclass.constructor.call(this, config);
48036 Roo.each(xitems, this.addxtype, this);
48040 Roo.extend(Roo.form.Layout, Roo.Component, {
48042 * @cfg {String/Object} autoCreate
48043 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
48046 * @cfg {String/Object/Function} style
48047 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
48048 * a function which returns such a specification.
48051 * @cfg {String} labelAlign
48052 * Valid values are "left," "top" and "right" (defaults to "left")
48055 * @cfg {Number} labelWidth
48056 * Fixed width in pixels of all field labels (defaults to undefined)
48059 * @cfg {Boolean} clear
48060 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
48064 * @cfg {String} labelSeparator
48065 * The separator to use after field labels (defaults to ':')
48067 labelSeparator : ':',
48069 * @cfg {Boolean} hideLabels
48070 * True to suppress the display of field labels in this layout (defaults to false)
48072 hideLabels : false,
48075 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
48080 onRender : function(ct, position){
48081 if(this.el){ // from markup
48082 this.el = Roo.get(this.el);
48083 }else { // generate
48084 var cfg = this.getAutoCreate();
48085 this.el = ct.createChild(cfg, position);
48088 this.el.applyStyles(this.style);
48090 if(this.labelAlign){
48091 this.el.addClass('x-form-label-'+this.labelAlign);
48093 if(this.hideLabels){
48094 this.labelStyle = "display:none";
48095 this.elementStyle = "padding-left:0;";
48097 if(typeof this.labelWidth == 'number'){
48098 this.labelStyle = "width:"+this.labelWidth+"px;";
48099 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
48101 if(this.labelAlign == 'top'){
48102 this.labelStyle = "width:auto;";
48103 this.elementStyle = "padding-left:0;";
48106 var stack = this.stack;
48107 var slen = stack.length;
48109 if(!this.fieldTpl){
48110 var t = new Roo.Template(
48111 '<div class="x-form-item {5}">',
48112 '<label for="{0}" style="{2}">{1}{4}</label>',
48113 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48115 '</div><div class="x-form-clear-left"></div>'
48117 t.disableFormats = true;
48119 Roo.form.Layout.prototype.fieldTpl = t;
48121 for(var i = 0; i < slen; i++) {
48122 if(stack[i].isFormField){
48123 this.renderField(stack[i]);
48125 this.renderComponent(stack[i]);
48130 this.el.createChild({cls:'x-form-clear'});
48135 renderField : function(f){
48136 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
48139 f.labelStyle||this.labelStyle||'', //2
48140 this.elementStyle||'', //3
48141 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
48142 f.itemCls||this.itemCls||'' //5
48143 ], true).getPrevSibling());
48147 renderComponent : function(c){
48148 c.render(c.isLayout ? this.el : this.el.createChild());
48151 * Adds a object form elements (using the xtype property as the factory method.)
48152 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
48153 * @param {Object} config
48155 addxtype : function(o)
48157 // create the lement.
48158 o.form = this.form;
48159 var fe = Roo.factory(o, Roo.form);
48160 this.form.allItems.push(fe);
48161 this.stack.push(fe);
48163 if (fe.isFormField) {
48164 this.form.items.add(fe);
48172 * @class Roo.form.Column
48173 * @extends Roo.form.Layout
48174 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
48176 * @param {Object} config Configuration options
48178 Roo.form.Column = function(config){
48179 Roo.form.Column.superclass.constructor.call(this, config);
48182 Roo.extend(Roo.form.Column, Roo.form.Layout, {
48184 * @cfg {Number/String} width
48185 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48188 * @cfg {String/Object} autoCreate
48189 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
48193 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
48196 onRender : function(ct, position){
48197 Roo.form.Column.superclass.onRender.call(this, ct, position);
48199 this.el.setWidth(this.width);
48206 * @class Roo.form.Row
48207 * @extends Roo.form.Layout
48208 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
48210 * @param {Object} config Configuration options
48214 Roo.form.Row = function(config){
48215 Roo.form.Row.superclass.constructor.call(this, config);
48218 Roo.extend(Roo.form.Row, Roo.form.Layout, {
48220 * @cfg {Number/String} width
48221 * The fixed width of the column in pixels or CSS value (defaults to "auto")
48224 * @cfg {Number/String} height
48225 * The fixed height of the column in pixels or CSS value (defaults to "auto")
48227 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
48231 onRender : function(ct, position){
48232 //console.log('row render');
48234 var t = new Roo.Template(
48235 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
48236 '<label for="{0}" style="{2}">{1}{4}</label>',
48237 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
48241 t.disableFormats = true;
48243 Roo.form.Layout.prototype.rowTpl = t;
48245 this.fieldTpl = this.rowTpl;
48247 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
48248 var labelWidth = 100;
48250 if ((this.labelAlign != 'top')) {
48251 if (typeof this.labelWidth == 'number') {
48252 labelWidth = this.labelWidth
48254 this.padWidth = 20 + labelWidth;
48258 Roo.form.Column.superclass.onRender.call(this, ct, position);
48260 this.el.setWidth(this.width);
48263 this.el.setHeight(this.height);
48268 renderField : function(f){
48269 f.fieldEl = this.fieldTpl.append(this.el, [
48270 f.id, f.fieldLabel,
48271 f.labelStyle||this.labelStyle||'',
48272 this.elementStyle||'',
48273 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
48274 f.itemCls||this.itemCls||'',
48275 f.width ? f.width + this.padWidth : 160 + this.padWidth
48282 * @class Roo.form.FieldSet
48283 * @extends Roo.form.Layout
48284 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
48286 * @param {Object} config Configuration options
48288 Roo.form.FieldSet = function(config){
48289 Roo.form.FieldSet.superclass.constructor.call(this, config);
48292 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
48294 * @cfg {String} legend
48295 * The text to display as the legend for the FieldSet (defaults to '')
48298 * @cfg {String/Object} autoCreate
48299 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
48303 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
48306 onRender : function(ct, position){
48307 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
48309 this.setLegend(this.legend);
48314 setLegend : function(text){
48316 this.el.child('legend').update(text);
48321 * Ext JS Library 1.1.1
48322 * Copyright(c) 2006-2007, Ext JS, LLC.
48324 * Originally Released Under LGPL - original licence link has changed is not relivant.
48327 * <script type="text/javascript">
48330 * @class Roo.form.VTypes
48331 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
48334 Roo.form.VTypes = function(){
48335 // closure these in so they are only created once.
48336 var alpha = /^[a-zA-Z_]+$/;
48337 var alphanum = /^[a-zA-Z0-9_]+$/;
48338 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
48339 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
48341 // All these messages and functions are configurable
48344 * The function used to validate email addresses
48345 * @param {String} value The email address
48347 'email' : function(v){
48348 return email.test(v);
48351 * The error text to display when the email validation function returns false
48354 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
48356 * The keystroke filter mask to be applied on email input
48359 'emailMask' : /[a-z0-9_\.\-@]/i,
48362 * The function used to validate URLs
48363 * @param {String} value The URL
48365 'url' : function(v){
48366 return url.test(v);
48369 * The error text to display when the url validation function returns false
48372 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
48375 * The function used to validate alpha values
48376 * @param {String} value The value
48378 'alpha' : function(v){
48379 return alpha.test(v);
48382 * The error text to display when the alpha validation function returns false
48385 'alphaText' : 'This field should only contain letters and _',
48387 * The keystroke filter mask to be applied on alpha input
48390 'alphaMask' : /[a-z_]/i,
48393 * The function used to validate alphanumeric values
48394 * @param {String} value The value
48396 'alphanum' : function(v){
48397 return alphanum.test(v);
48400 * The error text to display when the alphanumeric validation function returns false
48403 'alphanumText' : 'This field should only contain letters, numbers and _',
48405 * The keystroke filter mask to be applied on alphanumeric input
48408 'alphanumMask' : /[a-z0-9_]/i
48410 }();//<script type="text/javascript">
48413 * @class Roo.form.FCKeditor
48414 * @extends Roo.form.TextArea
48415 * Wrapper around the FCKEditor http://www.fckeditor.net
48417 * Creates a new FCKeditor
48418 * @param {Object} config Configuration options
48420 Roo.form.FCKeditor = function(config){
48421 Roo.form.FCKeditor.superclass.constructor.call(this, config);
48424 * @event editorinit
48425 * Fired when the editor is initialized - you can add extra handlers here..
48426 * @param {FCKeditor} this
48427 * @param {Object} the FCK object.
48434 Roo.form.FCKeditor.editors = { };
48435 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
48437 //defaultAutoCreate : {
48438 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
48442 * @cfg {Object} fck options - see fck manual for details.
48447 * @cfg {Object} fck toolbar set (Basic or Default)
48449 toolbarSet : 'Basic',
48451 * @cfg {Object} fck BasePath
48453 basePath : '/fckeditor/',
48461 onRender : function(ct, position)
48464 this.defaultAutoCreate = {
48466 style:"width:300px;height:60px;",
48467 autocomplete: "new-password"
48470 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
48473 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
48474 if(this.preventScrollbars){
48475 this.el.setStyle("overflow", "hidden");
48477 this.el.setHeight(this.growMin);
48480 //console.log('onrender' + this.getId() );
48481 Roo.form.FCKeditor.editors[this.getId()] = this;
48484 this.replaceTextarea() ;
48488 getEditor : function() {
48489 return this.fckEditor;
48492 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
48493 * @param {Mixed} value The value to set
48497 setValue : function(value)
48499 //console.log('setValue: ' + value);
48501 if(typeof(value) == 'undefined') { // not sure why this is happending...
48504 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48506 //if(!this.el || !this.getEditor()) {
48507 // this.value = value;
48508 //this.setValue.defer(100,this,[value]);
48512 if(!this.getEditor()) {
48516 this.getEditor().SetData(value);
48523 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
48524 * @return {Mixed} value The field value
48526 getValue : function()
48529 if (this.frame && this.frame.dom.style.display == 'none') {
48530 return Roo.form.FCKeditor.superclass.getValue.call(this);
48533 if(!this.el || !this.getEditor()) {
48535 // this.getValue.defer(100,this);
48540 var value=this.getEditor().GetData();
48541 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
48542 return Roo.form.FCKeditor.superclass.getValue.call(this);
48548 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
48549 * @return {Mixed} value The field value
48551 getRawValue : function()
48553 if (this.frame && this.frame.dom.style.display == 'none') {
48554 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48557 if(!this.el || !this.getEditor()) {
48558 //this.getRawValue.defer(100,this);
48565 var value=this.getEditor().GetData();
48566 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
48567 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
48571 setSize : function(w,h) {
48575 //if (this.frame && this.frame.dom.style.display == 'none') {
48576 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48579 //if(!this.el || !this.getEditor()) {
48580 // this.setSize.defer(100,this, [w,h]);
48586 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
48588 this.frame.dom.setAttribute('width', w);
48589 this.frame.dom.setAttribute('height', h);
48590 this.frame.setSize(w,h);
48594 toggleSourceEdit : function(value) {
48598 this.el.dom.style.display = value ? '' : 'none';
48599 this.frame.dom.style.display = value ? 'none' : '';
48604 focus: function(tag)
48606 if (this.frame.dom.style.display == 'none') {
48607 return Roo.form.FCKeditor.superclass.focus.call(this);
48609 if(!this.el || !this.getEditor()) {
48610 this.focus.defer(100,this, [tag]);
48617 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
48618 this.getEditor().Focus();
48620 if (!this.getEditor().Selection.GetSelection()) {
48621 this.focus.defer(100,this, [tag]);
48626 var r = this.getEditor().EditorDocument.createRange();
48627 r.setStart(tgs[0],0);
48628 r.setEnd(tgs[0],0);
48629 this.getEditor().Selection.GetSelection().removeAllRanges();
48630 this.getEditor().Selection.GetSelection().addRange(r);
48631 this.getEditor().Focus();
48638 replaceTextarea : function()
48640 if ( document.getElementById( this.getId() + '___Frame' ) ) {
48643 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
48645 // We must check the elements firstly using the Id and then the name.
48646 var oTextarea = document.getElementById( this.getId() );
48648 var colElementsByName = document.getElementsByName( this.getId() ) ;
48650 oTextarea.style.display = 'none' ;
48652 if ( oTextarea.tabIndex ) {
48653 this.TabIndex = oTextarea.tabIndex ;
48656 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
48657 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
48658 this.frame = Roo.get(this.getId() + '___Frame')
48661 _getConfigHtml : function()
48665 for ( var o in this.fckconfig ) {
48666 sConfig += sConfig.length > 0 ? '&' : '';
48667 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
48670 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
48674 _getIFrameHtml : function()
48676 var sFile = 'fckeditor.html' ;
48677 /* no idea what this is about..
48680 if ( (/fcksource=true/i).test( window.top.location.search ) )
48681 sFile = 'fckeditor.original.html' ;
48686 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
48687 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
48690 var html = '<iframe id="' + this.getId() +
48691 '___Frame" src="' + sLink +
48692 '" width="' + this.width +
48693 '" height="' + this.height + '"' +
48694 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
48695 ' frameborder="0" scrolling="no"></iframe>' ;
48700 _insertHtmlBefore : function( html, element )
48702 if ( element.insertAdjacentHTML ) {
48704 element.insertAdjacentHTML( 'beforeBegin', html ) ;
48706 var oRange = document.createRange() ;
48707 oRange.setStartBefore( element ) ;
48708 var oFragment = oRange.createContextualFragment( html );
48709 element.parentNode.insertBefore( oFragment, element ) ;
48722 //Roo.reg('fckeditor', Roo.form.FCKeditor);
48724 function FCKeditor_OnComplete(editorInstance){
48725 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
48726 f.fckEditor = editorInstance;
48727 //console.log("loaded");
48728 f.fireEvent('editorinit', f, editorInstance);
48748 //<script type="text/javascript">
48750 * @class Roo.form.GridField
48751 * @extends Roo.form.Field
48752 * Embed a grid (or editable grid into a form)
48755 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
48757 * xgrid.store = Roo.data.Store
48758 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
48759 * xgrid.store.reader = Roo.data.JsonReader
48763 * Creates a new GridField
48764 * @param {Object} config Configuration options
48766 Roo.form.GridField = function(config){
48767 Roo.form.GridField.superclass.constructor.call(this, config);
48771 Roo.extend(Roo.form.GridField, Roo.form.Field, {
48773 * @cfg {Number} width - used to restrict width of grid..
48777 * @cfg {Number} height - used to restrict height of grid..
48781 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
48787 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48788 * {tag: "input", type: "checkbox", autocomplete: "off"})
48790 // defaultAutoCreate : { tag: 'div' },
48791 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
48793 * @cfg {String} addTitle Text to include for adding a title.
48797 onResize : function(){
48798 Roo.form.Field.superclass.onResize.apply(this, arguments);
48801 initEvents : function(){
48802 // Roo.form.Checkbox.superclass.initEvents.call(this);
48803 // has no events...
48808 getResizeEl : function(){
48812 getPositionEl : function(){
48817 onRender : function(ct, position){
48819 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
48820 var style = this.style;
48823 Roo.form.GridField.superclass.onRender.call(this, ct, position);
48824 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
48825 this.viewEl = this.wrap.createChild({ tag: 'div' });
48827 this.viewEl.applyStyles(style);
48830 this.viewEl.setWidth(this.width);
48833 this.viewEl.setHeight(this.height);
48835 //if(this.inputValue !== undefined){
48836 //this.setValue(this.value);
48839 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
48842 this.grid.render();
48843 this.grid.getDataSource().on('remove', this.refreshValue, this);
48844 this.grid.getDataSource().on('update', this.refreshValue, this);
48845 this.grid.on('afteredit', this.refreshValue, this);
48851 * Sets the value of the item.
48852 * @param {String} either an object or a string..
48854 setValue : function(v){
48856 v = v || []; // empty set..
48857 // this does not seem smart - it really only affects memoryproxy grids..
48858 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
48859 var ds = this.grid.getDataSource();
48860 // assumes a json reader..
48862 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
48863 ds.loadData( data);
48865 // clear selection so it does not get stale.
48866 if (this.grid.sm) {
48867 this.grid.sm.clearSelections();
48870 Roo.form.GridField.superclass.setValue.call(this, v);
48871 this.refreshValue();
48872 // should load data in the grid really....
48876 refreshValue: function() {
48878 this.grid.getDataSource().each(function(r) {
48881 this.el.dom.value = Roo.encode(val);
48889 * Ext JS Library 1.1.1
48890 * Copyright(c) 2006-2007, Ext JS, LLC.
48892 * Originally Released Under LGPL - original licence link has changed is not relivant.
48895 * <script type="text/javascript">
48898 * @class Roo.form.DisplayField
48899 * @extends Roo.form.Field
48900 * A generic Field to display non-editable data.
48901 * @cfg {Boolean} closable (true|false) default false
48903 * Creates a new Display Field item.
48904 * @param {Object} config Configuration options
48906 Roo.form.DisplayField = function(config){
48907 Roo.form.DisplayField.superclass.constructor.call(this, config);
48912 * Fires after the click the close btn
48913 * @param {Roo.form.DisplayField} this
48919 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
48920 inputType: 'hidden',
48926 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
48928 focusClass : undefined,
48930 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
48932 fieldClass: 'x-form-field',
48935 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
48937 valueRenderer: undefined,
48941 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
48942 * {tag: "input", type: "checkbox", autocomplete: "off"})
48945 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
48949 onResize : function(){
48950 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
48954 initEvents : function(){
48955 // Roo.form.Checkbox.superclass.initEvents.call(this);
48956 // has no events...
48959 this.closeEl.on('click', this.onClose, this);
48965 getResizeEl : function(){
48969 getPositionEl : function(){
48974 onRender : function(ct, position){
48976 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
48977 //if(this.inputValue !== undefined){
48978 this.wrap = this.el.wrap();
48980 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
48983 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
48986 if (this.bodyStyle) {
48987 this.viewEl.applyStyles(this.bodyStyle);
48989 //this.viewEl.setStyle('padding', '2px');
48991 this.setValue(this.value);
48996 initValue : Roo.emptyFn,
49001 onClick : function(){
49006 * Sets the checked state of the checkbox.
49007 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
49009 setValue : function(v){
49011 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
49012 // this might be called before we have a dom element..
49013 if (!this.viewEl) {
49016 this.viewEl.dom.innerHTML = html;
49017 Roo.form.DisplayField.superclass.setValue.call(this, v);
49021 onClose : function(e)
49023 e.preventDefault();
49025 this.fireEvent('close', this);
49034 * @class Roo.form.DayPicker
49035 * @extends Roo.form.Field
49036 * A Day picker show [M] [T] [W] ....
49038 * Creates a new Day Picker
49039 * @param {Object} config Configuration options
49041 Roo.form.DayPicker= function(config){
49042 Roo.form.DayPicker.superclass.constructor.call(this, config);
49046 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
49048 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
49050 focusClass : undefined,
49052 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
49054 fieldClass: "x-form-field",
49057 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
49058 * {tag: "input", type: "checkbox", autocomplete: "off"})
49060 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
49063 actionMode : 'viewEl',
49067 inputType : 'hidden',
49070 inputElement: false, // real input element?
49071 basedOn: false, // ????
49073 isFormField: true, // not sure where this is needed!!!!
49075 onResize : function(){
49076 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
49077 if(!this.boxLabel){
49078 this.el.alignTo(this.wrap, 'c-c');
49082 initEvents : function(){
49083 Roo.form.Checkbox.superclass.initEvents.call(this);
49084 this.el.on("click", this.onClick, this);
49085 this.el.on("change", this.onClick, this);
49089 getResizeEl : function(){
49093 getPositionEl : function(){
49099 onRender : function(ct, position){
49100 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
49102 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
49104 var r1 = '<table><tr>';
49105 var r2 = '<tr class="x-form-daypick-icons">';
49106 for (var i=0; i < 7; i++) {
49107 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
49108 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
49111 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
49112 viewEl.select('img').on('click', this.onClick, this);
49113 this.viewEl = viewEl;
49116 // this will not work on Chrome!!!
49117 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
49118 this.el.on('propertychange', this.setFromHidden, this); //ie
49126 initValue : Roo.emptyFn,
49129 * Returns the checked state of the checkbox.
49130 * @return {Boolean} True if checked, else false
49132 getValue : function(){
49133 return this.el.dom.value;
49138 onClick : function(e){
49139 //this.setChecked(!this.checked);
49140 Roo.get(e.target).toggleClass('x-menu-item-checked');
49141 this.refreshValue();
49142 //if(this.el.dom.checked != this.checked){
49143 // this.setValue(this.el.dom.checked);
49148 refreshValue : function()
49151 this.viewEl.select('img',true).each(function(e,i,n) {
49152 val += e.is(".x-menu-item-checked") ? String(n) : '';
49154 this.setValue(val, true);
49158 * Sets the checked state of the checkbox.
49159 * On is always based on a string comparison between inputValue and the param.
49160 * @param {Boolean/String} value - the value to set
49161 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
49163 setValue : function(v,suppressEvent){
49164 if (!this.el.dom) {
49167 var old = this.el.dom.value ;
49168 this.el.dom.value = v;
49169 if (suppressEvent) {
49173 // update display..
49174 this.viewEl.select('img',true).each(function(e,i,n) {
49176 var on = e.is(".x-menu-item-checked");
49177 var newv = v.indexOf(String(n)) > -1;
49179 e.toggleClass('x-menu-item-checked');
49185 this.fireEvent('change', this, v, old);
49190 // handle setting of hidden value by some other method!!?!?
49191 setFromHidden: function()
49196 //console.log("SET FROM HIDDEN");
49197 //alert('setFrom hidden');
49198 this.setValue(this.el.dom.value);
49201 onDestroy : function()
49204 Roo.get(this.viewEl).remove();
49207 Roo.form.DayPicker.superclass.onDestroy.call(this);
49211 * RooJS Library 1.1.1
49212 * Copyright(c) 2008-2011 Alan Knowles
49219 * @class Roo.form.ComboCheck
49220 * @extends Roo.form.ComboBox
49221 * A combobox for multiple select items.
49223 * FIXME - could do with a reset button..
49226 * Create a new ComboCheck
49227 * @param {Object} config Configuration options
49229 Roo.form.ComboCheck = function(config){
49230 Roo.form.ComboCheck.superclass.constructor.call(this, config);
49231 // should verify some data...
49233 // hiddenName = required..
49234 // displayField = required
49235 // valudField == required
49236 var req= [ 'hiddenName', 'displayField', 'valueField' ];
49238 Roo.each(req, function(e) {
49239 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
49240 throw "Roo.form.ComboCheck : missing value for: " + e;
49247 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
49252 selectedClass: 'x-menu-item-checked',
49255 onRender : function(ct, position){
49261 var cls = 'x-combo-list';
49264 this.tpl = new Roo.Template({
49265 html : '<div class="'+cls+'-item x-menu-check-item">' +
49266 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
49267 '<span>{' + this.displayField + '}</span>' +
49274 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
49275 this.view.singleSelect = false;
49276 this.view.multiSelect = true;
49277 this.view.toggleSelect = true;
49278 this.pageTb.add(new Roo.Toolbar.Fill(), {
49281 handler: function()
49288 onViewOver : function(e, t){
49294 onViewClick : function(doFocus,index){
49298 select: function () {
49299 //Roo.log("SELECT CALLED");
49302 selectByValue : function(xv, scrollIntoView){
49303 var ar = this.getValueArray();
49306 Roo.each(ar, function(v) {
49307 if(v === undefined || v === null){
49310 var r = this.findRecord(this.valueField, v);
49312 sels.push(this.store.indexOf(r))
49316 this.view.select(sels);
49322 onSelect : function(record, index){
49323 // Roo.log("onselect Called");
49324 // this is only called by the clear button now..
49325 this.view.clearSelections();
49326 this.setValue('[]');
49327 if (this.value != this.valueBefore) {
49328 this.fireEvent('change', this, this.value, this.valueBefore);
49329 this.valueBefore = this.value;
49332 getValueArray : function()
49337 //Roo.log(this.value);
49338 if (typeof(this.value) == 'undefined') {
49341 var ar = Roo.decode(this.value);
49342 return ar instanceof Array ? ar : []; //?? valid?
49345 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
49350 expand : function ()
49353 Roo.form.ComboCheck.superclass.expand.call(this);
49354 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
49355 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
49360 collapse : function(){
49361 Roo.form.ComboCheck.superclass.collapse.call(this);
49362 var sl = this.view.getSelectedIndexes();
49363 var st = this.store;
49367 Roo.each(sl, function(i) {
49369 nv.push(r.get(this.valueField));
49371 this.setValue(Roo.encode(nv));
49372 if (this.value != this.valueBefore) {
49374 this.fireEvent('change', this, this.value, this.valueBefore);
49375 this.valueBefore = this.value;
49380 setValue : function(v){
49384 var vals = this.getValueArray();
49386 Roo.each(vals, function(k) {
49387 var r = this.findRecord(this.valueField, k);
49389 tv.push(r.data[this.displayField]);
49390 }else if(this.valueNotFoundText !== undefined){
49391 tv.push( this.valueNotFoundText );
49396 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
49397 this.hiddenField.value = v;
49403 * Ext JS Library 1.1.1
49404 * Copyright(c) 2006-2007, Ext JS, LLC.
49406 * Originally Released Under LGPL - original licence link has changed is not relivant.
49409 * <script type="text/javascript">
49413 * @class Roo.form.Signature
49414 * @extends Roo.form.Field
49418 * @param {Object} config Configuration options
49421 Roo.form.Signature = function(config){
49422 Roo.form.Signature.superclass.constructor.call(this, config);
49424 this.addEvents({// not in used??
49427 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
49428 * @param {Roo.form.Signature} combo This combo box
49433 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
49434 * @param {Roo.form.ComboBox} combo This combo box
49435 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
49441 Roo.extend(Roo.form.Signature, Roo.form.Field, {
49443 * @cfg {Object} labels Label to use when rendering a form.
49447 * confirm : "Confirm"
49452 confirm : "Confirm"
49455 * @cfg {Number} width The signature panel width (defaults to 300)
49459 * @cfg {Number} height The signature panel height (defaults to 100)
49463 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
49465 allowBlank : false,
49468 // {Object} signPanel The signature SVG panel element (defaults to {})
49470 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
49471 isMouseDown : false,
49472 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
49473 isConfirmed : false,
49474 // {String} signatureTmp SVG mapping string (defaults to empty string)
49478 defaultAutoCreate : { // modified by initCompnoent..
49484 onRender : function(ct, position){
49486 Roo.form.Signature.superclass.onRender.call(this, ct, position);
49488 this.wrap = this.el.wrap({
49489 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
49492 this.createToolbar(this);
49493 this.signPanel = this.wrap.createChild({
49495 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
49499 this.svgID = Roo.id();
49500 this.svgEl = this.signPanel.createChild({
49501 xmlns : 'http://www.w3.org/2000/svg',
49503 id : this.svgID + "-svg",
49505 height: this.height,
49506 viewBox: '0 0 '+this.width+' '+this.height,
49510 id: this.svgID + "-svg-r",
49512 height: this.height,
49517 id: this.svgID + "-svg-l",
49519 y1: (this.height*0.8), // start set the line in 80% of height
49520 x2: this.width, // end
49521 y2: (this.height*0.8), // end set the line in 80% of height
49523 'stroke-width': "1",
49524 'stroke-dasharray': "3",
49525 'shape-rendering': "crispEdges",
49526 'pointer-events': "none"
49530 id: this.svgID + "-svg-p",
49532 'stroke-width': "3",
49534 'pointer-events': 'none'
49539 this.svgBox = this.svgEl.dom.getScreenCTM();
49541 createSVG : function(){
49542 var svg = this.signPanel;
49543 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
49546 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
49547 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
49548 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
49549 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
49550 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
49551 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
49552 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
49555 isTouchEvent : function(e){
49556 return e.type.match(/^touch/);
49558 getCoords : function (e) {
49559 var pt = this.svgEl.dom.createSVGPoint();
49562 if (this.isTouchEvent(e)) {
49563 pt.x = e.targetTouches[0].clientX;
49564 pt.y = e.targetTouches[0].clientY;
49566 var a = this.svgEl.dom.getScreenCTM();
49567 var b = a.inverse();
49568 var mx = pt.matrixTransform(b);
49569 return mx.x + ',' + mx.y;
49571 //mouse event headler
49572 down : function (e) {
49573 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
49574 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
49576 this.isMouseDown = true;
49578 e.preventDefault();
49580 move : function (e) {
49581 if (this.isMouseDown) {
49582 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
49583 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
49586 e.preventDefault();
49588 up : function (e) {
49589 this.isMouseDown = false;
49590 var sp = this.signatureTmp.split(' ');
49593 if(!sp[sp.length-2].match(/^L/)){
49597 this.signatureTmp = sp.join(" ");
49600 if(this.getValue() != this.signatureTmp){
49601 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49602 this.isConfirmed = false;
49604 e.preventDefault();
49608 * Protected method that will not generally be called directly. It
49609 * is called when the editor creates its toolbar. Override this method if you need to
49610 * add custom toolbar buttons.
49611 * @param {HtmlEditor} editor
49613 createToolbar : function(editor){
49614 function btn(id, toggle, handler){
49615 var xid = fid + '-'+ id ;
49619 cls : 'x-btn-icon x-edit-'+id,
49620 enableToggle:toggle !== false,
49621 scope: editor, // was editor...
49622 handler:handler||editor.relayBtnCmd,
49623 clickEvent:'mousedown',
49624 tooltip: etb.buttonTips[id] || undefined, ///tips ???
49630 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
49634 cls : ' x-signature-btn x-signature-'+id,
49635 scope: editor, // was editor...
49636 handler: this.reset,
49637 clickEvent:'mousedown',
49638 text: this.labels.clear
49645 cls : ' x-signature-btn x-signature-'+id,
49646 scope: editor, // was editor...
49647 handler: this.confirmHandler,
49648 clickEvent:'mousedown',
49649 text: this.labels.confirm
49656 * when user is clicked confirm then show this image.....
49658 * @return {String} Image Data URI
49660 getImageDataURI : function(){
49661 var svg = this.svgEl.dom.parentNode.innerHTML;
49662 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
49667 * @return {Boolean} this.isConfirmed
49669 getConfirmed : function(){
49670 return this.isConfirmed;
49674 * @return {Number} this.width
49676 getWidth : function(){
49681 * @return {Number} this.height
49683 getHeight : function(){
49684 return this.height;
49687 getSignature : function(){
49688 return this.signatureTmp;
49691 reset : function(){
49692 this.signatureTmp = '';
49693 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49694 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
49695 this.isConfirmed = false;
49696 Roo.form.Signature.superclass.reset.call(this);
49698 setSignature : function(s){
49699 this.signatureTmp = s;
49700 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
49701 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
49703 this.isConfirmed = false;
49704 Roo.form.Signature.superclass.reset.call(this);
49707 // Roo.log(this.signPanel.dom.contentWindow.up())
49710 setConfirmed : function(){
49714 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
49717 confirmHandler : function(){
49718 if(!this.getSignature()){
49722 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
49723 this.setValue(this.getSignature());
49724 this.isConfirmed = true;
49726 this.fireEvent('confirm', this);
49729 // Subclasses should provide the validation implementation by overriding this
49730 validateValue : function(value){
49731 if(this.allowBlank){
49735 if(this.isConfirmed){
49742 * Ext JS Library 1.1.1
49743 * Copyright(c) 2006-2007, Ext JS, LLC.
49745 * Originally Released Under LGPL - original licence link has changed is not relivant.
49748 * <script type="text/javascript">
49753 * @class Roo.form.ComboBox
49754 * @extends Roo.form.TriggerField
49755 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
49757 * Create a new ComboBox.
49758 * @param {Object} config Configuration options
49760 Roo.form.Select = function(config){
49761 Roo.form.Select.superclass.constructor.call(this, config);
49765 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
49767 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
49770 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
49771 * rendering into an Roo.Editor, defaults to false)
49774 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
49775 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
49778 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
49781 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
49782 * the dropdown list (defaults to undefined, with no header element)
49786 * @cfg {String/Roo.Template} tpl The template to use to render the output
49790 defaultAutoCreate : {tag: "select" },
49792 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
49794 listWidth: undefined,
49796 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
49797 * mode = 'remote' or 'text' if mode = 'local')
49799 displayField: undefined,
49801 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
49802 * mode = 'remote' or 'value' if mode = 'local').
49803 * Note: use of a valueField requires the user make a selection
49804 * in order for a value to be mapped.
49806 valueField: undefined,
49810 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
49811 * field's data value (defaults to the underlying DOM element's name)
49813 hiddenName: undefined,
49815 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
49819 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
49821 selectedClass: 'x-combo-selected',
49823 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
49824 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
49825 * which displays a downward arrow icon).
49827 triggerClass : 'x-form-arrow-trigger',
49829 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
49833 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
49834 * anchor positions (defaults to 'tl-bl')
49836 listAlign: 'tl-bl?',
49838 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
49842 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
49843 * query specified by the allQuery config option (defaults to 'query')
49845 triggerAction: 'query',
49847 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
49848 * (defaults to 4, does not apply if editable = false)
49852 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
49853 * delay (typeAheadDelay) if it matches a known value (defaults to false)
49857 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
49858 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
49862 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
49863 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
49867 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
49868 * when editable = true (defaults to false)
49870 selectOnFocus:false,
49872 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
49874 queryParam: 'query',
49876 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
49877 * when mode = 'remote' (defaults to 'Loading...')
49879 loadingText: 'Loading...',
49881 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
49885 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
49889 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
49890 * traditional select (defaults to true)
49894 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
49898 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
49902 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
49903 * listWidth has a higher value)
49907 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
49908 * allow the user to set arbitrary text into the field (defaults to false)
49910 forceSelection:false,
49912 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
49913 * if typeAhead = true (defaults to 250)
49915 typeAheadDelay : 250,
49917 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
49918 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
49920 valueNotFoundText : undefined,
49923 * @cfg {String} defaultValue The value displayed after loading the store.
49928 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
49930 blockFocus : false,
49933 * @cfg {Boolean} disableClear Disable showing of clear button.
49935 disableClear : false,
49937 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
49939 alwaysQuery : false,
49945 // element that contains real text value.. (when hidden is used..)
49948 onRender : function(ct, position){
49949 Roo.form.Field.prototype.onRender.call(this, ct, position);
49952 this.store.on('beforeload', this.onBeforeLoad, this);
49953 this.store.on('load', this.onLoad, this);
49954 this.store.on('loadexception', this.onLoadException, this);
49955 this.store.load({});
49963 initEvents : function(){
49964 //Roo.form.ComboBox.superclass.initEvents.call(this);
49968 onDestroy : function(){
49971 this.store.un('beforeload', this.onBeforeLoad, this);
49972 this.store.un('load', this.onLoad, this);
49973 this.store.un('loadexception', this.onLoadException, this);
49975 //Roo.form.ComboBox.superclass.onDestroy.call(this);
49979 fireKey : function(e){
49980 if(e.isNavKeyPress() && !this.list.isVisible()){
49981 this.fireEvent("specialkey", this, e);
49986 onResize: function(w, h){
49994 * Allow or prevent the user from directly editing the field text. If false is passed,
49995 * the user will only be able to select from the items defined in the dropdown list. This method
49996 * is the runtime equivalent of setting the 'editable' config option at config time.
49997 * @param {Boolean} value True to allow the user to directly edit the field text
49999 setEditable : function(value){
50004 onBeforeLoad : function(){
50006 Roo.log("Select before load");
50009 this.innerList.update(this.loadingText ?
50010 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
50011 //this.restrictHeight();
50012 this.selectedIndex = -1;
50016 onLoad : function(){
50019 var dom = this.el.dom;
50020 dom.innerHTML = '';
50021 var od = dom.ownerDocument;
50023 if (this.emptyText) {
50024 var op = od.createElement('option');
50025 op.setAttribute('value', '');
50026 op.innerHTML = String.format('{0}', this.emptyText);
50027 dom.appendChild(op);
50029 if(this.store.getCount() > 0){
50031 var vf = this.valueField;
50032 var df = this.displayField;
50033 this.store.data.each(function(r) {
50034 // which colmsn to use... testing - cdoe / title..
50035 var op = od.createElement('option');
50036 op.setAttribute('value', r.data[vf]);
50037 op.innerHTML = String.format('{0}', r.data[df]);
50038 dom.appendChild(op);
50040 if (typeof(this.defaultValue != 'undefined')) {
50041 this.setValue(this.defaultValue);
50046 //this.onEmptyResults();
50051 onLoadException : function()
50053 dom.innerHTML = '';
50055 Roo.log("Select on load exception");
50059 Roo.log(this.store.reader.jsonData);
50060 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
50061 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
50067 onTypeAhead : function(){
50072 onSelect : function(record, index){
50073 Roo.log('on select?');
50075 if(this.fireEvent('beforeselect', this, record, index) !== false){
50076 this.setFromData(index > -1 ? record.data : false);
50078 this.fireEvent('select', this, record, index);
50083 * Returns the currently selected field value or empty string if no value is set.
50084 * @return {String} value The selected value
50086 getValue : function(){
50087 var dom = this.el.dom;
50088 this.value = dom.options[dom.selectedIndex].value;
50094 * Clears any text/value currently set in the field
50096 clearValue : function(){
50098 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
50103 * Sets the specified value into the field. If the value finds a match, the corresponding record text
50104 * will be displayed in the field. If the value does not match the data value of an existing item,
50105 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
50106 * Otherwise the field will be blank (although the value will still be set).
50107 * @param {String} value The value to match
50109 setValue : function(v){
50110 var d = this.el.dom;
50111 for (var i =0; i < d.options.length;i++) {
50112 if (v == d.options[i].value) {
50113 d.selectedIndex = i;
50121 * @property {Object} the last set data for the element
50126 * Sets the value of the field based on a object which is related to the record format for the store.
50127 * @param {Object} value the value to set as. or false on reset?
50129 setFromData : function(o){
50130 Roo.log('setfrom data?');
50136 reset : function(){
50140 findRecord : function(prop, value){
50145 if(this.store.getCount() > 0){
50146 this.store.each(function(r){
50147 if(r.data[prop] == value){
50157 getName: function()
50159 // returns hidden if it's set..
50160 if (!this.rendered) {return ''};
50161 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
50169 onEmptyResults : function(){
50170 Roo.log('empty results');
50175 * Returns true if the dropdown list is expanded, else false.
50177 isExpanded : function(){
50182 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
50183 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50184 * @param {String} value The data value of the item to select
50185 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50186 * selected item if it is not currently in view (defaults to true)
50187 * @return {Boolean} True if the value matched an item in the list, else false
50189 selectByValue : function(v, scrollIntoView){
50190 Roo.log('select By Value');
50193 if(v !== undefined && v !== null){
50194 var r = this.findRecord(this.valueField || this.displayField, v);
50196 this.select(this.store.indexOf(r), scrollIntoView);
50204 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
50205 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
50206 * @param {Number} index The zero-based index of the list item to select
50207 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
50208 * selected item if it is not currently in view (defaults to true)
50210 select : function(index, scrollIntoView){
50211 Roo.log('select ');
50214 this.selectedIndex = index;
50215 this.view.select(index);
50216 if(scrollIntoView !== false){
50217 var el = this.view.getNode(index);
50219 this.innerList.scrollChildIntoView(el, false);
50227 validateBlur : function(){
50234 initQuery : function(){
50235 this.doQuery(this.getRawValue());
50239 doForce : function(){
50240 if(this.el.dom.value.length > 0){
50241 this.el.dom.value =
50242 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
50248 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
50249 * query allowing the query action to be canceled if needed.
50250 * @param {String} query The SQL query to execute
50251 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
50252 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
50253 * saved in the current store (defaults to false)
50255 doQuery : function(q, forceAll){
50257 Roo.log('doQuery?');
50258 if(q === undefined || q === null){
50263 forceAll: forceAll,
50267 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
50271 forceAll = qe.forceAll;
50272 if(forceAll === true || (q.length >= this.minChars)){
50273 if(this.lastQuery != q || this.alwaysQuery){
50274 this.lastQuery = q;
50275 if(this.mode == 'local'){
50276 this.selectedIndex = -1;
50278 this.store.clearFilter();
50280 this.store.filter(this.displayField, q);
50284 this.store.baseParams[this.queryParam] = q;
50286 params: this.getParams(q)
50291 this.selectedIndex = -1;
50298 getParams : function(q){
50300 //p[this.queryParam] = q;
50303 p.limit = this.pageSize;
50309 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
50311 collapse : function(){
50316 collapseIf : function(e){
50321 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
50323 expand : function(){
50331 * @cfg {Boolean} grow
50335 * @cfg {Number} growMin
50339 * @cfg {Number} growMax
50347 setWidth : function()
50351 getResizeEl : function(){
50354 });//<script type="text/javasscript">
50358 * @class Roo.DDView
50359 * A DnD enabled version of Roo.View.
50360 * @param {Element/String} container The Element in which to create the View.
50361 * @param {String} tpl The template string used to create the markup for each element of the View
50362 * @param {Object} config The configuration properties. These include all the config options of
50363 * {@link Roo.View} plus some specific to this class.<br>
50365 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
50366 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
50368 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
50369 .x-view-drag-insert-above {
50370 border-top:1px dotted #3366cc;
50372 .x-view-drag-insert-below {
50373 border-bottom:1px dotted #3366cc;
50379 Roo.DDView = function(container, tpl, config) {
50380 Roo.DDView.superclass.constructor.apply(this, arguments);
50381 this.getEl().setStyle("outline", "0px none");
50382 this.getEl().unselectable();
50383 if (this.dragGroup) {
50384 this.setDraggable(this.dragGroup.split(","));
50386 if (this.dropGroup) {
50387 this.setDroppable(this.dropGroup.split(","));
50389 if (this.deletable) {
50390 this.setDeletable();
50392 this.isDirtyFlag = false;
50398 Roo.extend(Roo.DDView, Roo.View, {
50399 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
50400 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
50401 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
50402 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
50406 reset: Roo.emptyFn,
50408 clearInvalid: Roo.form.Field.prototype.clearInvalid,
50410 validate: function() {
50414 destroy: function() {
50415 this.purgeListeners();
50416 this.getEl.removeAllListeners();
50417 this.getEl().remove();
50418 if (this.dragZone) {
50419 if (this.dragZone.destroy) {
50420 this.dragZone.destroy();
50423 if (this.dropZone) {
50424 if (this.dropZone.destroy) {
50425 this.dropZone.destroy();
50430 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
50431 getName: function() {
50435 /** Loads the View from a JSON string representing the Records to put into the Store. */
50436 setValue: function(v) {
50438 throw "DDView.setValue(). DDView must be constructed with a valid Store";
50441 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
50442 this.store.proxy = new Roo.data.MemoryProxy(data);
50446 /** @return {String} a parenthesised list of the ids of the Records in the View. */
50447 getValue: function() {
50449 this.store.each(function(rec) {
50450 result += rec.id + ',';
50452 return result.substr(0, result.length - 1) + ')';
50455 getIds: function() {
50456 var i = 0, result = new Array(this.store.getCount());
50457 this.store.each(function(rec) {
50458 result[i++] = rec.id;
50463 isDirty: function() {
50464 return this.isDirtyFlag;
50468 * Part of the Roo.dd.DropZone interface. If no target node is found, the
50469 * whole Element becomes the target, and this causes the drop gesture to append.
50471 getTargetFromEvent : function(e) {
50472 var target = e.getTarget();
50473 while ((target !== null) && (target.parentNode != this.el.dom)) {
50474 target = target.parentNode;
50477 target = this.el.dom.lastChild || this.el.dom;
50483 * Create the drag data which consists of an object which has the property "ddel" as
50484 * the drag proxy element.
50486 getDragData : function(e) {
50487 var target = this.findItemFromChild(e.getTarget());
50489 this.handleSelection(e);
50490 var selNodes = this.getSelectedNodes();
50493 copy: this.copy || (this.allowCopy && e.ctrlKey),
50497 var selectedIndices = this.getSelectedIndexes();
50498 for (var i = 0; i < selectedIndices.length; i++) {
50499 dragData.records.push(this.store.getAt(selectedIndices[i]));
50501 if (selNodes.length == 1) {
50502 dragData.ddel = target.cloneNode(true); // the div element
50504 var div = document.createElement('div'); // create the multi element drag "ghost"
50505 div.className = 'multi-proxy';
50506 for (var i = 0, len = selNodes.length; i < len; i++) {
50507 div.appendChild(selNodes[i].cloneNode(true));
50509 dragData.ddel = div;
50511 //console.log(dragData)
50512 //console.log(dragData.ddel.innerHTML)
50515 //console.log('nodragData')
50519 /** Specify to which ddGroup items in this DDView may be dragged. */
50520 setDraggable: function(ddGroup) {
50521 if (ddGroup instanceof Array) {
50522 Roo.each(ddGroup, this.setDraggable, this);
50525 if (this.dragZone) {
50526 this.dragZone.addToGroup(ddGroup);
50528 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
50529 containerScroll: true,
50533 // Draggability implies selection. DragZone's mousedown selects the element.
50534 if (!this.multiSelect) { this.singleSelect = true; }
50536 // Wire the DragZone's handlers up to methods in *this*
50537 this.dragZone.getDragData = this.getDragData.createDelegate(this);
50541 /** Specify from which ddGroup this DDView accepts drops. */
50542 setDroppable: function(ddGroup) {
50543 if (ddGroup instanceof Array) {
50544 Roo.each(ddGroup, this.setDroppable, this);
50547 if (this.dropZone) {
50548 this.dropZone.addToGroup(ddGroup);
50550 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
50551 containerScroll: true,
50555 // Wire the DropZone's handlers up to methods in *this*
50556 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
50557 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
50558 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
50559 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
50560 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
50564 /** Decide whether to drop above or below a View node. */
50565 getDropPoint : function(e, n, dd){
50566 if (n == this.el.dom) { return "above"; }
50567 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
50568 var c = t + (b - t) / 2;
50569 var y = Roo.lib.Event.getPageY(e);
50577 onNodeEnter : function(n, dd, e, data){
50581 onNodeOver : function(n, dd, e, data){
50582 var pt = this.getDropPoint(e, n, dd);
50583 // set the insert point style on the target node
50584 var dragElClass = this.dropNotAllowed;
50587 if (pt == "above"){
50588 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
50589 targetElClass = "x-view-drag-insert-above";
50591 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
50592 targetElClass = "x-view-drag-insert-below";
50594 if (this.lastInsertClass != targetElClass){
50595 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
50596 this.lastInsertClass = targetElClass;
50599 return dragElClass;
50602 onNodeOut : function(n, dd, e, data){
50603 this.removeDropIndicators(n);
50606 onNodeDrop : function(n, dd, e, data){
50607 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
50610 var pt = this.getDropPoint(e, n, dd);
50611 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
50612 if (pt == "below") { insertAt++; }
50613 for (var i = 0; i < data.records.length; i++) {
50614 var r = data.records[i];
50615 var dup = this.store.getById(r.id);
50616 if (dup && (dd != this.dragZone)) {
50617 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
50620 this.store.insert(insertAt++, r.copy());
50622 data.source.isDirtyFlag = true;
50624 this.store.insert(insertAt++, r);
50626 this.isDirtyFlag = true;
50629 this.dragZone.cachedTarget = null;
50633 removeDropIndicators : function(n){
50635 Roo.fly(n).removeClass([
50636 "x-view-drag-insert-above",
50637 "x-view-drag-insert-below"]);
50638 this.lastInsertClass = "_noclass";
50643 * Utility method. Add a delete option to the DDView's context menu.
50644 * @param {String} imageUrl The URL of the "delete" icon image.
50646 setDeletable: function(imageUrl) {
50647 if (!this.singleSelect && !this.multiSelect) {
50648 this.singleSelect = true;
50650 var c = this.getContextMenu();
50651 this.contextMenu.on("itemclick", function(item) {
50654 this.remove(this.getSelectedIndexes());
50658 this.contextMenu.add({
50665 /** Return the context menu for this DDView. */
50666 getContextMenu: function() {
50667 if (!this.contextMenu) {
50668 // Create the View's context menu
50669 this.contextMenu = new Roo.menu.Menu({
50670 id: this.id + "-contextmenu"
50672 this.el.on("contextmenu", this.showContextMenu, this);
50674 return this.contextMenu;
50677 disableContextMenu: function() {
50678 if (this.contextMenu) {
50679 this.el.un("contextmenu", this.showContextMenu, this);
50683 showContextMenu: function(e, item) {
50684 item = this.findItemFromChild(e.getTarget());
50687 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
50688 this.contextMenu.showAt(e.getXY());
50693 * Remove {@link Roo.data.Record}s at the specified indices.
50694 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
50696 remove: function(selectedIndices) {
50697 selectedIndices = [].concat(selectedIndices);
50698 for (var i = 0; i < selectedIndices.length; i++) {
50699 var rec = this.store.getAt(selectedIndices[i]);
50700 this.store.remove(rec);
50705 * Double click fires the event, but also, if this is draggable, and there is only one other
50706 * related DropZone, it transfers the selected node.
50708 onDblClick : function(e){
50709 var item = this.findItemFromChild(e.getTarget());
50711 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
50714 if (this.dragGroup) {
50715 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
50716 while (targets.indexOf(this.dropZone) > -1) {
50717 targets.remove(this.dropZone);
50719 if (targets.length == 1) {
50720 this.dragZone.cachedTarget = null;
50721 var el = Roo.get(targets[0].getEl());
50722 var box = el.getBox(true);
50723 targets[0].onNodeDrop(el.dom, {
50725 xy: [box.x, box.y + box.height - 1]
50726 }, null, this.getDragData(e));
50732 handleSelection: function(e) {
50733 this.dragZone.cachedTarget = null;
50734 var item = this.findItemFromChild(e.getTarget());
50736 this.clearSelections(true);
50739 if (item && (this.multiSelect || this.singleSelect)){
50740 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
50741 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
50742 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
50743 this.unselect(item);
50745 this.select(item, this.multiSelect && e.ctrlKey);
50746 this.lastSelection = item;
50751 onItemClick : function(item, index, e){
50752 if(this.fireEvent("beforeclick", this, index, item, e) === false){
50758 unselect : function(nodeInfo, suppressEvent){
50759 var node = this.getNode(nodeInfo);
50760 if(node && this.isSelected(node)){
50761 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
50762 Roo.fly(node).removeClass(this.selectedClass);
50763 this.selections.remove(node);
50764 if(!suppressEvent){
50765 this.fireEvent("selectionchange", this, this.selections);
50773 * Ext JS Library 1.1.1
50774 * Copyright(c) 2006-2007, Ext JS, LLC.
50776 * Originally Released Under LGPL - original licence link has changed is not relivant.
50779 * <script type="text/javascript">
50783 * @class Roo.LayoutManager
50784 * @extends Roo.util.Observable
50785 * Base class for layout managers.
50787 Roo.LayoutManager = function(container, config){
50788 Roo.LayoutManager.superclass.constructor.call(this);
50789 this.el = Roo.get(container);
50790 // ie scrollbar fix
50791 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
50792 document.body.scroll = "no";
50793 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
50794 this.el.position('relative');
50796 this.id = this.el.id;
50797 this.el.addClass("x-layout-container");
50798 /** false to disable window resize monitoring @type Boolean */
50799 this.monitorWindowResize = true;
50804 * Fires when a layout is performed.
50805 * @param {Roo.LayoutManager} this
50809 * @event regionresized
50810 * Fires when the user resizes a region.
50811 * @param {Roo.LayoutRegion} region The resized region
50812 * @param {Number} newSize The new size (width for east/west, height for north/south)
50814 "regionresized" : true,
50816 * @event regioncollapsed
50817 * Fires when a region is collapsed.
50818 * @param {Roo.LayoutRegion} region The collapsed region
50820 "regioncollapsed" : true,
50822 * @event regionexpanded
50823 * Fires when a region is expanded.
50824 * @param {Roo.LayoutRegion} region The expanded region
50826 "regionexpanded" : true
50828 this.updating = false;
50829 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
50832 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
50834 * Returns true if this layout is currently being updated
50835 * @return {Boolean}
50837 isUpdating : function(){
50838 return this.updating;
50842 * Suspend the LayoutManager from doing auto-layouts while
50843 * making multiple add or remove calls
50845 beginUpdate : function(){
50846 this.updating = true;
50850 * Restore auto-layouts and optionally disable the manager from performing a layout
50851 * @param {Boolean} noLayout true to disable a layout update
50853 endUpdate : function(noLayout){
50854 this.updating = false;
50860 layout: function(){
50864 onRegionResized : function(region, newSize){
50865 this.fireEvent("regionresized", region, newSize);
50869 onRegionCollapsed : function(region){
50870 this.fireEvent("regioncollapsed", region);
50873 onRegionExpanded : function(region){
50874 this.fireEvent("regionexpanded", region);
50878 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
50879 * performs box-model adjustments.
50880 * @return {Object} The size as an object {width: (the width), height: (the height)}
50882 getViewSize : function(){
50884 if(this.el.dom != document.body){
50885 size = this.el.getSize();
50887 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
50889 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
50890 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
50895 * Returns the Element this layout is bound to.
50896 * @return {Roo.Element}
50898 getEl : function(){
50903 * Returns the specified region.
50904 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
50905 * @return {Roo.LayoutRegion}
50907 getRegion : function(target){
50908 return this.regions[target.toLowerCase()];
50911 onWindowResize : function(){
50912 if(this.monitorWindowResize){
50918 * Ext JS Library 1.1.1
50919 * Copyright(c) 2006-2007, Ext JS, LLC.
50921 * Originally Released Under LGPL - original licence link has changed is not relivant.
50924 * <script type="text/javascript">
50927 * @class Roo.BorderLayout
50928 * @extends Roo.LayoutManager
50929 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
50930 * please see: <br><br>
50931 * <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>
50932 * <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>
50935 var layout = new Roo.BorderLayout(document.body, {
50969 preferredTabWidth: 150
50974 var CP = Roo.ContentPanel;
50976 layout.beginUpdate();
50977 layout.add("north", new CP("north", "North"));
50978 layout.add("south", new CP("south", {title: "South", closable: true}));
50979 layout.add("west", new CP("west", {title: "West"}));
50980 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
50981 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
50982 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
50983 layout.getRegion("center").showPanel("center1");
50984 layout.endUpdate();
50987 <b>The container the layout is rendered into can be either the body element or any other element.
50988 If it is not the body element, the container needs to either be an absolute positioned element,
50989 or you will need to add "position:relative" to the css of the container. You will also need to specify
50990 the container size if it is not the body element.</b>
50993 * Create a new BorderLayout
50994 * @param {String/HTMLElement/Element} container The container this layout is bound to
50995 * @param {Object} config Configuration options
50997 Roo.BorderLayout = function(container, config){
50998 config = config || {};
50999 Roo.BorderLayout.superclass.constructor.call(this, container, config);
51000 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
51001 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
51002 var target = this.factory.validRegions[i];
51003 if(config[target]){
51004 this.addRegion(target, config[target]);
51009 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
51011 * Creates and adds a new region if it doesn't already exist.
51012 * @param {String} target The target region key (north, south, east, west or center).
51013 * @param {Object} config The regions config object
51014 * @return {BorderLayoutRegion} The new region
51016 addRegion : function(target, config){
51017 if(!this.regions[target]){
51018 var r = this.factory.create(target, this, config);
51019 this.bindRegion(target, r);
51021 return this.regions[target];
51025 bindRegion : function(name, r){
51026 this.regions[name] = r;
51027 r.on("visibilitychange", this.layout, this);
51028 r.on("paneladded", this.layout, this);
51029 r.on("panelremoved", this.layout, this);
51030 r.on("invalidated", this.layout, this);
51031 r.on("resized", this.onRegionResized, this);
51032 r.on("collapsed", this.onRegionCollapsed, this);
51033 r.on("expanded", this.onRegionExpanded, this);
51037 * Performs a layout update.
51039 layout : function(){
51040 if(this.updating) {
51043 var size = this.getViewSize();
51044 var w = size.width;
51045 var h = size.height;
51050 //var x = 0, y = 0;
51052 var rs = this.regions;
51053 var north = rs["north"];
51054 var south = rs["south"];
51055 var west = rs["west"];
51056 var east = rs["east"];
51057 var center = rs["center"];
51058 //if(this.hideOnLayout){ // not supported anymore
51059 //c.el.setStyle("display", "none");
51061 if(north && north.isVisible()){
51062 var b = north.getBox();
51063 var m = north.getMargins();
51064 b.width = w - (m.left+m.right);
51067 centerY = b.height + b.y + m.bottom;
51068 centerH -= centerY;
51069 north.updateBox(this.safeBox(b));
51071 if(south && south.isVisible()){
51072 var b = south.getBox();
51073 var m = south.getMargins();
51074 b.width = w - (m.left+m.right);
51076 var totalHeight = (b.height + m.top + m.bottom);
51077 b.y = h - totalHeight + m.top;
51078 centerH -= totalHeight;
51079 south.updateBox(this.safeBox(b));
51081 if(west && west.isVisible()){
51082 var b = west.getBox();
51083 var m = west.getMargins();
51084 b.height = centerH - (m.top+m.bottom);
51086 b.y = centerY + m.top;
51087 var totalWidth = (b.width + m.left + m.right);
51088 centerX += totalWidth;
51089 centerW -= totalWidth;
51090 west.updateBox(this.safeBox(b));
51092 if(east && east.isVisible()){
51093 var b = east.getBox();
51094 var m = east.getMargins();
51095 b.height = centerH - (m.top+m.bottom);
51096 var totalWidth = (b.width + m.left + m.right);
51097 b.x = w - totalWidth + m.left;
51098 b.y = centerY + m.top;
51099 centerW -= totalWidth;
51100 east.updateBox(this.safeBox(b));
51103 var m = center.getMargins();
51105 x: centerX + m.left,
51106 y: centerY + m.top,
51107 width: centerW - (m.left+m.right),
51108 height: centerH - (m.top+m.bottom)
51110 //if(this.hideOnLayout){
51111 //center.el.setStyle("display", "block");
51113 center.updateBox(this.safeBox(centerBox));
51116 this.fireEvent("layout", this);
51120 safeBox : function(box){
51121 box.width = Math.max(0, box.width);
51122 box.height = Math.max(0, box.height);
51127 * Adds a ContentPanel (or subclass) to this layout.
51128 * @param {String} target The target region key (north, south, east, west or center).
51129 * @param {Roo.ContentPanel} panel The panel to add
51130 * @return {Roo.ContentPanel} The added panel
51132 add : function(target, panel){
51134 target = target.toLowerCase();
51135 return this.regions[target].add(panel);
51139 * Remove a ContentPanel (or subclass) to this layout.
51140 * @param {String} target The target region key (north, south, east, west or center).
51141 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
51142 * @return {Roo.ContentPanel} The removed panel
51144 remove : function(target, panel){
51145 target = target.toLowerCase();
51146 return this.regions[target].remove(panel);
51150 * Searches all regions for a panel with the specified id
51151 * @param {String} panelId
51152 * @return {Roo.ContentPanel} The panel or null if it wasn't found
51154 findPanel : function(panelId){
51155 var rs = this.regions;
51156 for(var target in rs){
51157 if(typeof rs[target] != "function"){
51158 var p = rs[target].getPanel(panelId);
51168 * Searches all regions for a panel with the specified id and activates (shows) it.
51169 * @param {String/ContentPanel} panelId The panels id or the panel itself
51170 * @return {Roo.ContentPanel} The shown panel or null
51172 showPanel : function(panelId) {
51173 var rs = this.regions;
51174 for(var target in rs){
51175 var r = rs[target];
51176 if(typeof r != "function"){
51177 if(r.hasPanel(panelId)){
51178 return r.showPanel(panelId);
51186 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
51187 * @param {Roo.state.Provider} provider (optional) An alternate state provider
51189 restoreState : function(provider){
51191 provider = Roo.state.Manager;
51193 var sm = new Roo.LayoutStateManager();
51194 sm.init(this, provider);
51198 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
51199 * object should contain properties for each region to add ContentPanels to, and each property's value should be
51200 * a valid ContentPanel config object. Example:
51202 // Create the main layout
51203 var layout = new Roo.BorderLayout('main-ct', {
51214 // Create and add multiple ContentPanels at once via configs
51217 id: 'source-files',
51219 title:'Ext Source Files',
51232 * @param {Object} regions An object containing ContentPanel configs by region name
51234 batchAdd : function(regions){
51235 this.beginUpdate();
51236 for(var rname in regions){
51237 var lr = this.regions[rname];
51239 this.addTypedPanels(lr, regions[rname]);
51246 addTypedPanels : function(lr, ps){
51247 if(typeof ps == 'string'){
51248 lr.add(new Roo.ContentPanel(ps));
51250 else if(ps instanceof Array){
51251 for(var i =0, len = ps.length; i < len; i++){
51252 this.addTypedPanels(lr, ps[i]);
51255 else if(!ps.events){ // raw config?
51257 delete ps.el; // prevent conflict
51258 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
51260 else { // panel object assumed!
51265 * Adds a xtype elements to the layout.
51269 xtype : 'ContentPanel',
51276 xtype : 'NestedLayoutPanel',
51282 items : [ ... list of content panels or nested layout panels.. ]
51286 * @param {Object} cfg Xtype definition of item to add.
51288 addxtype : function(cfg)
51290 // basically accepts a pannel...
51291 // can accept a layout region..!?!?
51292 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
51294 if (!cfg.xtype.match(/Panel$/)) {
51299 if (typeof(cfg.region) == 'undefined') {
51300 Roo.log("Failed to add Panel, region was not set");
51304 var region = cfg.region;
51310 xitems = cfg.items;
51317 case 'ContentPanel': // ContentPanel (el, cfg)
51318 case 'ScrollPanel': // ContentPanel (el, cfg)
51320 if(cfg.autoCreate) {
51321 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51323 var el = this.el.createChild();
51324 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
51327 this.add(region, ret);
51331 case 'TreePanel': // our new panel!
51332 cfg.el = this.el.createChild();
51333 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51334 this.add(region, ret);
51337 case 'NestedLayoutPanel':
51338 // create a new Layout (which is a Border Layout...
51339 var el = this.el.createChild();
51340 var clayout = cfg.layout;
51342 clayout.items = clayout.items || [];
51343 // replace this exitems with the clayout ones..
51344 xitems = clayout.items;
51347 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
51348 cfg.background = false;
51350 var layout = new Roo.BorderLayout(el, clayout);
51352 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
51353 //console.log('adding nested layout panel ' + cfg.toSource());
51354 this.add(region, ret);
51355 nb = {}; /// find first...
51360 // needs grid and region
51362 //var el = this.getRegion(region).el.createChild();
51363 var el = this.el.createChild();
51364 // create the grid first...
51366 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
51368 if (region == 'center' && this.active ) {
51369 cfg.background = false;
51371 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
51373 this.add(region, ret);
51374 if (cfg.background) {
51375 ret.on('activate', function(gp) {
51376 if (!gp.grid.rendered) {
51391 if (typeof(Roo[cfg.xtype]) != 'undefined') {
51393 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
51394 this.add(region, ret);
51397 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
51401 // GridPanel (grid, cfg)
51404 this.beginUpdate();
51408 Roo.each(xitems, function(i) {
51409 region = nb && i.region ? i.region : false;
51411 var add = ret.addxtype(i);
51414 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
51415 if (!i.background) {
51416 abn[region] = nb[region] ;
51423 // make the last non-background panel active..
51424 //if (nb) { Roo.log(abn); }
51427 for(var r in abn) {
51428 region = this.getRegion(r);
51430 // tried using nb[r], but it does not work..
51432 region.showPanel(abn[r]);
51443 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
51444 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
51445 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
51446 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
51449 var CP = Roo.ContentPanel;
51451 var layout = Roo.BorderLayout.create({
51455 panels: [new CP("north", "North")]
51464 panels: [new CP("west", {title: "West"})]
51473 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
51482 panels: [new CP("south", {title: "South", closable: true})]
51489 preferredTabWidth: 150,
51491 new CP("center1", {title: "Close Me", closable: true}),
51492 new CP("center2", {title: "Center Panel", closable: false})
51497 layout.getRegion("center").showPanel("center1");
51502 Roo.BorderLayout.create = function(config, targetEl){
51503 var layout = new Roo.BorderLayout(targetEl || document.body, config);
51504 layout.beginUpdate();
51505 var regions = Roo.BorderLayout.RegionFactory.validRegions;
51506 for(var j = 0, jlen = regions.length; j < jlen; j++){
51507 var lr = regions[j];
51508 if(layout.regions[lr] && config[lr].panels){
51509 var r = layout.regions[lr];
51510 var ps = config[lr].panels;
51511 layout.addTypedPanels(r, ps);
51514 layout.endUpdate();
51519 Roo.BorderLayout.RegionFactory = {
51521 validRegions : ["north","south","east","west","center"],
51524 create : function(target, mgr, config){
51525 target = target.toLowerCase();
51526 if(config.lightweight || config.basic){
51527 return new Roo.BasicLayoutRegion(mgr, config, target);
51531 return new Roo.NorthLayoutRegion(mgr, config);
51533 return new Roo.SouthLayoutRegion(mgr, config);
51535 return new Roo.EastLayoutRegion(mgr, config);
51537 return new Roo.WestLayoutRegion(mgr, config);
51539 return new Roo.CenterLayoutRegion(mgr, config);
51541 throw 'Layout region "'+target+'" not supported.';
51545 * Ext JS Library 1.1.1
51546 * Copyright(c) 2006-2007, Ext JS, LLC.
51548 * Originally Released Under LGPL - original licence link has changed is not relivant.
51551 * <script type="text/javascript">
51555 * @class Roo.BasicLayoutRegion
51556 * @extends Roo.util.Observable
51557 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
51558 * and does not have a titlebar, tabs or any other features. All it does is size and position
51559 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
51561 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
51563 this.position = pos;
51566 * @scope Roo.BasicLayoutRegion
51570 * @event beforeremove
51571 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
51572 * @param {Roo.LayoutRegion} this
51573 * @param {Roo.ContentPanel} panel The panel
51574 * @param {Object} e The cancel event object
51576 "beforeremove" : true,
51578 * @event invalidated
51579 * Fires when the layout for this region is changed.
51580 * @param {Roo.LayoutRegion} this
51582 "invalidated" : true,
51584 * @event visibilitychange
51585 * Fires when this region is shown or hidden
51586 * @param {Roo.LayoutRegion} this
51587 * @param {Boolean} visibility true or false
51589 "visibilitychange" : true,
51591 * @event paneladded
51592 * Fires when a panel is added.
51593 * @param {Roo.LayoutRegion} this
51594 * @param {Roo.ContentPanel} panel The panel
51596 "paneladded" : true,
51598 * @event panelremoved
51599 * Fires when a panel is removed.
51600 * @param {Roo.LayoutRegion} this
51601 * @param {Roo.ContentPanel} panel The panel
51603 "panelremoved" : true,
51605 * @event beforecollapse
51606 * Fires when this region before collapse.
51607 * @param {Roo.LayoutRegion} this
51609 "beforecollapse" : true,
51612 * Fires when this region is collapsed.
51613 * @param {Roo.LayoutRegion} this
51615 "collapsed" : true,
51618 * Fires when this region is expanded.
51619 * @param {Roo.LayoutRegion} this
51624 * Fires when this region is slid into view.
51625 * @param {Roo.LayoutRegion} this
51627 "slideshow" : true,
51630 * Fires when this region slides out of view.
51631 * @param {Roo.LayoutRegion} this
51633 "slidehide" : true,
51635 * @event panelactivated
51636 * Fires when a panel is activated.
51637 * @param {Roo.LayoutRegion} this
51638 * @param {Roo.ContentPanel} panel The activated panel
51640 "panelactivated" : true,
51643 * Fires when the user resizes this region.
51644 * @param {Roo.LayoutRegion} this
51645 * @param {Number} newSize The new size (width for east/west, height for north/south)
51649 /** A collection of panels in this region. @type Roo.util.MixedCollection */
51650 this.panels = new Roo.util.MixedCollection();
51651 this.panels.getKey = this.getPanelId.createDelegate(this);
51653 this.activePanel = null;
51654 // ensure listeners are added...
51656 if (config.listeners || config.events) {
51657 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
51658 listeners : config.listeners || {},
51659 events : config.events || {}
51663 if(skipConfig !== true){
51664 this.applyConfig(config);
51668 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
51669 getPanelId : function(p){
51673 applyConfig : function(config){
51674 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51675 this.config = config;
51680 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
51681 * the width, for horizontal (north, south) the height.
51682 * @param {Number} newSize The new width or height
51684 resizeTo : function(newSize){
51685 var el = this.el ? this.el :
51686 (this.activePanel ? this.activePanel.getEl() : null);
51688 switch(this.position){
51691 el.setWidth(newSize);
51692 this.fireEvent("resized", this, newSize);
51696 el.setHeight(newSize);
51697 this.fireEvent("resized", this, newSize);
51703 getBox : function(){
51704 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
51707 getMargins : function(){
51708 return this.margins;
51711 updateBox : function(box){
51713 var el = this.activePanel.getEl();
51714 el.dom.style.left = box.x + "px";
51715 el.dom.style.top = box.y + "px";
51716 this.activePanel.setSize(box.width, box.height);
51720 * Returns the container element for this region.
51721 * @return {Roo.Element}
51723 getEl : function(){
51724 return this.activePanel;
51728 * Returns true if this region is currently visible.
51729 * @return {Boolean}
51731 isVisible : function(){
51732 return this.activePanel ? true : false;
51735 setActivePanel : function(panel){
51736 panel = this.getPanel(panel);
51737 if(this.activePanel && this.activePanel != panel){
51738 this.activePanel.setActiveState(false);
51739 this.activePanel.getEl().setLeftTop(-10000,-10000);
51741 this.activePanel = panel;
51742 panel.setActiveState(true);
51744 panel.setSize(this.box.width, this.box.height);
51746 this.fireEvent("panelactivated", this, panel);
51747 this.fireEvent("invalidated");
51751 * Show the specified panel.
51752 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
51753 * @return {Roo.ContentPanel} The shown panel or null
51755 showPanel : function(panel){
51756 if(panel = this.getPanel(panel)){
51757 this.setActivePanel(panel);
51763 * Get the active panel for this region.
51764 * @return {Roo.ContentPanel} The active panel or null
51766 getActivePanel : function(){
51767 return this.activePanel;
51771 * Add the passed ContentPanel(s)
51772 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
51773 * @return {Roo.ContentPanel} The panel added (if only one was added)
51775 add : function(panel){
51776 if(arguments.length > 1){
51777 for(var i = 0, len = arguments.length; i < len; i++) {
51778 this.add(arguments[i]);
51782 if(this.hasPanel(panel)){
51783 this.showPanel(panel);
51786 var el = panel.getEl();
51787 if(el.dom.parentNode != this.mgr.el.dom){
51788 this.mgr.el.dom.appendChild(el.dom);
51790 if(panel.setRegion){
51791 panel.setRegion(this);
51793 this.panels.add(panel);
51794 el.setStyle("position", "absolute");
51795 if(!panel.background){
51796 this.setActivePanel(panel);
51797 if(this.config.initialSize && this.panels.getCount()==1){
51798 this.resizeTo(this.config.initialSize);
51801 this.fireEvent("paneladded", this, panel);
51806 * Returns true if the panel is in this region.
51807 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51808 * @return {Boolean}
51810 hasPanel : function(panel){
51811 if(typeof panel == "object"){ // must be panel obj
51812 panel = panel.getId();
51814 return this.getPanel(panel) ? true : false;
51818 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
51819 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51820 * @param {Boolean} preservePanel Overrides the config preservePanel option
51821 * @return {Roo.ContentPanel} The panel that was removed
51823 remove : function(panel, preservePanel){
51824 panel = this.getPanel(panel);
51829 this.fireEvent("beforeremove", this, panel, e);
51830 if(e.cancel === true){
51833 var panelId = panel.getId();
51834 this.panels.removeKey(panelId);
51839 * Returns the panel specified or null if it's not in this region.
51840 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
51841 * @return {Roo.ContentPanel}
51843 getPanel : function(id){
51844 if(typeof id == "object"){ // must be panel obj
51847 return this.panels.get(id);
51851 * Returns this regions position (north/south/east/west/center).
51854 getPosition: function(){
51855 return this.position;
51859 * Ext JS Library 1.1.1
51860 * Copyright(c) 2006-2007, Ext JS, LLC.
51862 * Originally Released Under LGPL - original licence link has changed is not relivant.
51865 * <script type="text/javascript">
51869 * @class Roo.LayoutRegion
51870 * @extends Roo.BasicLayoutRegion
51871 * This class represents a region in a layout manager.
51872 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
51873 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
51874 * @cfg {Boolean} floatable False to disable floating (defaults to true)
51875 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
51876 * @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})
51877 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
51878 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
51879 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
51880 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
51881 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
51882 * @cfg {String} title The title for the region (overrides panel titles)
51883 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
51884 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
51885 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
51886 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
51887 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
51888 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
51889 * the space available, similar to FireFox 1.5 tabs (defaults to false)
51890 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
51891 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
51892 * @cfg {Boolean} showPin True to show a pin button
51893 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
51894 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
51895 * @cfg {Boolean} disableTabTips True to disable tab tooltips
51896 * @cfg {Number} width For East/West panels
51897 * @cfg {Number} height For North/South panels
51898 * @cfg {Boolean} split To show the splitter
51899 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
51901 Roo.LayoutRegion = function(mgr, config, pos){
51902 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
51903 var dh = Roo.DomHelper;
51904 /** This region's container element
51905 * @type Roo.Element */
51906 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
51907 /** This region's title element
51908 * @type Roo.Element */
51910 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
51911 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
51912 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
51914 this.titleEl.enableDisplayMode();
51915 /** This region's title text element
51916 * @type HTMLElement */
51917 this.titleTextEl = this.titleEl.dom.firstChild;
51918 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
51919 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
51920 this.closeBtn.enableDisplayMode();
51921 this.closeBtn.on("click", this.closeClicked, this);
51922 this.closeBtn.hide();
51924 this.createBody(config);
51925 this.visible = true;
51926 this.collapsed = false;
51928 if(config.hideWhenEmpty){
51930 this.on("paneladded", this.validateVisibility, this);
51931 this.on("panelremoved", this.validateVisibility, this);
51933 this.applyConfig(config);
51936 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
51938 createBody : function(){
51939 /** This region's body element
51940 * @type Roo.Element */
51941 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
51944 applyConfig : function(c){
51945 if(c.collapsible && this.position != "center" && !this.collapsedEl){
51946 var dh = Roo.DomHelper;
51947 if(c.titlebar !== false){
51948 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
51949 this.collapseBtn.on("click", this.collapse, this);
51950 this.collapseBtn.enableDisplayMode();
51952 if(c.showPin === true || this.showPin){
51953 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
51954 this.stickBtn.enableDisplayMode();
51955 this.stickBtn.on("click", this.expand, this);
51956 this.stickBtn.hide();
51959 /** This region's collapsed element
51960 * @type Roo.Element */
51961 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
51962 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
51964 if(c.floatable !== false){
51965 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
51966 this.collapsedEl.on("click", this.collapseClick, this);
51969 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
51970 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
51971 id: "message", unselectable: "on", style:{"float":"left"}});
51972 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
51974 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
51975 this.expandBtn.on("click", this.expand, this);
51977 if(this.collapseBtn){
51978 this.collapseBtn.setVisible(c.collapsible == true);
51980 this.cmargins = c.cmargins || this.cmargins ||
51981 (this.position == "west" || this.position == "east" ?
51982 {top: 0, left: 2, right:2, bottom: 0} :
51983 {top: 2, left: 0, right:0, bottom: 2});
51984 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
51985 this.bottomTabs = c.tabPosition != "top";
51986 this.autoScroll = c.autoScroll || false;
51987 if(this.autoScroll){
51988 this.bodyEl.setStyle("overflow", "auto");
51990 this.bodyEl.setStyle("overflow", "hidden");
51992 //if(c.titlebar !== false){
51993 if((!c.titlebar && !c.title) || c.titlebar === false){
51994 this.titleEl.hide();
51996 this.titleEl.show();
51998 this.titleTextEl.innerHTML = c.title;
52002 this.duration = c.duration || .30;
52003 this.slideDuration = c.slideDuration || .45;
52006 this.collapse(true);
52013 * Returns true if this region is currently visible.
52014 * @return {Boolean}
52016 isVisible : function(){
52017 return this.visible;
52021 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
52022 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
52024 setCollapsedTitle : function(title){
52025 title = title || " ";
52026 if(this.collapsedTitleTextEl){
52027 this.collapsedTitleTextEl.innerHTML = title;
52031 getBox : function(){
52033 if(!this.collapsed){
52034 b = this.el.getBox(false, true);
52036 b = this.collapsedEl.getBox(false, true);
52041 getMargins : function(){
52042 return this.collapsed ? this.cmargins : this.margins;
52045 highlight : function(){
52046 this.el.addClass("x-layout-panel-dragover");
52049 unhighlight : function(){
52050 this.el.removeClass("x-layout-panel-dragover");
52053 updateBox : function(box){
52055 if(!this.collapsed){
52056 this.el.dom.style.left = box.x + "px";
52057 this.el.dom.style.top = box.y + "px";
52058 this.updateBody(box.width, box.height);
52060 this.collapsedEl.dom.style.left = box.x + "px";
52061 this.collapsedEl.dom.style.top = box.y + "px";
52062 this.collapsedEl.setSize(box.width, box.height);
52065 this.tabs.autoSizeTabs();
52069 updateBody : function(w, h){
52071 this.el.setWidth(w);
52072 w -= this.el.getBorderWidth("rl");
52073 if(this.config.adjustments){
52074 w += this.config.adjustments[0];
52078 this.el.setHeight(h);
52079 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
52080 h -= this.el.getBorderWidth("tb");
52081 if(this.config.adjustments){
52082 h += this.config.adjustments[1];
52084 this.bodyEl.setHeight(h);
52086 h = this.tabs.syncHeight(h);
52089 if(this.panelSize){
52090 w = w !== null ? w : this.panelSize.width;
52091 h = h !== null ? h : this.panelSize.height;
52093 if(this.activePanel){
52094 var el = this.activePanel.getEl();
52095 w = w !== null ? w : el.getWidth();
52096 h = h !== null ? h : el.getHeight();
52097 this.panelSize = {width: w, height: h};
52098 this.activePanel.setSize(w, h);
52100 if(Roo.isIE && this.tabs){
52101 this.tabs.el.repaint();
52106 * Returns the container element for this region.
52107 * @return {Roo.Element}
52109 getEl : function(){
52114 * Hides this region.
52117 if(!this.collapsed){
52118 this.el.dom.style.left = "-2000px";
52121 this.collapsedEl.dom.style.left = "-2000px";
52122 this.collapsedEl.hide();
52124 this.visible = false;
52125 this.fireEvent("visibilitychange", this, false);
52129 * Shows this region if it was previously hidden.
52132 if(!this.collapsed){
52135 this.collapsedEl.show();
52137 this.visible = true;
52138 this.fireEvent("visibilitychange", this, true);
52141 closeClicked : function(){
52142 if(this.activePanel){
52143 this.remove(this.activePanel);
52147 collapseClick : function(e){
52149 e.stopPropagation();
52152 e.stopPropagation();
52158 * Collapses this region.
52159 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
52161 collapse : function(skipAnim, skipCheck = false){
52162 if(this.collapsed) {
52166 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
52168 this.collapsed = true;
52170 this.split.el.hide();
52172 if(this.config.animate && skipAnim !== true){
52173 this.fireEvent("invalidated", this);
52174 this.animateCollapse();
52176 this.el.setLocation(-20000,-20000);
52178 this.collapsedEl.show();
52179 this.fireEvent("collapsed", this);
52180 this.fireEvent("invalidated", this);
52186 animateCollapse : function(){
52191 * Expands this region if it was previously collapsed.
52192 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
52193 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
52195 expand : function(e, skipAnim){
52197 e.stopPropagation();
52199 if(!this.collapsed || this.el.hasActiveFx()) {
52203 this.afterSlideIn();
52206 this.collapsed = false;
52207 if(this.config.animate && skipAnim !== true){
52208 this.animateExpand();
52212 this.split.el.show();
52214 this.collapsedEl.setLocation(-2000,-2000);
52215 this.collapsedEl.hide();
52216 this.fireEvent("invalidated", this);
52217 this.fireEvent("expanded", this);
52221 animateExpand : function(){
52225 initTabs : function()
52227 this.bodyEl.setStyle("overflow", "hidden");
52228 var ts = new Roo.TabPanel(
52231 tabPosition: this.bottomTabs ? 'bottom' : 'top',
52232 disableTooltips: this.config.disableTabTips,
52233 toolbar : this.config.toolbar
52236 if(this.config.hideTabs){
52237 ts.stripWrap.setDisplayed(false);
52240 ts.resizeTabs = this.config.resizeTabs === true;
52241 ts.minTabWidth = this.config.minTabWidth || 40;
52242 ts.maxTabWidth = this.config.maxTabWidth || 250;
52243 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
52244 ts.monitorResize = false;
52245 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52246 ts.bodyEl.addClass('x-layout-tabs-body');
52247 this.panels.each(this.initPanelAsTab, this);
52250 initPanelAsTab : function(panel){
52251 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
52252 this.config.closeOnTab && panel.isClosable());
52253 if(panel.tabTip !== undefined){
52254 ti.setTooltip(panel.tabTip);
52256 ti.on("activate", function(){
52257 this.setActivePanel(panel);
52259 if(this.config.closeOnTab){
52260 ti.on("beforeclose", function(t, e){
52262 this.remove(panel);
52268 updatePanelTitle : function(panel, title){
52269 if(this.activePanel == panel){
52270 this.updateTitle(title);
52273 var ti = this.tabs.getTab(panel.getEl().id);
52275 if(panel.tabTip !== undefined){
52276 ti.setTooltip(panel.tabTip);
52281 updateTitle : function(title){
52282 if(this.titleTextEl && !this.config.title){
52283 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
52287 setActivePanel : function(panel){
52288 panel = this.getPanel(panel);
52289 if(this.activePanel && this.activePanel != panel){
52290 this.activePanel.setActiveState(false);
52292 this.activePanel = panel;
52293 panel.setActiveState(true);
52294 if(this.panelSize){
52295 panel.setSize(this.panelSize.width, this.panelSize.height);
52298 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
52300 this.updateTitle(panel.getTitle());
52302 this.fireEvent("invalidated", this);
52304 this.fireEvent("panelactivated", this, panel);
52308 * Shows the specified panel.
52309 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
52310 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
52312 showPanel : function(panel)
52314 panel = this.getPanel(panel);
52317 var tab = this.tabs.getTab(panel.getEl().id);
52318 if(tab.isHidden()){
52319 this.tabs.unhideTab(tab.id);
52323 this.setActivePanel(panel);
52330 * Get the active panel for this region.
52331 * @return {Roo.ContentPanel} The active panel or null
52333 getActivePanel : function(){
52334 return this.activePanel;
52337 validateVisibility : function(){
52338 if(this.panels.getCount() < 1){
52339 this.updateTitle(" ");
52340 this.closeBtn.hide();
52343 if(!this.isVisible()){
52350 * Adds the passed ContentPanel(s) to this region.
52351 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
52352 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
52354 add : function(panel){
52355 if(arguments.length > 1){
52356 for(var i = 0, len = arguments.length; i < len; i++) {
52357 this.add(arguments[i]);
52361 if(this.hasPanel(panel)){
52362 this.showPanel(panel);
52365 panel.setRegion(this);
52366 this.panels.add(panel);
52367 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
52368 this.bodyEl.dom.appendChild(panel.getEl().dom);
52369 if(panel.background !== true){
52370 this.setActivePanel(panel);
52372 this.fireEvent("paneladded", this, panel);
52378 this.initPanelAsTab(panel);
52380 if(panel.background !== true){
52381 this.tabs.activate(panel.getEl().id);
52383 this.fireEvent("paneladded", this, panel);
52388 * Hides the tab for the specified panel.
52389 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52391 hidePanel : function(panel){
52392 if(this.tabs && (panel = this.getPanel(panel))){
52393 this.tabs.hideTab(panel.getEl().id);
52398 * Unhides the tab for a previously hidden panel.
52399 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52401 unhidePanel : function(panel){
52402 if(this.tabs && (panel = this.getPanel(panel))){
52403 this.tabs.unhideTab(panel.getEl().id);
52407 clearPanels : function(){
52408 while(this.panels.getCount() > 0){
52409 this.remove(this.panels.first());
52414 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
52415 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
52416 * @param {Boolean} preservePanel Overrides the config preservePanel option
52417 * @return {Roo.ContentPanel} The panel that was removed
52419 remove : function(panel, preservePanel){
52420 panel = this.getPanel(panel);
52425 this.fireEvent("beforeremove", this, panel, e);
52426 if(e.cancel === true){
52429 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
52430 var panelId = panel.getId();
52431 this.panels.removeKey(panelId);
52433 document.body.appendChild(panel.getEl().dom);
52436 this.tabs.removeTab(panel.getEl().id);
52437 }else if (!preservePanel){
52438 this.bodyEl.dom.removeChild(panel.getEl().dom);
52440 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
52441 var p = this.panels.first();
52442 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
52443 tempEl.appendChild(p.getEl().dom);
52444 this.bodyEl.update("");
52445 this.bodyEl.dom.appendChild(p.getEl().dom);
52447 this.updateTitle(p.getTitle());
52449 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
52450 this.setActivePanel(p);
52452 panel.setRegion(null);
52453 if(this.activePanel == panel){
52454 this.activePanel = null;
52456 if(this.config.autoDestroy !== false && preservePanel !== true){
52457 try{panel.destroy();}catch(e){}
52459 this.fireEvent("panelremoved", this, panel);
52464 * Returns the TabPanel component used by this region
52465 * @return {Roo.TabPanel}
52467 getTabs : function(){
52471 createTool : function(parentEl, className){
52472 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
52473 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
52474 btn.addClassOnOver("x-layout-tools-button-over");
52479 * Ext JS Library 1.1.1
52480 * Copyright(c) 2006-2007, Ext JS, LLC.
52482 * Originally Released Under LGPL - original licence link has changed is not relivant.
52485 * <script type="text/javascript">
52491 * @class Roo.SplitLayoutRegion
52492 * @extends Roo.LayoutRegion
52493 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
52495 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
52496 this.cursor = cursor;
52497 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
52500 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
52501 splitTip : "Drag to resize.",
52502 collapsibleSplitTip : "Drag to resize. Double click to hide.",
52503 useSplitTips : false,
52505 applyConfig : function(config){
52506 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
52509 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
52510 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
52511 /** The SplitBar for this region
52512 * @type Roo.SplitBar */
52513 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
52514 this.split.on("moved", this.onSplitMove, this);
52515 this.split.useShim = config.useShim === true;
52516 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
52517 if(this.useSplitTips){
52518 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
52520 if(config.collapsible){
52521 this.split.el.on("dblclick", this.collapse, this);
52524 if(typeof config.minSize != "undefined"){
52525 this.split.minSize = config.minSize;
52527 if(typeof config.maxSize != "undefined"){
52528 this.split.maxSize = config.maxSize;
52530 if(config.hideWhenEmpty || config.hidden || config.collapsed){
52531 this.hideSplitter();
52536 getHMaxSize : function(){
52537 var cmax = this.config.maxSize || 10000;
52538 var center = this.mgr.getRegion("center");
52539 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
52542 getVMaxSize : function(){
52543 var cmax = this.config.maxSize || 10000;
52544 var center = this.mgr.getRegion("center");
52545 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
52548 onSplitMove : function(split, newSize){
52549 this.fireEvent("resized", this, newSize);
52553 * Returns the {@link Roo.SplitBar} for this region.
52554 * @return {Roo.SplitBar}
52556 getSplitBar : function(){
52561 this.hideSplitter();
52562 Roo.SplitLayoutRegion.superclass.hide.call(this);
52565 hideSplitter : function(){
52567 this.split.el.setLocation(-2000,-2000);
52568 this.split.el.hide();
52574 this.split.el.show();
52576 Roo.SplitLayoutRegion.superclass.show.call(this);
52579 beforeSlide: function(){
52580 if(Roo.isGecko){// firefox overflow auto bug workaround
52581 this.bodyEl.clip();
52583 this.tabs.bodyEl.clip();
52585 if(this.activePanel){
52586 this.activePanel.getEl().clip();
52588 if(this.activePanel.beforeSlide){
52589 this.activePanel.beforeSlide();
52595 afterSlide : function(){
52596 if(Roo.isGecko){// firefox overflow auto bug workaround
52597 this.bodyEl.unclip();
52599 this.tabs.bodyEl.unclip();
52601 if(this.activePanel){
52602 this.activePanel.getEl().unclip();
52603 if(this.activePanel.afterSlide){
52604 this.activePanel.afterSlide();
52610 initAutoHide : function(){
52611 if(this.autoHide !== false){
52612 if(!this.autoHideHd){
52613 var st = new Roo.util.DelayedTask(this.slideIn, this);
52614 this.autoHideHd = {
52615 "mouseout": function(e){
52616 if(!e.within(this.el, true)){
52620 "mouseover" : function(e){
52626 this.el.on(this.autoHideHd);
52630 clearAutoHide : function(){
52631 if(this.autoHide !== false){
52632 this.el.un("mouseout", this.autoHideHd.mouseout);
52633 this.el.un("mouseover", this.autoHideHd.mouseover);
52637 clearMonitor : function(){
52638 Roo.get(document).un("click", this.slideInIf, this);
52641 // these names are backwards but not changed for compat
52642 slideOut : function(){
52643 if(this.isSlid || this.el.hasActiveFx()){
52646 this.isSlid = true;
52647 if(this.collapseBtn){
52648 this.collapseBtn.hide();
52650 this.closeBtnState = this.closeBtn.getStyle('display');
52651 this.closeBtn.hide();
52653 this.stickBtn.show();
52656 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
52657 this.beforeSlide();
52658 this.el.setStyle("z-index", 10001);
52659 this.el.slideIn(this.getSlideAnchor(), {
52660 callback: function(){
52662 this.initAutoHide();
52663 Roo.get(document).on("click", this.slideInIf, this);
52664 this.fireEvent("slideshow", this);
52671 afterSlideIn : function(){
52672 this.clearAutoHide();
52673 this.isSlid = false;
52674 this.clearMonitor();
52675 this.el.setStyle("z-index", "");
52676 if(this.collapseBtn){
52677 this.collapseBtn.show();
52679 this.closeBtn.setStyle('display', this.closeBtnState);
52681 this.stickBtn.hide();
52683 this.fireEvent("slidehide", this);
52686 slideIn : function(cb){
52687 if(!this.isSlid || this.el.hasActiveFx()){
52691 this.isSlid = false;
52692 this.beforeSlide();
52693 this.el.slideOut(this.getSlideAnchor(), {
52694 callback: function(){
52695 this.el.setLeftTop(-10000, -10000);
52697 this.afterSlideIn();
52705 slideInIf : function(e){
52706 if(!e.within(this.el)){
52711 animateCollapse : function(){
52712 this.beforeSlide();
52713 this.el.setStyle("z-index", 20000);
52714 var anchor = this.getSlideAnchor();
52715 this.el.slideOut(anchor, {
52716 callback : function(){
52717 this.el.setStyle("z-index", "");
52718 this.collapsedEl.slideIn(anchor, {duration:.3});
52720 this.el.setLocation(-10000,-10000);
52722 this.fireEvent("collapsed", this);
52729 animateExpand : function(){
52730 this.beforeSlide();
52731 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
52732 this.el.setStyle("z-index", 20000);
52733 this.collapsedEl.hide({
52736 this.el.slideIn(this.getSlideAnchor(), {
52737 callback : function(){
52738 this.el.setStyle("z-index", "");
52741 this.split.el.show();
52743 this.fireEvent("invalidated", this);
52744 this.fireEvent("expanded", this);
52772 getAnchor : function(){
52773 return this.anchors[this.position];
52776 getCollapseAnchor : function(){
52777 return this.canchors[this.position];
52780 getSlideAnchor : function(){
52781 return this.sanchors[this.position];
52784 getAlignAdj : function(){
52785 var cm = this.cmargins;
52786 switch(this.position){
52802 getExpandAdj : function(){
52803 var c = this.collapsedEl, cm = this.cmargins;
52804 switch(this.position){
52806 return [-(cm.right+c.getWidth()+cm.left), 0];
52809 return [cm.right+c.getWidth()+cm.left, 0];
52812 return [0, -(cm.top+cm.bottom+c.getHeight())];
52815 return [0, cm.top+cm.bottom+c.getHeight()];
52821 * Ext JS Library 1.1.1
52822 * Copyright(c) 2006-2007, Ext JS, LLC.
52824 * Originally Released Under LGPL - original licence link has changed is not relivant.
52827 * <script type="text/javascript">
52830 * These classes are private internal classes
52832 Roo.CenterLayoutRegion = function(mgr, config){
52833 Roo.LayoutRegion.call(this, mgr, config, "center");
52834 this.visible = true;
52835 this.minWidth = config.minWidth || 20;
52836 this.minHeight = config.minHeight || 20;
52839 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
52841 // center panel can't be hidden
52845 // center panel can't be hidden
52848 getMinWidth: function(){
52849 return this.minWidth;
52852 getMinHeight: function(){
52853 return this.minHeight;
52858 Roo.NorthLayoutRegion = function(mgr, config){
52859 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
52861 this.split.placement = Roo.SplitBar.TOP;
52862 this.split.orientation = Roo.SplitBar.VERTICAL;
52863 this.split.el.addClass("x-layout-split-v");
52865 var size = config.initialSize || config.height;
52866 if(typeof size != "undefined"){
52867 this.el.setHeight(size);
52870 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
52871 orientation: Roo.SplitBar.VERTICAL,
52872 getBox : function(){
52873 if(this.collapsed){
52874 return this.collapsedEl.getBox();
52876 var box = this.el.getBox();
52878 box.height += this.split.el.getHeight();
52883 updateBox : function(box){
52884 if(this.split && !this.collapsed){
52885 box.height -= this.split.el.getHeight();
52886 this.split.el.setLeft(box.x);
52887 this.split.el.setTop(box.y+box.height);
52888 this.split.el.setWidth(box.width);
52890 if(this.collapsed){
52891 this.updateBody(box.width, null);
52893 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52897 Roo.SouthLayoutRegion = function(mgr, config){
52898 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
52900 this.split.placement = Roo.SplitBar.BOTTOM;
52901 this.split.orientation = Roo.SplitBar.VERTICAL;
52902 this.split.el.addClass("x-layout-split-v");
52904 var size = config.initialSize || config.height;
52905 if(typeof size != "undefined"){
52906 this.el.setHeight(size);
52909 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
52910 orientation: Roo.SplitBar.VERTICAL,
52911 getBox : function(){
52912 if(this.collapsed){
52913 return this.collapsedEl.getBox();
52915 var box = this.el.getBox();
52917 var sh = this.split.el.getHeight();
52924 updateBox : function(box){
52925 if(this.split && !this.collapsed){
52926 var sh = this.split.el.getHeight();
52929 this.split.el.setLeft(box.x);
52930 this.split.el.setTop(box.y-sh);
52931 this.split.el.setWidth(box.width);
52933 if(this.collapsed){
52934 this.updateBody(box.width, null);
52936 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52940 Roo.EastLayoutRegion = function(mgr, config){
52941 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
52943 this.split.placement = Roo.SplitBar.RIGHT;
52944 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52945 this.split.el.addClass("x-layout-split-h");
52947 var size = config.initialSize || config.width;
52948 if(typeof size != "undefined"){
52949 this.el.setWidth(size);
52952 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
52953 orientation: Roo.SplitBar.HORIZONTAL,
52954 getBox : function(){
52955 if(this.collapsed){
52956 return this.collapsedEl.getBox();
52958 var box = this.el.getBox();
52960 var sw = this.split.el.getWidth();
52967 updateBox : function(box){
52968 if(this.split && !this.collapsed){
52969 var sw = this.split.el.getWidth();
52971 this.split.el.setLeft(box.x);
52972 this.split.el.setTop(box.y);
52973 this.split.el.setHeight(box.height);
52976 if(this.collapsed){
52977 this.updateBody(null, box.height);
52979 Roo.LayoutRegion.prototype.updateBox.call(this, box);
52983 Roo.WestLayoutRegion = function(mgr, config){
52984 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
52986 this.split.placement = Roo.SplitBar.LEFT;
52987 this.split.orientation = Roo.SplitBar.HORIZONTAL;
52988 this.split.el.addClass("x-layout-split-h");
52990 var size = config.initialSize || config.width;
52991 if(typeof size != "undefined"){
52992 this.el.setWidth(size);
52995 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
52996 orientation: Roo.SplitBar.HORIZONTAL,
52997 getBox : function(){
52998 if(this.collapsed){
52999 return this.collapsedEl.getBox();
53001 var box = this.el.getBox();
53003 box.width += this.split.el.getWidth();
53008 updateBox : function(box){
53009 if(this.split && !this.collapsed){
53010 var sw = this.split.el.getWidth();
53012 this.split.el.setLeft(box.x+box.width);
53013 this.split.el.setTop(box.y);
53014 this.split.el.setHeight(box.height);
53016 if(this.collapsed){
53017 this.updateBody(null, box.height);
53019 Roo.LayoutRegion.prototype.updateBox.call(this, box);
53024 * Ext JS Library 1.1.1
53025 * Copyright(c) 2006-2007, Ext JS, LLC.
53027 * Originally Released Under LGPL - original licence link has changed is not relivant.
53030 * <script type="text/javascript">
53035 * Private internal class for reading and applying state
53037 Roo.LayoutStateManager = function(layout){
53038 // default empty state
53047 Roo.LayoutStateManager.prototype = {
53048 init : function(layout, provider){
53049 this.provider = provider;
53050 var state = provider.get(layout.id+"-layout-state");
53052 var wasUpdating = layout.isUpdating();
53054 layout.beginUpdate();
53056 for(var key in state){
53057 if(typeof state[key] != "function"){
53058 var rstate = state[key];
53059 var r = layout.getRegion(key);
53062 r.resizeTo(rstate.size);
53064 if(rstate.collapsed == true){
53067 r.expand(null, true);
53073 layout.endUpdate();
53075 this.state = state;
53077 this.layout = layout;
53078 layout.on("regionresized", this.onRegionResized, this);
53079 layout.on("regioncollapsed", this.onRegionCollapsed, this);
53080 layout.on("regionexpanded", this.onRegionExpanded, this);
53083 storeState : function(){
53084 this.provider.set(this.layout.id+"-layout-state", this.state);
53087 onRegionResized : function(region, newSize){
53088 this.state[region.getPosition()].size = newSize;
53092 onRegionCollapsed : function(region){
53093 this.state[region.getPosition()].collapsed = true;
53097 onRegionExpanded : function(region){
53098 this.state[region.getPosition()].collapsed = false;
53103 * Ext JS Library 1.1.1
53104 * Copyright(c) 2006-2007, Ext JS, LLC.
53106 * Originally Released Under LGPL - original licence link has changed is not relivant.
53109 * <script type="text/javascript">
53112 * @class Roo.ContentPanel
53113 * @extends Roo.util.Observable
53114 * A basic ContentPanel element.
53115 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
53116 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
53117 * @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
53118 * @cfg {Boolean} closable True if the panel can be closed/removed
53119 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
53120 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
53121 * @cfg {Toolbar} toolbar A toolbar for this panel
53122 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
53123 * @cfg {String} title The title for this panel
53124 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
53125 * @cfg {String} url Calls {@link #setUrl} with this value
53126 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
53127 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
53128 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
53129 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
53132 * Create a new ContentPanel.
53133 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
53134 * @param {String/Object} config A string to set only the title or a config object
53135 * @param {String} content (optional) Set the HTML content for this panel
53136 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
53138 Roo.ContentPanel = function(el, config, content){
53142 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
53146 if (config && config.parentLayout) {
53147 el = config.parentLayout.el.createChild();
53150 if(el.autoCreate){ // xtype is available if this is called from factory
53154 this.el = Roo.get(el);
53155 if(!this.el && config && config.autoCreate){
53156 if(typeof config.autoCreate == "object"){
53157 if(!config.autoCreate.id){
53158 config.autoCreate.id = config.id||el;
53160 this.el = Roo.DomHelper.append(document.body,
53161 config.autoCreate, true);
53163 this.el = Roo.DomHelper.append(document.body,
53164 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
53167 this.closable = false;
53168 this.loaded = false;
53169 this.active = false;
53170 if(typeof config == "string"){
53171 this.title = config;
53173 Roo.apply(this, config);
53176 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
53177 this.wrapEl = this.el.wrap();
53178 this.toolbar.container = this.el.insertSibling(false, 'before');
53179 this.toolbar = new Roo.Toolbar(this.toolbar);
53182 // xtype created footer. - not sure if will work as we normally have to render first..
53183 if (this.footer && !this.footer.el && this.footer.xtype) {
53184 if (!this.wrapEl) {
53185 this.wrapEl = this.el.wrap();
53188 this.footer.container = this.wrapEl.createChild();
53190 this.footer = Roo.factory(this.footer, Roo);
53195 this.resizeEl = Roo.get(this.resizeEl, true);
53197 this.resizeEl = this.el;
53199 // handle view.xtype
53207 * Fires when this panel is activated.
53208 * @param {Roo.ContentPanel} this
53212 * @event deactivate
53213 * Fires when this panel is activated.
53214 * @param {Roo.ContentPanel} this
53216 "deactivate" : true,
53220 * Fires when this panel is resized if fitToFrame is true.
53221 * @param {Roo.ContentPanel} this
53222 * @param {Number} width The width after any component adjustments
53223 * @param {Number} height The height after any component adjustments
53229 * Fires when this tab is created
53230 * @param {Roo.ContentPanel} this
53241 if(this.autoScroll){
53242 this.resizeEl.setStyle("overflow", "auto");
53244 // fix randome scrolling
53245 this.el.on('scroll', function() {
53246 Roo.log('fix random scolling');
53247 this.scrollTo('top',0);
53250 content = content || this.content;
53252 this.setContent(content);
53254 if(config && config.url){
53255 this.setUrl(this.url, this.params, this.loadOnce);
53260 Roo.ContentPanel.superclass.constructor.call(this);
53262 if (this.view && typeof(this.view.xtype) != 'undefined') {
53263 this.view.el = this.el.appendChild(document.createElement("div"));
53264 this.view = Roo.factory(this.view);
53265 this.view.render && this.view.render(false, '');
53269 this.fireEvent('render', this);
53272 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
53274 setRegion : function(region){
53275 this.region = region;
53277 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
53279 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
53284 * Returns the toolbar for this Panel if one was configured.
53285 * @return {Roo.Toolbar}
53287 getToolbar : function(){
53288 return this.toolbar;
53291 setActiveState : function(active){
53292 this.active = active;
53294 this.fireEvent("deactivate", this);
53296 this.fireEvent("activate", this);
53300 * Updates this panel's element
53301 * @param {String} content The new content
53302 * @param {Boolean} loadScripts (optional) true to look for and process scripts
53304 setContent : function(content, loadScripts){
53305 this.el.update(content, loadScripts);
53308 ignoreResize : function(w, h){
53309 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
53312 this.lastSize = {width: w, height: h};
53317 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
53318 * @return {Roo.UpdateManager} The UpdateManager
53320 getUpdateManager : function(){
53321 return this.el.getUpdateManager();
53324 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
53325 * @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:
53328 url: "your-url.php",
53329 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
53330 callback: yourFunction,
53331 scope: yourObject, //(optional scope)
53334 text: "Loading...",
53339 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
53340 * 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.
53341 * @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}
53342 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
53343 * @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.
53344 * @return {Roo.ContentPanel} this
53347 var um = this.el.getUpdateManager();
53348 um.update.apply(um, arguments);
53354 * 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.
53355 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
53356 * @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)
53357 * @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)
53358 * @return {Roo.UpdateManager} The UpdateManager
53360 setUrl : function(url, params, loadOnce){
53361 if(this.refreshDelegate){
53362 this.removeListener("activate", this.refreshDelegate);
53364 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
53365 this.on("activate", this.refreshDelegate);
53366 return this.el.getUpdateManager();
53369 _handleRefresh : function(url, params, loadOnce){
53370 if(!loadOnce || !this.loaded){
53371 var updater = this.el.getUpdateManager();
53372 updater.update(url, params, this._setLoaded.createDelegate(this));
53376 _setLoaded : function(){
53377 this.loaded = true;
53381 * Returns this panel's id
53384 getId : function(){
53389 * Returns this panel's element - used by regiosn to add.
53390 * @return {Roo.Element}
53392 getEl : function(){
53393 return this.wrapEl || this.el;
53396 adjustForComponents : function(width, height)
53398 //Roo.log('adjustForComponents ');
53399 if(this.resizeEl != this.el){
53400 width -= this.el.getFrameWidth('lr');
53401 height -= this.el.getFrameWidth('tb');
53404 var te = this.toolbar.getEl();
53405 height -= te.getHeight();
53406 te.setWidth(width);
53409 var te = this.footer.getEl();
53410 Roo.log("footer:" + te.getHeight());
53412 height -= te.getHeight();
53413 te.setWidth(width);
53417 if(this.adjustments){
53418 width += this.adjustments[0];
53419 height += this.adjustments[1];
53421 return {"width": width, "height": height};
53424 setSize : function(width, height){
53425 if(this.fitToFrame && !this.ignoreResize(width, height)){
53426 if(this.fitContainer && this.resizeEl != this.el){
53427 this.el.setSize(width, height);
53429 var size = this.adjustForComponents(width, height);
53430 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
53431 this.fireEvent('resize', this, size.width, size.height);
53436 * Returns this panel's title
53439 getTitle : function(){
53444 * Set this panel's title
53445 * @param {String} title
53447 setTitle : function(title){
53448 this.title = title;
53450 this.region.updatePanelTitle(this, title);
53455 * Returns true is this panel was configured to be closable
53456 * @return {Boolean}
53458 isClosable : function(){
53459 return this.closable;
53462 beforeSlide : function(){
53464 this.resizeEl.clip();
53467 afterSlide : function(){
53469 this.resizeEl.unclip();
53473 * Force a content refresh from the URL specified in the {@link #setUrl} method.
53474 * Will fail silently if the {@link #setUrl} method has not been called.
53475 * This does not activate the panel, just updates its content.
53477 refresh : function(){
53478 if(this.refreshDelegate){
53479 this.loaded = false;
53480 this.refreshDelegate();
53485 * Destroys this panel
53487 destroy : function(){
53488 this.el.removeAllListeners();
53489 var tempEl = document.createElement("span");
53490 tempEl.appendChild(this.el.dom);
53491 tempEl.innerHTML = "";
53497 * form - if the content panel contains a form - this is a reference to it.
53498 * @type {Roo.form.Form}
53502 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
53503 * This contains a reference to it.
53509 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
53519 * @param {Object} cfg Xtype definition of item to add.
53522 addxtype : function(cfg) {
53524 if (cfg.xtype.match(/^Form$/)) {
53527 //if (this.footer) {
53528 // el = this.footer.container.insertSibling(false, 'before');
53530 el = this.el.createChild();
53533 this.form = new Roo.form.Form(cfg);
53536 if ( this.form.allItems.length) {
53537 this.form.render(el.dom);
53541 // should only have one of theses..
53542 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
53543 // views.. should not be just added - used named prop 'view''
53545 cfg.el = this.el.appendChild(document.createElement("div"));
53548 var ret = new Roo.factory(cfg);
53550 ret.render && ret.render(false, ''); // render blank..
53559 * @class Roo.GridPanel
53560 * @extends Roo.ContentPanel
53562 * Create a new GridPanel.
53563 * @param {Roo.grid.Grid} grid The grid for this panel
53564 * @param {String/Object} config A string to set only the panel's title, or a config object
53566 Roo.GridPanel = function(grid, config){
53569 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
53570 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
53572 this.wrapper.dom.appendChild(grid.getGridEl().dom);
53574 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
53577 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
53579 // xtype created footer. - not sure if will work as we normally have to render first..
53580 if (this.footer && !this.footer.el && this.footer.xtype) {
53582 this.footer.container = this.grid.getView().getFooterPanel(true);
53583 this.footer.dataSource = this.grid.dataSource;
53584 this.footer = Roo.factory(this.footer, Roo);
53588 grid.monitorWindowResize = false; // turn off autosizing
53589 grid.autoHeight = false;
53590 grid.autoWidth = false;
53592 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
53595 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
53596 getId : function(){
53597 return this.grid.id;
53601 * Returns the grid for this panel
53602 * @return {Roo.grid.Grid}
53604 getGrid : function(){
53608 setSize : function(width, height){
53609 if(!this.ignoreResize(width, height)){
53610 var grid = this.grid;
53611 var size = this.adjustForComponents(width, height);
53612 grid.getGridEl().setSize(size.width, size.height);
53617 beforeSlide : function(){
53618 this.grid.getView().scroller.clip();
53621 afterSlide : function(){
53622 this.grid.getView().scroller.unclip();
53625 destroy : function(){
53626 this.grid.destroy();
53628 Roo.GridPanel.superclass.destroy.call(this);
53634 * @class Roo.NestedLayoutPanel
53635 * @extends Roo.ContentPanel
53637 * Create a new NestedLayoutPanel.
53640 * @param {Roo.BorderLayout} layout The layout for this panel
53641 * @param {String/Object} config A string to set only the title or a config object
53643 Roo.NestedLayoutPanel = function(layout, config)
53645 // construct with only one argument..
53646 /* FIXME - implement nicer consturctors
53647 if (layout.layout) {
53649 layout = config.layout;
53650 delete config.layout;
53652 if (layout.xtype && !layout.getEl) {
53653 // then layout needs constructing..
53654 layout = Roo.factory(layout, Roo);
53659 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
53661 layout.monitorWindowResize = false; // turn off autosizing
53662 this.layout = layout;
53663 this.layout.getEl().addClass("x-layout-nested-layout");
53670 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
53672 setSize : function(width, height){
53673 if(!this.ignoreResize(width, height)){
53674 var size = this.adjustForComponents(width, height);
53675 var el = this.layout.getEl();
53676 el.setSize(size.width, size.height);
53677 var touch = el.dom.offsetWidth;
53678 this.layout.layout();
53679 // ie requires a double layout on the first pass
53680 if(Roo.isIE && !this.initialized){
53681 this.initialized = true;
53682 this.layout.layout();
53687 // activate all subpanels if not currently active..
53689 setActiveState : function(active){
53690 this.active = active;
53692 this.fireEvent("deactivate", this);
53696 this.fireEvent("activate", this);
53697 // not sure if this should happen before or after..
53698 if (!this.layout) {
53699 return; // should not happen..
53702 for (var r in this.layout.regions) {
53703 reg = this.layout.getRegion(r);
53704 if (reg.getActivePanel()) {
53705 //reg.showPanel(reg.getActivePanel()); // force it to activate..
53706 reg.setActivePanel(reg.getActivePanel());
53709 if (!reg.panels.length) {
53712 reg.showPanel(reg.getPanel(0));
53721 * Returns the nested BorderLayout for this panel
53722 * @return {Roo.BorderLayout}
53724 getLayout : function(){
53725 return this.layout;
53729 * Adds a xtype elements to the layout of the nested panel
53733 xtype : 'ContentPanel',
53740 xtype : 'NestedLayoutPanel',
53746 items : [ ... list of content panels or nested layout panels.. ]
53750 * @param {Object} cfg Xtype definition of item to add.
53752 addxtype : function(cfg) {
53753 return this.layout.addxtype(cfg);
53758 Roo.ScrollPanel = function(el, config, content){
53759 config = config || {};
53760 config.fitToFrame = true;
53761 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
53763 this.el.dom.style.overflow = "hidden";
53764 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
53765 this.el.removeClass("x-layout-inactive-content");
53766 this.el.on("mousewheel", this.onWheel, this);
53768 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
53769 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
53770 up.unselectable(); down.unselectable();
53771 up.on("click", this.scrollUp, this);
53772 down.on("click", this.scrollDown, this);
53773 up.addClassOnOver("x-scroller-btn-over");
53774 down.addClassOnOver("x-scroller-btn-over");
53775 up.addClassOnClick("x-scroller-btn-click");
53776 down.addClassOnClick("x-scroller-btn-click");
53777 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
53779 this.resizeEl = this.el;
53780 this.el = wrap; this.up = up; this.down = down;
53783 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
53785 wheelIncrement : 5,
53786 scrollUp : function(){
53787 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
53790 scrollDown : function(){
53791 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
53794 afterScroll : function(){
53795 var el = this.resizeEl;
53796 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
53797 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53798 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
53801 setSize : function(){
53802 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
53803 this.afterScroll();
53806 onWheel : function(e){
53807 var d = e.getWheelDelta();
53808 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
53809 this.afterScroll();
53813 setContent : function(content, loadScripts){
53814 this.resizeEl.update(content, loadScripts);
53828 * @class Roo.TreePanel
53829 * @extends Roo.ContentPanel
53831 * Create a new TreePanel. - defaults to fit/scoll contents.
53832 * @param {String/Object} config A string to set only the panel's title, or a config object
53833 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
53835 Roo.TreePanel = function(config){
53836 var el = config.el;
53837 var tree = config.tree;
53838 delete config.tree;
53839 delete config.el; // hopefull!
53841 // wrapper for IE7 strict & safari scroll issue
53843 var treeEl = el.createChild();
53844 config.resizeEl = treeEl;
53848 Roo.TreePanel.superclass.constructor.call(this, el, config);
53851 this.tree = new Roo.tree.TreePanel(treeEl , tree);
53852 //console.log(tree);
53853 this.on('activate', function()
53855 if (this.tree.rendered) {
53858 //console.log('render tree');
53859 this.tree.render();
53861 // this should not be needed.. - it's actually the 'el' that resizes?
53862 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
53864 //this.on('resize', function (cp, w, h) {
53865 // this.tree.innerCt.setWidth(w);
53866 // this.tree.innerCt.setHeight(h);
53867 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
53874 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
53891 * Ext JS Library 1.1.1
53892 * Copyright(c) 2006-2007, Ext JS, LLC.
53894 * Originally Released Under LGPL - original licence link has changed is not relivant.
53897 * <script type="text/javascript">
53902 * @class Roo.ReaderLayout
53903 * @extends Roo.BorderLayout
53904 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
53905 * center region containing two nested regions (a top one for a list view and one for item preview below),
53906 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
53907 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
53908 * expedites the setup of the overall layout and regions for this common application style.
53911 var reader = new Roo.ReaderLayout();
53912 var CP = Roo.ContentPanel; // shortcut for adding
53914 reader.beginUpdate();
53915 reader.add("north", new CP("north", "North"));
53916 reader.add("west", new CP("west", {title: "West"}));
53917 reader.add("east", new CP("east", {title: "East"}));
53919 reader.regions.listView.add(new CP("listView", "List"));
53920 reader.regions.preview.add(new CP("preview", "Preview"));
53921 reader.endUpdate();
53924 * Create a new ReaderLayout
53925 * @param {Object} config Configuration options
53926 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
53927 * document.body if omitted)
53929 Roo.ReaderLayout = function(config, renderTo){
53930 var c = config || {size:{}};
53931 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
53932 north: c.north !== false ? Roo.apply({
53936 }, c.north) : false,
53937 west: c.west !== false ? Roo.apply({
53945 margins:{left:5,right:0,bottom:5,top:5},
53946 cmargins:{left:5,right:5,bottom:5,top:5}
53947 }, c.west) : false,
53948 east: c.east !== false ? Roo.apply({
53956 margins:{left:0,right:5,bottom:5,top:5},
53957 cmargins:{left:5,right:5,bottom:5,top:5}
53958 }, c.east) : false,
53959 center: Roo.apply({
53960 tabPosition: 'top',
53964 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
53968 this.el.addClass('x-reader');
53970 this.beginUpdate();
53972 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
53973 south: c.preview !== false ? Roo.apply({
53980 cmargins:{top:5,left:0, right:0, bottom:0}
53981 }, c.preview) : false,
53982 center: Roo.apply({
53988 this.add('center', new Roo.NestedLayoutPanel(inner,
53989 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
53993 this.regions.preview = inner.getRegion('south');
53994 this.regions.listView = inner.getRegion('center');
53997 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
53999 * Ext JS Library 1.1.1
54000 * Copyright(c) 2006-2007, Ext JS, LLC.
54002 * Originally Released Under LGPL - original licence link has changed is not relivant.
54005 * <script type="text/javascript">
54009 * @class Roo.grid.Grid
54010 * @extends Roo.util.Observable
54011 * This class represents the primary interface of a component based grid control.
54012 * <br><br>Usage:<pre><code>
54013 var grid = new Roo.grid.Grid("my-container-id", {
54016 selModel: mySelectionModel,
54017 autoSizeColumns: true,
54018 monitorWindowResize: false,
54019 trackMouseOver: true
54024 * <b>Common Problems:</b><br/>
54025 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
54026 * element will correct this<br/>
54027 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
54028 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
54029 * are unpredictable.<br/>
54030 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
54031 * grid to calculate dimensions/offsets.<br/>
54033 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
54034 * The container MUST have some type of size defined for the grid to fill. The container will be
54035 * automatically set to position relative if it isn't already.
54036 * @param {Object} config A config object that sets properties on this grid.
54038 Roo.grid.Grid = function(container, config){
54039 // initialize the container
54040 this.container = Roo.get(container);
54041 this.container.update("");
54042 this.container.setStyle("overflow", "hidden");
54043 this.container.addClass('x-grid-container');
54045 this.id = this.container.id;
54047 Roo.apply(this, config);
54048 // check and correct shorthanded configs
54050 this.dataSource = this.ds;
54054 this.colModel = this.cm;
54058 this.selModel = this.sm;
54062 if (this.selModel) {
54063 this.selModel = Roo.factory(this.selModel, Roo.grid);
54064 this.sm = this.selModel;
54065 this.sm.xmodule = this.xmodule || false;
54067 if (typeof(this.colModel.config) == 'undefined') {
54068 this.colModel = new Roo.grid.ColumnModel(this.colModel);
54069 this.cm = this.colModel;
54070 this.cm.xmodule = this.xmodule || false;
54072 if (this.dataSource) {
54073 this.dataSource= Roo.factory(this.dataSource, Roo.data);
54074 this.ds = this.dataSource;
54075 this.ds.xmodule = this.xmodule || false;
54082 this.container.setWidth(this.width);
54086 this.container.setHeight(this.height);
54093 * The raw click event for the entire grid.
54094 * @param {Roo.EventObject} e
54099 * The raw dblclick event for the entire grid.
54100 * @param {Roo.EventObject} e
54104 * @event contextmenu
54105 * The raw contextmenu event for the entire grid.
54106 * @param {Roo.EventObject} e
54108 "contextmenu" : true,
54111 * The raw mousedown event for the entire grid.
54112 * @param {Roo.EventObject} e
54114 "mousedown" : true,
54117 * The raw mouseup event for the entire grid.
54118 * @param {Roo.EventObject} e
54123 * The raw mouseover event for the entire grid.
54124 * @param {Roo.EventObject} e
54126 "mouseover" : true,
54129 * The raw mouseout event for the entire grid.
54130 * @param {Roo.EventObject} e
54135 * The raw keypress event for the entire grid.
54136 * @param {Roo.EventObject} e
54141 * The raw keydown event for the entire grid.
54142 * @param {Roo.EventObject} e
54150 * Fires when a cell is clicked
54151 * @param {Grid} this
54152 * @param {Number} rowIndex
54153 * @param {Number} columnIndex
54154 * @param {Roo.EventObject} e
54156 "cellclick" : true,
54158 * @event celldblclick
54159 * Fires when a cell is double clicked
54160 * @param {Grid} this
54161 * @param {Number} rowIndex
54162 * @param {Number} columnIndex
54163 * @param {Roo.EventObject} e
54165 "celldblclick" : true,
54168 * Fires when a row is clicked
54169 * @param {Grid} this
54170 * @param {Number} rowIndex
54171 * @param {Roo.EventObject} e
54175 * @event rowdblclick
54176 * Fires when a row is double clicked
54177 * @param {Grid} this
54178 * @param {Number} rowIndex
54179 * @param {Roo.EventObject} e
54181 "rowdblclick" : true,
54183 * @event headerclick
54184 * Fires when a header is clicked
54185 * @param {Grid} this
54186 * @param {Number} columnIndex
54187 * @param {Roo.EventObject} e
54189 "headerclick" : true,
54191 * @event headerdblclick
54192 * Fires when a header cell is double clicked
54193 * @param {Grid} this
54194 * @param {Number} columnIndex
54195 * @param {Roo.EventObject} e
54197 "headerdblclick" : true,
54199 * @event rowcontextmenu
54200 * Fires when a row is right clicked
54201 * @param {Grid} this
54202 * @param {Number} rowIndex
54203 * @param {Roo.EventObject} e
54205 "rowcontextmenu" : true,
54207 * @event cellcontextmenu
54208 * Fires when a cell is right clicked
54209 * @param {Grid} this
54210 * @param {Number} rowIndex
54211 * @param {Number} cellIndex
54212 * @param {Roo.EventObject} e
54214 "cellcontextmenu" : true,
54216 * @event headercontextmenu
54217 * Fires when a header is right clicked
54218 * @param {Grid} this
54219 * @param {Number} columnIndex
54220 * @param {Roo.EventObject} e
54222 "headercontextmenu" : true,
54224 * @event bodyscroll
54225 * Fires when the body element is scrolled
54226 * @param {Number} scrollLeft
54227 * @param {Number} scrollTop
54229 "bodyscroll" : true,
54231 * @event columnresize
54232 * Fires when the user resizes a column
54233 * @param {Number} columnIndex
54234 * @param {Number} newSize
54236 "columnresize" : true,
54238 * @event columnmove
54239 * Fires when the user moves a column
54240 * @param {Number} oldIndex
54241 * @param {Number} newIndex
54243 "columnmove" : true,
54246 * Fires when row(s) start being dragged
54247 * @param {Grid} this
54248 * @param {Roo.GridDD} dd The drag drop object
54249 * @param {event} e The raw browser event
54251 "startdrag" : true,
54254 * Fires when a drag operation is complete
54255 * @param {Grid} this
54256 * @param {Roo.GridDD} dd The drag drop object
54257 * @param {event} e The raw browser event
54262 * Fires when dragged row(s) are dropped on a valid DD target
54263 * @param {Grid} this
54264 * @param {Roo.GridDD} dd The drag drop object
54265 * @param {String} targetId The target drag drop object
54266 * @param {event} e The raw browser event
54271 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
54272 * @param {Grid} this
54273 * @param {Roo.GridDD} dd The drag drop object
54274 * @param {String} targetId The target drag drop object
54275 * @param {event} e The raw browser event
54280 * Fires when the dragged row(s) first cross another DD target while being dragged
54281 * @param {Grid} this
54282 * @param {Roo.GridDD} dd The drag drop object
54283 * @param {String} targetId The target drag drop object
54284 * @param {event} e The raw browser event
54286 "dragenter" : true,
54289 * Fires when the dragged row(s) leave another DD target while being dragged
54290 * @param {Grid} this
54291 * @param {Roo.GridDD} dd The drag drop object
54292 * @param {String} targetId The target drag drop object
54293 * @param {event} e The raw browser event
54298 * Fires when a row is rendered, so you can change add a style to it.
54299 * @param {GridView} gridview The grid view
54300 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
54306 * Fires when the grid is rendered
54307 * @param {Grid} grid
54312 Roo.grid.Grid.superclass.constructor.call(this);
54314 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
54317 * @cfg {String} ddGroup - drag drop group.
54321 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
54323 minColumnWidth : 25,
54326 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
54327 * <b>on initial render.</b> It is more efficient to explicitly size the columns
54328 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
54330 autoSizeColumns : false,
54333 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
54335 autoSizeHeaders : true,
54338 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
54340 monitorWindowResize : true,
54343 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
54344 * rows measured to get a columns size. Default is 0 (all rows).
54346 maxRowsToMeasure : 0,
54349 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
54351 trackMouseOver : true,
54354 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
54358 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
54360 enableDragDrop : false,
54363 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
54365 enableColumnMove : true,
54368 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
54370 enableColumnHide : true,
54373 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
54375 enableRowHeightSync : false,
54378 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
54383 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
54385 autoHeight : false,
54388 * @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.
54390 autoExpandColumn : false,
54393 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
54396 autoExpandMin : 50,
54399 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
54401 autoExpandMax : 1000,
54404 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
54409 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
54413 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
54423 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
54424 * of a fixed width. Default is false.
54427 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
54430 * Called once after all setup has been completed and the grid is ready to be rendered.
54431 * @return {Roo.grid.Grid} this
54433 render : function()
54435 var c = this.container;
54436 // try to detect autoHeight/width mode
54437 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
54438 this.autoHeight = true;
54440 var view = this.getView();
54443 c.on("click", this.onClick, this);
54444 c.on("dblclick", this.onDblClick, this);
54445 c.on("contextmenu", this.onContextMenu, this);
54446 c.on("keydown", this.onKeyDown, this);
54448 c.on("touchstart", this.onTouchStart, this);
54451 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
54453 this.getSelectionModel().init(this);
54458 this.loadMask = new Roo.LoadMask(this.container,
54459 Roo.apply({store:this.dataSource}, this.loadMask));
54463 if (this.toolbar && this.toolbar.xtype) {
54464 this.toolbar.container = this.getView().getHeaderPanel(true);
54465 this.toolbar = new Roo.Toolbar(this.toolbar);
54467 if (this.footer && this.footer.xtype) {
54468 this.footer.dataSource = this.getDataSource();
54469 this.footer.container = this.getView().getFooterPanel(true);
54470 this.footer = Roo.factory(this.footer, Roo);
54472 if (this.dropTarget && this.dropTarget.xtype) {
54473 delete this.dropTarget.xtype;
54474 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
54478 this.rendered = true;
54479 this.fireEvent('render', this);
54484 * Reconfigures the grid to use a different Store and Column Model.
54485 * The View will be bound to the new objects and refreshed.
54486 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
54487 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
54489 reconfigure : function(dataSource, colModel){
54491 this.loadMask.destroy();
54492 this.loadMask = new Roo.LoadMask(this.container,
54493 Roo.apply({store:dataSource}, this.loadMask));
54495 this.view.bind(dataSource, colModel);
54496 this.dataSource = dataSource;
54497 this.colModel = colModel;
54498 this.view.refresh(true);
54502 onKeyDown : function(e){
54503 this.fireEvent("keydown", e);
54507 * Destroy this grid.
54508 * @param {Boolean} removeEl True to remove the element
54510 destroy : function(removeEl, keepListeners){
54512 this.loadMask.destroy();
54514 var c = this.container;
54515 c.removeAllListeners();
54516 this.view.destroy();
54517 this.colModel.purgeListeners();
54518 if(!keepListeners){
54519 this.purgeListeners();
54522 if(removeEl === true){
54528 processEvent : function(name, e){
54529 // does this fire select???
54530 //Roo.log('grid:processEvent ' + name);
54532 if (name != 'touchstart' ) {
54533 this.fireEvent(name, e);
54536 var t = e.getTarget();
54538 var header = v.findHeaderIndex(t);
54539 if(header !== false){
54540 var ename = name == 'touchstart' ? 'click' : name;
54542 this.fireEvent("header" + ename, this, header, e);
54544 var row = v.findRowIndex(t);
54545 var cell = v.findCellIndex(t);
54546 if (name == 'touchstart') {
54547 // first touch is always a click.
54548 // hopefull this happens after selection is updated.?
54551 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
54552 var cs = this.selModel.getSelectedCell();
54553 if (row == cs[0] && cell == cs[1]){
54557 if (typeof(this.selModel.getSelections) != 'undefined') {
54558 var cs = this.selModel.getSelections();
54559 var ds = this.dataSource;
54560 if (cs.length == 1 && ds.getAt(row) == cs[0]){
54571 this.fireEvent("row" + name, this, row, e);
54572 if(cell !== false){
54573 this.fireEvent("cell" + name, this, row, cell, e);
54580 onClick : function(e){
54581 this.processEvent("click", e);
54584 onTouchStart : function(e){
54585 this.processEvent("touchstart", e);
54589 onContextMenu : function(e, t){
54590 this.processEvent("contextmenu", e);
54594 onDblClick : function(e){
54595 this.processEvent("dblclick", e);
54599 walkCells : function(row, col, step, fn, scope){
54600 var cm = this.colModel, clen = cm.getColumnCount();
54601 var ds = this.dataSource, rlen = ds.getCount(), first = true;
54613 if(fn.call(scope || this, row, col, cm) === true){
54631 if(fn.call(scope || this, row, col, cm) === true){
54643 getSelections : function(){
54644 return this.selModel.getSelections();
54648 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
54649 * but if manual update is required this method will initiate it.
54651 autoSize : function(){
54653 this.view.layout();
54654 if(this.view.adjustForScroll){
54655 this.view.adjustForScroll();
54661 * Returns the grid's underlying element.
54662 * @return {Element} The element
54664 getGridEl : function(){
54665 return this.container;
54668 // private for compatibility, overridden by editor grid
54669 stopEditing : function(){},
54672 * Returns the grid's SelectionModel.
54673 * @return {SelectionModel}
54675 getSelectionModel : function(){
54676 if(!this.selModel){
54677 this.selModel = new Roo.grid.RowSelectionModel();
54679 return this.selModel;
54683 * Returns the grid's DataSource.
54684 * @return {DataSource}
54686 getDataSource : function(){
54687 return this.dataSource;
54691 * Returns the grid's ColumnModel.
54692 * @return {ColumnModel}
54694 getColumnModel : function(){
54695 return this.colModel;
54699 * Returns the grid's GridView object.
54700 * @return {GridView}
54702 getView : function(){
54704 this.view = new Roo.grid.GridView(this.viewConfig);
54709 * Called to get grid's drag proxy text, by default returns this.ddText.
54712 getDragDropText : function(){
54713 var count = this.selModel.getCount();
54714 return String.format(this.ddText, count, count == 1 ? '' : 's');
54718 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
54719 * %0 is replaced with the number of selected rows.
54722 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
54724 * Ext JS Library 1.1.1
54725 * Copyright(c) 2006-2007, Ext JS, LLC.
54727 * Originally Released Under LGPL - original licence link has changed is not relivant.
54730 * <script type="text/javascript">
54733 Roo.grid.AbstractGridView = function(){
54737 "beforerowremoved" : true,
54738 "beforerowsinserted" : true,
54739 "beforerefresh" : true,
54740 "rowremoved" : true,
54741 "rowsinserted" : true,
54742 "rowupdated" : true,
54745 Roo.grid.AbstractGridView.superclass.constructor.call(this);
54748 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
54749 rowClass : "x-grid-row",
54750 cellClass : "x-grid-cell",
54751 tdClass : "x-grid-td",
54752 hdClass : "x-grid-hd",
54753 splitClass : "x-grid-hd-split",
54755 init: function(grid){
54757 var cid = this.grid.getGridEl().id;
54758 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
54759 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
54760 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
54761 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
54764 getColumnRenderers : function(){
54765 var renderers = [];
54766 var cm = this.grid.colModel;
54767 var colCount = cm.getColumnCount();
54768 for(var i = 0; i < colCount; i++){
54769 renderers[i] = cm.getRenderer(i);
54774 getColumnIds : function(){
54776 var cm = this.grid.colModel;
54777 var colCount = cm.getColumnCount();
54778 for(var i = 0; i < colCount; i++){
54779 ids[i] = cm.getColumnId(i);
54784 getDataIndexes : function(){
54785 if(!this.indexMap){
54786 this.indexMap = this.buildIndexMap();
54788 return this.indexMap.colToData;
54791 getColumnIndexByDataIndex : function(dataIndex){
54792 if(!this.indexMap){
54793 this.indexMap = this.buildIndexMap();
54795 return this.indexMap.dataToCol[dataIndex];
54799 * Set a css style for a column dynamically.
54800 * @param {Number} colIndex The index of the column
54801 * @param {String} name The css property name
54802 * @param {String} value The css value
54804 setCSSStyle : function(colIndex, name, value){
54805 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
54806 Roo.util.CSS.updateRule(selector, name, value);
54809 generateRules : function(cm){
54810 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
54811 Roo.util.CSS.removeStyleSheet(rulesId);
54812 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
54813 var cid = cm.getColumnId(i);
54814 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
54815 this.tdSelector, cid, " {\n}\n",
54816 this.hdSelector, cid, " {\n}\n",
54817 this.splitSelector, cid, " {\n}\n");
54819 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
54823 * Ext JS Library 1.1.1
54824 * Copyright(c) 2006-2007, Ext JS, LLC.
54826 * Originally Released Under LGPL - original licence link has changed is not relivant.
54829 * <script type="text/javascript">
54833 // This is a support class used internally by the Grid components
54834 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
54836 this.view = grid.getView();
54837 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54838 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
54840 this.setHandleElId(Roo.id(hd));
54841 this.setOuterHandleElId(Roo.id(hd2));
54843 this.scroll = false;
54845 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
54847 getDragData : function(e){
54848 var t = Roo.lib.Event.getTarget(e);
54849 var h = this.view.findHeaderCell(t);
54851 return {ddel: h.firstChild, header:h};
54856 onInitDrag : function(e){
54857 this.view.headersDisabled = true;
54858 var clone = this.dragData.ddel.cloneNode(true);
54859 clone.id = Roo.id();
54860 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
54861 this.proxy.update(clone);
54865 afterValidDrop : function(){
54867 setTimeout(function(){
54868 v.headersDisabled = false;
54872 afterInvalidDrop : function(){
54874 setTimeout(function(){
54875 v.headersDisabled = false;
54881 * Ext JS Library 1.1.1
54882 * Copyright(c) 2006-2007, Ext JS, LLC.
54884 * Originally Released Under LGPL - original licence link has changed is not relivant.
54887 * <script type="text/javascript">
54890 // This is a support class used internally by the Grid components
54891 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
54893 this.view = grid.getView();
54894 // split the proxies so they don't interfere with mouse events
54895 this.proxyTop = Roo.DomHelper.append(document.body, {
54896 cls:"col-move-top", html:" "
54898 this.proxyBottom = Roo.DomHelper.append(document.body, {
54899 cls:"col-move-bottom", html:" "
54901 this.proxyTop.hide = this.proxyBottom.hide = function(){
54902 this.setLeftTop(-100,-100);
54903 this.setStyle("visibility", "hidden");
54905 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
54906 // temporarily disabled
54907 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
54908 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
54910 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
54911 proxyOffsets : [-4, -9],
54912 fly: Roo.Element.fly,
54914 getTargetFromEvent : function(e){
54915 var t = Roo.lib.Event.getTarget(e);
54916 var cindex = this.view.findCellIndex(t);
54917 if(cindex !== false){
54918 return this.view.getHeaderCell(cindex);
54923 nextVisible : function(h){
54924 var v = this.view, cm = this.grid.colModel;
54927 if(!cm.isHidden(v.getCellIndex(h))){
54935 prevVisible : function(h){
54936 var v = this.view, cm = this.grid.colModel;
54939 if(!cm.isHidden(v.getCellIndex(h))){
54947 positionIndicator : function(h, n, e){
54948 var x = Roo.lib.Event.getPageX(e);
54949 var r = Roo.lib.Dom.getRegion(n.firstChild);
54950 var px, pt, py = r.top + this.proxyOffsets[1];
54951 if((r.right - x) <= (r.right-r.left)/2){
54952 px = r.right+this.view.borderWidth;
54958 var oldIndex = this.view.getCellIndex(h);
54959 var newIndex = this.view.getCellIndex(n);
54961 if(this.grid.colModel.isFixed(newIndex)){
54965 var locked = this.grid.colModel.isLocked(newIndex);
54970 if(oldIndex < newIndex){
54973 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
54976 px += this.proxyOffsets[0];
54977 this.proxyTop.setLeftTop(px, py);
54978 this.proxyTop.show();
54979 if(!this.bottomOffset){
54980 this.bottomOffset = this.view.mainHd.getHeight();
54982 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
54983 this.proxyBottom.show();
54987 onNodeEnter : function(n, dd, e, data){
54988 if(data.header != n){
54989 this.positionIndicator(data.header, n, e);
54993 onNodeOver : function(n, dd, e, data){
54994 var result = false;
54995 if(data.header != n){
54996 result = this.positionIndicator(data.header, n, e);
54999 this.proxyTop.hide();
55000 this.proxyBottom.hide();
55002 return result ? this.dropAllowed : this.dropNotAllowed;
55005 onNodeOut : function(n, dd, e, data){
55006 this.proxyTop.hide();
55007 this.proxyBottom.hide();
55010 onNodeDrop : function(n, dd, e, data){
55011 var h = data.header;
55013 var cm = this.grid.colModel;
55014 var x = Roo.lib.Event.getPageX(e);
55015 var r = Roo.lib.Dom.getRegion(n.firstChild);
55016 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
55017 var oldIndex = this.view.getCellIndex(h);
55018 var newIndex = this.view.getCellIndex(n);
55019 var locked = cm.isLocked(newIndex);
55023 if(oldIndex < newIndex){
55026 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
55029 cm.setLocked(oldIndex, locked, true);
55030 cm.moveColumn(oldIndex, newIndex);
55031 this.grid.fireEvent("columnmove", oldIndex, newIndex);
55039 * Ext JS Library 1.1.1
55040 * Copyright(c) 2006-2007, Ext JS, LLC.
55042 * Originally Released Under LGPL - original licence link has changed is not relivant.
55045 * <script type="text/javascript">
55049 * @class Roo.grid.GridView
55050 * @extends Roo.util.Observable
55053 * @param {Object} config
55055 Roo.grid.GridView = function(config){
55056 Roo.grid.GridView.superclass.constructor.call(this);
55059 Roo.apply(this, config);
55062 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
55064 unselectable : 'unselectable="on"',
55065 unselectableCls : 'x-unselectable',
55068 rowClass : "x-grid-row",
55070 cellClass : "x-grid-col",
55072 tdClass : "x-grid-td",
55074 hdClass : "x-grid-hd",
55076 splitClass : "x-grid-split",
55078 sortClasses : ["sort-asc", "sort-desc"],
55080 enableMoveAnim : false,
55084 dh : Roo.DomHelper,
55086 fly : Roo.Element.fly,
55088 css : Roo.util.CSS,
55094 scrollIncrement : 22,
55096 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
55098 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
55100 bind : function(ds, cm){
55102 this.ds.un("load", this.onLoad, this);
55103 this.ds.un("datachanged", this.onDataChange, this);
55104 this.ds.un("add", this.onAdd, this);
55105 this.ds.un("remove", this.onRemove, this);
55106 this.ds.un("update", this.onUpdate, this);
55107 this.ds.un("clear", this.onClear, this);
55110 ds.on("load", this.onLoad, this);
55111 ds.on("datachanged", this.onDataChange, this);
55112 ds.on("add", this.onAdd, this);
55113 ds.on("remove", this.onRemove, this);
55114 ds.on("update", this.onUpdate, this);
55115 ds.on("clear", this.onClear, this);
55120 this.cm.un("widthchange", this.onColWidthChange, this);
55121 this.cm.un("headerchange", this.onHeaderChange, this);
55122 this.cm.un("hiddenchange", this.onHiddenChange, this);
55123 this.cm.un("columnmoved", this.onColumnMove, this);
55124 this.cm.un("columnlockchange", this.onColumnLock, this);
55127 this.generateRules(cm);
55128 cm.on("widthchange", this.onColWidthChange, this);
55129 cm.on("headerchange", this.onHeaderChange, this);
55130 cm.on("hiddenchange", this.onHiddenChange, this);
55131 cm.on("columnmoved", this.onColumnMove, this);
55132 cm.on("columnlockchange", this.onColumnLock, this);
55137 init: function(grid){
55138 Roo.grid.GridView.superclass.init.call(this, grid);
55140 this.bind(grid.dataSource, grid.colModel);
55142 grid.on("headerclick", this.handleHeaderClick, this);
55144 if(grid.trackMouseOver){
55145 grid.on("mouseover", this.onRowOver, this);
55146 grid.on("mouseout", this.onRowOut, this);
55148 grid.cancelTextSelection = function(){};
55149 this.gridId = grid.id;
55151 var tpls = this.templates || {};
55154 tpls.master = new Roo.Template(
55155 '<div class="x-grid" hidefocus="true">',
55156 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
55157 '<div class="x-grid-topbar"></div>',
55158 '<div class="x-grid-scroller"><div></div></div>',
55159 '<div class="x-grid-locked">',
55160 '<div class="x-grid-header">{lockedHeader}</div>',
55161 '<div class="x-grid-body">{lockedBody}</div>',
55163 '<div class="x-grid-viewport">',
55164 '<div class="x-grid-header">{header}</div>',
55165 '<div class="x-grid-body">{body}</div>',
55167 '<div class="x-grid-bottombar"></div>',
55169 '<div class="x-grid-resize-proxy"> </div>',
55172 tpls.master.disableformats = true;
55176 tpls.header = new Roo.Template(
55177 '<table border="0" cellspacing="0" cellpadding="0">',
55178 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
55181 tpls.header.disableformats = true;
55183 tpls.header.compile();
55186 tpls.hcell = new Roo.Template(
55187 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
55188 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
55191 tpls.hcell.disableFormats = true;
55193 tpls.hcell.compile();
55196 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
55197 this.unselectableCls + '" ' + this.unselectable +'> </div>');
55198 tpls.hsplit.disableFormats = true;
55200 tpls.hsplit.compile();
55203 tpls.body = new Roo.Template(
55204 '<table border="0" cellspacing="0" cellpadding="0">',
55205 "<tbody>{rows}</tbody>",
55208 tpls.body.disableFormats = true;
55210 tpls.body.compile();
55213 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
55214 tpls.row.disableFormats = true;
55216 tpls.row.compile();
55219 tpls.cell = new Roo.Template(
55220 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
55221 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
55222 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
55225 tpls.cell.disableFormats = true;
55227 tpls.cell.compile();
55229 this.templates = tpls;
55232 // remap these for backwards compat
55233 onColWidthChange : function(){
55234 this.updateColumns.apply(this, arguments);
55236 onHeaderChange : function(){
55237 this.updateHeaders.apply(this, arguments);
55239 onHiddenChange : function(){
55240 this.handleHiddenChange.apply(this, arguments);
55242 onColumnMove : function(){
55243 this.handleColumnMove.apply(this, arguments);
55245 onColumnLock : function(){
55246 this.handleLockChange.apply(this, arguments);
55249 onDataChange : function(){
55251 this.updateHeaderSortState();
55254 onClear : function(){
55258 onUpdate : function(ds, record){
55259 this.refreshRow(record);
55262 refreshRow : function(record){
55263 var ds = this.ds, index;
55264 if(typeof record == 'number'){
55266 record = ds.getAt(index);
55268 index = ds.indexOf(record);
55270 this.insertRows(ds, index, index, true);
55271 this.onRemove(ds, record, index+1, true);
55272 this.syncRowHeights(index, index);
55274 this.fireEvent("rowupdated", this, index, record);
55277 onAdd : function(ds, records, index){
55278 this.insertRows(ds, index, index + (records.length-1));
55281 onRemove : function(ds, record, index, isUpdate){
55282 if(isUpdate !== true){
55283 this.fireEvent("beforerowremoved", this, index, record);
55285 var bt = this.getBodyTable(), lt = this.getLockedTable();
55286 if(bt.rows[index]){
55287 bt.firstChild.removeChild(bt.rows[index]);
55289 if(lt.rows[index]){
55290 lt.firstChild.removeChild(lt.rows[index]);
55292 if(isUpdate !== true){
55293 this.stripeRows(index);
55294 this.syncRowHeights(index, index);
55296 this.fireEvent("rowremoved", this, index, record);
55300 onLoad : function(){
55301 this.scrollToTop();
55305 * Scrolls the grid to the top
55307 scrollToTop : function(){
55309 this.scroller.dom.scrollTop = 0;
55315 * Gets a panel in the header of the grid that can be used for toolbars etc.
55316 * After modifying the contents of this panel a call to grid.autoSize() may be
55317 * required to register any changes in size.
55318 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
55319 * @return Roo.Element
55321 getHeaderPanel : function(doShow){
55323 this.headerPanel.show();
55325 return this.headerPanel;
55329 * Gets a panel in the footer of the grid that can be used for toolbars etc.
55330 * After modifying the contents of this panel a call to grid.autoSize() may be
55331 * required to register any changes in size.
55332 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
55333 * @return Roo.Element
55335 getFooterPanel : function(doShow){
55337 this.footerPanel.show();
55339 return this.footerPanel;
55342 initElements : function(){
55343 var E = Roo.Element;
55344 var el = this.grid.getGridEl().dom.firstChild;
55345 var cs = el.childNodes;
55347 this.el = new E(el);
55349 this.focusEl = new E(el.firstChild);
55350 this.focusEl.swallowEvent("click", true);
55352 this.headerPanel = new E(cs[1]);
55353 this.headerPanel.enableDisplayMode("block");
55355 this.scroller = new E(cs[2]);
55356 this.scrollSizer = new E(this.scroller.dom.firstChild);
55358 this.lockedWrap = new E(cs[3]);
55359 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
55360 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
55362 this.mainWrap = new E(cs[4]);
55363 this.mainHd = new E(this.mainWrap.dom.firstChild);
55364 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
55366 this.footerPanel = new E(cs[5]);
55367 this.footerPanel.enableDisplayMode("block");
55369 this.resizeProxy = new E(cs[6]);
55371 this.headerSelector = String.format(
55372 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
55373 this.lockedHd.id, this.mainHd.id
55376 this.splitterSelector = String.format(
55377 '#{0} div.x-grid-split, #{1} div.x-grid-split',
55378 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
55381 idToCssName : function(s)
55383 return s.replace(/[^a-z0-9]+/ig, '-');
55386 getHeaderCell : function(index){
55387 return Roo.DomQuery.select(this.headerSelector)[index];
55390 getHeaderCellMeasure : function(index){
55391 return this.getHeaderCell(index).firstChild;
55394 getHeaderCellText : function(index){
55395 return this.getHeaderCell(index).firstChild.firstChild;
55398 getLockedTable : function(){
55399 return this.lockedBody.dom.firstChild;
55402 getBodyTable : function(){
55403 return this.mainBody.dom.firstChild;
55406 getLockedRow : function(index){
55407 return this.getLockedTable().rows[index];
55410 getRow : function(index){
55411 return this.getBodyTable().rows[index];
55414 getRowComposite : function(index){
55416 this.rowEl = new Roo.CompositeElementLite();
55418 var els = [], lrow, mrow;
55419 if(lrow = this.getLockedRow(index)){
55422 if(mrow = this.getRow(index)){
55425 this.rowEl.elements = els;
55429 * Gets the 'td' of the cell
55431 * @param {Integer} rowIndex row to select
55432 * @param {Integer} colIndex column to select
55436 getCell : function(rowIndex, colIndex){
55437 var locked = this.cm.getLockedCount();
55439 if(colIndex < locked){
55440 source = this.lockedBody.dom.firstChild;
55442 source = this.mainBody.dom.firstChild;
55443 colIndex -= locked;
55445 return source.rows[rowIndex].childNodes[colIndex];
55448 getCellText : function(rowIndex, colIndex){
55449 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
55452 getCellBox : function(cell){
55453 var b = this.fly(cell).getBox();
55454 if(Roo.isOpera){ // opera fails to report the Y
55455 b.y = cell.offsetTop + this.mainBody.getY();
55460 getCellIndex : function(cell){
55461 var id = String(cell.className).match(this.cellRE);
55463 return parseInt(id[1], 10);
55468 findHeaderIndex : function(n){
55469 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55470 return r ? this.getCellIndex(r) : false;
55473 findHeaderCell : function(n){
55474 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
55475 return r ? r : false;
55478 findRowIndex : function(n){
55482 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
55483 return r ? r.rowIndex : false;
55486 findCellIndex : function(node){
55487 var stop = this.el.dom;
55488 while(node && node != stop){
55489 if(this.findRE.test(node.className)){
55490 return this.getCellIndex(node);
55492 node = node.parentNode;
55497 getColumnId : function(index){
55498 return this.cm.getColumnId(index);
55501 getSplitters : function()
55503 if(this.splitterSelector){
55504 return Roo.DomQuery.select(this.splitterSelector);
55510 getSplitter : function(index){
55511 return this.getSplitters()[index];
55514 onRowOver : function(e, t){
55516 if((row = this.findRowIndex(t)) !== false){
55517 this.getRowComposite(row).addClass("x-grid-row-over");
55521 onRowOut : function(e, t){
55523 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
55524 this.getRowComposite(row).removeClass("x-grid-row-over");
55528 renderHeaders : function(){
55530 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
55531 var cb = [], lb = [], sb = [], lsb = [], p = {};
55532 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55533 p.cellId = "x-grid-hd-0-" + i;
55534 p.splitId = "x-grid-csplit-0-" + i;
55535 p.id = cm.getColumnId(i);
55536 p.value = cm.getColumnHeader(i) || "";
55537 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
55538 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
55539 if(!cm.isLocked(i)){
55540 cb[cb.length] = ct.apply(p);
55541 sb[sb.length] = st.apply(p);
55543 lb[lb.length] = ct.apply(p);
55544 lsb[lsb.length] = st.apply(p);
55547 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
55548 ht.apply({cells: cb.join(""), splits:sb.join("")})];
55551 updateHeaders : function(){
55552 var html = this.renderHeaders();
55553 this.lockedHd.update(html[0]);
55554 this.mainHd.update(html[1]);
55558 * Focuses the specified row.
55559 * @param {Number} row The row index
55561 focusRow : function(row)
55563 //Roo.log('GridView.focusRow');
55564 var x = this.scroller.dom.scrollLeft;
55565 this.focusCell(row, 0, false);
55566 this.scroller.dom.scrollLeft = x;
55570 * Focuses the specified cell.
55571 * @param {Number} row The row index
55572 * @param {Number} col The column index
55573 * @param {Boolean} hscroll false to disable horizontal scrolling
55575 focusCell : function(row, col, hscroll)
55577 //Roo.log('GridView.focusCell');
55578 var el = this.ensureVisible(row, col, hscroll);
55579 this.focusEl.alignTo(el, "tl-tl");
55581 this.focusEl.focus();
55583 this.focusEl.focus.defer(1, this.focusEl);
55588 * Scrolls the specified cell into view
55589 * @param {Number} row The row index
55590 * @param {Number} col The column index
55591 * @param {Boolean} hscroll false to disable horizontal scrolling
55593 ensureVisible : function(row, col, hscroll)
55595 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
55596 //return null; //disable for testing.
55597 if(typeof row != "number"){
55598 row = row.rowIndex;
55600 if(row < 0 && row >= this.ds.getCount()){
55603 col = (col !== undefined ? col : 0);
55604 var cm = this.grid.colModel;
55605 while(cm.isHidden(col)){
55609 var el = this.getCell(row, col);
55613 var c = this.scroller.dom;
55615 var ctop = parseInt(el.offsetTop, 10);
55616 var cleft = parseInt(el.offsetLeft, 10);
55617 var cbot = ctop + el.offsetHeight;
55618 var cright = cleft + el.offsetWidth;
55620 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
55621 var stop = parseInt(c.scrollTop, 10);
55622 var sleft = parseInt(c.scrollLeft, 10);
55623 var sbot = stop + ch;
55624 var sright = sleft + c.clientWidth;
55626 Roo.log('GridView.ensureVisible:' +
55628 ' c.clientHeight:' + c.clientHeight +
55629 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
55637 c.scrollTop = ctop;
55638 //Roo.log("set scrolltop to ctop DISABLE?");
55639 }else if(cbot > sbot){
55640 //Roo.log("set scrolltop to cbot-ch");
55641 c.scrollTop = cbot-ch;
55644 if(hscroll !== false){
55646 c.scrollLeft = cleft;
55647 }else if(cright > sright){
55648 c.scrollLeft = cright-c.clientWidth;
55655 updateColumns : function(){
55656 this.grid.stopEditing();
55657 var cm = this.grid.colModel, colIds = this.getColumnIds();
55658 //var totalWidth = cm.getTotalWidth();
55660 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55661 //if(cm.isHidden(i)) continue;
55662 var w = cm.getColumnWidth(i);
55663 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55664 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
55666 this.updateSplitters();
55669 generateRules : function(cm){
55670 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
55671 Roo.util.CSS.removeStyleSheet(rulesId);
55672 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55673 var cid = cm.getColumnId(i);
55675 if(cm.config[i].align){
55676 align = 'text-align:'+cm.config[i].align+';';
55679 if(cm.isHidden(i)){
55680 hidden = 'display:none;';
55682 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
55684 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
55685 this.hdSelector, cid, " {\n", align, width, "}\n",
55686 this.tdSelector, cid, " {\n",hidden,"\n}\n",
55687 this.splitSelector, cid, " {\n", hidden , "\n}\n");
55689 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
55692 updateSplitters : function(){
55693 var cm = this.cm, s = this.getSplitters();
55694 if(s){ // splitters not created yet
55695 var pos = 0, locked = true;
55696 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
55697 if(cm.isHidden(i)) {
55700 var w = cm.getColumnWidth(i); // make sure it's a number
55701 if(!cm.isLocked(i) && locked){
55706 s[i].style.left = (pos-this.splitOffset) + "px";
55711 handleHiddenChange : function(colModel, colIndex, hidden){
55713 this.hideColumn(colIndex);
55715 this.unhideColumn(colIndex);
55719 hideColumn : function(colIndex){
55720 var cid = this.getColumnId(colIndex);
55721 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
55722 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
55724 this.updateHeaders();
55726 this.updateSplitters();
55730 unhideColumn : function(colIndex){
55731 var cid = this.getColumnId(colIndex);
55732 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
55733 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
55736 this.updateHeaders();
55738 this.updateSplitters();
55742 insertRows : function(dm, firstRow, lastRow, isUpdate){
55743 if(firstRow == 0 && lastRow == dm.getCount()-1){
55747 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
55749 var s = this.getScrollState();
55750 var markup = this.renderRows(firstRow, lastRow);
55751 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
55752 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
55753 this.restoreScroll(s);
55755 this.fireEvent("rowsinserted", this, firstRow, lastRow);
55756 this.syncRowHeights(firstRow, lastRow);
55757 this.stripeRows(firstRow);
55763 bufferRows : function(markup, target, index){
55764 var before = null, trows = target.rows, tbody = target.tBodies[0];
55765 if(index < trows.length){
55766 before = trows[index];
55768 var b = document.createElement("div");
55769 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
55770 var rows = b.firstChild.rows;
55771 for(var i = 0, len = rows.length; i < len; i++){
55773 tbody.insertBefore(rows[0], before);
55775 tbody.appendChild(rows[0]);
55782 deleteRows : function(dm, firstRow, lastRow){
55783 if(dm.getRowCount()<1){
55784 this.fireEvent("beforerefresh", this);
55785 this.mainBody.update("");
55786 this.lockedBody.update("");
55787 this.fireEvent("refresh", this);
55789 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
55790 var bt = this.getBodyTable();
55791 var tbody = bt.firstChild;
55792 var rows = bt.rows;
55793 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
55794 tbody.removeChild(rows[firstRow]);
55796 this.stripeRows(firstRow);
55797 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
55801 updateRows : function(dataSource, firstRow, lastRow){
55802 var s = this.getScrollState();
55804 this.restoreScroll(s);
55807 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
55811 this.updateHeaderSortState();
55814 getScrollState : function(){
55816 var sb = this.scroller.dom;
55817 return {left: sb.scrollLeft, top: sb.scrollTop};
55820 stripeRows : function(startRow){
55821 if(!this.grid.stripeRows || this.ds.getCount() < 1){
55824 startRow = startRow || 0;
55825 var rows = this.getBodyTable().rows;
55826 var lrows = this.getLockedTable().rows;
55827 var cls = ' x-grid-row-alt ';
55828 for(var i = startRow, len = rows.length; i < len; i++){
55829 var row = rows[i], lrow = lrows[i];
55830 var isAlt = ((i+1) % 2 == 0);
55831 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
55832 if(isAlt == hasAlt){
55836 row.className += " x-grid-row-alt";
55838 row.className = row.className.replace("x-grid-row-alt", "");
55841 lrow.className = row.className;
55846 restoreScroll : function(state){
55847 //Roo.log('GridView.restoreScroll');
55848 var sb = this.scroller.dom;
55849 sb.scrollLeft = state.left;
55850 sb.scrollTop = state.top;
55854 syncScroll : function(){
55855 //Roo.log('GridView.syncScroll');
55856 var sb = this.scroller.dom;
55857 var sh = this.mainHd.dom;
55858 var bs = this.mainBody.dom;
55859 var lv = this.lockedBody.dom;
55860 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
55861 lv.scrollTop = bs.scrollTop = sb.scrollTop;
55864 handleScroll : function(e){
55866 var sb = this.scroller.dom;
55867 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
55871 handleWheel : function(e){
55872 var d = e.getWheelDelta();
55873 this.scroller.dom.scrollTop -= d*22;
55874 // set this here to prevent jumpy scrolling on large tables
55875 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
55879 renderRows : function(startRow, endRow){
55880 // pull in all the crap needed to render rows
55881 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
55882 var colCount = cm.getColumnCount();
55884 if(ds.getCount() < 1){
55888 // build a map for all the columns
55890 for(var i = 0; i < colCount; i++){
55891 var name = cm.getDataIndex(i);
55893 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
55894 renderer : cm.getRenderer(i),
55895 id : cm.getColumnId(i),
55896 locked : cm.isLocked(i),
55897 has_editor : cm.isCellEditable(i)
55901 startRow = startRow || 0;
55902 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
55904 // records to render
55905 var rs = ds.getRange(startRow, endRow);
55907 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
55910 // As much as I hate to duplicate code, this was branched because FireFox really hates
55911 // [].join("") on strings. The performance difference was substantial enough to
55912 // branch this function
55913 doRender : Roo.isGecko ?
55914 function(cs, rs, ds, startRow, colCount, stripe){
55915 var ts = this.templates, ct = ts.cell, rt = ts.row;
55917 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55919 var hasListener = this.grid.hasListener('rowclass');
55921 for(var j = 0, len = rs.length; j < len; j++){
55922 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
55923 for(var i = 0; i < colCount; i++){
55925 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55927 p.css = p.attr = "";
55928 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55929 if(p.value == undefined || p.value === "") {
55930 p.value = " ";
55933 p.css += ' x-grid-editable-cell';
55935 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
55936 p.css += ' x-grid-dirty-cell';
55938 var markup = ct.apply(p);
55946 if(stripe && ((rowIndex+1) % 2 == 0)){
55947 alt.push("x-grid-row-alt")
55950 alt.push( " x-grid-dirty-row");
55953 if(this.getRowClass){
55954 alt.push(this.getRowClass(r, rowIndex));
55960 rowIndex : rowIndex,
55963 this.grid.fireEvent('rowclass', this, rowcfg);
55964 alt.push(rowcfg.rowClass);
55966 rp.alt = alt.join(" ");
55967 lbuf+= rt.apply(rp);
55969 buf+= rt.apply(rp);
55971 return [lbuf, buf];
55973 function(cs, rs, ds, startRow, colCount, stripe){
55974 var ts = this.templates, ct = ts.cell, rt = ts.row;
55976 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
55977 var hasListener = this.grid.hasListener('rowclass');
55980 for(var j = 0, len = rs.length; j < len; j++){
55981 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
55982 for(var i = 0; i < colCount; i++){
55984 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
55986 p.css = p.attr = "";
55987 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
55988 if(p.value == undefined || p.value === "") {
55989 p.value = " ";
55993 p.css += ' x-grid-editable-cell';
55995 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
55996 p.css += ' x-grid-dirty-cell'
55999 var markup = ct.apply(p);
56001 cb[cb.length] = markup;
56003 lcb[lcb.length] = markup;
56007 if(stripe && ((rowIndex+1) % 2 == 0)){
56008 alt.push( "x-grid-row-alt");
56011 alt.push(" x-grid-dirty-row");
56014 if(this.getRowClass){
56015 alt.push( this.getRowClass(r, rowIndex));
56021 rowIndex : rowIndex,
56024 this.grid.fireEvent('rowclass', this, rowcfg);
56025 alt.push(rowcfg.rowClass);
56028 rp.alt = alt.join(" ");
56029 rp.cells = lcb.join("");
56030 lbuf[lbuf.length] = rt.apply(rp);
56031 rp.cells = cb.join("");
56032 buf[buf.length] = rt.apply(rp);
56034 return [lbuf.join(""), buf.join("")];
56037 renderBody : function(){
56038 var markup = this.renderRows();
56039 var bt = this.templates.body;
56040 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
56044 * Refreshes the grid
56045 * @param {Boolean} headersToo
56047 refresh : function(headersToo){
56048 this.fireEvent("beforerefresh", this);
56049 this.grid.stopEditing();
56050 var result = this.renderBody();
56051 this.lockedBody.update(result[0]);
56052 this.mainBody.update(result[1]);
56053 if(headersToo === true){
56054 this.updateHeaders();
56055 this.updateColumns();
56056 this.updateSplitters();
56057 this.updateHeaderSortState();
56059 this.syncRowHeights();
56061 this.fireEvent("refresh", this);
56064 handleColumnMove : function(cm, oldIndex, newIndex){
56065 this.indexMap = null;
56066 var s = this.getScrollState();
56067 this.refresh(true);
56068 this.restoreScroll(s);
56069 this.afterMove(newIndex);
56072 afterMove : function(colIndex){
56073 if(this.enableMoveAnim && Roo.enableFx){
56074 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
56076 // if multisort - fix sortOrder, and reload..
56077 if (this.grid.dataSource.multiSort) {
56078 // the we can call sort again..
56079 var dm = this.grid.dataSource;
56080 var cm = this.grid.colModel;
56082 for(var i = 0; i < cm.config.length; i++ ) {
56084 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
56085 continue; // dont' bother, it's not in sort list or being set.
56088 so.push(cm.config[i].dataIndex);
56091 dm.load(dm.lastOptions);
56098 updateCell : function(dm, rowIndex, dataIndex){
56099 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
56100 if(typeof colIndex == "undefined"){ // not present in grid
56103 var cm = this.grid.colModel;
56104 var cell = this.getCell(rowIndex, colIndex);
56105 var cellText = this.getCellText(rowIndex, colIndex);
56108 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
56109 id : cm.getColumnId(colIndex),
56110 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
56112 var renderer = cm.getRenderer(colIndex);
56113 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
56114 if(typeof val == "undefined" || val === "") {
56117 cellText.innerHTML = val;
56118 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
56119 this.syncRowHeights(rowIndex, rowIndex);
56122 calcColumnWidth : function(colIndex, maxRowsToMeasure){
56124 if(this.grid.autoSizeHeaders){
56125 var h = this.getHeaderCellMeasure(colIndex);
56126 maxWidth = Math.max(maxWidth, h.scrollWidth);
56129 if(this.cm.isLocked(colIndex)){
56130 tb = this.getLockedTable();
56133 tb = this.getBodyTable();
56134 index = colIndex - this.cm.getLockedCount();
56137 var rows = tb.rows;
56138 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
56139 for(var i = 0; i < stopIndex; i++){
56140 var cell = rows[i].childNodes[index].firstChild;
56141 maxWidth = Math.max(maxWidth, cell.scrollWidth);
56144 return maxWidth + /*margin for error in IE*/ 5;
56147 * Autofit a column to its content.
56148 * @param {Number} colIndex
56149 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
56151 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
56152 if(this.cm.isHidden(colIndex)){
56153 return; // can't calc a hidden column
56156 var cid = this.cm.getColumnId(colIndex);
56157 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
56158 if(this.grid.autoSizeHeaders){
56159 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
56162 var newWidth = this.calcColumnWidth(colIndex);
56163 this.cm.setColumnWidth(colIndex,
56164 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
56165 if(!suppressEvent){
56166 this.grid.fireEvent("columnresize", colIndex, newWidth);
56171 * Autofits all columns to their content and then expands to fit any extra space in the grid
56173 autoSizeColumns : function(){
56174 var cm = this.grid.colModel;
56175 var colCount = cm.getColumnCount();
56176 for(var i = 0; i < colCount; i++){
56177 this.autoSizeColumn(i, true, true);
56179 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
56182 this.updateColumns();
56188 * Autofits all columns to the grid's width proportionate with their current size
56189 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
56191 fitColumns : function(reserveScrollSpace){
56192 var cm = this.grid.colModel;
56193 var colCount = cm.getColumnCount();
56197 for (i = 0; i < colCount; i++){
56198 if(!cm.isHidden(i) && !cm.isFixed(i)){
56199 w = cm.getColumnWidth(i);
56205 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
56206 if(reserveScrollSpace){
56209 var frac = (avail - cm.getTotalWidth())/width;
56210 while (cols.length){
56213 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
56215 this.updateColumns();
56219 onRowSelect : function(rowIndex){
56220 var row = this.getRowComposite(rowIndex);
56221 row.addClass("x-grid-row-selected");
56224 onRowDeselect : function(rowIndex){
56225 var row = this.getRowComposite(rowIndex);
56226 row.removeClass("x-grid-row-selected");
56229 onCellSelect : function(row, col){
56230 var cell = this.getCell(row, col);
56232 Roo.fly(cell).addClass("x-grid-cell-selected");
56236 onCellDeselect : function(row, col){
56237 var cell = this.getCell(row, col);
56239 Roo.fly(cell).removeClass("x-grid-cell-selected");
56243 updateHeaderSortState : function(){
56245 // sort state can be single { field: xxx, direction : yyy}
56246 // or { xxx=>ASC , yyy : DESC ..... }
56249 if (!this.ds.multiSort) {
56250 var state = this.ds.getSortState();
56254 mstate[state.field] = state.direction;
56255 // FIXME... - this is not used here.. but might be elsewhere..
56256 this.sortState = state;
56259 mstate = this.ds.sortToggle;
56261 //remove existing sort classes..
56263 var sc = this.sortClasses;
56264 var hds = this.el.select(this.headerSelector).removeClass(sc);
56266 for(var f in mstate) {
56268 var sortColumn = this.cm.findColumnIndex(f);
56270 if(sortColumn != -1){
56271 var sortDir = mstate[f];
56272 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
56281 handleHeaderClick : function(g, index,e){
56283 Roo.log("header click");
56286 // touch events on header are handled by context
56287 this.handleHdCtx(g,index,e);
56292 if(this.headersDisabled){
56295 var dm = g.dataSource, cm = g.colModel;
56296 if(!cm.isSortable(index)){
56301 if (dm.multiSort) {
56302 // update the sortOrder
56304 for(var i = 0; i < cm.config.length; i++ ) {
56306 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
56307 continue; // dont' bother, it's not in sort list or being set.
56310 so.push(cm.config[i].dataIndex);
56316 dm.sort(cm.getDataIndex(index));
56320 destroy : function(){
56322 this.colMenu.removeAll();
56323 Roo.menu.MenuMgr.unregister(this.colMenu);
56324 this.colMenu.getEl().remove();
56325 delete this.colMenu;
56328 this.hmenu.removeAll();
56329 Roo.menu.MenuMgr.unregister(this.hmenu);
56330 this.hmenu.getEl().remove();
56333 if(this.grid.enableColumnMove){
56334 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56336 for(var dd in dds){
56337 if(!dds[dd].config.isTarget && dds[dd].dragElId){
56338 var elid = dds[dd].dragElId;
56340 Roo.get(elid).remove();
56341 } else if(dds[dd].config.isTarget){
56342 dds[dd].proxyTop.remove();
56343 dds[dd].proxyBottom.remove();
56346 if(Roo.dd.DDM.locationCache[dd]){
56347 delete Roo.dd.DDM.locationCache[dd];
56350 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
56353 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
56354 this.bind(null, null);
56355 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
56358 handleLockChange : function(){
56359 this.refresh(true);
56362 onDenyColumnLock : function(){
56366 onDenyColumnHide : function(){
56370 handleHdMenuClick : function(item){
56371 var index = this.hdCtxIndex;
56372 var cm = this.cm, ds = this.ds;
56375 ds.sort(cm.getDataIndex(index), "ASC");
56378 ds.sort(cm.getDataIndex(index), "DESC");
56381 var lc = cm.getLockedCount();
56382 if(cm.getColumnCount(true) <= lc+1){
56383 this.onDenyColumnLock();
56387 cm.setLocked(index, true, true);
56388 cm.moveColumn(index, lc);
56389 this.grid.fireEvent("columnmove", index, lc);
56391 cm.setLocked(index, true);
56395 var lc = cm.getLockedCount();
56396 if((lc-1) != index){
56397 cm.setLocked(index, false, true);
56398 cm.moveColumn(index, lc-1);
56399 this.grid.fireEvent("columnmove", index, lc-1);
56401 cm.setLocked(index, false);
56404 case 'wider': // used to expand cols on touch..
56406 var cw = cm.getColumnWidth(index);
56407 cw += (item.id == 'wider' ? 1 : -1) * 50;
56408 cw = Math.max(0, cw);
56409 cw = Math.min(cw,4000);
56410 cm.setColumnWidth(index, cw);
56414 index = cm.getIndexById(item.id.substr(4));
56416 if(item.checked && cm.getColumnCount(true) <= 1){
56417 this.onDenyColumnHide();
56420 cm.setHidden(index, item.checked);
56426 beforeColMenuShow : function(){
56427 var cm = this.cm, colCount = cm.getColumnCount();
56428 this.colMenu.removeAll();
56429 for(var i = 0; i < colCount; i++){
56430 this.colMenu.add(new Roo.menu.CheckItem({
56431 id: "col-"+cm.getColumnId(i),
56432 text: cm.getColumnHeader(i),
56433 checked: !cm.isHidden(i),
56439 handleHdCtx : function(g, index, e){
56441 var hd = this.getHeaderCell(index);
56442 this.hdCtxIndex = index;
56443 var ms = this.hmenu.items, cm = this.cm;
56444 ms.get("asc").setDisabled(!cm.isSortable(index));
56445 ms.get("desc").setDisabled(!cm.isSortable(index));
56446 if(this.grid.enableColLock !== false){
56447 ms.get("lock").setDisabled(cm.isLocked(index));
56448 ms.get("unlock").setDisabled(!cm.isLocked(index));
56450 this.hmenu.show(hd, "tl-bl");
56453 handleHdOver : function(e){
56454 var hd = this.findHeaderCell(e.getTarget());
56455 if(hd && !this.headersDisabled){
56456 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
56457 this.fly(hd).addClass("x-grid-hd-over");
56462 handleHdOut : function(e){
56463 var hd = this.findHeaderCell(e.getTarget());
56465 this.fly(hd).removeClass("x-grid-hd-over");
56469 handleSplitDblClick : function(e, t){
56470 var i = this.getCellIndex(t);
56471 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
56472 this.autoSizeColumn(i, true);
56477 render : function(){
56480 var colCount = cm.getColumnCount();
56482 if(this.grid.monitorWindowResize === true){
56483 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
56485 var header = this.renderHeaders();
56486 var body = this.templates.body.apply({rows:""});
56487 var html = this.templates.master.apply({
56490 lockedHeader: header[0],
56494 //this.updateColumns();
56496 this.grid.getGridEl().dom.innerHTML = html;
56498 this.initElements();
56500 // a kludge to fix the random scolling effect in webkit
56501 this.el.on("scroll", function() {
56502 this.el.dom.scrollTop=0; // hopefully not recursive..
56505 this.scroller.on("scroll", this.handleScroll, this);
56506 this.lockedBody.on("mousewheel", this.handleWheel, this);
56507 this.mainBody.on("mousewheel", this.handleWheel, this);
56509 this.mainHd.on("mouseover", this.handleHdOver, this);
56510 this.mainHd.on("mouseout", this.handleHdOut, this);
56511 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
56512 {delegate: "."+this.splitClass});
56514 this.lockedHd.on("mouseover", this.handleHdOver, this);
56515 this.lockedHd.on("mouseout", this.handleHdOut, this);
56516 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
56517 {delegate: "."+this.splitClass});
56519 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
56520 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56523 this.updateSplitters();
56525 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
56526 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56527 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
56530 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
56531 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
56533 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
56534 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
56536 if(this.grid.enableColLock !== false){
56537 this.hmenu.add('-',
56538 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
56539 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
56543 this.hmenu.add('-',
56544 {id:"wider", text: this.columnsWiderText},
56545 {id:"narrow", text: this.columnsNarrowText }
56551 if(this.grid.enableColumnHide !== false){
56553 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
56554 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
56555 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
56557 this.hmenu.add('-',
56558 {id:"columns", text: this.columnsText, menu: this.colMenu}
56561 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
56563 this.grid.on("headercontextmenu", this.handleHdCtx, this);
56566 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
56567 this.dd = new Roo.grid.GridDragZone(this.grid, {
56568 ddGroup : this.grid.ddGroup || 'GridDD'
56574 for(var i = 0; i < colCount; i++){
56575 if(cm.isHidden(i)){
56576 this.hideColumn(i);
56578 if(cm.config[i].align){
56579 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
56580 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
56584 this.updateHeaderSortState();
56586 this.beforeInitialResize();
56589 // two part rendering gives faster view to the user
56590 this.renderPhase2.defer(1, this);
56593 renderPhase2 : function(){
56594 // render the rows now
56596 if(this.grid.autoSizeColumns){
56597 this.autoSizeColumns();
56601 beforeInitialResize : function(){
56605 onColumnSplitterMoved : function(i, w){
56606 this.userResized = true;
56607 var cm = this.grid.colModel;
56608 cm.setColumnWidth(i, w, true);
56609 var cid = cm.getColumnId(i);
56610 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56611 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
56612 this.updateSplitters();
56614 this.grid.fireEvent("columnresize", i, w);
56617 syncRowHeights : function(startIndex, endIndex){
56618 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
56619 startIndex = startIndex || 0;
56620 var mrows = this.getBodyTable().rows;
56621 var lrows = this.getLockedTable().rows;
56622 var len = mrows.length-1;
56623 endIndex = Math.min(endIndex || len, len);
56624 for(var i = startIndex; i <= endIndex; i++){
56625 var m = mrows[i], l = lrows[i];
56626 var h = Math.max(m.offsetHeight, l.offsetHeight);
56627 m.style.height = l.style.height = h + "px";
56632 layout : function(initialRender, is2ndPass){
56634 var auto = g.autoHeight;
56635 var scrollOffset = 16;
56636 var c = g.getGridEl(), cm = this.cm,
56637 expandCol = g.autoExpandColumn,
56639 //c.beginMeasure();
56641 if(!c.dom.offsetWidth){ // display:none?
56643 this.lockedWrap.show();
56644 this.mainWrap.show();
56649 var hasLock = this.cm.isLocked(0);
56651 var tbh = this.headerPanel.getHeight();
56652 var bbh = this.footerPanel.getHeight();
56655 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
56656 var newHeight = ch + c.getBorderWidth("tb");
56658 newHeight = Math.min(g.maxHeight, newHeight);
56660 c.setHeight(newHeight);
56664 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
56667 var s = this.scroller;
56669 var csize = c.getSize(true);
56671 this.el.setSize(csize.width, csize.height);
56673 this.headerPanel.setWidth(csize.width);
56674 this.footerPanel.setWidth(csize.width);
56676 var hdHeight = this.mainHd.getHeight();
56677 var vw = csize.width;
56678 var vh = csize.height - (tbh + bbh);
56682 var bt = this.getBodyTable();
56684 if(cm.getLockedCount() == cm.config.length){
56685 bt = this.getLockedTable();
56688 var ltWidth = hasLock ?
56689 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
56691 var scrollHeight = bt.offsetHeight;
56692 var scrollWidth = ltWidth + bt.offsetWidth;
56693 var vscroll = false, hscroll = false;
56695 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
56697 var lw = this.lockedWrap, mw = this.mainWrap;
56698 var lb = this.lockedBody, mb = this.mainBody;
56700 setTimeout(function(){
56701 var t = s.dom.offsetTop;
56702 var w = s.dom.clientWidth,
56703 h = s.dom.clientHeight;
56706 lw.setSize(ltWidth, h);
56708 mw.setLeftTop(ltWidth, t);
56709 mw.setSize(w-ltWidth, h);
56711 lb.setHeight(h-hdHeight);
56712 mb.setHeight(h-hdHeight);
56714 if(is2ndPass !== true && !gv.userResized && expandCol){
56715 // high speed resize without full column calculation
56717 var ci = cm.getIndexById(expandCol);
56719 ci = cm.findColumnIndex(expandCol);
56721 ci = Math.max(0, ci); // make sure it's got at least the first col.
56722 var expandId = cm.getColumnId(ci);
56723 var tw = cm.getTotalWidth(false);
56724 var currentWidth = cm.getColumnWidth(ci);
56725 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
56726 if(currentWidth != cw){
56727 cm.setColumnWidth(ci, cw, true);
56728 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56729 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
56730 gv.updateSplitters();
56731 gv.layout(false, true);
56743 onWindowResize : function(){
56744 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
56750 appendFooter : function(parentEl){
56754 sortAscText : "Sort Ascending",
56755 sortDescText : "Sort Descending",
56756 lockText : "Lock Column",
56757 unlockText : "Unlock Column",
56758 columnsText : "Columns",
56760 columnsWiderText : "Wider",
56761 columnsNarrowText : "Thinner"
56765 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
56766 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
56767 this.proxy.el.addClass('x-grid3-col-dd');
56770 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
56771 handleMouseDown : function(e){
56775 callHandleMouseDown : function(e){
56776 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
56781 * Ext JS Library 1.1.1
56782 * Copyright(c) 2006-2007, Ext JS, LLC.
56784 * Originally Released Under LGPL - original licence link has changed is not relivant.
56787 * <script type="text/javascript">
56791 // This is a support class used internally by the Grid components
56792 Roo.grid.SplitDragZone = function(grid, hd, hd2){
56794 this.view = grid.getView();
56795 this.proxy = this.view.resizeProxy;
56796 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
56797 "gridSplitters" + this.grid.getGridEl().id, {
56798 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
56800 this.setHandleElId(Roo.id(hd));
56801 this.setOuterHandleElId(Roo.id(hd2));
56802 this.scroll = false;
56804 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
56805 fly: Roo.Element.fly,
56807 b4StartDrag : function(x, y){
56808 this.view.headersDisabled = true;
56809 this.proxy.setHeight(this.view.mainWrap.getHeight());
56810 var w = this.cm.getColumnWidth(this.cellIndex);
56811 var minw = Math.max(w-this.grid.minColumnWidth, 0);
56812 this.resetConstraints();
56813 this.setXConstraint(minw, 1000);
56814 this.setYConstraint(0, 0);
56815 this.minX = x - minw;
56816 this.maxX = x + 1000;
56818 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
56822 handleMouseDown : function(e){
56823 ev = Roo.EventObject.setEvent(e);
56824 var t = this.fly(ev.getTarget());
56825 if(t.hasClass("x-grid-split")){
56826 this.cellIndex = this.view.getCellIndex(t.dom);
56827 this.split = t.dom;
56828 this.cm = this.grid.colModel;
56829 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
56830 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
56835 endDrag : function(e){
56836 this.view.headersDisabled = false;
56837 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
56838 var diff = endX - this.startPos;
56839 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
56842 autoOffset : function(){
56843 this.setDelta(0,0);
56847 * Ext JS Library 1.1.1
56848 * Copyright(c) 2006-2007, Ext JS, LLC.
56850 * Originally Released Under LGPL - original licence link has changed is not relivant.
56853 * <script type="text/javascript">
56857 // This is a support class used internally by the Grid components
56858 Roo.grid.GridDragZone = function(grid, config){
56859 this.view = grid.getView();
56860 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
56861 if(this.view.lockedBody){
56862 this.setHandleElId(Roo.id(this.view.mainBody.dom));
56863 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
56865 this.scroll = false;
56867 this.ddel = document.createElement('div');
56868 this.ddel.className = 'x-grid-dd-wrap';
56871 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
56872 ddGroup : "GridDD",
56874 getDragData : function(e){
56875 var t = Roo.lib.Event.getTarget(e);
56876 var rowIndex = this.view.findRowIndex(t);
56877 var sm = this.grid.selModel;
56879 //Roo.log(rowIndex);
56881 if (sm.getSelectedCell) {
56882 // cell selection..
56883 if (!sm.getSelectedCell()) {
56886 if (rowIndex != sm.getSelectedCell()[0]) {
56892 if(rowIndex !== false){
56897 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
56899 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
56902 if (e.hasModifier()){
56903 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
56906 Roo.log("getDragData");
56911 rowIndex: rowIndex,
56912 selections:sm.getSelections ? sm.getSelections() : (
56913 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
56920 onInitDrag : function(e){
56921 var data = this.dragData;
56922 this.ddel.innerHTML = this.grid.getDragDropText();
56923 this.proxy.update(this.ddel);
56924 // fire start drag?
56927 afterRepair : function(){
56928 this.dragging = false;
56931 getRepairXY : function(e, data){
56935 onEndDrag : function(data, e){
56939 onValidDrop : function(dd, e, id){
56944 beforeInvalidDrop : function(e, id){
56949 * Ext JS Library 1.1.1
56950 * Copyright(c) 2006-2007, Ext JS, LLC.
56952 * Originally Released Under LGPL - original licence link has changed is not relivant.
56955 * <script type="text/javascript">
56960 * @class Roo.grid.ColumnModel
56961 * @extends Roo.util.Observable
56962 * This is the default implementation of a ColumnModel used by the Grid. It defines
56963 * the columns in the grid.
56966 var colModel = new Roo.grid.ColumnModel([
56967 {header: "Ticker", width: 60, sortable: true, locked: true},
56968 {header: "Company Name", width: 150, sortable: true},
56969 {header: "Market Cap.", width: 100, sortable: true},
56970 {header: "$ Sales", width: 100, sortable: true, renderer: money},
56971 {header: "Employees", width: 100, sortable: true, resizable: false}
56976 * The config options listed for this class are options which may appear in each
56977 * individual column definition.
56978 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
56980 * @param {Object} config An Array of column config objects. See this class's
56981 * config objects for details.
56983 Roo.grid.ColumnModel = function(config){
56985 * The config passed into the constructor
56987 this.config = config;
56990 // if no id, create one
56991 // if the column does not have a dataIndex mapping,
56992 // map it to the order it is in the config
56993 for(var i = 0, len = config.length; i < len; i++){
56995 if(typeof c.dataIndex == "undefined"){
56998 if(typeof c.renderer == "string"){
56999 c.renderer = Roo.util.Format[c.renderer];
57001 if(typeof c.id == "undefined"){
57004 if(c.editor && c.editor.xtype){
57005 c.editor = Roo.factory(c.editor, Roo.grid);
57007 if(c.editor && c.editor.isFormField){
57008 c.editor = new Roo.grid.GridEditor(c.editor);
57010 this.lookup[c.id] = c;
57014 * The width of columns which have no width specified (defaults to 100)
57017 this.defaultWidth = 100;
57020 * Default sortable of columns which have no sortable specified (defaults to false)
57023 this.defaultSortable = false;
57027 * @event widthchange
57028 * Fires when the width of a column changes.
57029 * @param {ColumnModel} this
57030 * @param {Number} columnIndex The column index
57031 * @param {Number} newWidth The new width
57033 "widthchange": true,
57035 * @event headerchange
57036 * Fires when the text of a header changes.
57037 * @param {ColumnModel} this
57038 * @param {Number} columnIndex The column index
57039 * @param {Number} newText The new header text
57041 "headerchange": true,
57043 * @event hiddenchange
57044 * Fires when a column is hidden or "unhidden".
57045 * @param {ColumnModel} this
57046 * @param {Number} columnIndex The column index
57047 * @param {Boolean} hidden true if hidden, false otherwise
57049 "hiddenchange": true,
57051 * @event columnmoved
57052 * Fires when a column is moved.
57053 * @param {ColumnModel} this
57054 * @param {Number} oldIndex
57055 * @param {Number} newIndex
57057 "columnmoved" : true,
57059 * @event columlockchange
57060 * Fires when a column's locked state is changed
57061 * @param {ColumnModel} this
57062 * @param {Number} colIndex
57063 * @param {Boolean} locked true if locked
57065 "columnlockchange" : true
57067 Roo.grid.ColumnModel.superclass.constructor.call(this);
57069 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
57071 * @cfg {String} header The header text to display in the Grid view.
57074 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
57075 * {@link Roo.data.Record} definition from which to draw the column's value. If not
57076 * specified, the column's index is used as an index into the Record's data Array.
57079 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
57080 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
57083 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
57084 * Defaults to the value of the {@link #defaultSortable} property.
57085 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
57088 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
57091 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
57094 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
57097 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
57100 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
57101 * given the cell's data value. See {@link #setRenderer}. If not specified, the
57102 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
57103 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
57106 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
57109 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
57112 * @cfg {String} cursor (Optional)
57115 * @cfg {String} tooltip (Optional)
57118 * @cfg {Number} xs (Optional)
57121 * @cfg {Number} sm (Optional)
57124 * @cfg {Number} md (Optional)
57127 * @cfg {Number} lg (Optional)
57130 * Returns the id of the column at the specified index.
57131 * @param {Number} index The column index
57132 * @return {String} the id
57134 getColumnId : function(index){
57135 return this.config[index].id;
57139 * Returns the column for a specified id.
57140 * @param {String} id The column id
57141 * @return {Object} the column
57143 getColumnById : function(id){
57144 return this.lookup[id];
57149 * Returns the column for a specified dataIndex.
57150 * @param {String} dataIndex The column dataIndex
57151 * @return {Object|Boolean} the column or false if not found
57153 getColumnByDataIndex: function(dataIndex){
57154 var index = this.findColumnIndex(dataIndex);
57155 return index > -1 ? this.config[index] : false;
57159 * Returns the index for a specified column id.
57160 * @param {String} id The column id
57161 * @return {Number} the index, or -1 if not found
57163 getIndexById : function(id){
57164 for(var i = 0, len = this.config.length; i < len; i++){
57165 if(this.config[i].id == id){
57173 * Returns the index for a specified column dataIndex.
57174 * @param {String} dataIndex The column dataIndex
57175 * @return {Number} the index, or -1 if not found
57178 findColumnIndex : function(dataIndex){
57179 for(var i = 0, len = this.config.length; i < len; i++){
57180 if(this.config[i].dataIndex == dataIndex){
57188 moveColumn : function(oldIndex, newIndex){
57189 var c = this.config[oldIndex];
57190 this.config.splice(oldIndex, 1);
57191 this.config.splice(newIndex, 0, c);
57192 this.dataMap = null;
57193 this.fireEvent("columnmoved", this, oldIndex, newIndex);
57196 isLocked : function(colIndex){
57197 return this.config[colIndex].locked === true;
57200 setLocked : function(colIndex, value, suppressEvent){
57201 if(this.isLocked(colIndex) == value){
57204 this.config[colIndex].locked = value;
57205 if(!suppressEvent){
57206 this.fireEvent("columnlockchange", this, colIndex, value);
57210 getTotalLockedWidth : function(){
57211 var totalWidth = 0;
57212 for(var i = 0; i < this.config.length; i++){
57213 if(this.isLocked(i) && !this.isHidden(i)){
57214 this.totalWidth += this.getColumnWidth(i);
57220 getLockedCount : function(){
57221 for(var i = 0, len = this.config.length; i < len; i++){
57222 if(!this.isLocked(i)){
57227 return this.config.length;
57231 * Returns the number of columns.
57234 getColumnCount : function(visibleOnly){
57235 if(visibleOnly === true){
57237 for(var i = 0, len = this.config.length; i < len; i++){
57238 if(!this.isHidden(i)){
57244 return this.config.length;
57248 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
57249 * @param {Function} fn
57250 * @param {Object} scope (optional)
57251 * @return {Array} result
57253 getColumnsBy : function(fn, scope){
57255 for(var i = 0, len = this.config.length; i < len; i++){
57256 var c = this.config[i];
57257 if(fn.call(scope||this, c, i) === true){
57265 * Returns true if the specified column is sortable.
57266 * @param {Number} col The column index
57267 * @return {Boolean}
57269 isSortable : function(col){
57270 if(typeof this.config[col].sortable == "undefined"){
57271 return this.defaultSortable;
57273 return this.config[col].sortable;
57277 * Returns the rendering (formatting) function defined for the column.
57278 * @param {Number} col The column index.
57279 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
57281 getRenderer : function(col){
57282 if(!this.config[col].renderer){
57283 return Roo.grid.ColumnModel.defaultRenderer;
57285 return this.config[col].renderer;
57289 * Sets the rendering (formatting) function for a column.
57290 * @param {Number} col The column index
57291 * @param {Function} fn The function to use to process the cell's raw data
57292 * to return HTML markup for the grid view. The render function is called with
57293 * the following parameters:<ul>
57294 * <li>Data value.</li>
57295 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
57296 * <li>css A CSS style string to apply to the table cell.</li>
57297 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
57298 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
57299 * <li>Row index</li>
57300 * <li>Column index</li>
57301 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
57303 setRenderer : function(col, fn){
57304 this.config[col].renderer = fn;
57308 * Returns the width for the specified column.
57309 * @param {Number} col The column index
57312 getColumnWidth : function(col){
57313 return this.config[col].width * 1 || this.defaultWidth;
57317 * Sets the width for a column.
57318 * @param {Number} col The column index
57319 * @param {Number} width The new width
57321 setColumnWidth : function(col, width, suppressEvent){
57322 this.config[col].width = width;
57323 this.totalWidth = null;
57324 if(!suppressEvent){
57325 this.fireEvent("widthchange", this, col, width);
57330 * Returns the total width of all columns.
57331 * @param {Boolean} includeHidden True to include hidden column widths
57334 getTotalWidth : function(includeHidden){
57335 if(!this.totalWidth){
57336 this.totalWidth = 0;
57337 for(var i = 0, len = this.config.length; i < len; i++){
57338 if(includeHidden || !this.isHidden(i)){
57339 this.totalWidth += this.getColumnWidth(i);
57343 return this.totalWidth;
57347 * Returns the header for the specified column.
57348 * @param {Number} col The column index
57351 getColumnHeader : function(col){
57352 return this.config[col].header;
57356 * Sets the header for a column.
57357 * @param {Number} col The column index
57358 * @param {String} header The new header
57360 setColumnHeader : function(col, header){
57361 this.config[col].header = header;
57362 this.fireEvent("headerchange", this, col, header);
57366 * Returns the tooltip for the specified column.
57367 * @param {Number} col The column index
57370 getColumnTooltip : function(col){
57371 return this.config[col].tooltip;
57374 * Sets the tooltip for a column.
57375 * @param {Number} col The column index
57376 * @param {String} tooltip The new tooltip
57378 setColumnTooltip : function(col, tooltip){
57379 this.config[col].tooltip = tooltip;
57383 * Returns the dataIndex for the specified column.
57384 * @param {Number} col The column index
57387 getDataIndex : function(col){
57388 return this.config[col].dataIndex;
57392 * Sets the dataIndex for a column.
57393 * @param {Number} col The column index
57394 * @param {Number} dataIndex The new dataIndex
57396 setDataIndex : function(col, dataIndex){
57397 this.config[col].dataIndex = dataIndex;
57403 * Returns true if the cell is editable.
57404 * @param {Number} colIndex The column index
57405 * @param {Number} rowIndex The row index - this is nto actually used..?
57406 * @return {Boolean}
57408 isCellEditable : function(colIndex, rowIndex){
57409 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
57413 * Returns the editor defined for the cell/column.
57414 * return false or null to disable editing.
57415 * @param {Number} colIndex The column index
57416 * @param {Number} rowIndex The row index
57419 getCellEditor : function(colIndex, rowIndex){
57420 return this.config[colIndex].editor;
57424 * Sets if a column is editable.
57425 * @param {Number} col The column index
57426 * @param {Boolean} editable True if the column is editable
57428 setEditable : function(col, editable){
57429 this.config[col].editable = editable;
57434 * Returns true if the column is hidden.
57435 * @param {Number} colIndex The column index
57436 * @return {Boolean}
57438 isHidden : function(colIndex){
57439 return this.config[colIndex].hidden;
57444 * Returns true if the column width cannot be changed
57446 isFixed : function(colIndex){
57447 return this.config[colIndex].fixed;
57451 * Returns true if the column can be resized
57452 * @return {Boolean}
57454 isResizable : function(colIndex){
57455 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
57458 * Sets if a column is hidden.
57459 * @param {Number} colIndex The column index
57460 * @param {Boolean} hidden True if the column is hidden
57462 setHidden : function(colIndex, hidden){
57463 this.config[colIndex].hidden = hidden;
57464 this.totalWidth = null;
57465 this.fireEvent("hiddenchange", this, colIndex, hidden);
57469 * Sets the editor for a column.
57470 * @param {Number} col The column index
57471 * @param {Object} editor The editor object
57473 setEditor : function(col, editor){
57474 this.config[col].editor = editor;
57478 Roo.grid.ColumnModel.defaultRenderer = function(value)
57480 if(typeof value == "object") {
57483 if(typeof value == "string" && value.length < 1){
57487 return String.format("{0}", value);
57490 // Alias for backwards compatibility
57491 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
57494 * Ext JS Library 1.1.1
57495 * Copyright(c) 2006-2007, Ext JS, LLC.
57497 * Originally Released Under LGPL - original licence link has changed is not relivant.
57500 * <script type="text/javascript">
57504 * @class Roo.grid.AbstractSelectionModel
57505 * @extends Roo.util.Observable
57506 * Abstract base class for grid SelectionModels. It provides the interface that should be
57507 * implemented by descendant classes. This class should not be directly instantiated.
57510 Roo.grid.AbstractSelectionModel = function(){
57511 this.locked = false;
57512 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
57515 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
57516 /** @ignore Called by the grid automatically. Do not call directly. */
57517 init : function(grid){
57523 * Locks the selections.
57526 this.locked = true;
57530 * Unlocks the selections.
57532 unlock : function(){
57533 this.locked = false;
57537 * Returns true if the selections are locked.
57538 * @return {Boolean}
57540 isLocked : function(){
57541 return this.locked;
57545 * Ext JS Library 1.1.1
57546 * Copyright(c) 2006-2007, Ext JS, LLC.
57548 * Originally Released Under LGPL - original licence link has changed is not relivant.
57551 * <script type="text/javascript">
57554 * @extends Roo.grid.AbstractSelectionModel
57555 * @class Roo.grid.RowSelectionModel
57556 * The default SelectionModel used by {@link Roo.grid.Grid}.
57557 * It supports multiple selections and keyboard selection/navigation.
57559 * @param {Object} config
57561 Roo.grid.RowSelectionModel = function(config){
57562 Roo.apply(this, config);
57563 this.selections = new Roo.util.MixedCollection(false, function(o){
57568 this.lastActive = false;
57572 * @event selectionchange
57573 * Fires when the selection changes
57574 * @param {SelectionModel} this
57576 "selectionchange" : true,
57578 * @event afterselectionchange
57579 * Fires after the selection changes (eg. by key press or clicking)
57580 * @param {SelectionModel} this
57582 "afterselectionchange" : true,
57584 * @event beforerowselect
57585 * Fires when a row is selected being selected, return false to cancel.
57586 * @param {SelectionModel} this
57587 * @param {Number} rowIndex The selected index
57588 * @param {Boolean} keepExisting False if other selections will be cleared
57590 "beforerowselect" : true,
57593 * Fires when a row is selected.
57594 * @param {SelectionModel} this
57595 * @param {Number} rowIndex The selected index
57596 * @param {Roo.data.Record} r The record
57598 "rowselect" : true,
57600 * @event rowdeselect
57601 * Fires when a row is deselected.
57602 * @param {SelectionModel} this
57603 * @param {Number} rowIndex The selected index
57605 "rowdeselect" : true
57607 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
57608 this.locked = false;
57611 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
57613 * @cfg {Boolean} singleSelect
57614 * True to allow selection of only one row at a time (defaults to false)
57616 singleSelect : false,
57619 initEvents : function(){
57621 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
57622 this.grid.on("mousedown", this.handleMouseDown, this);
57623 }else{ // allow click to work like normal
57624 this.grid.on("rowclick", this.handleDragableRowClick, this);
57627 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
57628 "up" : function(e){
57630 this.selectPrevious(e.shiftKey);
57631 }else if(this.last !== false && this.lastActive !== false){
57632 var last = this.last;
57633 this.selectRange(this.last, this.lastActive-1);
57634 this.grid.getView().focusRow(this.lastActive);
57635 if(last !== false){
57639 this.selectFirstRow();
57641 this.fireEvent("afterselectionchange", this);
57643 "down" : function(e){
57645 this.selectNext(e.shiftKey);
57646 }else if(this.last !== false && this.lastActive !== false){
57647 var last = this.last;
57648 this.selectRange(this.last, this.lastActive+1);
57649 this.grid.getView().focusRow(this.lastActive);
57650 if(last !== false){
57654 this.selectFirstRow();
57656 this.fireEvent("afterselectionchange", this);
57661 var view = this.grid.view;
57662 view.on("refresh", this.onRefresh, this);
57663 view.on("rowupdated", this.onRowUpdated, this);
57664 view.on("rowremoved", this.onRemove, this);
57668 onRefresh : function(){
57669 var ds = this.grid.dataSource, i, v = this.grid.view;
57670 var s = this.selections;
57671 s.each(function(r){
57672 if((i = ds.indexOfId(r.id)) != -1){
57674 s.add(ds.getAt(i)); // updating the selection relate data
57682 onRemove : function(v, index, r){
57683 this.selections.remove(r);
57687 onRowUpdated : function(v, index, r){
57688 if(this.isSelected(r)){
57689 v.onRowSelect(index);
57695 * @param {Array} records The records to select
57696 * @param {Boolean} keepExisting (optional) True to keep existing selections
57698 selectRecords : function(records, keepExisting){
57700 this.clearSelections();
57702 var ds = this.grid.dataSource;
57703 for(var i = 0, len = records.length; i < len; i++){
57704 this.selectRow(ds.indexOf(records[i]), true);
57709 * Gets the number of selected rows.
57712 getCount : function(){
57713 return this.selections.length;
57717 * Selects the first row in the grid.
57719 selectFirstRow : function(){
57724 * Select the last row.
57725 * @param {Boolean} keepExisting (optional) True to keep existing selections
57727 selectLastRow : function(keepExisting){
57728 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
57732 * Selects the row immediately following the last selected row.
57733 * @param {Boolean} keepExisting (optional) True to keep existing selections
57735 selectNext : function(keepExisting){
57736 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
57737 this.selectRow(this.last+1, keepExisting);
57738 this.grid.getView().focusRow(this.last);
57743 * Selects the row that precedes the last selected row.
57744 * @param {Boolean} keepExisting (optional) True to keep existing selections
57746 selectPrevious : function(keepExisting){
57748 this.selectRow(this.last-1, keepExisting);
57749 this.grid.getView().focusRow(this.last);
57754 * Returns the selected records
57755 * @return {Array} Array of selected records
57757 getSelections : function(){
57758 return [].concat(this.selections.items);
57762 * Returns the first selected record.
57765 getSelected : function(){
57766 return this.selections.itemAt(0);
57771 * Clears all selections.
57773 clearSelections : function(fast){
57778 var ds = this.grid.dataSource;
57779 var s = this.selections;
57780 s.each(function(r){
57781 this.deselectRow(ds.indexOfId(r.id));
57785 this.selections.clear();
57792 * Selects all rows.
57794 selectAll : function(){
57798 this.selections.clear();
57799 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
57800 this.selectRow(i, true);
57805 * Returns True if there is a selection.
57806 * @return {Boolean}
57808 hasSelection : function(){
57809 return this.selections.length > 0;
57813 * Returns True if the specified row is selected.
57814 * @param {Number/Record} record The record or index of the record to check
57815 * @return {Boolean}
57817 isSelected : function(index){
57818 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
57819 return (r && this.selections.key(r.id) ? true : false);
57823 * Returns True if the specified record id is selected.
57824 * @param {String} id The id of record to check
57825 * @return {Boolean}
57827 isIdSelected : function(id){
57828 return (this.selections.key(id) ? true : false);
57832 handleMouseDown : function(e, t){
57833 var view = this.grid.getView(), rowIndex;
57834 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
57837 if(e.shiftKey && this.last !== false){
57838 var last = this.last;
57839 this.selectRange(last, rowIndex, e.ctrlKey);
57840 this.last = last; // reset the last
57841 view.focusRow(rowIndex);
57843 var isSelected = this.isSelected(rowIndex);
57844 if(e.button !== 0 && isSelected){
57845 view.focusRow(rowIndex);
57846 }else if(e.ctrlKey && isSelected){
57847 this.deselectRow(rowIndex);
57848 }else if(!isSelected){
57849 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
57850 view.focusRow(rowIndex);
57853 this.fireEvent("afterselectionchange", this);
57856 handleDragableRowClick : function(grid, rowIndex, e)
57858 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
57859 this.selectRow(rowIndex, false);
57860 grid.view.focusRow(rowIndex);
57861 this.fireEvent("afterselectionchange", this);
57866 * Selects multiple rows.
57867 * @param {Array} rows Array of the indexes of the row to select
57868 * @param {Boolean} keepExisting (optional) True to keep existing selections
57870 selectRows : function(rows, keepExisting){
57872 this.clearSelections();
57874 for(var i = 0, len = rows.length; i < len; i++){
57875 this.selectRow(rows[i], true);
57880 * Selects a range of rows. All rows in between startRow and endRow are also selected.
57881 * @param {Number} startRow The index of the first row in the range
57882 * @param {Number} endRow The index of the last row in the range
57883 * @param {Boolean} keepExisting (optional) True to retain existing selections
57885 selectRange : function(startRow, endRow, keepExisting){
57890 this.clearSelections();
57892 if(startRow <= endRow){
57893 for(var i = startRow; i <= endRow; i++){
57894 this.selectRow(i, true);
57897 for(var i = startRow; i >= endRow; i--){
57898 this.selectRow(i, true);
57904 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
57905 * @param {Number} startRow The index of the first row in the range
57906 * @param {Number} endRow The index of the last row in the range
57908 deselectRange : function(startRow, endRow, preventViewNotify){
57912 for(var i = startRow; i <= endRow; i++){
57913 this.deselectRow(i, preventViewNotify);
57919 * @param {Number} row The index of the row to select
57920 * @param {Boolean} keepExisting (optional) True to keep existing selections
57922 selectRow : function(index, keepExisting, preventViewNotify){
57923 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) {
57926 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
57927 if(!keepExisting || this.singleSelect){
57928 this.clearSelections();
57930 var r = this.grid.dataSource.getAt(index);
57931 this.selections.add(r);
57932 this.last = this.lastActive = index;
57933 if(!preventViewNotify){
57934 this.grid.getView().onRowSelect(index);
57936 this.fireEvent("rowselect", this, index, r);
57937 this.fireEvent("selectionchange", this);
57943 * @param {Number} row The index of the row to deselect
57945 deselectRow : function(index, preventViewNotify){
57949 if(this.last == index){
57952 if(this.lastActive == index){
57953 this.lastActive = false;
57955 var r = this.grid.dataSource.getAt(index);
57956 this.selections.remove(r);
57957 if(!preventViewNotify){
57958 this.grid.getView().onRowDeselect(index);
57960 this.fireEvent("rowdeselect", this, index);
57961 this.fireEvent("selectionchange", this);
57965 restoreLast : function(){
57967 this.last = this._last;
57972 acceptsNav : function(row, col, cm){
57973 return !cm.isHidden(col) && cm.isCellEditable(col, row);
57977 onEditorKey : function(field, e){
57978 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
57983 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
57985 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
57987 }else if(k == e.ENTER && !e.ctrlKey){
57991 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
57993 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
57995 }else if(k == e.ESC){
57999 g.startEditing(newCell[0], newCell[1]);
58004 * Ext JS Library 1.1.1
58005 * Copyright(c) 2006-2007, Ext JS, LLC.
58007 * Originally Released Under LGPL - original licence link has changed is not relivant.
58010 * <script type="text/javascript">
58013 * @class Roo.grid.CellSelectionModel
58014 * @extends Roo.grid.AbstractSelectionModel
58015 * This class provides the basic implementation for cell selection in a grid.
58017 * @param {Object} config The object containing the configuration of this model.
58018 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
58020 Roo.grid.CellSelectionModel = function(config){
58021 Roo.apply(this, config);
58023 this.selection = null;
58027 * @event beforerowselect
58028 * Fires before a cell is selected.
58029 * @param {SelectionModel} this
58030 * @param {Number} rowIndex The selected row index
58031 * @param {Number} colIndex The selected cell index
58033 "beforecellselect" : true,
58035 * @event cellselect
58036 * Fires when a cell is selected.
58037 * @param {SelectionModel} this
58038 * @param {Number} rowIndex The selected row index
58039 * @param {Number} colIndex The selected cell index
58041 "cellselect" : true,
58043 * @event selectionchange
58044 * Fires when the active selection changes.
58045 * @param {SelectionModel} this
58046 * @param {Object} selection null for no selection or an object (o) with two properties
58048 <li>o.record: the record object for the row the selection is in</li>
58049 <li>o.cell: An array of [rowIndex, columnIndex]</li>
58052 "selectionchange" : true,
58055 * Fires when the tab (or enter) was pressed on the last editable cell
58056 * You can use this to trigger add new row.
58057 * @param {SelectionModel} this
58061 * @event beforeeditnext
58062 * Fires before the next editable sell is made active
58063 * You can use this to skip to another cell or fire the tabend
58064 * if you set cell to false
58065 * @param {Object} eventdata object : { cell : [ row, col ] }
58067 "beforeeditnext" : true
58069 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
58072 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
58074 enter_is_tab: false,
58077 initEvents : function(){
58078 this.grid.on("mousedown", this.handleMouseDown, this);
58079 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
58080 var view = this.grid.view;
58081 view.on("refresh", this.onViewChange, this);
58082 view.on("rowupdated", this.onRowUpdated, this);
58083 view.on("beforerowremoved", this.clearSelections, this);
58084 view.on("beforerowsinserted", this.clearSelections, this);
58085 if(this.grid.isEditor){
58086 this.grid.on("beforeedit", this.beforeEdit, this);
58091 beforeEdit : function(e){
58092 this.select(e.row, e.column, false, true, e.record);
58096 onRowUpdated : function(v, index, r){
58097 if(this.selection && this.selection.record == r){
58098 v.onCellSelect(index, this.selection.cell[1]);
58103 onViewChange : function(){
58104 this.clearSelections(true);
58108 * Returns the currently selected cell,.
58109 * @return {Array} The selected cell (row, column) or null if none selected.
58111 getSelectedCell : function(){
58112 return this.selection ? this.selection.cell : null;
58116 * Clears all selections.
58117 * @param {Boolean} true to prevent the gridview from being notified about the change.
58119 clearSelections : function(preventNotify){
58120 var s = this.selection;
58122 if(preventNotify !== true){
58123 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
58125 this.selection = null;
58126 this.fireEvent("selectionchange", this, null);
58131 * Returns true if there is a selection.
58132 * @return {Boolean}
58134 hasSelection : function(){
58135 return this.selection ? true : false;
58139 handleMouseDown : function(e, t){
58140 var v = this.grid.getView();
58141 if(this.isLocked()){
58144 var row = v.findRowIndex(t);
58145 var cell = v.findCellIndex(t);
58146 if(row !== false && cell !== false){
58147 this.select(row, cell);
58153 * @param {Number} rowIndex
58154 * @param {Number} collIndex
58156 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
58157 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
58158 this.clearSelections();
58159 r = r || this.grid.dataSource.getAt(rowIndex);
58162 cell : [rowIndex, colIndex]
58164 if(!preventViewNotify){
58165 var v = this.grid.getView();
58166 v.onCellSelect(rowIndex, colIndex);
58167 if(preventFocus !== true){
58168 v.focusCell(rowIndex, colIndex);
58171 this.fireEvent("cellselect", this, rowIndex, colIndex);
58172 this.fireEvent("selectionchange", this, this.selection);
58177 isSelectable : function(rowIndex, colIndex, cm){
58178 return !cm.isHidden(colIndex);
58182 handleKeyDown : function(e){
58183 //Roo.log('Cell Sel Model handleKeyDown');
58184 if(!e.isNavKeyPress()){
58187 var g = this.grid, s = this.selection;
58190 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
58192 this.select(cell[0], cell[1]);
58197 var walk = function(row, col, step){
58198 return g.walkCells(row, col, step, sm.isSelectable, sm);
58200 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
58207 // handled by onEditorKey
58208 if (g.isEditor && g.editing) {
58212 newCell = walk(r, c-1, -1);
58214 newCell = walk(r, c+1, 1);
58219 newCell = walk(r+1, c, 1);
58223 newCell = walk(r-1, c, -1);
58227 newCell = walk(r, c+1, 1);
58231 newCell = walk(r, c-1, -1);
58236 if(g.isEditor && !g.editing){
58237 g.startEditing(r, c);
58246 this.select(newCell[0], newCell[1]);
58252 acceptsNav : function(row, col, cm){
58253 return !cm.isHidden(col) && cm.isCellEditable(col, row);
58257 * @param {Number} field (not used) - as it's normally used as a listener
58258 * @param {Number} e - event - fake it by using
58260 * var e = Roo.EventObjectImpl.prototype;
58261 * e.keyCode = e.TAB
58265 onEditorKey : function(field, e){
58267 var k = e.getKey(),
58270 ed = g.activeEditor,
58272 ///Roo.log('onEditorKey' + k);
58275 if (this.enter_is_tab && k == e.ENTER) {
58281 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
58283 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58289 } else if(k == e.ENTER && !e.ctrlKey){
58292 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
58294 } else if(k == e.ESC){
58299 var ecall = { cell : newCell, forward : forward };
58300 this.fireEvent('beforeeditnext', ecall );
58301 newCell = ecall.cell;
58302 forward = ecall.forward;
58306 //Roo.log('next cell after edit');
58307 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
58308 } else if (forward) {
58309 // tabbed past last
58310 this.fireEvent.defer(100, this, ['tabend',this]);
58315 * Ext JS Library 1.1.1
58316 * Copyright(c) 2006-2007, Ext JS, LLC.
58318 * Originally Released Under LGPL - original licence link has changed is not relivant.
58321 * <script type="text/javascript">
58325 * @class Roo.grid.EditorGrid
58326 * @extends Roo.grid.Grid
58327 * Class for creating and editable grid.
58328 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58329 * The container MUST have some type of size defined for the grid to fill. The container will be
58330 * automatically set to position relative if it isn't already.
58331 * @param {Object} dataSource The data model to bind to
58332 * @param {Object} colModel The column model with info about this grid's columns
58334 Roo.grid.EditorGrid = function(container, config){
58335 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
58336 this.getGridEl().addClass("xedit-grid");
58338 if(!this.selModel){
58339 this.selModel = new Roo.grid.CellSelectionModel();
58342 this.activeEditor = null;
58346 * @event beforeedit
58347 * Fires before cell editing is triggered. The edit event object has the following properties <br />
58348 * <ul style="padding:5px;padding-left:16px;">
58349 * <li>grid - This grid</li>
58350 * <li>record - The record being edited</li>
58351 * <li>field - The field name being edited</li>
58352 * <li>value - The value for the field being edited.</li>
58353 * <li>row - The grid row index</li>
58354 * <li>column - The grid column index</li>
58355 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58357 * @param {Object} e An edit event (see above for description)
58359 "beforeedit" : true,
58362 * Fires after a cell is edited. <br />
58363 * <ul style="padding:5px;padding-left:16px;">
58364 * <li>grid - This grid</li>
58365 * <li>record - The record being edited</li>
58366 * <li>field - The field name being edited</li>
58367 * <li>value - The value being set</li>
58368 * <li>originalValue - The original value for the field, before the edit.</li>
58369 * <li>row - The grid row index</li>
58370 * <li>column - The grid column index</li>
58372 * @param {Object} e An edit event (see above for description)
58374 "afteredit" : true,
58376 * @event validateedit
58377 * Fires after a cell is edited, but before the value is set in the record.
58378 * You can use this to modify the value being set in the field, Return false
58379 * to cancel the change. The edit event object has the following properties <br />
58380 * <ul style="padding:5px;padding-left:16px;">
58381 * <li>editor - This editor</li>
58382 * <li>grid - This grid</li>
58383 * <li>record - The record being edited</li>
58384 * <li>field - The field name being edited</li>
58385 * <li>value - The value being set</li>
58386 * <li>originalValue - The original value for the field, before the edit.</li>
58387 * <li>row - The grid row index</li>
58388 * <li>column - The grid column index</li>
58389 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
58391 * @param {Object} e An edit event (see above for description)
58393 "validateedit" : true
58395 this.on("bodyscroll", this.stopEditing, this);
58396 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
58399 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
58401 * @cfg {Number} clicksToEdit
58402 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
58409 trackMouseOver: false, // causes very odd FF errors
58411 onCellDblClick : function(g, row, col){
58412 this.startEditing(row, col);
58415 onEditComplete : function(ed, value, startValue){
58416 this.editing = false;
58417 this.activeEditor = null;
58418 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
58420 var field = this.colModel.getDataIndex(ed.col);
58425 originalValue: startValue,
58432 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
58435 if(String(value) !== String(startValue)){
58437 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
58438 r.set(field, e.value);
58439 // if we are dealing with a combo box..
58440 // then we also set the 'name' colum to be the displayField
58441 if (ed.field.displayField && ed.field.name) {
58442 r.set(ed.field.name, ed.field.el.dom.value);
58445 delete e.cancel; //?? why!!!
58446 this.fireEvent("afteredit", e);
58449 this.fireEvent("afteredit", e); // always fire it!
58451 this.view.focusCell(ed.row, ed.col);
58455 * Starts editing the specified for the specified row/column
58456 * @param {Number} rowIndex
58457 * @param {Number} colIndex
58459 startEditing : function(row, col){
58460 this.stopEditing();
58461 if(this.colModel.isCellEditable(col, row)){
58462 this.view.ensureVisible(row, col, true);
58464 var r = this.dataSource.getAt(row);
58465 var field = this.colModel.getDataIndex(col);
58466 var cell = Roo.get(this.view.getCell(row,col));
58471 value: r.data[field],
58476 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
58477 this.editing = true;
58478 var ed = this.colModel.getCellEditor(col, row);
58484 ed.render(ed.parentEl || document.body);
58490 (function(){ // complex but required for focus issues in safari, ie and opera
58494 ed.on("complete", this.onEditComplete, this, {single: true});
58495 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
58496 this.activeEditor = ed;
58497 var v = r.data[field];
58498 ed.startEdit(this.view.getCell(row, col), v);
58499 // combo's with 'displayField and name set
58500 if (ed.field.displayField && ed.field.name) {
58501 ed.field.el.dom.value = r.data[ed.field.name];
58505 }).defer(50, this);
58511 * Stops any active editing
58513 stopEditing : function(){
58514 if(this.activeEditor){
58515 this.activeEditor.completeEdit();
58517 this.activeEditor = null;
58521 * Called to get grid's drag proxy text, by default returns this.ddText.
58524 getDragDropText : function(){
58525 var count = this.selModel.getSelectedCell() ? 1 : 0;
58526 return String.format(this.ddText, count, count == 1 ? '' : 's');
58531 * Ext JS Library 1.1.1
58532 * Copyright(c) 2006-2007, Ext JS, LLC.
58534 * Originally Released Under LGPL - original licence link has changed is not relivant.
58537 * <script type="text/javascript">
58540 // private - not really -- you end up using it !
58541 // This is a support class used internally by the Grid components
58544 * @class Roo.grid.GridEditor
58545 * @extends Roo.Editor
58546 * Class for creating and editable grid elements.
58547 * @param {Object} config any settings (must include field)
58549 Roo.grid.GridEditor = function(field, config){
58550 if (!config && field.field) {
58552 field = Roo.factory(config.field, Roo.form);
58554 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
58555 field.monitorTab = false;
58558 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
58561 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
58564 alignment: "tl-tl",
58567 cls: "x-small-editor x-grid-editor",
58572 * Ext JS Library 1.1.1
58573 * Copyright(c) 2006-2007, Ext JS, LLC.
58575 * Originally Released Under LGPL - original licence link has changed is not relivant.
58578 * <script type="text/javascript">
58583 Roo.grid.PropertyRecord = Roo.data.Record.create([
58584 {name:'name',type:'string'}, 'value'
58588 Roo.grid.PropertyStore = function(grid, source){
58590 this.store = new Roo.data.Store({
58591 recordType : Roo.grid.PropertyRecord
58593 this.store.on('update', this.onUpdate, this);
58595 this.setSource(source);
58597 Roo.grid.PropertyStore.superclass.constructor.call(this);
58602 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
58603 setSource : function(o){
58605 this.store.removeAll();
58608 if(this.isEditableValue(o[k])){
58609 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
58612 this.store.loadRecords({records: data}, {}, true);
58615 onUpdate : function(ds, record, type){
58616 if(type == Roo.data.Record.EDIT){
58617 var v = record.data['value'];
58618 var oldValue = record.modified['value'];
58619 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
58620 this.source[record.id] = v;
58622 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
58629 getProperty : function(row){
58630 return this.store.getAt(row);
58633 isEditableValue: function(val){
58634 if(val && val instanceof Date){
58636 }else if(typeof val == 'object' || typeof val == 'function'){
58642 setValue : function(prop, value){
58643 this.source[prop] = value;
58644 this.store.getById(prop).set('value', value);
58647 getSource : function(){
58648 return this.source;
58652 Roo.grid.PropertyColumnModel = function(grid, store){
58655 g.PropertyColumnModel.superclass.constructor.call(this, [
58656 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
58657 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
58659 this.store = store;
58660 this.bselect = Roo.DomHelper.append(document.body, {
58661 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
58662 {tag: 'option', value: 'true', html: 'true'},
58663 {tag: 'option', value: 'false', html: 'false'}
58666 Roo.id(this.bselect);
58669 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
58670 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
58671 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
58672 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
58673 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
58675 this.renderCellDelegate = this.renderCell.createDelegate(this);
58676 this.renderPropDelegate = this.renderProp.createDelegate(this);
58679 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
58683 valueText : 'Value',
58685 dateFormat : 'm/j/Y',
58688 renderDate : function(dateVal){
58689 return dateVal.dateFormat(this.dateFormat);
58692 renderBool : function(bVal){
58693 return bVal ? 'true' : 'false';
58696 isCellEditable : function(colIndex, rowIndex){
58697 return colIndex == 1;
58700 getRenderer : function(col){
58702 this.renderCellDelegate : this.renderPropDelegate;
58705 renderProp : function(v){
58706 return this.getPropertyName(v);
58709 renderCell : function(val){
58711 if(val instanceof Date){
58712 rv = this.renderDate(val);
58713 }else if(typeof val == 'boolean'){
58714 rv = this.renderBool(val);
58716 return Roo.util.Format.htmlEncode(rv);
58719 getPropertyName : function(name){
58720 var pn = this.grid.propertyNames;
58721 return pn && pn[name] ? pn[name] : name;
58724 getCellEditor : function(colIndex, rowIndex){
58725 var p = this.store.getProperty(rowIndex);
58726 var n = p.data['name'], val = p.data['value'];
58728 if(typeof(this.grid.customEditors[n]) == 'string'){
58729 return this.editors[this.grid.customEditors[n]];
58731 if(typeof(this.grid.customEditors[n]) != 'undefined'){
58732 return this.grid.customEditors[n];
58734 if(val instanceof Date){
58735 return this.editors['date'];
58736 }else if(typeof val == 'number'){
58737 return this.editors['number'];
58738 }else if(typeof val == 'boolean'){
58739 return this.editors['boolean'];
58741 return this.editors['string'];
58747 * @class Roo.grid.PropertyGrid
58748 * @extends Roo.grid.EditorGrid
58749 * This class represents the interface of a component based property grid control.
58750 * <br><br>Usage:<pre><code>
58751 var grid = new Roo.grid.PropertyGrid("my-container-id", {
58759 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58760 * The container MUST have some type of size defined for the grid to fill. The container will be
58761 * automatically set to position relative if it isn't already.
58762 * @param {Object} config A config object that sets properties on this grid.
58764 Roo.grid.PropertyGrid = function(container, config){
58765 config = config || {};
58766 var store = new Roo.grid.PropertyStore(this);
58767 this.store = store;
58768 var cm = new Roo.grid.PropertyColumnModel(this, store);
58769 store.store.sort('name', 'ASC');
58770 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
58773 enableColLock:false,
58774 enableColumnMove:false,
58776 trackMouseOver: false,
58779 this.getGridEl().addClass('x-props-grid');
58780 this.lastEditRow = null;
58781 this.on('columnresize', this.onColumnResize, this);
58784 * @event beforepropertychange
58785 * Fires before a property changes (return false to stop?)
58786 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58787 * @param {String} id Record Id
58788 * @param {String} newval New Value
58789 * @param {String} oldval Old Value
58791 "beforepropertychange": true,
58793 * @event propertychange
58794 * Fires after a property changes
58795 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
58796 * @param {String} id Record Id
58797 * @param {String} newval New Value
58798 * @param {String} oldval Old Value
58800 "propertychange": true
58802 this.customEditors = this.customEditors || {};
58804 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
58807 * @cfg {Object} customEditors map of colnames=> custom editors.
58808 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
58809 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
58810 * false disables editing of the field.
58814 * @cfg {Object} propertyNames map of property Names to their displayed value
58817 render : function(){
58818 Roo.grid.PropertyGrid.superclass.render.call(this);
58819 this.autoSize.defer(100, this);
58822 autoSize : function(){
58823 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
58825 this.view.fitColumns();
58829 onColumnResize : function(){
58830 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
58834 * Sets the data for the Grid
58835 * accepts a Key => Value object of all the elements avaiable.
58836 * @param {Object} data to appear in grid.
58838 setSource : function(source){
58839 this.store.setSource(source);
58843 * Gets all the data from the grid.
58844 * @return {Object} data data stored in grid
58846 getSource : function(){
58847 return this.store.getSource();
58856 * @class Roo.grid.Calendar
58857 * @extends Roo.util.Grid
58858 * This class extends the Grid to provide a calendar widget
58859 * <br><br>Usage:<pre><code>
58860 var grid = new Roo.grid.Calendar("my-container-id", {
58863 selModel: mySelectionModel,
58864 autoSizeColumns: true,
58865 monitorWindowResize: false,
58866 trackMouseOver: true
58867 eventstore : real data store..
58873 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
58874 * The container MUST have some type of size defined for the grid to fill. The container will be
58875 * automatically set to position relative if it isn't already.
58876 * @param {Object} config A config object that sets properties on this grid.
58878 Roo.grid.Calendar = function(container, config){
58879 // initialize the container
58880 this.container = Roo.get(container);
58881 this.container.update("");
58882 this.container.setStyle("overflow", "hidden");
58883 this.container.addClass('x-grid-container');
58885 this.id = this.container.id;
58887 Roo.apply(this, config);
58888 // check and correct shorthanded configs
58892 for (var r = 0;r < 6;r++) {
58895 for (var c =0;c < 7;c++) {
58899 if (this.eventStore) {
58900 this.eventStore= Roo.factory(this.eventStore, Roo.data);
58901 this.eventStore.on('load',this.onLoad, this);
58902 this.eventStore.on('beforeload',this.clearEvents, this);
58906 this.dataSource = new Roo.data.Store({
58907 proxy: new Roo.data.MemoryProxy(rows),
58908 reader: new Roo.data.ArrayReader({}, [
58909 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
58912 this.dataSource.load();
58913 this.ds = this.dataSource;
58914 this.ds.xmodule = this.xmodule || false;
58917 var cellRender = function(v,x,r)
58919 return String.format(
58920 '<div class="fc-day fc-widget-content"><div>' +
58921 '<div class="fc-event-container"></div>' +
58922 '<div class="fc-day-number">{0}</div>'+
58924 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
58925 '</div></div>', v);
58930 this.colModel = new Roo.grid.ColumnModel( [
58932 xtype: 'ColumnModel',
58934 dataIndex : 'weekday0',
58936 renderer : cellRender
58939 xtype: 'ColumnModel',
58941 dataIndex : 'weekday1',
58943 renderer : cellRender
58946 xtype: 'ColumnModel',
58948 dataIndex : 'weekday2',
58949 header : 'Tuesday',
58950 renderer : cellRender
58953 xtype: 'ColumnModel',
58955 dataIndex : 'weekday3',
58956 header : 'Wednesday',
58957 renderer : cellRender
58960 xtype: 'ColumnModel',
58962 dataIndex : 'weekday4',
58963 header : 'Thursday',
58964 renderer : cellRender
58967 xtype: 'ColumnModel',
58969 dataIndex : 'weekday5',
58971 renderer : cellRender
58974 xtype: 'ColumnModel',
58976 dataIndex : 'weekday6',
58977 header : 'Saturday',
58978 renderer : cellRender
58981 this.cm = this.colModel;
58982 this.cm.xmodule = this.xmodule || false;
58986 //this.selModel = new Roo.grid.CellSelectionModel();
58987 //this.sm = this.selModel;
58988 //this.selModel.init(this);
58992 this.container.setWidth(this.width);
58996 this.container.setHeight(this.height);
59003 * The raw click event for the entire grid.
59004 * @param {Roo.EventObject} e
59009 * The raw dblclick event for the entire grid.
59010 * @param {Roo.EventObject} e
59014 * @event contextmenu
59015 * The raw contextmenu event for the entire grid.
59016 * @param {Roo.EventObject} e
59018 "contextmenu" : true,
59021 * The raw mousedown event for the entire grid.
59022 * @param {Roo.EventObject} e
59024 "mousedown" : true,
59027 * The raw mouseup event for the entire grid.
59028 * @param {Roo.EventObject} e
59033 * The raw mouseover event for the entire grid.
59034 * @param {Roo.EventObject} e
59036 "mouseover" : true,
59039 * The raw mouseout event for the entire grid.
59040 * @param {Roo.EventObject} e
59045 * The raw keypress event for the entire grid.
59046 * @param {Roo.EventObject} e
59051 * The raw keydown event for the entire grid.
59052 * @param {Roo.EventObject} e
59060 * Fires when a cell is clicked
59061 * @param {Grid} this
59062 * @param {Number} rowIndex
59063 * @param {Number} columnIndex
59064 * @param {Roo.EventObject} e
59066 "cellclick" : true,
59068 * @event celldblclick
59069 * Fires when a cell is double clicked
59070 * @param {Grid} this
59071 * @param {Number} rowIndex
59072 * @param {Number} columnIndex
59073 * @param {Roo.EventObject} e
59075 "celldblclick" : true,
59078 * Fires when a row is clicked
59079 * @param {Grid} this
59080 * @param {Number} rowIndex
59081 * @param {Roo.EventObject} e
59085 * @event rowdblclick
59086 * Fires when a row is double clicked
59087 * @param {Grid} this
59088 * @param {Number} rowIndex
59089 * @param {Roo.EventObject} e
59091 "rowdblclick" : true,
59093 * @event headerclick
59094 * Fires when a header is clicked
59095 * @param {Grid} this
59096 * @param {Number} columnIndex
59097 * @param {Roo.EventObject} e
59099 "headerclick" : true,
59101 * @event headerdblclick
59102 * Fires when a header cell is double clicked
59103 * @param {Grid} this
59104 * @param {Number} columnIndex
59105 * @param {Roo.EventObject} e
59107 "headerdblclick" : true,
59109 * @event rowcontextmenu
59110 * Fires when a row is right clicked
59111 * @param {Grid} this
59112 * @param {Number} rowIndex
59113 * @param {Roo.EventObject} e
59115 "rowcontextmenu" : true,
59117 * @event cellcontextmenu
59118 * Fires when a cell is right clicked
59119 * @param {Grid} this
59120 * @param {Number} rowIndex
59121 * @param {Number} cellIndex
59122 * @param {Roo.EventObject} e
59124 "cellcontextmenu" : true,
59126 * @event headercontextmenu
59127 * Fires when a header is right clicked
59128 * @param {Grid} this
59129 * @param {Number} columnIndex
59130 * @param {Roo.EventObject} e
59132 "headercontextmenu" : true,
59134 * @event bodyscroll
59135 * Fires when the body element is scrolled
59136 * @param {Number} scrollLeft
59137 * @param {Number} scrollTop
59139 "bodyscroll" : true,
59141 * @event columnresize
59142 * Fires when the user resizes a column
59143 * @param {Number} columnIndex
59144 * @param {Number} newSize
59146 "columnresize" : true,
59148 * @event columnmove
59149 * Fires when the user moves a column
59150 * @param {Number} oldIndex
59151 * @param {Number} newIndex
59153 "columnmove" : true,
59156 * Fires when row(s) start being dragged
59157 * @param {Grid} this
59158 * @param {Roo.GridDD} dd The drag drop object
59159 * @param {event} e The raw browser event
59161 "startdrag" : true,
59164 * Fires when a drag operation is complete
59165 * @param {Grid} this
59166 * @param {Roo.GridDD} dd The drag drop object
59167 * @param {event} e The raw browser event
59172 * Fires when dragged row(s) are dropped on a valid DD target
59173 * @param {Grid} this
59174 * @param {Roo.GridDD} dd The drag drop object
59175 * @param {String} targetId The target drag drop object
59176 * @param {event} e The raw browser event
59181 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
59182 * @param {Grid} this
59183 * @param {Roo.GridDD} dd The drag drop object
59184 * @param {String} targetId The target drag drop object
59185 * @param {event} e The raw browser event
59190 * Fires when the dragged row(s) first cross another DD target while being dragged
59191 * @param {Grid} this
59192 * @param {Roo.GridDD} dd The drag drop object
59193 * @param {String} targetId The target drag drop object
59194 * @param {event} e The raw browser event
59196 "dragenter" : true,
59199 * Fires when the dragged row(s) leave another DD target while being dragged
59200 * @param {Grid} this
59201 * @param {Roo.GridDD} dd The drag drop object
59202 * @param {String} targetId The target drag drop object
59203 * @param {event} e The raw browser event
59208 * Fires when a row is rendered, so you can change add a style to it.
59209 * @param {GridView} gridview The grid view
59210 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
59216 * Fires when the grid is rendered
59217 * @param {Grid} grid
59222 * Fires when a date is selected
59223 * @param {DatePicker} this
59224 * @param {Date} date The selected date
59228 * @event monthchange
59229 * Fires when the displayed month changes
59230 * @param {DatePicker} this
59231 * @param {Date} date The selected month
59233 'monthchange': true,
59235 * @event evententer
59236 * Fires when mouse over an event
59237 * @param {Calendar} this
59238 * @param {event} Event
59240 'evententer': true,
59242 * @event eventleave
59243 * Fires when the mouse leaves an
59244 * @param {Calendar} this
59247 'eventleave': true,
59249 * @event eventclick
59250 * Fires when the mouse click an
59251 * @param {Calendar} this
59254 'eventclick': true,
59256 * @event eventrender
59257 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
59258 * @param {Calendar} this
59259 * @param {data} data to be modified
59261 'eventrender': true
59265 Roo.grid.Grid.superclass.constructor.call(this);
59266 this.on('render', function() {
59267 this.view.el.addClass('x-grid-cal');
59269 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
59273 if (!Roo.grid.Calendar.style) {
59274 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
59277 '.x-grid-cal .x-grid-col' : {
59278 height: 'auto !important',
59279 'vertical-align': 'top'
59281 '.x-grid-cal .fc-event-hori' : {
59292 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
59294 * @cfg {Store} eventStore The store that loads events.
59299 activeDate : false,
59302 monitorWindowResize : false,
59305 resizeColumns : function() {
59306 var col = (this.view.el.getWidth() / 7) - 3;
59307 // loop through cols, and setWidth
59308 for(var i =0 ; i < 7 ; i++){
59309 this.cm.setColumnWidth(i, col);
59312 setDate :function(date) {
59314 Roo.log('setDate?');
59316 this.resizeColumns();
59317 var vd = this.activeDate;
59318 this.activeDate = date;
59319 // if(vd && this.el){
59320 // var t = date.getTime();
59321 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
59322 // Roo.log('using add remove');
59324 // this.fireEvent('monthchange', this, date);
59326 // this.cells.removeClass("fc-state-highlight");
59327 // this.cells.each(function(c){
59328 // if(c.dateValue == t){
59329 // c.addClass("fc-state-highlight");
59330 // setTimeout(function(){
59331 // try{c.dom.firstChild.focus();}catch(e){}
59341 var days = date.getDaysInMonth();
59343 var firstOfMonth = date.getFirstDateOfMonth();
59344 var startingPos = firstOfMonth.getDay()-this.startDay;
59346 if(startingPos < this.startDay){
59350 var pm = date.add(Date.MONTH, -1);
59351 var prevStart = pm.getDaysInMonth()-startingPos;
59355 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59357 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
59358 //this.cells.addClassOnOver('fc-state-hover');
59360 var cells = this.cells.elements;
59361 var textEls = this.textNodes;
59363 //Roo.each(cells, function(cell){
59364 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
59367 days += startingPos;
59369 // convert everything to numbers so it's fast
59370 var day = 86400000;
59371 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
59374 //Roo.log(prevStart);
59376 var today = new Date().clearTime().getTime();
59377 var sel = date.clearTime().getTime();
59378 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
59379 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
59380 var ddMatch = this.disabledDatesRE;
59381 var ddText = this.disabledDatesText;
59382 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
59383 var ddaysText = this.disabledDaysText;
59384 var format = this.format;
59386 var setCellClass = function(cal, cell){
59388 //Roo.log('set Cell Class');
59390 var t = d.getTime();
59395 cell.dateValue = t;
59397 cell.className += " fc-today";
59398 cell.className += " fc-state-highlight";
59399 cell.title = cal.todayText;
59402 // disable highlight in other month..
59403 cell.className += " fc-state-highlight";
59408 //cell.className = " fc-state-disabled";
59409 cell.title = cal.minText;
59413 //cell.className = " fc-state-disabled";
59414 cell.title = cal.maxText;
59418 if(ddays.indexOf(d.getDay()) != -1){
59419 // cell.title = ddaysText;
59420 // cell.className = " fc-state-disabled";
59423 if(ddMatch && format){
59424 var fvalue = d.dateFormat(format);
59425 if(ddMatch.test(fvalue)){
59426 cell.title = ddText.replace("%0", fvalue);
59427 cell.className = " fc-state-disabled";
59431 if (!cell.initialClassName) {
59432 cell.initialClassName = cell.dom.className;
59435 cell.dom.className = cell.initialClassName + ' ' + cell.className;
59440 for(; i < startingPos; i++) {
59441 cells[i].dayName = (++prevStart);
59442 Roo.log(textEls[i]);
59443 d.setDate(d.getDate()+1);
59445 //cells[i].className = "fc-past fc-other-month";
59446 setCellClass(this, cells[i]);
59451 for(; i < days; i++){
59452 intDay = i - startingPos + 1;
59453 cells[i].dayName = (intDay);
59454 d.setDate(d.getDate()+1);
59456 cells[i].className = ''; // "x-date-active";
59457 setCellClass(this, cells[i]);
59461 for(; i < 42; i++) {
59462 //textEls[i].innerHTML = (++extraDays);
59464 d.setDate(d.getDate()+1);
59465 cells[i].dayName = (++extraDays);
59466 cells[i].className = "fc-future fc-other-month";
59467 setCellClass(this, cells[i]);
59470 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
59472 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
59474 // this will cause all the cells to mis
59477 for (var r = 0;r < 6;r++) {
59478 for (var c =0;c < 7;c++) {
59479 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
59483 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
59484 for(i=0;i<cells.length;i++) {
59486 this.cells.elements[i].dayName = cells[i].dayName ;
59487 this.cells.elements[i].className = cells[i].className;
59488 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
59489 this.cells.elements[i].title = cells[i].title ;
59490 this.cells.elements[i].dateValue = cells[i].dateValue ;
59496 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
59497 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
59499 ////if(totalRows != 6){
59500 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
59501 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
59504 this.fireEvent('monthchange', this, date);
59509 * Returns the grid's SelectionModel.
59510 * @return {SelectionModel}
59512 getSelectionModel : function(){
59513 if(!this.selModel){
59514 this.selModel = new Roo.grid.CellSelectionModel();
59516 return this.selModel;
59520 this.eventStore.load()
59526 findCell : function(dt) {
59527 dt = dt.clearTime().getTime();
59529 this.cells.each(function(c){
59530 //Roo.log("check " +c.dateValue + '?=' + dt);
59531 if(c.dateValue == dt){
59541 findCells : function(rec) {
59542 var s = rec.data.start_dt.clone().clearTime().getTime();
59544 var e= rec.data.end_dt.clone().clearTime().getTime();
59547 this.cells.each(function(c){
59548 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
59550 if(c.dateValue > e){
59553 if(c.dateValue < s){
59562 findBestRow: function(cells)
59566 for (var i =0 ; i < cells.length;i++) {
59567 ret = Math.max(cells[i].rows || 0,ret);
59574 addItem : function(rec)
59576 // look for vertical location slot in
59577 var cells = this.findCells(rec);
59579 rec.row = this.findBestRow(cells);
59581 // work out the location.
59585 for(var i =0; i < cells.length; i++) {
59593 if (crow.start.getY() == cells[i].getY()) {
59595 crow.end = cells[i];
59611 for (var i = 0; i < cells.length;i++) {
59612 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
59619 clearEvents: function() {
59621 if (!this.eventStore.getCount()) {
59624 // reset number of rows in cells.
59625 Roo.each(this.cells.elements, function(c){
59629 this.eventStore.each(function(e) {
59630 this.clearEvent(e);
59635 clearEvent : function(ev)
59638 Roo.each(ev.els, function(el) {
59639 el.un('mouseenter' ,this.onEventEnter, this);
59640 el.un('mouseleave' ,this.onEventLeave, this);
59648 renderEvent : function(ev,ctr) {
59650 ctr = this.view.el.select('.fc-event-container',true).first();
59654 this.clearEvent(ev);
59660 var cells = ev.cells;
59661 var rows = ev.rows;
59662 this.fireEvent('eventrender', this, ev);
59664 for(var i =0; i < rows.length; i++) {
59668 cls += ' fc-event-start';
59670 if ((i+1) == rows.length) {
59671 cls += ' fc-event-end';
59674 //Roo.log(ev.data);
59675 // how many rows should it span..
59676 var cg = this.eventTmpl.append(ctr,Roo.apply({
59679 }, ev.data) , true);
59682 cg.on('mouseenter' ,this.onEventEnter, this, ev);
59683 cg.on('mouseleave' ,this.onEventLeave, this, ev);
59684 cg.on('click', this.onEventClick, this, ev);
59688 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
59689 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
59692 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
59693 cg.setWidth(ebox.right - sbox.x -2);
59697 renderEvents: function()
59699 // first make sure there is enough space..
59701 if (!this.eventTmpl) {
59702 this.eventTmpl = new Roo.Template(
59703 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
59704 '<div class="fc-event-inner">' +
59705 '<span class="fc-event-time">{time}</span>' +
59706 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
59708 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
59716 this.cells.each(function(c) {
59717 //Roo.log(c.select('.fc-day-content div',true).first());
59718 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
59721 var ctr = this.view.el.select('.fc-event-container',true).first();
59724 this.eventStore.each(function(ev){
59726 this.renderEvent(ev);
59730 this.view.layout();
59734 onEventEnter: function (e, el,event,d) {
59735 this.fireEvent('evententer', this, el, event);
59738 onEventLeave: function (e, el,event,d) {
59739 this.fireEvent('eventleave', this, el, event);
59742 onEventClick: function (e, el,event,d) {
59743 this.fireEvent('eventclick', this, el, event);
59746 onMonthChange: function () {
59750 onLoad: function () {
59752 //Roo.log('calendar onload');
59754 if(this.eventStore.getCount() > 0){
59758 this.eventStore.each(function(d){
59763 if (typeof(add.end_dt) == 'undefined') {
59764 Roo.log("Missing End time in calendar data: ");
59768 if (typeof(add.start_dt) == 'undefined') {
59769 Roo.log("Missing Start time in calendar data: ");
59773 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
59774 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
59775 add.id = add.id || d.id;
59776 add.title = add.title || '??';
59784 this.renderEvents();
59794 render : function ()
59798 if (!this.view.el.hasClass('course-timesheet')) {
59799 this.view.el.addClass('course-timesheet');
59801 if (this.tsStyle) {
59806 Roo.log(_this.grid.view.el.getWidth());
59809 this.tsStyle = Roo.util.CSS.createStyleSheet({
59810 '.course-timesheet .x-grid-row' : {
59813 '.x-grid-row td' : {
59814 'vertical-align' : 0
59816 '.course-edit-link' : {
59818 'text-overflow' : 'ellipsis',
59819 'overflow' : 'hidden',
59820 'white-space' : 'nowrap',
59821 'cursor' : 'pointer'
59826 '.de-act-sup-link' : {
59827 'color' : 'purple',
59828 'text-decoration' : 'line-through'
59832 'text-decoration' : 'line-through'
59834 '.course-timesheet .course-highlight' : {
59835 'border-top-style': 'dashed !important',
59836 'border-bottom-bottom': 'dashed !important'
59838 '.course-timesheet .course-item' : {
59839 'font-family' : 'tahoma, arial, helvetica',
59840 'font-size' : '11px',
59841 'overflow' : 'hidden',
59842 'padding-left' : '10px',
59843 'padding-right' : '10px',
59844 'padding-top' : '10px'
59852 monitorWindowResize : false,
59853 cellrenderer : function(v,x,r)
59858 xtype: 'CellSelectionModel',
59865 beforeload : function (_self, options)
59867 options.params = options.params || {};
59868 options.params._month = _this.monthField.getValue();
59869 options.params.limit = 9999;
59870 options.params['sort'] = 'when_dt';
59871 options.params['dir'] = 'ASC';
59872 this.proxy.loadResponse = this.loadResponse;
59874 //this.addColumns();
59876 load : function (_self, records, options)
59878 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
59879 // if you click on the translation.. you can edit it...
59880 var el = Roo.get(this);
59881 var id = el.dom.getAttribute('data-id');
59882 var d = el.dom.getAttribute('data-date');
59883 var t = el.dom.getAttribute('data-time');
59884 //var id = this.child('span').dom.textContent;
59887 Pman.Dialog.CourseCalendar.show({
59891 productitem_active : id ? 1 : 0
59893 _this.grid.ds.load({});
59898 _this.panel.fireEvent('resize', [ '', '' ]);
59901 loadResponse : function(o, success, response){
59902 // this is overridden on before load..
59904 Roo.log("our code?");
59905 //Roo.log(success);
59906 //Roo.log(response)
59907 delete this.activeRequest;
59909 this.fireEvent("loadexception", this, o, response);
59910 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59915 result = o.reader.read(response);
59917 Roo.log("load exception?");
59918 this.fireEvent("loadexception", this, o, response, e);
59919 o.request.callback.call(o.request.scope, null, o.request.arg, false);
59922 Roo.log("ready...");
59923 // loop through result.records;
59924 // and set this.tdate[date] = [] << array of records..
59926 Roo.each(result.records, function(r){
59928 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
59929 _this.tdata[r.data.when_dt.format('j')] = [];
59931 _this.tdata[r.data.when_dt.format('j')].push(r.data);
59934 //Roo.log(_this.tdata);
59936 result.records = [];
59937 result.totalRecords = 6;
59939 // let's generate some duumy records for the rows.
59940 //var st = _this.dateField.getValue();
59942 // work out monday..
59943 //st = st.add(Date.DAY, -1 * st.format('w'));
59945 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
59947 var firstOfMonth = date.getFirstDayOfMonth();
59948 var days = date.getDaysInMonth();
59950 var firstAdded = false;
59951 for (var i = 0; i < result.totalRecords ; i++) {
59952 //var d= st.add(Date.DAY, i);
59955 for(var w = 0 ; w < 7 ; w++){
59956 if(!firstAdded && firstOfMonth != w){
59963 var dd = (d > 0 && d < 10) ? "0"+d : d;
59964 row['weekday'+w] = String.format(
59965 '<span style="font-size: 16px;"><b>{0}</b></span>'+
59966 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
59968 date.format('Y-m-')+dd
59971 if(typeof(_this.tdata[d]) != 'undefined'){
59972 Roo.each(_this.tdata[d], function(r){
59976 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
59977 if(r.parent_id*1>0){
59978 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
59981 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
59982 deactive = 'de-act-link';
59985 row['weekday'+w] += String.format(
59986 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
59988 r.product_id_name, //1
59989 r.when_dt.format('h:ia'), //2
59999 // only do this if something added..
60001 result.records.push(_this.grid.dataSource.reader.newRow(row));
60005 // push it twice. (second one with an hour..
60009 this.fireEvent("load", this, o, o.request.arg);
60010 o.request.callback.call(o.request.scope, result, o.request.arg, true);
60012 sortInfo : {field: 'when_dt', direction : 'ASC' },
60014 xtype: 'HttpProxy',
60017 url : baseURL + '/Roo/Shop_course.php'
60020 xtype: 'JsonReader',
60037 'name': 'parent_id',
60041 'name': 'product_id',
60045 'name': 'productitem_id',
60063 click : function (_self, e)
60065 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60066 sd.setMonth(sd.getMonth()-1);
60067 _this.monthField.setValue(sd.format('Y-m-d'));
60068 _this.grid.ds.load({});
60074 xtype: 'Separator',
60078 xtype: 'MonthField',
60081 render : function (_self)
60083 _this.monthField = _self;
60084 // _this.monthField.set today
60086 select : function (combo, date)
60088 _this.grid.ds.load({});
60091 value : (function() { return new Date(); })()
60094 xtype: 'Separator',
60100 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
60110 click : function (_self, e)
60112 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
60113 sd.setMonth(sd.getMonth()+1);
60114 _this.monthField.setValue(sd.format('Y-m-d'));
60115 _this.grid.ds.load({});
60128 * Ext JS Library 1.1.1
60129 * Copyright(c) 2006-2007, Ext JS, LLC.
60131 * Originally Released Under LGPL - original licence link has changed is not relivant.
60134 * <script type="text/javascript">
60138 * @class Roo.LoadMask
60139 * A simple utility class for generically masking elements while loading data. If the element being masked has
60140 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
60141 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
60142 * element's UpdateManager load indicator and will be destroyed after the initial load.
60144 * Create a new LoadMask
60145 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
60146 * @param {Object} config The config object
60148 Roo.LoadMask = function(el, config){
60149 this.el = Roo.get(el);
60150 Roo.apply(this, config);
60152 this.store.on('beforeload', this.onBeforeLoad, this);
60153 this.store.on('load', this.onLoad, this);
60154 this.store.on('loadexception', this.onLoadException, this);
60155 this.removeMask = false;
60157 var um = this.el.getUpdateManager();
60158 um.showLoadIndicator = false; // disable the default indicator
60159 um.on('beforeupdate', this.onBeforeLoad, this);
60160 um.on('update', this.onLoad, this);
60161 um.on('failure', this.onLoad, this);
60162 this.removeMask = true;
60166 Roo.LoadMask.prototype = {
60168 * @cfg {Boolean} removeMask
60169 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
60170 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
60173 * @cfg {String} msg
60174 * The text to display in a centered loading message box (defaults to 'Loading...')
60176 msg : 'Loading...',
60178 * @cfg {String} msgCls
60179 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
60181 msgCls : 'x-mask-loading',
60184 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
60190 * Disables the mask to prevent it from being displayed
60192 disable : function(){
60193 this.disabled = true;
60197 * Enables the mask so that it can be displayed
60199 enable : function(){
60200 this.disabled = false;
60203 onLoadException : function()
60205 Roo.log(arguments);
60207 if (typeof(arguments[3]) != 'undefined') {
60208 Roo.MessageBox.alert("Error loading",arguments[3]);
60212 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
60213 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
60220 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60223 onLoad : function()
60225 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
60229 onBeforeLoad : function(){
60230 if(!this.disabled){
60231 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
60236 destroy : function(){
60238 this.store.un('beforeload', this.onBeforeLoad, this);
60239 this.store.un('load', this.onLoad, this);
60240 this.store.un('loadexception', this.onLoadException, this);
60242 var um = this.el.getUpdateManager();
60243 um.un('beforeupdate', this.onBeforeLoad, this);
60244 um.un('update', this.onLoad, this);
60245 um.un('failure', this.onLoad, this);
60250 * Ext JS Library 1.1.1
60251 * Copyright(c) 2006-2007, Ext JS, LLC.
60253 * Originally Released Under LGPL - original licence link has changed is not relivant.
60256 * <script type="text/javascript">
60261 * @class Roo.XTemplate
60262 * @extends Roo.Template
60263 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
60265 var t = new Roo.XTemplate(
60266 '<select name="{name}">',
60267 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
60271 // then append, applying the master template values
60274 * Supported features:
60279 {a_variable} - output encoded.
60280 {a_variable.format:("Y-m-d")} - call a method on the variable
60281 {a_variable:raw} - unencoded output
60282 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
60283 {a_variable:this.method_on_template(...)} - call a method on the template object.
60288 <tpl for="a_variable or condition.."></tpl>
60289 <tpl if="a_variable or condition"></tpl>
60290 <tpl exec="some javascript"></tpl>
60291 <tpl name="named_template"></tpl> (experimental)
60293 <tpl for="."></tpl> - just iterate the property..
60294 <tpl for=".."></tpl> - iterates with the parent (probably the template)
60298 Roo.XTemplate = function()
60300 Roo.XTemplate.superclass.constructor.apply(this, arguments);
60307 Roo.extend(Roo.XTemplate, Roo.Template, {
60310 * The various sub templates
60315 * basic tag replacing syntax
60318 * // you can fake an object call by doing this
60322 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
60325 * compile the template
60327 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
60330 compile: function()
60334 s = ['<tpl>', s, '</tpl>'].join('');
60336 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
60337 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
60338 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
60339 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
60340 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
60345 while(true == !!(m = s.match(re))){
60346 var forMatch = m[0].match(nameRe),
60347 ifMatch = m[0].match(ifRe),
60348 execMatch = m[0].match(execRe),
60349 namedMatch = m[0].match(namedRe),
60354 name = forMatch && forMatch[1] ? forMatch[1] : '';
60357 // if - puts fn into test..
60358 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
60360 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
60365 // exec - calls a function... returns empty if true is returned.
60366 exp = execMatch && execMatch[1] ? execMatch[1] : null;
60368 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
60376 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
60377 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
60378 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
60381 var uid = namedMatch ? namedMatch[1] : id;
60385 id: namedMatch ? namedMatch[1] : id,
60392 s = s.replace(m[0], '');
60394 s = s.replace(m[0], '{xtpl'+ id + '}');
60399 for(var i = tpls.length-1; i >= 0; --i){
60400 this.compileTpl(tpls[i]);
60401 this.tpls[tpls[i].id] = tpls[i];
60403 this.master = tpls[tpls.length-1];
60407 * same as applyTemplate, except it's done to one of the subTemplates
60408 * when using named templates, you can do:
60410 * var str = pl.applySubTemplate('your-name', values);
60413 * @param {Number} id of the template
60414 * @param {Object} values to apply to template
60415 * @param {Object} parent (normaly the instance of this object)
60417 applySubTemplate : function(id, values, parent)
60421 var t = this.tpls[id];
60425 if(t.test && !t.test.call(this, values, parent)){
60429 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
60430 Roo.log(e.toString());
60436 if(t.exec && t.exec.call(this, values, parent)){
60440 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
60441 Roo.log(e.toString());
60446 var vs = t.target ? t.target.call(this, values, parent) : values;
60447 parent = t.target ? values : parent;
60448 if(t.target && vs instanceof Array){
60450 for(var i = 0, len = vs.length; i < len; i++){
60451 buf[buf.length] = t.compiled.call(this, vs[i], parent);
60453 return buf.join('');
60455 return t.compiled.call(this, vs, parent);
60457 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
60458 Roo.log(e.toString());
60459 Roo.log(t.compiled);
60464 compileTpl : function(tpl)
60466 var fm = Roo.util.Format;
60467 var useF = this.disableFormats !== true;
60468 var sep = Roo.isGecko ? "+" : ",";
60469 var undef = function(str) {
60470 Roo.log("Property not found :" + str);
60474 var fn = function(m, name, format, args)
60476 //Roo.log(arguments);
60477 args = args ? args.replace(/\\'/g,"'") : args;
60478 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
60479 if (typeof(format) == 'undefined') {
60480 format= 'htmlEncode';
60482 if (format == 'raw' ) {
60486 if(name.substr(0, 4) == 'xtpl'){
60487 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
60490 // build an array of options to determine if value is undefined..
60492 // basically get 'xxxx.yyyy' then do
60493 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
60494 // (function () { Roo.log("Property not found"); return ''; })() :
60499 Roo.each(name.split('.'), function(st) {
60500 lookfor += (lookfor.length ? '.': '') + st;
60501 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
60504 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
60507 if(format && useF){
60509 args = args ? ',' + args : "";
60511 if(format.substr(0, 5) != "this."){
60512 format = "fm." + format + '(';
60514 format = 'this.call("'+ format.substr(5) + '", ';
60518 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
60522 // called with xxyx.yuu:(test,test)
60524 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
60526 // raw.. - :raw modifier..
60527 return "'"+ sep + udef_st + name + ")"+sep+"'";
60531 // branched to use + in gecko and [].join() in others
60533 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
60534 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
60537 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
60538 body.push(tpl.body.replace(/(\r\n|\n)/g,
60539 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
60540 body.push("'].join('');};};");
60541 body = body.join('');
60544 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
60546 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
60552 applyTemplate : function(values){
60553 return this.master.compiled.call(this, values, {});
60554 //var s = this.subs;
60557 apply : function(){
60558 return this.applyTemplate.apply(this, arguments);
60563 Roo.XTemplate.from = function(el){
60564 el = Roo.getDom(el);
60565 return new Roo.XTemplate(el.value || el.innerHTML);