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);
673 * Find the current bootstrap width Grid size
674 * Note xs is the default for smaller.. - this is currently used by grids to render correct columns
675 * @returns {String} (xs|sm|md|lg|xl)
678 getGridSize : function()
689 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
690 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
693 "Roo.bootstrap.dash");
696 * Ext JS Library 1.1.1
697 * Copyright(c) 2006-2007, Ext JS, LLC.
699 * Originally Released Under LGPL - original licence link has changed is not relivant.
702 * <script type="text/javascript">
706 // wrappedn so fnCleanup is not in global scope...
708 function fnCleanUp() {
709 var p = Function.prototype;
710 delete p.createSequence;
712 delete p.createDelegate;
713 delete p.createCallback;
714 delete p.createInterceptor;
716 window.detachEvent("onunload", fnCleanUp);
718 window.attachEvent("onunload", fnCleanUp);
725 * These functions are available on every Function object (any JavaScript function).
727 Roo.apply(Function.prototype, {
729 * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
730 * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
731 * Will create a function that is bound to those 2 args.
732 * @return {Function} The new function
734 createCallback : function(/*args...*/){
735 // make args available, in function below
736 var args = arguments;
739 return method.apply(window, args);
744 * Creates a delegate (callback) that sets the scope to obj.
745 * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
746 * Will create a function that is automatically scoped to this.
747 * @param {Object} obj (optional) The object for which the scope is set
748 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
749 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
750 * if a number the args are inserted at the specified position
751 * @return {Function} The new function
753 createDelegate : function(obj, args, appendArgs){
756 var callArgs = args || arguments;
757 if(appendArgs === true){
758 callArgs = Array.prototype.slice.call(arguments, 0);
759 callArgs = callArgs.concat(args);
760 }else if(typeof appendArgs == "number"){
761 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
762 var applyArgs = [appendArgs, 0].concat(args); // create method call params
763 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
765 return method.apply(obj || window, callArgs);
770 * Calls this function after the number of millseconds specified.
771 * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
772 * @param {Object} obj (optional) The object for which the scope is set
773 * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
774 * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
775 * if a number the args are inserted at the specified position
776 * @return {Number} The timeout id that can be used with clearTimeout
778 defer : function(millis, obj, args, appendArgs){
779 var fn = this.createDelegate(obj, args, appendArgs);
781 return setTimeout(fn, millis);
787 * Create a combined function call sequence of the original function + the passed function.
788 * The resulting function returns the results of the original function.
789 * The passed fcn is called with the parameters of the original function
790 * @param {Function} fcn The function to sequence
791 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
792 * @return {Function} The new function
794 createSequence : function(fcn, scope){
795 if(typeof fcn != "function"){
800 var retval = method.apply(this || window, arguments);
801 fcn.apply(scope || this || window, arguments);
807 * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
808 * The resulting function returns the results of the original function.
809 * The passed fcn is called with the parameters of the original function.
811 * @param {Function} fcn The function to call before the original
812 * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
813 * @return {Function} The new function
815 createInterceptor : function(fcn, scope){
816 if(typeof fcn != "function"){
823 if(fcn.apply(scope || this || window, arguments) === false){
826 return method.apply(this || window, arguments);
832 * Ext JS Library 1.1.1
833 * Copyright(c) 2006-2007, Ext JS, LLC.
835 * Originally Released Under LGPL - original licence link has changed is not relivant.
838 * <script type="text/javascript">
841 Roo.applyIf(String, {
846 * Escapes the passed string for ' and \
847 * @param {String} string The string to escape
848 * @return {String} The escaped string
851 escape : function(string) {
852 return string.replace(/('|\\)/g, "\\$1");
856 * Pads the left side of a string with a specified character. This is especially useful
857 * for normalizing number and date strings. Example usage:
859 var s = String.leftPad('123', 5, '0');
860 // s now contains the string: '00123'
862 * @param {String} string The original string
863 * @param {Number} size The total length of the output string
864 * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
865 * @return {String} The padded string
868 leftPad : function (val, size, ch) {
869 var result = new String(val);
870 if(ch === null || ch === undefined || ch === '') {
873 while (result.length < size) {
874 result = ch + result;
880 * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
881 * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
883 var cls = 'my-class', text = 'Some text';
884 var s = String.format('<div class="{0}">{1}</div>', cls, text);
885 // s now contains the string: '<div class="my-class">Some text</div>'
887 * @param {String} string The tokenized string to be formatted
888 * @param {String} value1 The value to replace token {0}
889 * @param {String} value2 Etc...
890 * @return {String} The formatted string
893 format : function(format){
894 var args = Array.prototype.slice.call(arguments, 1);
895 return format.replace(/\{(\d+)\}/g, function(m, i){
896 return Roo.util.Format.htmlEncode(args[i]);
904 * Utility function that allows you to easily switch a string between two alternating values. The passed value
905 * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
906 * they are already different, the first value passed in is returned. Note that this method returns the new value
907 * but does not change the current string.
909 // alternate sort directions
910 sort = sort.toggle('ASC', 'DESC');
912 // instead of conditional logic:
913 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
915 * @param {String} value The value to compare to the current string
916 * @param {String} other The new value to use if the string already equals the first value passed in
917 * @return {String} The new value
920 String.prototype.toggle = function(value, other){
921 return this == value ? other : value;
926 * Remove invalid unicode characters from a string
928 * @return {String} The clean string
930 String.prototype.unicodeClean = function () {
931 return this.replace(/[\s\S]/g,
932 function(character) {
933 if (character.charCodeAt()< 256) {
937 encodeURIComponent(character);
948 * Ext JS Library 1.1.1
949 * Copyright(c) 2006-2007, Ext JS, LLC.
951 * Originally Released Under LGPL - original licence link has changed is not relivant.
954 * <script type="text/javascript">
960 Roo.applyIf(Number.prototype, {
962 * Checks whether or not the current number is within a desired range. If the number is already within the
963 * range it is returned, otherwise the min or max value is returned depending on which side of the range is
964 * exceeded. Note that this method returns the constrained value but does not change the current number.
965 * @param {Number} min The minimum number in the range
966 * @param {Number} max The maximum number in the range
967 * @return {Number} The constrained value if outside the range, otherwise the current value
969 constrain : function(min, max){
970 return Math.min(Math.max(this, min), max);
974 * Ext JS Library 1.1.1
975 * Copyright(c) 2006-2007, Ext JS, LLC.
977 * Originally Released Under LGPL - original licence link has changed is not relivant.
980 * <script type="text/javascript">
985 Roo.applyIf(Array.prototype, {
988 * Checks whether or not the specified object exists in the array.
989 * @param {Object} o The object to check for
990 * @return {Number} The index of o in the array (or -1 if it is not found)
992 indexOf : function(o){
993 for (var i = 0, len = this.length; i < len; i++){
994 if(this[i] == o) { return i; }
1000 * Removes the specified object from the array. If the object is not found nothing happens.
1001 * @param {Object} o The object to remove
1003 remove : function(o){
1004 var index = this.indexOf(o);
1006 this.splice(index, 1);
1010 * Map (JS 1.6 compatibility)
1011 * @param {Function} function to call
1013 map : function(fun )
1015 var len = this.length >>> 0;
1016 if (typeof fun != "function") {
1017 throw new TypeError();
1019 var res = new Array(len);
1020 var thisp = arguments[1];
1021 for (var i = 0; i < len; i++)
1024 res[i] = fun.call(thisp, this[i], i, this);
1032 * @param {Array} o The array to compare to
1033 * @returns {Boolean} true if the same
1035 equals : function(b)
1037 // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript
1044 if (this.length !== b.length) {
1048 // sort?? a.sort().equals(b.sort());
1050 for (var i = 0; i < this.length; ++i) {
1051 if (this[i] !== b[i]) {
1063 * Ext JS Library 1.1.1
1064 * Copyright(c) 2006-2007, Ext JS, LLC.
1066 * Originally Released Under LGPL - original licence link has changed is not relivant.
1069 * <script type="text/javascript">
1075 * The date parsing and format syntax is a subset of
1076 * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
1077 * supported will provide results equivalent to their PHP versions.
1079 * Following is the list of all currently supported formats:
1082 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1084 Format Output Description
1085 ------ ---------- --------------------------------------------------------------
1086 d 10 Day of the month, 2 digits with leading zeros
1087 D Wed A textual representation of a day, three letters
1088 j 10 Day of the month without leading zeros
1089 l Wednesday A full textual representation of the day of the week
1090 S th English ordinal day of month suffix, 2 chars (use with j)
1091 w 3 Numeric representation of the day of the week
1092 z 9 The julian date, or day of the year (0-365)
1093 W 01 ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1094 F January A full textual representation of the month
1095 m 01 Numeric representation of a month, with leading zeros
1096 M Jan Month name abbreviation, three letters
1097 n 1 Numeric representation of a month, without leading zeros
1098 t 31 Number of days in the given month
1099 L 0 Whether it's a leap year (1 if it is a leap year, else 0)
1100 Y 2007 A full numeric representation of a year, 4 digits
1101 y 07 A two digit representation of a year
1102 a pm Lowercase Ante meridiem and Post meridiem
1103 A PM Uppercase Ante meridiem and Post meridiem
1104 g 3 12-hour format of an hour without leading zeros
1105 G 15 24-hour format of an hour without leading zeros
1106 h 03 12-hour format of an hour with leading zeros
1107 H 15 24-hour format of an hour with leading zeros
1108 i 05 Minutes with leading zeros
1109 s 01 Seconds, with leading zeros
1110 O -0600 Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1111 P -06:00 Difference to Greenwich time (GMT) with colon between hours and minutes
1112 T CST Timezone setting of the machine running the code
1113 Z -21600 Timezone offset in seconds (negative if west of UTC, positive if east)
1116 * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1118 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1119 document.write(dt.format('Y-m-d')); //2007-01-10
1120 document.write(dt.format('F j, Y, g:i a')); //January 10, 2007, 3:05 pm
1121 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
1124 * Here are some standard date/time patterns that you might find helpful. They
1125 * are not part of the source of Date.js, but to use them you can simply copy this
1126 * block of code into any script that is included after Date.js and they will also become
1127 * globally available on the Date object. Feel free to add or remove patterns as needed in your code.
1130 ISO8601Long:"Y-m-d H:i:s",
1131 ISO8601Short:"Y-m-d",
1133 LongDate: "l, F d, Y",
1134 FullDateTime: "l, F d, Y g:i:s A",
1137 LongTime: "g:i:s A",
1138 SortableDateTime: "Y-m-d\\TH:i:s",
1139 UniversalSortableDateTime: "Y-m-d H:i:sO",
1146 var dt = new Date();
1147 document.write(dt.format(Date.patterns.ShortDate));
1152 * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1153 * They generate precompiled functions from date formats instead of parsing and
1154 * processing the pattern every time you format a date. These functions are available
1155 * on every Date object (any javascript function).
1157 * The original article and download are here:
1158 * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1165 Returns the number of milliseconds between this date and date
1166 @param {Date} date (optional) Defaults to now
1167 @return {Number} The diff in milliseconds
1168 @member Date getElapsed
1170 Date.prototype.getElapsed = function(date) {
1171 return Math.abs((date || new Date()).getTime()-this.getTime());
1173 // was in date file..
1177 Date.parseFunctions = {count:0};
1179 Date.parseRegexes = [];
1181 Date.formatFunctions = {count:0};
1184 Date.prototype.dateFormat = function(format) {
1185 if (Date.formatFunctions[format] == null) {
1186 Date.createNewFormat(format);
1188 var func = Date.formatFunctions[format];
1189 return this[func]();
1194 * Formats a date given the supplied format string
1195 * @param {String} format The format string
1196 * @return {String} The formatted date
1199 Date.prototype.format = Date.prototype.dateFormat;
1202 Date.createNewFormat = function(format) {
1203 var funcName = "format" + Date.formatFunctions.count++;
1204 Date.formatFunctions[format] = funcName;
1205 var code = "Date.prototype." + funcName + " = function(){return ";
1206 var special = false;
1208 for (var i = 0; i < format.length; ++i) {
1209 ch = format.charAt(i);
1210 if (!special && ch == "\\") {
1215 code += "'" + String.escape(ch) + "' + ";
1218 code += Date.getFormatCode(ch);
1221 /** eval:var:zzzzzzzzzzzzz */
1222 eval(code.substring(0, code.length - 3) + ";}");
1226 Date.getFormatCode = function(character) {
1227 switch (character) {
1229 return "String.leftPad(this.getDate(), 2, '0') + ";
1231 return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1233 return "this.getDate() + ";
1235 return "Date.dayNames[this.getDay()] + ";
1237 return "this.getSuffix() + ";
1239 return "this.getDay() + ";
1241 return "this.getDayOfYear() + ";
1243 return "this.getWeekOfYear() + ";
1245 return "Date.monthNames[this.getMonth()] + ";
1247 return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1249 return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1251 return "(this.getMonth() + 1) + ";
1253 return "this.getDaysInMonth() + ";
1255 return "(this.isLeapYear() ? 1 : 0) + ";
1257 return "this.getFullYear() + ";
1259 return "('' + this.getFullYear()).substring(2, 4) + ";
1261 return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1263 return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1265 return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1267 return "this.getHours() + ";
1269 return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1271 return "String.leftPad(this.getHours(), 2, '0') + ";
1273 return "String.leftPad(this.getMinutes(), 2, '0') + ";
1275 return "String.leftPad(this.getSeconds(), 2, '0') + ";
1277 return "this.getGMTOffset() + ";
1279 return "this.getGMTColonOffset() + ";
1281 return "this.getTimezone() + ";
1283 return "(this.getTimezoneOffset() * -60) + ";
1285 return "'" + String.escape(character) + "' + ";
1290 * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1291 * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates. Any part of
1292 * the date format that is not specified will default to the current date value for that part. Time parts can also
1293 * be specified, but default to 0. Keep in mind that the input date string must precisely match the specified format
1294 * string or the parse operation will fail.
1297 //dt = Fri May 25 2007 (current date)
1298 var dt = new Date();
1300 //dt = Thu May 25 2006 (today's month/day in 2006)
1301 dt = Date.parseDate("2006", "Y");
1303 //dt = Sun Jan 15 2006 (all date parts specified)
1304 dt = Date.parseDate("2006-1-15", "Y-m-d");
1306 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1307 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1309 * @param {String} input The unparsed date as a string
1310 * @param {String} format The format the date is in
1311 * @return {Date} The parsed date
1314 Date.parseDate = function(input, format) {
1315 if (Date.parseFunctions[format] == null) {
1316 Date.createParser(format);
1318 var func = Date.parseFunctions[format];
1319 return Date[func](input);
1325 Date.createParser = function(format) {
1326 var funcName = "parse" + Date.parseFunctions.count++;
1327 var regexNum = Date.parseRegexes.length;
1328 var currentGroup = 1;
1329 Date.parseFunctions[format] = funcName;
1331 var code = "Date." + funcName + " = function(input){\n"
1332 + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1333 + "var d = new Date();\n"
1334 + "y = d.getFullYear();\n"
1335 + "m = d.getMonth();\n"
1336 + "d = d.getDate();\n"
1337 + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1338 + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1339 + "if (results && results.length > 0) {";
1342 var special = false;
1344 for (var i = 0; i < format.length; ++i) {
1345 ch = format.charAt(i);
1346 if (!special && ch == "\\") {
1351 regex += String.escape(ch);
1354 var obj = Date.formatCodeToRegex(ch, currentGroup);
1355 currentGroup += obj.g;
1357 if (obj.g && obj.c) {
1363 code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1364 + "{v = new Date(y, m, d, h, i, s);}\n"
1365 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1366 + "{v = new Date(y, m, d, h, i);}\n"
1367 + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1368 + "{v = new Date(y, m, d, h);}\n"
1369 + "else if (y >= 0 && m >= 0 && d > 0)\n"
1370 + "{v = new Date(y, m, d);}\n"
1371 + "else if (y >= 0 && m >= 0)\n"
1372 + "{v = new Date(y, m);}\n"
1373 + "else if (y >= 0)\n"
1374 + "{v = new Date(y);}\n"
1375 + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1376 + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1377 + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1380 Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1381 /** eval:var:zzzzzzzzzzzzz */
1386 Date.formatCodeToRegex = function(character, currentGroup) {
1387 switch (character) {
1391 s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1394 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1395 s:"(\\d{1,2})"}; // day of month without leading zeroes
1398 c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1399 s:"(\\d{2})"}; // day of month with leading zeroes
1403 s:"(?:" + Date.dayNames.join("|") + ")"};
1407 s:"(?:st|nd|rd|th)"};
1422 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1423 s:"(" + Date.monthNames.join("|") + ")"};
1426 c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1427 s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1430 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1431 s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1434 c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1435 s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1446 c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1450 c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1451 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1455 c:"if (results[" + currentGroup + "] == 'am') {\n"
1456 + "if (h == 12) { h = 0; }\n"
1457 + "} else { if (h < 12) { h += 12; }}",
1461 c:"if (results[" + currentGroup + "] == 'AM') {\n"
1462 + "if (h == 12) { h = 0; }\n"
1463 + "} else { if (h < 12) { h += 12; }}",
1468 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1469 s:"(\\d{1,2})"}; // 12/24-hr format format of an hour without leading zeroes
1473 c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1474 s:"(\\d{2})"}; // 12/24-hr format format of an hour with leading zeroes
1477 c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1481 c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1486 "o = results[", currentGroup, "];\n",
1487 "var sn = o.substring(0,1);\n", // get + / - sign
1488 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1489 "var mn = o.substring(3,5) % 60;\n", // get minutes
1490 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1491 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1493 s:"([+\-]\\d{2,4})"};
1499 "o = results[", currentGroup, "];\n",
1500 "var sn = o.substring(0,1);\n",
1501 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1502 "var mn = o.substring(4,6) % 60;\n",
1503 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1504 " (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1510 s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1513 c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1514 + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1515 s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1519 s:String.escape(character)};
1524 * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1525 * @return {String} The abbreviated timezone name (e.g. 'CST')
1527 Date.prototype.getTimezone = function() {
1528 return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1532 * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1533 * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1535 Date.prototype.getGMTOffset = function() {
1536 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1537 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1538 + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1542 * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1543 * @return {String} 2-characters representing hours and 2-characters representing minutes
1544 * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1546 Date.prototype.getGMTColonOffset = function() {
1547 return (this.getTimezoneOffset() > 0 ? "-" : "+")
1548 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1550 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1554 * Get the numeric day number of the year, adjusted for leap year.
1555 * @return {Number} 0 through 364 (365 in leap years)
1557 Date.prototype.getDayOfYear = function() {
1559 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1560 for (var i = 0; i < this.getMonth(); ++i) {
1561 num += Date.daysInMonth[i];
1563 return num + this.getDate() - 1;
1567 * Get the string representation of the numeric week number of the year
1568 * (equivalent to the format specifier 'W').
1569 * @return {String} '00' through '52'
1571 Date.prototype.getWeekOfYear = function() {
1572 // Skip to Thursday of this week
1573 var now = this.getDayOfYear() + (4 - this.getDay());
1574 // Find the first Thursday of the year
1575 var jan1 = new Date(this.getFullYear(), 0, 1);
1576 var then = (7 - jan1.getDay() + 4);
1577 return String.leftPad(((now - then) / 7) + 1, 2, "0");
1581 * Whether or not the current date is in a leap year.
1582 * @return {Boolean} True if the current date is in a leap year, else false
1584 Date.prototype.isLeapYear = function() {
1585 var year = this.getFullYear();
1586 return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1590 * Get the first day of the current month, adjusted for leap year. The returned value
1591 * is the numeric day index within the week (0-6) which can be used in conjunction with
1592 * the {@link #monthNames} array to retrieve the textual day name.
1595 var dt = new Date('1/10/2007');
1596 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1598 * @return {Number} The day number (0-6)
1600 Date.prototype.getFirstDayOfMonth = function() {
1601 var day = (this.getDay() - (this.getDate() - 1)) % 7;
1602 return (day < 0) ? (day + 7) : day;
1606 * Get the last day of the current month, adjusted for leap year. The returned value
1607 * is the numeric day index within the week (0-6) which can be used in conjunction with
1608 * the {@link #monthNames} array to retrieve the textual day name.
1611 var dt = new Date('1/10/2007');
1612 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1614 * @return {Number} The day number (0-6)
1616 Date.prototype.getLastDayOfMonth = function() {
1617 var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1618 return (day < 0) ? (day + 7) : day;
1623 * Get the first date of this date's month
1626 Date.prototype.getFirstDateOfMonth = function() {
1627 return new Date(this.getFullYear(), this.getMonth(), 1);
1631 * Get the last date of this date's month
1634 Date.prototype.getLastDateOfMonth = function() {
1635 return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1638 * Get the number of days in the current month, adjusted for leap year.
1639 * @return {Number} The number of days in the month
1641 Date.prototype.getDaysInMonth = function() {
1642 Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1643 return Date.daysInMonth[this.getMonth()];
1647 * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1648 * @return {String} 'st, 'nd', 'rd' or 'th'
1650 Date.prototype.getSuffix = function() {
1651 switch (this.getDate()) {
1668 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1671 * An array of textual month names.
1672 * Override these values for international dates, for example...
1673 * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1692 * An array of textual day names.
1693 * Override these values for international dates, for example...
1694 * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1710 Date.monthNumbers = {
1725 * Creates and returns a new Date instance with the exact same date value as the called instance.
1726 * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1727 * variable will also be changed. When the intention is to create a new variable that will not
1728 * modify the original instance, you should create a clone.
1730 * Example of correctly cloning a date:
1733 var orig = new Date('10/1/2006');
1736 document.write(orig); //returns 'Thu Oct 05 2006'!
1739 var orig = new Date('10/1/2006');
1740 var copy = orig.clone();
1742 document.write(orig); //returns 'Thu Oct 01 2006'
1744 * @return {Date} The new Date instance
1746 Date.prototype.clone = function() {
1747 return new Date(this.getTime());
1751 * Clears any time information from this date
1752 @param {Boolean} clone true to create a clone of this date, clear the time and return it
1753 @return {Date} this or the clone
1755 Date.prototype.clearTime = function(clone){
1757 return this.clone().clearTime();
1762 this.setMilliseconds(0);
1767 // safari setMonth is broken -- check that this is only donw once...
1768 if(Roo.isSafari && typeof(Date.brokenSetMonth) == 'undefined'){
1769 Date.brokenSetMonth = Date.prototype.setMonth;
1770 Date.prototype.setMonth = function(num){
1772 var n = Math.ceil(-num);
1773 var back_year = Math.ceil(n/12);
1774 var month = (n % 12) ? 12 - n % 12 : 0 ;
1775 this.setFullYear(this.getFullYear() - back_year);
1776 return Date.brokenSetMonth.call(this, month);
1778 return Date.brokenSetMonth.apply(this, arguments);
1783 /** Date interval constant
1787 /** Date interval constant
1791 /** Date interval constant
1795 /** Date interval constant
1799 /** Date interval constant
1803 /** Date interval constant
1807 /** Date interval constant
1813 * Provides a convenient method of performing basic date arithmetic. This method
1814 * does not modify the Date instance being called - it creates and returns
1815 * a new Date instance containing the resulting date value.
1820 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1821 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1823 //Negative values will subtract correctly:
1824 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1825 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1827 //You can even chain several calls together in one line!
1828 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1829 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1832 * @param {String} interval A valid date interval enum value
1833 * @param {Number} value The amount to add to the current date
1834 * @return {Date} The new Date instance
1836 Date.prototype.add = function(interval, value){
1837 var d = this.clone();
1838 if (!interval || value === 0) { return d; }
1839 switch(interval.toLowerCase()){
1841 d.setMilliseconds(this.getMilliseconds() + value);
1844 d.setSeconds(this.getSeconds() + value);
1847 d.setMinutes(this.getMinutes() + value);
1850 d.setHours(this.getHours() + value);
1853 d.setDate(this.getDate() + value);
1856 var day = this.getDate();
1858 day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1861 d.setMonth(this.getMonth() + value);
1864 d.setFullYear(this.getFullYear() + value);
1871 * Ext JS Library 1.1.1
1872 * Copyright(c) 2006-2007, Ext JS, LLC.
1874 * Originally Released Under LGPL - original licence link has changed is not relivant.
1877 * <script type="text/javascript">
1881 * @class Roo.lib.Dom
1884 * Dom utils (from YIU afaik)
1889 * Get the view width
1890 * @param {Boolean} full True will get the full document, otherwise it's the view width
1891 * @return {Number} The width
1894 getViewWidth : function(full) {
1895 return full ? this.getDocumentWidth() : this.getViewportWidth();
1898 * Get the view height
1899 * @param {Boolean} full True will get the full document, otherwise it's the view height
1900 * @return {Number} The height
1902 getViewHeight : function(full) {
1903 return full ? this.getDocumentHeight() : this.getViewportHeight();
1906 getDocumentHeight: function() {
1907 var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1908 return Math.max(scrollHeight, this.getViewportHeight());
1911 getDocumentWidth: function() {
1912 var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1913 return Math.max(scrollWidth, this.getViewportWidth());
1916 getViewportHeight: function() {
1917 var height = self.innerHeight;
1918 var mode = document.compatMode;
1920 if ((mode || Roo.isIE) && !Roo.isOpera) {
1921 height = (mode == "CSS1Compat") ?
1922 document.documentElement.clientHeight :
1923 document.body.clientHeight;
1929 getViewportWidth: function() {
1930 var width = self.innerWidth;
1931 var mode = document.compatMode;
1933 if (mode || Roo.isIE) {
1934 width = (mode == "CSS1Compat") ?
1935 document.documentElement.clientWidth :
1936 document.body.clientWidth;
1941 isAncestor : function(p, c) {
1948 if (p.contains && !Roo.isSafari) {
1949 return p.contains(c);
1950 } else if (p.compareDocumentPosition) {
1951 return !!(p.compareDocumentPosition(c) & 16);
1953 var parent = c.parentNode;
1958 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1961 parent = parent.parentNode;
1967 getRegion : function(el) {
1968 return Roo.lib.Region.getRegion(el);
1971 getY : function(el) {
1972 return this.getXY(el)[1];
1975 getX : function(el) {
1976 return this.getXY(el)[0];
1979 getXY : function(el) {
1980 var p, pe, b, scroll, bd = document.body;
1981 el = Roo.getDom(el);
1982 var fly = Roo.lib.AnimBase.fly;
1983 if (el.getBoundingClientRect) {
1984 b = el.getBoundingClientRect();
1985 scroll = fly(document).getScroll();
1986 return [b.left + scroll.left, b.top + scroll.top];
1992 var hasAbsolute = fly(el).getStyle("position") == "absolute";
1999 if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
2006 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
2007 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
2014 if (p != el && pe.getStyle('overflow') != 'visible') {
2022 if (Roo.isSafari && hasAbsolute) {
2027 if (Roo.isGecko && !hasAbsolute) {
2029 x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
2030 y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
2034 while (p && p != bd) {
2035 if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
2047 setXY : function(el, xy) {
2048 el = Roo.fly(el, '_setXY');
2050 var pts = el.translatePoints(xy);
2051 if (xy[0] !== false) {
2052 el.dom.style.left = pts.left + "px";
2054 if (xy[1] !== false) {
2055 el.dom.style.top = pts.top + "px";
2059 setX : function(el, x) {
2060 this.setXY(el, [x, false]);
2063 setY : function(el, y) {
2064 this.setXY(el, [false, y]);
2068 * Portions of this file are based on pieces of Yahoo User Interface Library
2069 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2070 * YUI licensed under the BSD License:
2071 * http://developer.yahoo.net/yui/license.txt
2072 * <script type="text/javascript">
2076 Roo.lib.Event = function() {
2077 var loadComplete = false;
2079 var unloadListeners = [];
2081 var onAvailStack = [];
2083 var lastError = null;
2096 startInterval: function() {
2097 if (!this._interval) {
2099 var callback = function() {
2100 self._tryPreloadAttach();
2102 this._interval = setInterval(callback, this.POLL_INTERVAL);
2107 onAvailable: function(p_id, p_fn, p_obj, p_override) {
2108 onAvailStack.push({ id: p_id,
2111 override: p_override,
2112 checkReady: false });
2114 retryCount = this.POLL_RETRYS;
2115 this.startInterval();
2119 addListener: function(el, eventName, fn) {
2120 el = Roo.getDom(el);
2125 if ("unload" == eventName) {
2126 unloadListeners[unloadListeners.length] =
2127 [el, eventName, fn];
2131 var wrappedFn = function(e) {
2132 return fn(Roo.lib.Event.getEvent(e));
2135 var li = [el, eventName, fn, wrappedFn];
2137 var index = listeners.length;
2138 listeners[index] = li;
2140 this.doAdd(el, eventName, wrappedFn, false);
2146 removeListener: function(el, eventName, fn) {
2149 el = Roo.getDom(el);
2152 return this.purgeElement(el, false, eventName);
2156 if ("unload" == eventName) {
2158 for (i = 0,len = unloadListeners.length; i < len; i++) {
2159 var li = unloadListeners[i];
2162 li[1] == eventName &&
2164 unloadListeners.splice(i, 1);
2172 var cacheItem = null;
2175 var index = arguments[3];
2177 if ("undefined" == typeof index) {
2178 index = this._getCacheIndex(el, eventName, fn);
2182 cacheItem = listeners[index];
2185 if (!el || !cacheItem) {
2189 this.doRemove(el, eventName, cacheItem[this.WFN], false);
2191 delete listeners[index][this.WFN];
2192 delete listeners[index][this.FN];
2193 listeners.splice(index, 1);
2200 getTarget: function(ev, resolveTextNode) {
2201 ev = ev.browserEvent || ev;
2202 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2203 var t = ev.target || ev.srcElement;
2204 return this.resolveTextNode(t);
2208 resolveTextNode: function(node) {
2209 if (Roo.isSafari && node && 3 == node.nodeType) {
2210 return node.parentNode;
2217 getPageX: function(ev) {
2218 ev = ev.browserEvent || ev;
2219 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2221 if (!x && 0 !== x) {
2222 x = ev.clientX || 0;
2225 x += this.getScroll()[1];
2233 getPageY: function(ev) {
2234 ev = ev.browserEvent || ev;
2235 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2237 if (!y && 0 !== y) {
2238 y = ev.clientY || 0;
2241 y += this.getScroll()[0];
2250 getXY: function(ev) {
2251 ev = ev.browserEvent || ev;
2252 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2253 return [this.getPageX(ev), this.getPageY(ev)];
2257 getRelatedTarget: function(ev) {
2258 ev = ev.browserEvent || ev;
2259 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2260 var t = ev.relatedTarget;
2262 if (ev.type == "mouseout") {
2264 } else if (ev.type == "mouseover") {
2269 return this.resolveTextNode(t);
2273 getTime: function(ev) {
2274 ev = ev.browserEvent || ev;
2275 ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev ) : ev;
2277 var t = new Date().getTime();
2281 this.lastError = ex;
2290 stopEvent: function(ev) {
2291 this.stopPropagation(ev);
2292 this.preventDefault(ev);
2296 stopPropagation: function(ev) {
2297 ev = ev.browserEvent || ev;
2298 if (ev.stopPropagation) {
2299 ev.stopPropagation();
2301 ev.cancelBubble = true;
2306 preventDefault: function(ev) {
2307 ev = ev.browserEvent || ev;
2308 if(ev.preventDefault) {
2309 ev.preventDefault();
2311 ev.returnValue = false;
2316 getEvent: function(e) {
2317 var ev = e || window.event;
2319 var c = this.getEvent.caller;
2321 ev = c.arguments[0];
2322 if (ev && Event == ev.constructor) {
2332 getCharCode: function(ev) {
2333 ev = ev.browserEvent || ev;
2334 return ev.charCode || ev.keyCode || 0;
2338 _getCacheIndex: function(el, eventName, fn) {
2339 for (var i = 0,len = listeners.length; i < len; ++i) {
2340 var li = listeners[i];
2342 li[this.FN] == fn &&
2343 li[this.EL] == el &&
2344 li[this.TYPE] == eventName) {
2356 getEl: function(id) {
2357 return document.getElementById(id);
2361 clearCache: function() {
2365 _load: function(e) {
2366 loadComplete = true;
2367 var EU = Roo.lib.Event;
2371 EU.doRemove(window, "load", EU._load);
2376 _tryPreloadAttach: function() {
2385 var tryAgain = !loadComplete;
2387 tryAgain = (retryCount > 0);
2392 for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2393 var item = onAvailStack[i];
2395 var el = this.getEl(item.id);
2398 if (!item.checkReady ||
2401 (document && document.body)) {
2404 if (item.override) {
2405 if (item.override === true) {
2408 scope = item.override;
2411 item.fn.call(scope, item.obj);
2412 onAvailStack[i] = null;
2415 notAvail.push(item);
2420 retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2424 this.startInterval();
2426 clearInterval(this._interval);
2427 this._interval = null;
2430 this.locked = false;
2437 purgeElement: function(el, recurse, eventName) {
2438 var elListeners = this.getListeners(el, eventName);
2440 for (var i = 0,len = elListeners.length; i < len; ++i) {
2441 var l = elListeners[i];
2442 this.removeListener(el, l.type, l.fn);
2446 if (recurse && el && el.childNodes) {
2447 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2448 this.purgeElement(el.childNodes[i], recurse, eventName);
2454 getListeners: function(el, eventName) {
2455 var results = [], searchLists;
2457 searchLists = [listeners, unloadListeners];
2458 } else if (eventName == "unload") {
2459 searchLists = [unloadListeners];
2461 searchLists = [listeners];
2464 for (var j = 0; j < searchLists.length; ++j) {
2465 var searchList = searchLists[j];
2466 if (searchList && searchList.length > 0) {
2467 for (var i = 0,len = searchList.length; i < len; ++i) {
2468 var l = searchList[i];
2469 if (l && l[this.EL] === el &&
2470 (!eventName || eventName === l[this.TYPE])) {
2475 adjust: l[this.ADJ_SCOPE],
2483 return (results.length) ? results : null;
2487 _unload: function(e) {
2489 var EU = Roo.lib.Event, i, j, l, len, index;
2491 for (i = 0,len = unloadListeners.length; i < len; ++i) {
2492 l = unloadListeners[i];
2495 if (l[EU.ADJ_SCOPE]) {
2496 if (l[EU.ADJ_SCOPE] === true) {
2499 scope = l[EU.ADJ_SCOPE];
2502 l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2503 unloadListeners[i] = null;
2509 unloadListeners = null;
2511 if (listeners && listeners.length > 0) {
2512 j = listeners.length;
2515 l = listeners[index];
2517 EU.removeListener(l[EU.EL], l[EU.TYPE],
2527 EU.doRemove(window, "unload", EU._unload);
2532 getScroll: function() {
2533 var dd = document.documentElement, db = document.body;
2534 if (dd && (dd.scrollTop || dd.scrollLeft)) {
2535 return [dd.scrollTop, dd.scrollLeft];
2537 return [db.scrollTop, db.scrollLeft];
2544 doAdd: function () {
2545 if (window.addEventListener) {
2546 return function(el, eventName, fn, capture) {
2547 el.addEventListener(eventName, fn, (capture));
2549 } else if (window.attachEvent) {
2550 return function(el, eventName, fn, capture) {
2551 el.attachEvent("on" + eventName, fn);
2560 doRemove: function() {
2561 if (window.removeEventListener) {
2562 return function (el, eventName, fn, capture) {
2563 el.removeEventListener(eventName, fn, (capture));
2565 } else if (window.detachEvent) {
2566 return function (el, eventName, fn) {
2567 el.detachEvent("on" + eventName, fn);
2579 var E = Roo.lib.Event;
2580 E.on = E.addListener;
2581 E.un = E.removeListener;
2583 if (document && document.body) {
2586 E.doAdd(window, "load", E._load);
2588 E.doAdd(window, "unload", E._unload);
2589 E._tryPreloadAttach();
2593 * Portions of this file are based on pieces of Yahoo User Interface Library
2594 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2595 * YUI licensed under the BSD License:
2596 * http://developer.yahoo.net/yui/license.txt
2597 * <script type="text/javascript">
2603 * @class Roo.lib.Ajax
2610 request : function(method, uri, cb, data, options) {
2612 var hs = options.headers;
2615 if(hs.hasOwnProperty(h)){
2616 this.initHeader(h, hs[h], false);
2620 if(options.xmlData){
2621 this.initHeader('Content-Type', 'text/xml', false);
2623 data = options.xmlData;
2627 return this.asyncRequest(method, uri, cb, data);
2630 serializeForm : function(form) {
2631 if(typeof form == 'string') {
2632 form = (document.getElementById(form) || document.forms[form]);
2635 var el, name, val, disabled, data = '', hasSubmit = false;
2636 for (var i = 0; i < form.elements.length; i++) {
2637 el = form.elements[i];
2638 disabled = form.elements[i].disabled;
2639 name = form.elements[i].name;
2640 val = form.elements[i].value;
2642 if (!disabled && name){
2646 case 'select-multiple':
2647 for (var j = 0; j < el.options.length; j++) {
2648 if (el.options[j].selected) {
2650 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2653 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2661 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2674 if(hasSubmit == false) {
2675 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2680 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2685 data = data.substr(0, data.length - 1);
2693 useDefaultHeader:true,
2695 defaultPostHeader:'application/x-www-form-urlencoded',
2697 useDefaultXhrHeader:true,
2699 defaultXhrHeader:'XMLHttpRequest',
2701 hasDefaultHeaders:true,
2713 setProgId:function(id)
2715 this.activeX.unshift(id);
2718 setDefaultPostHeader:function(b)
2720 this.useDefaultHeader = b;
2723 setDefaultXhrHeader:function(b)
2725 this.useDefaultXhrHeader = b;
2728 setPollingInterval:function(i)
2730 if (typeof i == 'number' && isFinite(i)) {
2731 this.pollInterval = i;
2735 createXhrObject:function(transactionId)
2741 http = new XMLHttpRequest();
2743 obj = { conn:http, tId:transactionId };
2747 for (var i = 0; i < this.activeX.length; ++i) {
2751 http = new ActiveXObject(this.activeX[i]);
2753 obj = { conn:http, tId:transactionId };
2766 getConnectionObject:function()
2769 var tId = this.transactionId;
2773 o = this.createXhrObject(tId);
2775 this.transactionId++;
2786 asyncRequest:function(method, uri, callback, postData)
2788 var o = this.getConnectionObject();
2794 o.conn.open(method, uri, true);
2796 if (this.useDefaultXhrHeader) {
2797 if (!this.defaultHeaders['X-Requested-With']) {
2798 this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2802 if(postData && this.useDefaultHeader){
2803 this.initHeader('Content-Type', this.defaultPostHeader);
2806 if (this.hasDefaultHeaders || this.hasHeaders) {
2810 this.handleReadyState(o, callback);
2811 o.conn.send(postData || null);
2817 handleReadyState:function(o, callback)
2821 if (callback && callback.timeout) {
2823 this.timeout[o.tId] = window.setTimeout(function() {
2824 oConn.abort(o, callback, true);
2825 }, callback.timeout);
2828 this.poll[o.tId] = window.setInterval(
2830 if (o.conn && o.conn.readyState == 4) {
2831 window.clearInterval(oConn.poll[o.tId]);
2832 delete oConn.poll[o.tId];
2834 if(callback && callback.timeout) {
2835 window.clearTimeout(oConn.timeout[o.tId]);
2836 delete oConn.timeout[o.tId];
2839 oConn.handleTransactionResponse(o, callback);
2842 , this.pollInterval);
2845 handleTransactionResponse:function(o, callback, isAbort)
2849 this.releaseObject(o);
2853 var httpStatus, responseObject;
2857 if (o.conn.status !== undefined && o.conn.status != 0) {
2858 httpStatus = o.conn.status;
2870 if (httpStatus >= 200 && httpStatus < 300) {
2871 responseObject = this.createResponseObject(o, callback.argument);
2872 if (callback.success) {
2873 if (!callback.scope) {
2874 callback.success(responseObject);
2879 callback.success.apply(callback.scope, [responseObject]);
2884 switch (httpStatus) {
2892 responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2893 if (callback.failure) {
2894 if (!callback.scope) {
2895 callback.failure(responseObject);
2898 callback.failure.apply(callback.scope, [responseObject]);
2903 responseObject = this.createResponseObject(o, callback.argument);
2904 if (callback.failure) {
2905 if (!callback.scope) {
2906 callback.failure(responseObject);
2909 callback.failure.apply(callback.scope, [responseObject]);
2915 this.releaseObject(o);
2916 responseObject = null;
2919 createResponseObject:function(o, callbackArg)
2926 var headerStr = o.conn.getAllResponseHeaders();
2927 var header = headerStr.split('\n');
2928 for (var i = 0; i < header.length; i++) {
2929 var delimitPos = header[i].indexOf(':');
2930 if (delimitPos != -1) {
2931 headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2939 obj.status = o.conn.status;
2940 obj.statusText = o.conn.statusText;
2941 obj.getResponseHeader = headerObj;
2942 obj.getAllResponseHeaders = headerStr;
2943 obj.responseText = o.conn.responseText;
2944 obj.responseXML = o.conn.responseXML;
2946 if (typeof callbackArg !== undefined) {
2947 obj.argument = callbackArg;
2953 createExceptionObject:function(tId, callbackArg, isAbort)
2956 var COMM_ERROR = 'communication failure';
2957 var ABORT_CODE = -1;
2958 var ABORT_ERROR = 'transaction aborted';
2964 obj.status = ABORT_CODE;
2965 obj.statusText = ABORT_ERROR;
2968 obj.status = COMM_CODE;
2969 obj.statusText = COMM_ERROR;
2973 obj.argument = callbackArg;
2979 initHeader:function(label, value, isDefault)
2981 var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2983 if (headerObj[label] === undefined) {
2984 headerObj[label] = value;
2989 headerObj[label] = value + "," + headerObj[label];
2993 this.hasDefaultHeaders = true;
2996 this.hasHeaders = true;
3001 setHeader:function(o)
3003 if (this.hasDefaultHeaders) {
3004 for (var prop in this.defaultHeaders) {
3005 if (this.defaultHeaders.hasOwnProperty(prop)) {
3006 o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
3011 if (this.hasHeaders) {
3012 for (var prop in this.headers) {
3013 if (this.headers.hasOwnProperty(prop)) {
3014 o.conn.setRequestHeader(prop, this.headers[prop]);
3018 this.hasHeaders = false;
3022 resetDefaultHeaders:function() {
3023 delete this.defaultHeaders;
3024 this.defaultHeaders = {};
3025 this.hasDefaultHeaders = false;
3028 abort:function(o, callback, isTimeout)
3030 if(this.isCallInProgress(o)) {
3032 window.clearInterval(this.poll[o.tId]);
3033 delete this.poll[o.tId];
3035 delete this.timeout[o.tId];
3038 this.handleTransactionResponse(o, callback, true);
3048 isCallInProgress:function(o)
3051 return o.conn.readyState != 4 && o.conn.readyState != 0;
3060 releaseObject:function(o)
3069 'MSXML2.XMLHTTP.3.0',
3077 * Portions of this file are based on pieces of Yahoo User Interface Library
3078 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3079 * YUI licensed under the BSD License:
3080 * http://developer.yahoo.net/yui/license.txt
3081 * <script type="text/javascript">
3085 Roo.lib.Region = function(t, r, b, l) {
3095 Roo.lib.Region.prototype = {
3096 contains : function(region) {
3097 return ( region.left >= this.left &&
3098 region.right <= this.right &&
3099 region.top >= this.top &&
3100 region.bottom <= this.bottom );
3104 getArea : function() {
3105 return ( (this.bottom - this.top) * (this.right - this.left) );
3108 intersect : function(region) {
3109 var t = Math.max(this.top, region.top);
3110 var r = Math.min(this.right, region.right);
3111 var b = Math.min(this.bottom, region.bottom);
3112 var l = Math.max(this.left, region.left);
3114 if (b >= t && r >= l) {
3115 return new Roo.lib.Region(t, r, b, l);
3120 union : function(region) {
3121 var t = Math.min(this.top, region.top);
3122 var r = Math.max(this.right, region.right);
3123 var b = Math.max(this.bottom, region.bottom);
3124 var l = Math.min(this.left, region.left);
3126 return new Roo.lib.Region(t, r, b, l);
3129 adjust : function(t, l, b, r) {
3138 Roo.lib.Region.getRegion = function(el) {
3139 var p = Roo.lib.Dom.getXY(el);
3142 var r = p[0] + el.offsetWidth;
3143 var b = p[1] + el.offsetHeight;
3146 return new Roo.lib.Region(t, r, b, l);
3149 * Portions of this file are based on pieces of Yahoo User Interface Library
3150 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3151 * YUI licensed under the BSD License:
3152 * http://developer.yahoo.net/yui/license.txt
3153 * <script type="text/javascript">
3156 //@@dep Roo.lib.Region
3159 Roo.lib.Point = function(x, y) {
3160 if (x instanceof Array) {
3164 this.x = this.right = this.left = this[0] = x;
3165 this.y = this.top = this.bottom = this[1] = y;
3168 Roo.lib.Point.prototype = new Roo.lib.Region();
3170 * Portions of this file are based on pieces of Yahoo User Interface Library
3171 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3172 * YUI licensed under the BSD License:
3173 * http://developer.yahoo.net/yui/license.txt
3174 * <script type="text/javascript">
3181 scroll : function(el, args, duration, easing, cb, scope) {
3182 this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3185 motion : function(el, args, duration, easing, cb, scope) {
3186 this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3189 color : function(el, args, duration, easing, cb, scope) {
3190 this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3193 run : function(el, args, duration, easing, cb, scope, type) {
3194 type = type || Roo.lib.AnimBase;
3195 if (typeof easing == "string") {
3196 easing = Roo.lib.Easing[easing];
3198 var anim = new type(el, args, duration, easing);
3199 anim.animateX(function() {
3200 Roo.callback(cb, scope);
3206 * Portions of this file are based on pieces of Yahoo User Interface Library
3207 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3208 * YUI licensed under the BSD License:
3209 * http://developer.yahoo.net/yui/license.txt
3210 * <script type="text/javascript">
3218 if (!libFlyweight) {
3219 libFlyweight = new Roo.Element.Flyweight();
3221 libFlyweight.dom = el;
3222 return libFlyweight;
3225 // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3229 Roo.lib.AnimBase = function(el, attributes, duration, method) {
3231 this.init(el, attributes, duration, method);
3235 Roo.lib.AnimBase.fly = fly;
3239 Roo.lib.AnimBase.prototype = {
3241 toString: function() {
3242 var el = this.getEl();
3243 var id = el.id || el.tagName;
3244 return ("Anim " + id);
3248 noNegatives: /width|height|opacity|padding/i,
3249 offsetAttribute: /^((width|height)|(top|left))$/,
3250 defaultUnit: /width|height|top$|bottom$|left$|right$/i,
3251 offsetUnit: /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3255 doMethod: function(attr, start, end) {
3256 return this.method(this.currentFrame, start, end - start, this.totalFrames);
3260 setAttribute: function(attr, val, unit) {
3261 if (this.patterns.noNegatives.test(attr)) {
3262 val = (val > 0) ? val : 0;
3265 Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3269 getAttribute: function(attr) {
3270 var el = this.getEl();
3271 var val = fly(el).getStyle(attr);
3273 if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3274 return parseFloat(val);
3277 var a = this.patterns.offsetAttribute.exec(attr) || [];
3278 var pos = !!( a[3] );
3279 var box = !!( a[2] );
3282 if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3283 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3292 getDefaultUnit: function(attr) {
3293 if (this.patterns.defaultUnit.test(attr)) {
3300 animateX : function(callback, scope) {
3301 var f = function() {
3302 this.onComplete.removeListener(f);
3303 if (typeof callback == "function") {
3304 callback.call(scope || this, this);
3307 this.onComplete.addListener(f, this);
3312 setRuntimeAttribute: function(attr) {
3315 var attributes = this.attributes;
3317 this.runtimeAttributes[attr] = {};
3319 var isset = function(prop) {
3320 return (typeof prop !== 'undefined');
3323 if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3327 start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3330 if (isset(attributes[attr]['to'])) {
3331 end = attributes[attr]['to'];
3332 } else if (isset(attributes[attr]['by'])) {
3333 if (start.constructor == Array) {
3335 for (var i = 0, len = start.length; i < len; ++i) {
3336 end[i] = start[i] + attributes[attr]['by'][i];
3339 end = start + attributes[attr]['by'];
3343 this.runtimeAttributes[attr].start = start;
3344 this.runtimeAttributes[attr].end = end;
3347 this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3351 init: function(el, attributes, duration, method) {
3353 var isAnimated = false;
3356 var startTime = null;
3359 var actualFrames = 0;
3362 el = Roo.getDom(el);
3365 this.attributes = attributes || {};
3368 this.duration = duration || 1;
3371 this.method = method || Roo.lib.Easing.easeNone;
3374 this.useSeconds = true;
3377 this.currentFrame = 0;
3380 this.totalFrames = Roo.lib.AnimMgr.fps;
3383 this.getEl = function() {
3388 this.isAnimated = function() {
3393 this.getStartTime = function() {
3397 this.runtimeAttributes = {};
3400 this.animate = function() {
3401 if (this.isAnimated()) {
3405 this.currentFrame = 0;
3407 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3409 Roo.lib.AnimMgr.registerElement(this);
3413 this.stop = function(finish) {
3415 this.currentFrame = this.totalFrames;
3416 this._onTween.fire();
3418 Roo.lib.AnimMgr.stop(this);
3421 var onStart = function() {
3422 this.onStart.fire();
3424 this.runtimeAttributes = {};
3425 for (var attr in this.attributes) {
3426 this.setRuntimeAttribute(attr);
3431 startTime = new Date();
3435 var onTween = function() {
3437 duration: new Date() - this.getStartTime(),
3438 currentFrame: this.currentFrame
3441 data.toString = function() {
3443 'duration: ' + data.duration +
3444 ', currentFrame: ' + data.currentFrame
3448 this.onTween.fire(data);
3450 var runtimeAttributes = this.runtimeAttributes;
3452 for (var attr in runtimeAttributes) {
3453 this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3459 var onComplete = function() {
3460 var actual_duration = (new Date() - startTime) / 1000 ;
3463 duration: actual_duration,
3464 frames: actualFrames,
3465 fps: actualFrames / actual_duration
3468 data.toString = function() {
3470 'duration: ' + data.duration +
3471 ', frames: ' + data.frames +
3472 ', fps: ' + data.fps
3478 this.onComplete.fire(data);
3482 this._onStart = new Roo.util.Event(this);
3483 this.onStart = new Roo.util.Event(this);
3484 this.onTween = new Roo.util.Event(this);
3485 this._onTween = new Roo.util.Event(this);
3486 this.onComplete = new Roo.util.Event(this);
3487 this._onComplete = new Roo.util.Event(this);
3488 this._onStart.addListener(onStart);
3489 this._onTween.addListener(onTween);
3490 this._onComplete.addListener(onComplete);
3495 * Portions of this file are based on pieces of Yahoo User Interface Library
3496 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3497 * YUI licensed under the BSD License:
3498 * http://developer.yahoo.net/yui/license.txt
3499 * <script type="text/javascript">
3503 Roo.lib.AnimMgr = new function() {
3520 this.registerElement = function(tween) {
3521 queue[queue.length] = tween;
3523 tween._onStart.fire();
3528 this.unRegister = function(tween, index) {
3529 tween._onComplete.fire();
3530 index = index || getIndex(tween);
3532 queue.splice(index, 1);
3536 if (tweenCount <= 0) {
3542 this.start = function() {
3543 if (thread === null) {
3544 thread = setInterval(this.run, this.delay);
3549 this.stop = function(tween) {
3551 clearInterval(thread);
3553 for (var i = 0, len = queue.length; i < len; ++i) {
3554 if (queue[0].isAnimated()) {
3555 this.unRegister(queue[0], 0);
3564 this.unRegister(tween);
3569 this.run = function() {
3570 for (var i = 0, len = queue.length; i < len; ++i) {
3571 var tween = queue[i];
3572 if (!tween || !tween.isAnimated()) {
3576 if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3578 tween.currentFrame += 1;
3580 if (tween.useSeconds) {
3581 correctFrame(tween);
3583 tween._onTween.fire();
3586 Roo.lib.AnimMgr.stop(tween, i);
3591 var getIndex = function(anim) {
3592 for (var i = 0, len = queue.length; i < len; ++i) {
3593 if (queue[i] == anim) {
3601 var correctFrame = function(tween) {
3602 var frames = tween.totalFrames;
3603 var frame = tween.currentFrame;
3604 var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3605 var elapsed = (new Date() - tween.getStartTime());
3608 if (elapsed < tween.duration * 1000) {
3609 tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3611 tweak = frames - (frame + 1);
3613 if (tweak > 0 && isFinite(tweak)) {
3614 if (tween.currentFrame + tweak >= frames) {
3615 tweak = frames - (frame + 1);
3618 tween.currentFrame += tweak;
3624 * Portions of this file are based on pieces of Yahoo User Interface Library
3625 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3626 * YUI licensed under the BSD License:
3627 * http://developer.yahoo.net/yui/license.txt
3628 * <script type="text/javascript">
3631 Roo.lib.Bezier = new function() {
3633 this.getPosition = function(points, t) {
3634 var n = points.length;
3637 for (var i = 0; i < n; ++i) {
3638 tmp[i] = [points[i][0], points[i][1]];
3641 for (var j = 1; j < n; ++j) {
3642 for (i = 0; i < n - j; ++i) {
3643 tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3644 tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3648 return [ tmp[0][0], tmp[0][1] ];
3652 * Portions of this file are based on pieces of Yahoo User Interface Library
3653 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3654 * YUI licensed under the BSD License:
3655 * http://developer.yahoo.net/yui/license.txt
3656 * <script type="text/javascript">
3661 Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3662 Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3665 Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3667 var fly = Roo.lib.AnimBase.fly;
3669 var superclass = Y.ColorAnim.superclass;
3670 var proto = Y.ColorAnim.prototype;
3672 proto.toString = function() {
3673 var el = this.getEl();
3674 var id = el.id || el.tagName;
3675 return ("ColorAnim " + id);
3678 proto.patterns.color = /color$/i;
3679 proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3680 proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3681 proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3682 proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3685 proto.parseColor = function(s) {
3686 if (s.length == 3) {
3690 var c = this.patterns.hex.exec(s);
3691 if (c && c.length == 4) {
3692 return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3695 c = this.patterns.rgb.exec(s);
3696 if (c && c.length == 4) {
3697 return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3700 c = this.patterns.hex3.exec(s);
3701 if (c && c.length == 4) {
3702 return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3707 // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3708 proto.getAttribute = function(attr) {
3709 var el = this.getEl();
3710 if (this.patterns.color.test(attr)) {
3711 var val = fly(el).getStyle(attr);
3713 if (this.patterns.transparent.test(val)) {
3714 var parent = el.parentNode;
3715 val = fly(parent).getStyle(attr);
3717 while (parent && this.patterns.transparent.test(val)) {
3718 parent = parent.parentNode;
3719 val = fly(parent).getStyle(attr);
3720 if (parent.tagName.toUpperCase() == 'HTML') {
3726 val = superclass.getAttribute.call(this, attr);
3731 proto.getAttribute = function(attr) {
3732 var el = this.getEl();
3733 if (this.patterns.color.test(attr)) {
3734 var val = fly(el).getStyle(attr);
3736 if (this.patterns.transparent.test(val)) {
3737 var parent = el.parentNode;
3738 val = fly(parent).getStyle(attr);
3740 while (parent && this.patterns.transparent.test(val)) {
3741 parent = parent.parentNode;
3742 val = fly(parent).getStyle(attr);
3743 if (parent.tagName.toUpperCase() == 'HTML') {
3749 val = superclass.getAttribute.call(this, attr);
3755 proto.doMethod = function(attr, start, end) {
3758 if (this.patterns.color.test(attr)) {
3760 for (var i = 0, len = start.length; i < len; ++i) {
3761 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3764 val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3767 val = superclass.doMethod.call(this, attr, start, end);
3773 proto.setRuntimeAttribute = function(attr) {
3774 superclass.setRuntimeAttribute.call(this, attr);
3776 if (this.patterns.color.test(attr)) {
3777 var attributes = this.attributes;
3778 var start = this.parseColor(this.runtimeAttributes[attr].start);
3779 var end = this.parseColor(this.runtimeAttributes[attr].end);
3781 if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3782 end = this.parseColor(attributes[attr].by);
3784 for (var i = 0, len = start.length; i < len; ++i) {
3785 end[i] = start[i] + end[i];
3789 this.runtimeAttributes[attr].start = start;
3790 this.runtimeAttributes[attr].end = end;
3796 * Portions of this file are based on pieces of Yahoo User Interface Library
3797 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3798 * YUI licensed under the BSD License:
3799 * http://developer.yahoo.net/yui/license.txt
3800 * <script type="text/javascript">
3806 easeNone: function (t, b, c, d) {
3807 return c * t / d + b;
3811 easeIn: function (t, b, c, d) {
3812 return c * (t /= d) * t + b;
3816 easeOut: function (t, b, c, d) {
3817 return -c * (t /= d) * (t - 2) + b;
3821 easeBoth: function (t, b, c, d) {
3822 if ((t /= d / 2) < 1) {
3823 return c / 2 * t * t + b;
3826 return -c / 2 * ((--t) * (t - 2) - 1) + b;
3830 easeInStrong: function (t, b, c, d) {
3831 return c * (t /= d) * t * t * t + b;
3835 easeOutStrong: function (t, b, c, d) {
3836 return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3840 easeBothStrong: function (t, b, c, d) {
3841 if ((t /= d / 2) < 1) {
3842 return c / 2 * t * t * t * t + b;
3845 return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3850 elasticIn: function (t, b, c, d, a, p) {
3854 if ((t /= d) == 1) {
3861 if (!a || a < Math.abs(c)) {
3866 var s = p / (2 * Math.PI) * Math.asin(c / a);
3869 return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3873 elasticOut: function (t, b, c, d, a, p) {
3877 if ((t /= d) == 1) {
3884 if (!a || a < Math.abs(c)) {
3889 var s = p / (2 * Math.PI) * Math.asin(c / a);
3892 return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3896 elasticBoth: function (t, b, c, d, a, p) {
3901 if ((t /= d / 2) == 2) {
3909 if (!a || a < Math.abs(c)) {
3914 var s = p / (2 * Math.PI) * Math.asin(c / a);
3918 return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3919 Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3921 return a * Math.pow(2, -10 * (t -= 1)) *
3922 Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3927 backIn: function (t, b, c, d, s) {
3928 if (typeof s == 'undefined') {
3931 return c * (t /= d) * t * ((s + 1) * t - s) + b;
3935 backOut: function (t, b, c, d, s) {
3936 if (typeof s == 'undefined') {
3939 return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3943 backBoth: function (t, b, c, d, s) {
3944 if (typeof s == 'undefined') {
3948 if ((t /= d / 2 ) < 1) {
3949 return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3951 return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3955 bounceIn: function (t, b, c, d) {
3956 return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3960 bounceOut: function (t, b, c, d) {
3961 if ((t /= d) < (1 / 2.75)) {
3962 return c * (7.5625 * t * t) + b;
3963 } else if (t < (2 / 2.75)) {
3964 return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3965 } else if (t < (2.5 / 2.75)) {
3966 return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3968 return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3972 bounceBoth: function (t, b, c, d) {
3974 return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3976 return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3979 * Portions of this file are based on pieces of Yahoo User Interface Library
3980 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3981 * YUI licensed under the BSD License:
3982 * http://developer.yahoo.net/yui/license.txt
3983 * <script type="text/javascript">
3987 Roo.lib.Motion = function(el, attributes, duration, method) {
3989 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3993 Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3997 var superclass = Y.Motion.superclass;
3998 var proto = Y.Motion.prototype;
4000 proto.toString = function() {
4001 var el = this.getEl();
4002 var id = el.id || el.tagName;
4003 return ("Motion " + id);
4006 proto.patterns.points = /^points$/i;
4008 proto.setAttribute = function(attr, val, unit) {
4009 if (this.patterns.points.test(attr)) {
4010 unit = unit || 'px';
4011 superclass.setAttribute.call(this, 'left', val[0], unit);
4012 superclass.setAttribute.call(this, 'top', val[1], unit);
4014 superclass.setAttribute.call(this, attr, val, unit);
4018 proto.getAttribute = function(attr) {
4019 if (this.patterns.points.test(attr)) {
4021 superclass.getAttribute.call(this, 'left'),
4022 superclass.getAttribute.call(this, 'top')
4025 val = superclass.getAttribute.call(this, attr);
4031 proto.doMethod = function(attr, start, end) {
4034 if (this.patterns.points.test(attr)) {
4035 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
4036 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
4038 val = superclass.doMethod.call(this, attr, start, end);
4043 proto.setRuntimeAttribute = function(attr) {
4044 if (this.patterns.points.test(attr)) {
4045 var el = this.getEl();
4046 var attributes = this.attributes;
4048 var control = attributes['points']['control'] || [];
4052 if (control.length > 0 && !(control[0] instanceof Array)) {
4053 control = [control];
4056 for (i = 0,len = control.length; i < len; ++i) {
4057 tmp[i] = control[i];
4062 Roo.fly(el).position();
4064 if (isset(attributes['points']['from'])) {
4065 Roo.lib.Dom.setXY(el, attributes['points']['from']);
4068 Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
4071 start = this.getAttribute('points');
4074 if (isset(attributes['points']['to'])) {
4075 end = translateValues.call(this, attributes['points']['to'], start);
4077 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4078 for (i = 0,len = control.length; i < len; ++i) {
4079 control[i] = translateValues.call(this, control[i], start);
4083 } else if (isset(attributes['points']['by'])) {
4084 end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4086 for (i = 0,len = control.length; i < len; ++i) {
4087 control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4091 this.runtimeAttributes[attr] = [start];
4093 if (control.length > 0) {
4094 this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4097 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4100 superclass.setRuntimeAttribute.call(this, attr);
4104 var translateValues = function(val, start) {
4105 var pageXY = Roo.lib.Dom.getXY(this.getEl());
4106 val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4111 var isset = function(prop) {
4112 return (typeof prop !== 'undefined');
4116 * Portions of this file are based on pieces of Yahoo User Interface Library
4117 * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4118 * YUI licensed under the BSD License:
4119 * http://developer.yahoo.net/yui/license.txt
4120 * <script type="text/javascript">
4124 Roo.lib.Scroll = function(el, attributes, duration, method) {
4126 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4130 Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4134 var superclass = Y.Scroll.superclass;
4135 var proto = Y.Scroll.prototype;
4137 proto.toString = function() {
4138 var el = this.getEl();
4139 var id = el.id || el.tagName;
4140 return ("Scroll " + id);
4143 proto.doMethod = function(attr, start, end) {
4146 if (attr == 'scroll') {
4148 this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4149 this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4153 val = superclass.doMethod.call(this, attr, start, end);
4158 proto.getAttribute = function(attr) {
4160 var el = this.getEl();
4162 if (attr == 'scroll') {
4163 val = [ el.scrollLeft, el.scrollTop ];
4165 val = superclass.getAttribute.call(this, attr);
4171 proto.setAttribute = function(attr, val, unit) {
4172 var el = this.getEl();
4174 if (attr == 'scroll') {
4175 el.scrollLeft = val[0];
4176 el.scrollTop = val[1];
4178 superclass.setAttribute.call(this, attr, val, unit);
4184 * Ext JS Library 1.1.1
4185 * Copyright(c) 2006-2007, Ext JS, LLC.
4187 * Originally Released Under LGPL - original licence link has changed is not relivant.
4190 * <script type="text/javascript">
4194 // nasty IE9 hack - what a pile of crap that is..
4196 if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4197 Range.prototype.createContextualFragment = function (html) {
4198 var doc = window.document;
4199 var container = doc.createElement("div");
4200 container.innerHTML = html;
4201 var frag = doc.createDocumentFragment(), n;
4202 while ((n = container.firstChild)) {
4203 frag.appendChild(n);
4210 * @class Roo.DomHelper
4211 * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4212 * 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>.
4215 Roo.DomHelper = function(){
4216 var tempTableEl = null;
4217 var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4218 var tableRe = /^table|tbody|tr|td$/i;
4220 // build as innerHTML where available
4222 var createHtml = function(o){
4223 if(typeof o == 'string'){
4232 if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") { continue; }
4233 if(attr == "style"){
4235 if(typeof s == "function"){
4238 if(typeof s == "string"){
4239 b += ' style="' + s + '"';
4240 }else if(typeof s == "object"){
4243 if(typeof s[key] != "function"){
4244 b += key + ":" + s[key] + ";";
4251 b += ' class="' + o["cls"] + '"';
4252 }else if(attr == "htmlFor"){
4253 b += ' for="' + o["htmlFor"] + '"';
4255 b += " " + attr + '="' + o[attr] + '"';
4259 if(emptyTags.test(o.tag)){
4263 var cn = o.children || o.cn;
4265 //http://bugs.kde.org/show_bug.cgi?id=71506
4266 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4267 for(var i = 0, len = cn.length; i < len; i++) {
4268 b += createHtml(cn[i], b);
4271 b += createHtml(cn, b);
4277 b += "</" + o.tag + ">";
4284 var createDom = function(o, parentNode){
4286 // defininition craeted..
4288 if (o.ns && o.ns != 'html') {
4290 if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4291 xmlns[o.ns] = o.xmlns;
4294 if (typeof(xmlns[o.ns]) == 'undefined') {
4295 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4301 if (typeof(o) == 'string') {
4302 return parentNode.appendChild(document.createTextNode(o));
4304 o.tag = o.tag || div;
4305 if (o.ns && Roo.isIE) {
4307 o.tag = o.ns + ':' + o.tag;
4310 var el = ns ? document.createElementNS( ns, o.tag||'div') : document.createElement(o.tag||'div');
4311 var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4314 if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" ||
4315 attr == "style" || typeof o[attr] == "function") { continue; }
4317 if(attr=="cls" && Roo.isIE){
4318 el.className = o["cls"];
4320 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4326 Roo.DomHelper.applyStyles(el, o.style);
4327 var cn = o.children || o.cn;
4329 //http://bugs.kde.org/show_bug.cgi?id=71506
4330 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4331 for(var i = 0, len = cn.length; i < len; i++) {
4332 createDom(cn[i], el);
4339 el.innerHTML = o.html;
4342 parentNode.appendChild(el);
4347 var ieTable = function(depth, s, h, e){
4348 tempTableEl.innerHTML = [s, h, e].join('');
4349 var i = -1, el = tempTableEl;
4356 // kill repeat to save bytes
4360 tbe = '</tbody>'+te,
4366 * Nasty code for IE's broken table implementation
4368 var insertIntoTable = function(tag, where, el, html){
4370 tempTableEl = document.createElement('div');
4375 if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4378 if(where == 'beforebegin'){
4382 before = el.nextSibling;
4385 node = ieTable(4, trs, html, tre);
4387 else if(tag == 'tr'){
4388 if(where == 'beforebegin'){
4391 node = ieTable(3, tbs, html, tbe);
4392 } else if(where == 'afterend'){
4393 before = el.nextSibling;
4395 node = ieTable(3, tbs, html, tbe);
4396 } else{ // INTO a TR
4397 if(where == 'afterbegin'){
4398 before = el.firstChild;
4400 node = ieTable(4, trs, html, tre);
4402 } else if(tag == 'tbody'){
4403 if(where == 'beforebegin'){
4406 node = ieTable(2, ts, html, te);
4407 } else if(where == 'afterend'){
4408 before = el.nextSibling;
4410 node = ieTable(2, ts, html, te);
4412 if(where == 'afterbegin'){
4413 before = el.firstChild;
4415 node = ieTable(3, tbs, html, tbe);
4418 if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4421 if(where == 'afterbegin'){
4422 before = el.firstChild;
4424 node = ieTable(2, ts, html, te);
4426 el.insertBefore(node, before);
4431 /** True to force the use of DOM instead of html fragments @type Boolean */
4435 * Returns the markup for the passed Element(s) config
4436 * @param {Object} o The Dom object spec (and children)
4439 markup : function(o){
4440 return createHtml(o);
4444 * Applies a style specification to an element
4445 * @param {String/HTMLElement} el The element to apply styles to
4446 * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4447 * a function which returns such a specification.
4449 applyStyles : function(el, styles){
4452 if(typeof styles == "string"){
4453 var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4455 while ((matches = re.exec(styles)) != null){
4456 el.setStyle(matches[1], matches[2]);
4458 }else if (typeof styles == "object"){
4459 for (var style in styles){
4460 el.setStyle(style, styles[style]);
4462 }else if (typeof styles == "function"){
4463 Roo.DomHelper.applyStyles(el, styles.call());
4469 * Inserts an HTML fragment into the Dom
4470 * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4471 * @param {HTMLElement} el The context element
4472 * @param {String} html The HTML fragmenet
4473 * @return {HTMLElement} The new node
4475 insertHtml : function(where, el, html){
4476 where = where.toLowerCase();
4477 if(el.insertAdjacentHTML){
4478 if(tableRe.test(el.tagName)){
4480 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4486 el.insertAdjacentHTML('BeforeBegin', html);
4487 return el.previousSibling;
4489 el.insertAdjacentHTML('AfterBegin', html);
4490 return el.firstChild;
4492 el.insertAdjacentHTML('BeforeEnd', html);
4493 return el.lastChild;
4495 el.insertAdjacentHTML('AfterEnd', html);
4496 return el.nextSibling;
4498 throw 'Illegal insertion point -> "' + where + '"';
4500 var range = el.ownerDocument.createRange();
4504 range.setStartBefore(el);
4505 frag = range.createContextualFragment(html);
4506 el.parentNode.insertBefore(frag, el);
4507 return el.previousSibling;
4510 range.setStartBefore(el.firstChild);
4511 frag = range.createContextualFragment(html);
4512 el.insertBefore(frag, el.firstChild);
4513 return el.firstChild;
4515 el.innerHTML = html;
4516 return el.firstChild;
4520 range.setStartAfter(el.lastChild);
4521 frag = range.createContextualFragment(html);
4522 el.appendChild(frag);
4523 return el.lastChild;
4525 el.innerHTML = html;
4526 return el.lastChild;
4529 range.setStartAfter(el);
4530 frag = range.createContextualFragment(html);
4531 el.parentNode.insertBefore(frag, el.nextSibling);
4532 return el.nextSibling;
4534 throw 'Illegal insertion point -> "' + where + '"';
4538 * Creates new Dom element(s) and inserts them before el
4539 * @param {String/HTMLElement/Element} el The context element
4540 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4541 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4542 * @return {HTMLElement/Roo.Element} The new node
4544 insertBefore : function(el, o, returnElement){
4545 return this.doInsert(el, o, returnElement, "beforeBegin");
4549 * Creates new Dom element(s) and inserts them after el
4550 * @param {String/HTMLElement/Element} el The context element
4551 * @param {Object} o The Dom object spec (and children)
4552 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4553 * @return {HTMLElement/Roo.Element} The new node
4555 insertAfter : function(el, o, returnElement){
4556 return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4560 * Creates new Dom element(s) and inserts them as the first child of el
4561 * @param {String/HTMLElement/Element} el The context element
4562 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4563 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4564 * @return {HTMLElement/Roo.Element} The new node
4566 insertFirst : function(el, o, returnElement){
4567 return this.doInsert(el, o, returnElement, "afterBegin");
4571 doInsert : function(el, o, returnElement, pos, sibling){
4572 el = Roo.getDom(el);
4574 if(this.useDom || o.ns){
4575 newNode = createDom(o, null);
4576 el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4578 var html = createHtml(o);
4579 newNode = this.insertHtml(pos, el, html);
4581 return returnElement ? Roo.get(newNode, true) : newNode;
4585 * Creates new Dom element(s) and appends them to el
4586 * @param {String/HTMLElement/Element} el The context element
4587 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4588 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4589 * @return {HTMLElement/Roo.Element} The new node
4591 append : function(el, o, returnElement){
4592 el = Roo.getDom(el);
4594 if(this.useDom || o.ns){
4595 newNode = createDom(o, null);
4596 el.appendChild(newNode);
4598 var html = createHtml(o);
4599 newNode = this.insertHtml("beforeEnd", el, html);
4601 return returnElement ? Roo.get(newNode, true) : newNode;
4605 * Creates new Dom element(s) and overwrites the contents of el with them
4606 * @param {String/HTMLElement/Element} el The context element
4607 * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4608 * @param {Boolean} returnElement (optional) true to return a Roo.Element
4609 * @return {HTMLElement/Roo.Element} The new node
4611 overwrite : function(el, o, returnElement){
4612 el = Roo.getDom(el);
4615 while (el.childNodes.length) {
4616 el.removeChild(el.firstChild);
4620 el.innerHTML = createHtml(o);
4623 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4627 * Creates a new Roo.DomHelper.Template from the Dom object spec
4628 * @param {Object} o The Dom object spec (and children)
4629 * @return {Roo.DomHelper.Template} The new template
4631 createTemplate : function(o){
4632 var html = createHtml(o);
4633 return new Roo.Template(html);
4639 * Ext JS Library 1.1.1
4640 * Copyright(c) 2006-2007, Ext JS, LLC.
4642 * Originally Released Under LGPL - original licence link has changed is not relivant.
4645 * <script type="text/javascript">
4649 * @class Roo.Template
4650 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4651 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4654 var t = new Roo.Template({
4655 html : '<div name="{id}">' +
4656 '<span class="{cls}">{name:trim} {someval:this.myformat}{value:ellipsis(10)}</span>' +
4658 myformat: function (value, allValues) {
4659 return 'XX' + value;
4662 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4664 * For more information see this blog post with examples:
4665 * <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4666 - Create Elements using DOM, HTML fragments and Templates</a>.
4668 * @param {Object} cfg - Configuration object.
4670 Roo.Template = function(cfg){
4672 if(cfg instanceof Array){
4674 }else if(arguments.length > 1){
4675 cfg = Array.prototype.join.call(arguments, "");
4679 if (typeof(cfg) == 'object') {
4690 Roo.Template.prototype = {
4693 * @cfg {Function} onLoad Called after the template has been loaded and complied (usually from a remove source)
4699 * @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..
4700 * it should be fixed so that template is observable...
4704 * @cfg {String} html The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4712 * Returns an HTML fragment of this template with the specified values applied.
4713 * @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'})
4714 * @return {String} The HTML fragment
4719 applyTemplate : function(values){
4720 //Roo.log(["applyTemplate", values]);
4724 return this.compiled(values);
4726 var useF = this.disableFormats !== true;
4727 var fm = Roo.util.Format, tpl = this;
4728 var fn = function(m, name, format, args){
4730 if(format.substr(0, 5) == "this."){
4731 return tpl.call(format.substr(5), values[name], values);
4734 // quoted values are required for strings in compiled templates,
4735 // but for non compiled we need to strip them
4736 // quoted reversed for jsmin
4737 var re = /^\s*['"](.*)["']\s*$/;
4738 args = args.split(',');
4739 for(var i = 0, len = args.length; i < len; i++){
4740 args[i] = args[i].replace(re, "$1");
4742 args = [values[name]].concat(args);
4744 args = [values[name]];
4746 return fm[format].apply(fm, args);
4749 return values[name] !== undefined ? values[name] : "";
4752 return this.html.replace(this.re, fn);
4770 this.loading = true;
4771 this.compiled = false;
4773 var cx = new Roo.data.Connection();
4777 success : function (response) {
4781 _t.set(response.responseText,true);
4787 failure : function(response) {
4788 Roo.log("Template failed to load from " + _t.url);
4795 * Sets the HTML used as the template and optionally compiles it.
4796 * @param {String} html
4797 * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4798 * @return {Roo.Template} this
4800 set : function(html, compile){
4802 this.compiled = false;
4810 * True to disable format functions (defaults to false)
4813 disableFormats : false,
4816 * The regular expression used to match template variables
4820 re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4823 * Compiles the template into an internal function, eliminating the RegEx overhead.
4824 * @return {Roo.Template} this
4826 compile : function(){
4827 var fm = Roo.util.Format;
4828 var useF = this.disableFormats !== true;
4829 var sep = Roo.isGecko ? "+" : ",";
4830 var fn = function(m, name, format, args){
4832 args = args ? ',' + args : "";
4833 if(format.substr(0, 5) != "this."){
4834 format = "fm." + format + '(';
4836 format = 'this.call("'+ format.substr(5) + '", ';
4840 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4842 return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4845 // branched to use + in gecko and [].join() in others
4847 body = "this.compiled = function(values){ return '" +
4848 this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4851 body = ["this.compiled = function(values){ return ['"];
4852 body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4853 body.push("'].join('');};");
4854 body = body.join('');
4864 // private function used to call members
4865 call : function(fnName, value, allValues){
4866 return this[fnName](value, allValues);
4870 * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4871 * @param {String/HTMLElement/Roo.Element} el The context element
4872 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4873 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4874 * @return {HTMLElement/Roo.Element} The new node or Element
4876 insertFirst: function(el, values, returnElement){
4877 return this.doInsert('afterBegin', el, values, returnElement);
4881 * Applies the supplied values to the template and inserts the new node(s) before el.
4882 * @param {String/HTMLElement/Roo.Element} el The context element
4883 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4884 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4885 * @return {HTMLElement/Roo.Element} The new node or Element
4887 insertBefore: function(el, values, returnElement){
4888 return this.doInsert('beforeBegin', el, values, returnElement);
4892 * Applies the supplied values to the template and inserts the new node(s) after el.
4893 * @param {String/HTMLElement/Roo.Element} el The context element
4894 * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4895 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4896 * @return {HTMLElement/Roo.Element} The new node or Element
4898 insertAfter : function(el, values, returnElement){
4899 return this.doInsert('afterEnd', el, values, returnElement);
4903 * Applies the supplied values to the template and appends the new node(s) to el.
4904 * @param {String/HTMLElement/Roo.Element} el The context element
4905 * @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'})
4906 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4907 * @return {HTMLElement/Roo.Element} The new node or Element
4909 append : function(el, values, returnElement){
4910 return this.doInsert('beforeEnd', el, values, returnElement);
4913 doInsert : function(where, el, values, returnEl){
4914 el = Roo.getDom(el);
4915 var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4916 return returnEl ? Roo.get(newNode, true) : newNode;
4920 * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4921 * @param {String/HTMLElement/Roo.Element} el The context element
4922 * @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'})
4923 * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4924 * @return {HTMLElement/Roo.Element} The new node or Element
4926 overwrite : function(el, values, returnElement){
4927 el = Roo.getDom(el);
4928 el.innerHTML = this.applyTemplate(values);
4929 return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4933 * Alias for {@link #applyTemplate}
4936 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4939 Roo.DomHelper.Template = Roo.Template;
4942 * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4943 * @param {String/HTMLElement} el A DOM element or its id
4944 * @returns {Roo.Template} The created template
4947 Roo.Template.from = function(el){
4948 el = Roo.getDom(el);
4949 return new Roo.Template(el.value || el.innerHTML);
4952 * Ext JS Library 1.1.1
4953 * Copyright(c) 2006-2007, Ext JS, LLC.
4955 * Originally Released Under LGPL - original licence link has changed is not relivant.
4958 * <script type="text/javascript">
4963 * This is code is also distributed under MIT license for use
4964 * with jQuery and prototype JavaScript libraries.
4967 * @class Roo.DomQuery
4968 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).
4970 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>
4973 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.
4975 <h4>Element Selectors:</h4>
4977 <li> <b>*</b> any element</li>
4978 <li> <b>E</b> an element with the tag E</li>
4979 <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4980 <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4981 <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4982 <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4984 <h4>Attribute Selectors:</h4>
4985 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4987 <li> <b>E[foo]</b> has an attribute "foo"</li>
4988 <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4989 <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4990 <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4991 <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4992 <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4993 <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4995 <h4>Pseudo Classes:</h4>
4997 <li> <b>E:first-child</b> E is the first child of its parent</li>
4998 <li> <b>E:last-child</b> E is the last child of its parent</li>
4999 <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>
5000 <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
5001 <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
5002 <li> <b>E:only-child</b> E is the only child of its parent</li>
5003 <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>
5004 <li> <b>E:first</b> the first E in the resultset</li>
5005 <li> <b>E:last</b> the last E in the resultset</li>
5006 <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
5007 <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
5008 <li> <b>E:even</b> shortcut for :nth-child(even)</li>
5009 <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
5010 <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
5011 <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
5012 <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
5013 <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
5014 <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
5016 <h4>CSS Value Selectors:</h4>
5018 <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
5019 <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
5020 <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
5021 <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
5022 <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
5023 <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
5027 Roo.DomQuery = function(){
5028 var cache = {}, simpleCache = {}, valueCache = {};
5029 var nonSpace = /\S/;
5030 var trimRe = /^\s+|\s+$/g;
5031 var tplRe = /\{(\d+)\}/g;
5032 var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
5033 var tagTokenRe = /^(#)?([\w-\*]+)/;
5034 var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
5036 function child(p, index){
5038 var n = p.firstChild;
5040 if(n.nodeType == 1){
5051 while((n = n.nextSibling) && n.nodeType != 1);
5056 while((n = n.previousSibling) && n.nodeType != 1);
5060 function children(d){
5061 var n = d.firstChild, ni = -1;
5063 var nx = n.nextSibling;
5064 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
5074 function byClassName(c, a, v){
5078 var r = [], ri = -1, cn;
5079 for(var i = 0, ci; ci = c[i]; i++){
5083 ( (ci instanceof SVGElement) ? ci.className.baseVal : ci.className)
5084 +' ').indexOf(v) != -1){
5091 function attrValue(n, attr){
5092 if(!n.tagName && typeof n.length != "undefined"){
5101 if(attr == "class" || attr == "className"){
5102 return (n instanceof SVGElement) ? n.className.baseVal : n.className;
5104 return n.getAttribute(attr) || n[attr];
5108 function getNodes(ns, mode, tagName){
5109 var result = [], ri = -1, cs;
5113 tagName = tagName || "*";
5114 if(typeof ns.getElementsByTagName != "undefined"){
5118 for(var i = 0, ni; ni = ns[i]; i++){
5119 cs = ni.getElementsByTagName(tagName);
5120 for(var j = 0, ci; ci = cs[j]; j++){
5124 }else if(mode == "/" || mode == ">"){
5125 var utag = tagName.toUpperCase();
5126 for(var i = 0, ni, cn; ni = ns[i]; i++){
5127 cn = ni.children || ni.childNodes;
5128 for(var j = 0, cj; cj = cn[j]; j++){
5129 if(cj.nodeName == utag || cj.nodeName == tagName || tagName == '*'){
5134 }else if(mode == "+"){
5135 var utag = tagName.toUpperCase();
5136 for(var i = 0, n; n = ns[i]; i++){
5137 while((n = n.nextSibling) && n.nodeType != 1);
5138 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5142 }else if(mode == "~"){
5143 for(var i = 0, n; n = ns[i]; i++){
5144 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5153 function concat(a, b){
5157 for(var i = 0, l = b.length; i < l; i++){
5163 function byTag(cs, tagName){
5164 if(cs.tagName || cs == document){
5170 var r = [], ri = -1;
5171 tagName = tagName.toLowerCase();
5172 for(var i = 0, ci; ci = cs[i]; i++){
5173 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5180 function byId(cs, attr, id){
5181 if(cs.tagName || cs == document){
5187 var r = [], ri = -1;
5188 for(var i = 0,ci; ci = cs[i]; i++){
5189 if(ci && ci.id == id){
5197 function byAttribute(cs, attr, value, op, custom){
5198 var r = [], ri = -1, st = custom=="{";
5199 var f = Roo.DomQuery.operators[op];
5200 for(var i = 0, ci; ci = cs[i]; i++){
5203 a = Roo.DomQuery.getStyle(ci, attr);
5205 else if(attr == "class" || attr == "className"){
5206 a = (ci instanceof SVGElement) ? ci.className.baseVal : ci.className;
5207 }else if(attr == "for"){
5209 }else if(attr == "href"){
5210 a = ci.getAttribute("href", 2);
5212 a = ci.getAttribute(attr);
5214 if((f && f(a, value)) || (!f && a)){
5221 function byPseudo(cs, name, value){
5222 return Roo.DomQuery.pseudos[name](cs, value);
5225 // This is for IE MSXML which does not support expandos.
5226 // IE runs the same speed using setAttribute, however FF slows way down
5227 // and Safari completely fails so they need to continue to use expandos.
5228 var isIE = window.ActiveXObject ? true : false;
5230 // this eval is stop the compressor from
5231 // renaming the variable to something shorter
5233 /** eval:var:batch */
5238 function nodupIEXml(cs){
5240 cs[0].setAttribute("_nodup", d);
5242 for(var i = 1, len = cs.length; i < len; i++){
5244 if(!c.getAttribute("_nodup") != d){
5245 c.setAttribute("_nodup", d);
5249 for(var i = 0, len = cs.length; i < len; i++){
5250 cs[i].removeAttribute("_nodup");
5259 var len = cs.length, c, i, r = cs, cj, ri = -1;
5260 if(!len || typeof cs.nodeType != "undefined" || len == 1){
5263 if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5264 return nodupIEXml(cs);
5268 for(i = 1; c = cs[i]; i++){
5273 for(var j = 0; j < i; j++){
5276 for(j = i+1; cj = cs[j]; j++){
5288 function quickDiffIEXml(c1, c2){
5290 for(var i = 0, len = c1.length; i < len; i++){
5291 c1[i].setAttribute("_qdiff", d);
5294 for(var i = 0, len = c2.length; i < len; i++){
5295 if(c2[i].getAttribute("_qdiff") != d){
5296 r[r.length] = c2[i];
5299 for(var i = 0, len = c1.length; i < len; i++){
5300 c1[i].removeAttribute("_qdiff");
5305 function quickDiff(c1, c2){
5306 var len1 = c1.length;
5310 if(isIE && c1[0].selectSingleNode){
5311 return quickDiffIEXml(c1, c2);
5314 for(var i = 0; i < len1; i++){
5318 for(var i = 0, len = c2.length; i < len; i++){
5319 if(c2[i]._qdiff != d){
5320 r[r.length] = c2[i];
5326 function quickId(ns, mode, root, id){
5328 var d = root.ownerDocument || root;
5329 return d.getElementById(id);
5331 ns = getNodes(ns, mode, "*");
5332 return byId(ns, null, id);
5336 getStyle : function(el, name){
5337 return Roo.fly(el).getStyle(name);
5340 * Compiles a selector/xpath query into a reusable function. The returned function
5341 * takes one parameter "root" (optional), which is the context node from where the query should start.
5342 * @param {String} selector The selector/xpath query
5343 * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5344 * @return {Function}
5346 compile : function(path, type){
5347 type = type || "select";
5349 var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5350 var q = path, mode, lq;
5351 var tk = Roo.DomQuery.matchers;
5352 var tklen = tk.length;
5355 // accept leading mode switch
5356 var lmode = q.match(modeRe);
5357 if(lmode && lmode[1]){
5358 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5359 q = q.replace(lmode[1], "");
5361 // strip leading slashes
5362 while(path.substr(0, 1)=="/"){
5363 path = path.substr(1);
5366 while(q && lq != q){
5368 var tm = q.match(tagTokenRe);
5369 if(type == "select"){
5372 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5374 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5376 q = q.replace(tm[0], "");
5377 }else if(q.substr(0, 1) != '@'){
5378 fn[fn.length] = 'n = getNodes(n, mode, "*");';
5383 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5385 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5387 q = q.replace(tm[0], "");
5390 while(!(mm = q.match(modeRe))){
5391 var matched = false;
5392 for(var j = 0; j < tklen; j++){
5394 var m = q.match(t.re);
5396 fn[fn.length] = t.select.replace(tplRe, function(x, i){
5399 q = q.replace(m[0], "");
5404 // prevent infinite loop on bad selector
5406 throw 'Error parsing selector, parsing failed at "' + q + '"';
5410 fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5411 q = q.replace(mm[1], "");
5414 fn[fn.length] = "return nodup(n);\n}";
5417 * list of variables that need from compression as they are used by eval.
5427 * eval:var:byClassName
5429 * eval:var:byAttribute
5430 * eval:var:attrValue
5438 * Selects a group of elements.
5439 * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5440 * @param {Node} root (optional) The start of the query (defaults to document).
5443 select : function(path, root, type){
5444 if(!root || root == document){
5447 if(typeof root == "string"){
5448 root = document.getElementById(root);
5450 var paths = path.split(",");
5452 for(var i = 0, len = paths.length; i < len; i++){
5453 var p = paths[i].replace(trimRe, "");
5455 cache[p] = Roo.DomQuery.compile(p);
5457 throw p + " is not a valid selector";
5460 var result = cache[p](root);
5461 if(result && result != document){
5462 results = results.concat(result);
5465 if(paths.length > 1){
5466 return nodup(results);
5472 * Selects a single element.
5473 * @param {String} selector The selector/xpath query
5474 * @param {Node} root (optional) The start of the query (defaults to document).
5477 selectNode : function(path, root){
5478 return Roo.DomQuery.select(path, root)[0];
5482 * Selects the value of a node, optionally replacing null with the defaultValue.
5483 * @param {String} selector The selector/xpath query
5484 * @param {Node} root (optional) The start of the query (defaults to document).
5485 * @param {String} defaultValue
5487 selectValue : function(path, root, defaultValue){
5488 path = path.replace(trimRe, "");
5489 if(!valueCache[path]){
5490 valueCache[path] = Roo.DomQuery.compile(path, "select");
5492 var n = valueCache[path](root);
5493 n = n[0] ? n[0] : n;
5494 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5495 return ((v === null||v === undefined||v==='') ? defaultValue : v);
5499 * Selects the value of a node, parsing integers and floats.
5500 * @param {String} selector The selector/xpath query
5501 * @param {Node} root (optional) The start of the query (defaults to document).
5502 * @param {Number} defaultValue
5505 selectNumber : function(path, root, defaultValue){
5506 var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5507 return parseFloat(v);
5511 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5512 * @param {String/HTMLElement/Array} el An element id, element or array of elements
5513 * @param {String} selector The simple selector to test
5516 is : function(el, ss){
5517 if(typeof el == "string"){
5518 el = document.getElementById(el);
5520 var isArray = (el instanceof Array);
5521 var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5522 return isArray ? (result.length == el.length) : (result.length > 0);
5526 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5527 * @param {Array} el An array of elements to filter
5528 * @param {String} selector The simple selector to test
5529 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5530 * the selector instead of the ones that match
5533 filter : function(els, ss, nonMatches){
5534 ss = ss.replace(trimRe, "");
5535 if(!simpleCache[ss]){
5536 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5538 var result = simpleCache[ss](els);
5539 return nonMatches ? quickDiff(result, els) : result;
5543 * Collection of matching regular expressions and code snippets.
5547 select: 'n = byClassName(n, null, " {1} ");'
5549 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5550 select: 'n = byPseudo(n, "{1}", "{2}");'
5552 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5553 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5556 select: 'n = byId(n, null, "{1}");'
5559 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5564 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5565 * 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, > <.
5568 "=" : function(a, v){
5571 "!=" : function(a, v){
5574 "^=" : function(a, v){
5575 return a && a.substr(0, v.length) == v;
5577 "$=" : function(a, v){
5578 return a && a.substr(a.length-v.length) == v;
5580 "*=" : function(a, v){
5581 return a && a.indexOf(v) !== -1;
5583 "%=" : function(a, v){
5584 return (a % v) == 0;
5586 "|=" : function(a, v){
5587 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5589 "~=" : function(a, v){
5590 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5595 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5596 * and the argument (if any) supplied in the selector.
5599 "first-child" : function(c){
5600 var r = [], ri = -1, n;
5601 for(var i = 0, ci; ci = n = c[i]; i++){
5602 while((n = n.previousSibling) && n.nodeType != 1);
5610 "last-child" : function(c){
5611 var r = [], ri = -1, n;
5612 for(var i = 0, ci; ci = n = c[i]; i++){
5613 while((n = n.nextSibling) && n.nodeType != 1);
5621 "nth-child" : function(c, a) {
5622 var r = [], ri = -1;
5623 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5624 var f = (m[1] || 1) - 0, l = m[2] - 0;
5625 for(var i = 0, n; n = c[i]; i++){
5626 var pn = n.parentNode;
5627 if (batch != pn._batch) {
5629 for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5630 if(cn.nodeType == 1){
5637 if (l == 0 || n.nodeIndex == l){
5640 } else if ((n.nodeIndex + l) % f == 0){
5648 "only-child" : function(c){
5649 var r = [], ri = -1;;
5650 for(var i = 0, ci; ci = c[i]; i++){
5651 if(!prev(ci) && !next(ci)){
5658 "empty" : function(c){
5659 var r = [], ri = -1;
5660 for(var i = 0, ci; ci = c[i]; i++){
5661 var cns = ci.childNodes, j = 0, cn, empty = true;
5664 if(cn.nodeType == 1 || cn.nodeType == 3){
5676 "contains" : function(c, v){
5677 var r = [], ri = -1;
5678 for(var i = 0, ci; ci = c[i]; i++){
5679 if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5686 "nodeValue" : function(c, v){
5687 var r = [], ri = -1;
5688 for(var i = 0, ci; ci = c[i]; i++){
5689 if(ci.firstChild && ci.firstChild.nodeValue == v){
5696 "checked" : function(c){
5697 var r = [], ri = -1;
5698 for(var i = 0, ci; ci = c[i]; i++){
5699 if(ci.checked == true){
5706 "not" : function(c, ss){
5707 return Roo.DomQuery.filter(c, ss, true);
5710 "odd" : function(c){
5711 return this["nth-child"](c, "odd");
5714 "even" : function(c){
5715 return this["nth-child"](c, "even");
5718 "nth" : function(c, a){
5719 return c[a-1] || [];
5722 "first" : function(c){
5726 "last" : function(c){
5727 return c[c.length-1] || [];
5730 "has" : function(c, ss){
5731 var s = Roo.DomQuery.select;
5732 var r = [], ri = -1;
5733 for(var i = 0, ci; ci = c[i]; i++){
5734 if(s(ss, ci).length > 0){
5741 "next" : function(c, ss){
5742 var is = Roo.DomQuery.is;
5743 var r = [], ri = -1;
5744 for(var i = 0, ci; ci = c[i]; i++){
5753 "prev" : function(c, ss){
5754 var is = Roo.DomQuery.is;
5755 var r = [], ri = -1;
5756 for(var i = 0, ci; ci = c[i]; i++){
5769 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5770 * @param {String} path The selector/xpath query
5771 * @param {Node} root (optional) The start of the query (defaults to document).
5776 Roo.query = Roo.DomQuery.select;
5779 * Ext JS Library 1.1.1
5780 * Copyright(c) 2006-2007, Ext JS, LLC.
5782 * Originally Released Under LGPL - original licence link has changed is not relivant.
5785 * <script type="text/javascript">
5789 * @class Roo.util.Observable
5790 * Base class that provides a common interface for publishing events. Subclasses are expected to
5791 * to have a property "events" with all the events defined.<br>
5794 Employee = function(name){
5801 Roo.extend(Employee, Roo.util.Observable);
5803 * @param {Object} config properties to use (incuding events / listeners)
5806 Roo.util.Observable = function(cfg){
5809 this.addEvents(cfg.events || {});
5811 delete cfg.events; // make sure
5814 Roo.apply(this, cfg);
5817 this.on(this.listeners);
5818 delete this.listeners;
5821 Roo.util.Observable.prototype = {
5823 * @cfg {Object} listeners list of events and functions to call for this object,
5827 'click' : function(e) {
5837 * Fires the specified event with the passed parameters (minus the event name).
5838 * @param {String} eventName
5839 * @param {Object...} args Variable number of parameters are passed to handlers
5840 * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5842 fireEvent : function(){
5843 var ce = this.events[arguments[0].toLowerCase()];
5844 if(typeof ce == "object"){
5845 return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5852 filterOptRe : /^(?:scope|delay|buffer|single)$/,
5855 * Appends an event handler to this component
5856 * @param {String} eventName The type of event to listen for
5857 * @param {Function} handler The method the event invokes
5858 * @param {Object} scope (optional) The scope in which to execute the handler
5859 * function. The handler function's "this" context.
5860 * @param {Object} options (optional) An object containing handler configuration
5861 * properties. This may contain any of the following properties:<ul>
5862 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5863 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5864 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5865 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5866 * by the specified number of milliseconds. If the event fires again within that time, the original
5867 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5870 * <b>Combining Options</b><br>
5871 * Using the options argument, it is possible to combine different types of listeners:<br>
5873 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5875 el.on('click', this.onClick, this, {
5882 * <b>Attaching multiple handlers in 1 call</b><br>
5883 * The method also allows for a single argument to be passed which is a config object containing properties
5884 * which specify multiple handlers.
5893 fn: this.onMouseOver,
5897 fn: this.onMouseOut,
5903 * Or a shorthand syntax which passes the same scope object to all handlers:
5906 'click': this.onClick,
5907 'mouseover': this.onMouseOver,
5908 'mouseout': this.onMouseOut,
5913 addListener : function(eventName, fn, scope, o){
5914 if(typeof eventName == "object"){
5917 if(this.filterOptRe.test(e)){
5920 if(typeof o[e] == "function"){
5922 this.addListener(e, o[e], o.scope, o);
5924 // individual options
5925 this.addListener(e, o[e].fn, o[e].scope, o[e]);
5930 o = (!o || typeof o == "boolean") ? {} : o;
5931 eventName = eventName.toLowerCase();
5932 var ce = this.events[eventName] || true;
5933 if(typeof ce == "boolean"){
5934 ce = new Roo.util.Event(this, eventName);
5935 this.events[eventName] = ce;
5937 ce.addListener(fn, scope, o);
5941 * Removes a listener
5942 * @param {String} eventName The type of event to listen for
5943 * @param {Function} handler The handler to remove
5944 * @param {Object} scope (optional) The scope (this object) for the handler
5946 removeListener : function(eventName, fn, scope){
5947 var ce = this.events[eventName.toLowerCase()];
5948 if(typeof ce == "object"){
5949 ce.removeListener(fn, scope);
5954 * Removes all listeners for this object
5956 purgeListeners : function(){
5957 for(var evt in this.events){
5958 if(typeof this.events[evt] == "object"){
5959 this.events[evt].clearListeners();
5964 relayEvents : function(o, events){
5965 var createHandler = function(ename){
5968 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5971 for(var i = 0, len = events.length; i < len; i++){
5972 var ename = events[i];
5973 if(!this.events[ename]){
5974 this.events[ename] = true;
5976 o.on(ename, createHandler(ename), this);
5981 * Used to define events on this Observable
5982 * @param {Object} object The object with the events defined
5984 addEvents : function(o){
5988 Roo.applyIf(this.events, o);
5992 * Checks to see if this object has any listeners for a specified event
5993 * @param {String} eventName The name of the event to check for
5994 * @return {Boolean} True if the event is being listened for, else false
5996 hasListener : function(eventName){
5997 var e = this.events[eventName];
5998 return typeof e == "object" && e.listeners.length > 0;
6002 * Appends an event handler to this element (shorthand for addListener)
6003 * @param {String} eventName The type of event to listen for
6004 * @param {Function} handler The method the event invokes
6005 * @param {Object} scope (optional) The scope in which to execute the handler
6006 * function. The handler function's "this" context.
6007 * @param {Object} options (optional)
6010 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
6012 * Removes a listener (shorthand for removeListener)
6013 * @param {String} eventName The type of event to listen for
6014 * @param {Function} handler The handler to remove
6015 * @param {Object} scope (optional) The scope (this object) for the handler
6018 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
6021 * Starts capture on the specified Observable. All events will be passed
6022 * to the supplied function with the event name + standard signature of the event
6023 * <b>before</b> the event is fired. If the supplied function returns false,
6024 * the event will not fire.
6025 * @param {Observable} o The Observable to capture
6026 * @param {Function} fn The function to call
6027 * @param {Object} scope (optional) The scope (this object) for the fn
6030 Roo.util.Observable.capture = function(o, fn, scope){
6031 o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
6035 * Removes <b>all</b> added captures from the Observable.
6036 * @param {Observable} o The Observable to release
6039 Roo.util.Observable.releaseCapture = function(o){
6040 o.fireEvent = Roo.util.Observable.prototype.fireEvent;
6045 var createBuffered = function(h, o, scope){
6046 var task = new Roo.util.DelayedTask();
6048 task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
6052 var createSingle = function(h, e, fn, scope){
6054 e.removeListener(fn, scope);
6055 return h.apply(scope, arguments);
6059 var createDelayed = function(h, o, scope){
6061 var args = Array.prototype.slice.call(arguments, 0);
6062 setTimeout(function(){
6063 h.apply(scope, args);
6068 Roo.util.Event = function(obj, name){
6071 this.listeners = [];
6074 Roo.util.Event.prototype = {
6075 addListener : function(fn, scope, options){
6076 var o = options || {};
6077 scope = scope || this.obj;
6078 if(!this.isListening(fn, scope)){
6079 var l = {fn: fn, scope: scope, options: o};
6082 h = createDelayed(h, o, scope);
6085 h = createSingle(h, this, fn, scope);
6088 h = createBuffered(h, o, scope);
6091 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
6092 this.listeners.push(l);
6094 this.listeners = this.listeners.slice(0);
6095 this.listeners.push(l);
6100 findListener : function(fn, scope){
6101 scope = scope || this.obj;
6102 var ls = this.listeners;
6103 for(var i = 0, len = ls.length; i < len; i++){
6105 if(l.fn == fn && l.scope == scope){
6112 isListening : function(fn, scope){
6113 return this.findListener(fn, scope) != -1;
6116 removeListener : function(fn, scope){
6118 if((index = this.findListener(fn, scope)) != -1){
6120 this.listeners.splice(index, 1);
6122 this.listeners = this.listeners.slice(0);
6123 this.listeners.splice(index, 1);
6130 clearListeners : function(){
6131 this.listeners = [];
6135 var ls = this.listeners, scope, len = ls.length;
6138 var args = Array.prototype.slice.call(arguments, 0);
6139 for(var i = 0; i < len; i++){
6141 if(l.fireFn.apply(l.scope||this.obj||window, args) === false){
6142 this.firing = false;
6146 this.firing = false;
6153 * Copyright(c) 2007-2017, Roo J Solutions Ltd
6160 * @class Roo.Document
6161 * @extends Roo.util.Observable
6162 * This is a convience class to wrap up the main document loading code.. , rather than adding Roo.onReady(......)
6164 * @param {Object} config the methods and properties of the 'base' class for the application.
6166 * Generic Page handler - implement this to start your app..
6169 * MyProject = new Roo.Document({
6171 'load' : true // your events..
6174 'ready' : function() {
6175 // fired on Roo.onReady()
6180 Roo.Document = function(cfg) {
6185 Roo.util.Observable.call(this,cfg);
6189 Roo.onReady(function() {
6190 _this.fireEvent('ready');
6196 Roo.extend(Roo.Document, Roo.util.Observable, {});/*
6198 * Ext JS Library 1.1.1
6199 * Copyright(c) 2006-2007, Ext JS, LLC.
6201 * Originally Released Under LGPL - original licence link has changed is not relivant.
6204 * <script type="text/javascript">
6208 * @class Roo.EventManager
6209 * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
6210 * several useful events directly.
6211 * See {@link Roo.EventObject} for more details on normalized event objects.
6214 Roo.EventManager = function(){
6215 var docReadyEvent, docReadyProcId, docReadyState = false;
6216 var resizeEvent, resizeTask, textEvent, textSize;
6217 var E = Roo.lib.Event;
6218 var D = Roo.lib.Dom;
6223 var fireDocReady = function(){
6225 docReadyState = true;
6228 clearInterval(docReadyProcId);
6230 if(Roo.isGecko || Roo.isOpera) {
6231 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6234 var defer = document.getElementById("ie-deferred-loader");
6236 defer.onreadystatechange = null;
6237 defer.parentNode.removeChild(defer);
6241 docReadyEvent.fire();
6242 docReadyEvent.clearListeners();
6247 var initDocReady = function(){
6248 docReadyEvent = new Roo.util.Event();
6249 if(Roo.isGecko || Roo.isOpera) {
6250 document.addEventListener("DOMContentLoaded", fireDocReady, false);
6252 document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6253 var defer = document.getElementById("ie-deferred-loader");
6254 defer.onreadystatechange = function(){
6255 if(this.readyState == "complete"){
6259 }else if(Roo.isSafari){
6260 docReadyProcId = setInterval(function(){
6261 var rs = document.readyState;
6262 if(rs == "complete") {
6267 // no matter what, make sure it fires on load
6268 E.on(window, "load", fireDocReady);
6271 var createBuffered = function(h, o){
6272 var task = new Roo.util.DelayedTask(h);
6274 // create new event object impl so new events don't wipe out properties
6275 e = new Roo.EventObjectImpl(e);
6276 task.delay(o.buffer, h, null, [e]);
6280 var createSingle = function(h, el, ename, fn){
6282 Roo.EventManager.removeListener(el, ename, fn);
6287 var createDelayed = function(h, o){
6289 // create new event object impl so new events don't wipe out properties
6290 e = new Roo.EventObjectImpl(e);
6291 setTimeout(function(){
6296 var transitionEndVal = false;
6298 var transitionEnd = function()
6300 if (transitionEndVal) {
6301 return transitionEndVal;
6303 var el = document.createElement('div');
6305 var transEndEventNames = {
6306 WebkitTransition : 'webkitTransitionEnd',
6307 MozTransition : 'transitionend',
6308 OTransition : 'oTransitionEnd otransitionend',
6309 transition : 'transitionend'
6312 for (var name in transEndEventNames) {
6313 if (el.style[name] !== undefined) {
6314 transitionEndVal = transEndEventNames[name];
6315 return transitionEndVal ;
6322 var listen = function(element, ename, opt, fn, scope)
6324 var o = (!opt || typeof opt == "boolean") ? {} : opt;
6325 fn = fn || o.fn; scope = scope || o.scope;
6326 var el = Roo.getDom(element);
6330 throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6333 if (ename == 'transitionend') {
6334 ename = transitionEnd();
6336 var h = function(e){
6337 e = Roo.EventObject.setEvent(e);
6340 t = e.getTarget(o.delegate, el);
6347 if(o.stopEvent === true){
6350 if(o.preventDefault === true){
6353 if(o.stopPropagation === true){
6354 e.stopPropagation();
6357 if(o.normalized === false){
6361 fn.call(scope || el, e, t, o);
6364 h = createDelayed(h, o);
6367 h = createSingle(h, el, ename, fn);
6370 h = createBuffered(h, o);
6373 fn._handlers = fn._handlers || [];
6376 fn._handlers.push([Roo.id(el), ename, h]);
6380 E.on(el, ename, h); // this adds the actuall listener to the object..
6383 if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6384 el.addEventListener("DOMMouseScroll", h, false);
6385 E.on(window, 'unload', function(){
6386 el.removeEventListener("DOMMouseScroll", h, false);
6389 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6390 Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6395 var stopListening = function(el, ename, fn){
6396 var id = Roo.id(el), hds = fn._handlers, hd = fn;
6398 for(var i = 0, len = hds.length; i < len; i++){
6400 if(h[0] == id && h[1] == ename){
6407 E.un(el, ename, hd);
6408 el = Roo.getDom(el);
6409 if(ename == "mousewheel" && el.addEventListener){
6410 el.removeEventListener("DOMMouseScroll", hd, false);
6412 if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6413 Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6417 var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6424 * @scope Roo.EventManager
6429 * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6430 * object with a Roo.EventObject
6431 * @param {Function} fn The method the event invokes
6432 * @param {Object} scope An object that becomes the scope of the handler
6433 * @param {boolean} override If true, the obj passed in becomes
6434 * the execution scope of the listener
6435 * @return {Function} The wrapped function
6438 wrap : function(fn, scope, override){
6440 Roo.EventObject.setEvent(e);
6441 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6446 * Appends an event handler to an element (shorthand for addListener)
6447 * @param {String/HTMLElement} element The html element or id to assign the
6448 * @param {String} eventName The type of event to listen for
6449 * @param {Function} handler The method the event invokes
6450 * @param {Object} scope (optional) The scope in which to execute the handler
6451 * function. The handler function's "this" context.
6452 * @param {Object} options (optional) An object containing handler configuration
6453 * properties. This may contain any of the following properties:<ul>
6454 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6455 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6456 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6457 * <li>preventDefault {Boolean} True to prevent the default action</li>
6458 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6459 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6460 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6461 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6462 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6463 * by the specified number of milliseconds. If the event fires again within that time, the original
6464 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6467 * <b>Combining Options</b><br>
6468 * Using the options argument, it is possible to combine different types of listeners:<br>
6470 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6472 el.on('click', this.onClick, this, {
6479 * <b>Attaching multiple handlers in 1 call</b><br>
6480 * The method also allows for a single argument to be passed which is a config object containing properties
6481 * which specify multiple handlers.
6491 fn: this.onMouseOver
6500 * Or a shorthand syntax:<br>
6503 'click' : this.onClick,
6504 'mouseover' : this.onMouseOver,
6505 'mouseout' : this.onMouseOut
6509 addListener : function(element, eventName, fn, scope, options){
6510 if(typeof eventName == "object"){
6516 if(typeof o[e] == "function"){
6518 listen(element, e, o, o[e], o.scope);
6520 // individual options
6521 listen(element, e, o[e]);
6526 return listen(element, eventName, options, fn, scope);
6530 * Removes an event handler
6532 * @param {String/HTMLElement} element The id or html element to remove the
6534 * @param {String} eventName The type of event
6535 * @param {Function} fn
6536 * @return {Boolean} True if a listener was actually removed
6538 removeListener : function(element, eventName, fn){
6539 return stopListening(element, eventName, fn);
6543 * Fires when the document is ready (before onload and before images are loaded). Can be
6544 * accessed shorthanded Roo.onReady().
6545 * @param {Function} fn The method the event invokes
6546 * @param {Object} scope An object that becomes the scope of the handler
6547 * @param {boolean} options
6549 onDocumentReady : function(fn, scope, options){
6550 if(docReadyState){ // if it already fired
6551 docReadyEvent.addListener(fn, scope, options);
6552 docReadyEvent.fire();
6553 docReadyEvent.clearListeners();
6559 docReadyEvent.addListener(fn, scope, options);
6563 * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6564 * @param {Function} fn The method the event invokes
6565 * @param {Object} scope An object that becomes the scope of the handler
6566 * @param {boolean} options
6568 onWindowResize : function(fn, scope, options){
6570 resizeEvent = new Roo.util.Event();
6571 resizeTask = new Roo.util.DelayedTask(function(){
6572 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6574 E.on(window, "resize", function(){
6576 resizeTask.delay(50);
6578 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6582 resizeEvent.addListener(fn, scope, options);
6586 * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6587 * @param {Function} fn The method the event invokes
6588 * @param {Object} scope An object that becomes the scope of the handler
6589 * @param {boolean} options
6591 onTextResize : function(fn, scope, options){
6593 textEvent = new Roo.util.Event();
6594 var textEl = new Roo.Element(document.createElement('div'));
6595 textEl.dom.className = 'x-text-resize';
6596 textEl.dom.innerHTML = 'X';
6597 textEl.appendTo(document.body);
6598 textSize = textEl.dom.offsetHeight;
6599 setInterval(function(){
6600 if(textEl.dom.offsetHeight != textSize){
6601 textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6603 }, this.textResizeInterval);
6605 textEvent.addListener(fn, scope, options);
6609 * Removes the passed window resize listener.
6610 * @param {Function} fn The method the event invokes
6611 * @param {Object} scope The scope of handler
6613 removeResizeListener : function(fn, scope){
6615 resizeEvent.removeListener(fn, scope);
6620 fireResize : function(){
6622 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6626 * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6630 * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6632 textResizeInterval : 50
6637 * @scopeAlias pub=Roo.EventManager
6641 * Appends an event handler to an element (shorthand for addListener)
6642 * @param {String/HTMLElement} element The html element or id to assign the
6643 * @param {String} eventName The type of event to listen for
6644 * @param {Function} handler The method the event invokes
6645 * @param {Object} scope (optional) The scope in which to execute the handler
6646 * function. The handler function's "this" context.
6647 * @param {Object} options (optional) An object containing handler configuration
6648 * properties. This may contain any of the following properties:<ul>
6649 * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6650 * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6651 * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6652 * <li>preventDefault {Boolean} True to prevent the default action</li>
6653 * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6654 * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6655 * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6656 * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6657 * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6658 * by the specified number of milliseconds. If the event fires again within that time, the original
6659 * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6662 * <b>Combining Options</b><br>
6663 * Using the options argument, it is possible to combine different types of listeners:<br>
6665 * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6667 el.on('click', this.onClick, this, {
6674 * <b>Attaching multiple handlers in 1 call</b><br>
6675 * The method also allows for a single argument to be passed which is a config object containing properties
6676 * which specify multiple handlers.
6686 fn: this.onMouseOver
6695 * Or a shorthand syntax:<br>
6698 'click' : this.onClick,
6699 'mouseover' : this.onMouseOver,
6700 'mouseout' : this.onMouseOut
6704 pub.on = pub.addListener;
6705 pub.un = pub.removeListener;
6707 pub.stoppedMouseDownEvent = new Roo.util.Event();
6711 * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Roo.EventManager#onDocumentReady}.
6712 * @param {Function} fn The method the event invokes
6713 * @param {Object} scope An object that becomes the scope of the handler
6714 * @param {boolean} override If true, the obj passed in becomes
6715 * the execution scope of the listener
6719 Roo.onReady = Roo.EventManager.onDocumentReady;
6721 Roo.onReady(function(){
6722 var bd = Roo.get(document.body);
6727 : Roo.isIE11 ? "roo-ie11"
6728 : Roo.isEdge ? "roo-edge"
6729 : Roo.isGecko ? "roo-gecko"
6730 : Roo.isOpera ? "roo-opera"
6731 : Roo.isSafari ? "roo-safari" : ""];
6734 cls.push("roo-mac");
6737 cls.push("roo-linux");
6740 cls.push("roo-ios");
6743 cls.push("roo-touch");
6745 if(Roo.isBorderBox){
6746 cls.push('roo-border-box');
6748 if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6749 var p = bd.dom.parentNode;
6751 p.className += ' roo-strict';
6754 bd.addClass(cls.join(' '));
6758 * @class Roo.EventObject
6759 * EventObject exposes the Yahoo! UI Event functionality directly on the object
6760 * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
6763 function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6765 var target = e.getTarget();
6768 var myDiv = Roo.get("myDiv");
6769 myDiv.on("click", handleClick);
6771 Roo.EventManager.on("myDiv", 'click', handleClick);
6772 Roo.EventManager.addListener("myDiv", 'click', handleClick);
6776 Roo.EventObject = function(){
6778 var E = Roo.lib.Event;
6780 // safari keypress events for special keys return bad keycodes
6783 63235 : 39, // right
6786 63276 : 33, // page up
6787 63277 : 34, // page down
6788 63272 : 46, // delete
6793 // normalize button clicks
6794 var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6795 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6797 Roo.EventObjectImpl = function(e){
6799 this.setEvent(e.browserEvent || e);
6802 Roo.EventObjectImpl.prototype = {
6804 * Used to fix doc tools.
6805 * @scope Roo.EventObject.prototype
6811 /** The normal browser event */
6812 browserEvent : null,
6813 /** The button pressed in a mouse event */
6815 /** True if the shift key was down during the event */
6817 /** True if the control key was down during the event */
6819 /** True if the alt key was down during the event */
6878 setEvent : function(e){
6879 if(e == this || (e && e.browserEvent)){ // already wrapped
6882 this.browserEvent = e;
6884 // normalize buttons
6885 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6886 if(e.type == 'click' && this.button == -1){
6890 this.shiftKey = e.shiftKey;
6891 // mac metaKey behaves like ctrlKey
6892 this.ctrlKey = e.ctrlKey || e.metaKey;
6893 this.altKey = e.altKey;
6894 // in getKey these will be normalized for the mac
6895 this.keyCode = e.keyCode;
6896 // keyup warnings on firefox.
6897 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6898 // cache the target for the delayed and or buffered events
6899 this.target = E.getTarget(e);
6901 this.xy = E.getXY(e);
6904 this.shiftKey = false;
6905 this.ctrlKey = false;
6906 this.altKey = false;
6916 * Stop the event (preventDefault and stopPropagation)
6918 stopEvent : function(){
6919 if(this.browserEvent){
6920 if(this.browserEvent.type == 'mousedown'){
6921 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6923 E.stopEvent(this.browserEvent);
6928 * Prevents the browsers default handling of the event.
6930 preventDefault : function(){
6931 if(this.browserEvent){
6932 E.preventDefault(this.browserEvent);
6937 isNavKeyPress : function(){
6938 var k = this.keyCode;
6939 k = Roo.isSafari ? (safariKeys[k] || k) : k;
6940 return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6943 isSpecialKey : function(){
6944 var k = this.keyCode;
6945 return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
6946 (k == 16) || (k == 17) ||
6947 (k >= 18 && k <= 20) ||
6948 (k >= 33 && k <= 35) ||
6949 (k >= 36 && k <= 39) ||
6950 (k >= 44 && k <= 45);
6953 * Cancels bubbling of the event.
6955 stopPropagation : function(){
6956 if(this.browserEvent){
6957 if(this.type == 'mousedown'){
6958 Roo.EventManager.stoppedMouseDownEvent.fire(this);
6960 E.stopPropagation(this.browserEvent);
6965 * Gets the key code for the event.
6968 getCharCode : function(){
6969 return this.charCode || this.keyCode;
6973 * Returns a normalized keyCode for the event.
6974 * @return {Number} The key code
6976 getKey : function(){
6977 var k = this.keyCode || this.charCode;
6978 return Roo.isSafari ? (safariKeys[k] || k) : k;
6982 * Gets the x coordinate of the event.
6985 getPageX : function(){
6990 * Gets the y coordinate of the event.
6993 getPageY : function(){
6998 * Gets the time of the event.
7001 getTime : function(){
7002 if(this.browserEvent){
7003 return E.getTime(this.browserEvent);
7009 * Gets the page coordinates of the event.
7010 * @return {Array} The xy values like [x, y]
7017 * Gets the target for the event.
7018 * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
7019 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7020 search as a number or element (defaults to 10 || document.body)
7021 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7022 * @return {HTMLelement}
7024 getTarget : function(selector, maxDepth, returnEl){
7025 return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
7028 * Gets the related target.
7029 * @return {HTMLElement}
7031 getRelatedTarget : function(){
7032 if(this.browserEvent){
7033 return E.getRelatedTarget(this.browserEvent);
7039 * Normalizes mouse wheel delta across browsers
7040 * @return {Number} The delta
7042 getWheelDelta : function(){
7043 var e = this.browserEvent;
7045 if(e.wheelDelta){ /* IE/Opera. */
7046 delta = e.wheelDelta/120;
7047 }else if(e.detail){ /* Mozilla case. */
7048 delta = -e.detail/3;
7054 * Returns true if the control, meta, shift or alt key was pressed during this event.
7057 hasModifier : function(){
7058 return !!((this.ctrlKey || this.altKey) || this.shiftKey);
7062 * Returns true if the target of this event equals el or is a child of el
7063 * @param {String/HTMLElement/Element} el
7064 * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
7067 within : function(el, related){
7068 var t = this[related ? "getRelatedTarget" : "getTarget"]();
7069 return t && Roo.fly(el).contains(t);
7072 getPoint : function(){
7073 return new Roo.lib.Point(this.xy[0], this.xy[1]);
7077 return new Roo.EventObjectImpl();
7082 * Ext JS Library 1.1.1
7083 * Copyright(c) 2006-2007, Ext JS, LLC.
7085 * Originally Released Under LGPL - original licence link has changed is not relivant.
7088 * <script type="text/javascript">
7092 // was in Composite Element!??!?!
7095 var D = Roo.lib.Dom;
7096 var E = Roo.lib.Event;
7097 var A = Roo.lib.Anim;
7099 // local style camelizing for speed
7101 var camelRe = /(-[a-z])/gi;
7102 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
7103 var view = document.defaultView;
7106 * @class Roo.Element
7107 * Represents an Element in the DOM.<br><br>
7110 var el = Roo.get("my-div");
7113 var el = getEl("my-div");
7115 // or with a DOM element
7116 var el = Roo.get(myDivElement);
7118 * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
7119 * each call instead of constructing a new one.<br><br>
7120 * <b>Animations</b><br />
7121 * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
7122 * should either be a boolean (true) or an object literal with animation options. The animation options are:
7124 Option Default Description
7125 --------- -------- ---------------------------------------------
7126 duration .35 The duration of the animation in seconds
7127 easing easeOut The YUI easing method
7128 callback none A function to execute when the anim completes
7129 scope this The scope (this) of the callback function
7131 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
7132 * manipulate the animation. Here's an example:
7134 var el = Roo.get("my-div");
7139 // default animation
7140 el.setWidth(100, true);
7142 // animation with some options set
7149 // using the "anim" property to get the Anim object
7155 el.setWidth(100, opt);
7157 if(opt.anim.isAnimated()){
7161 * <b> Composite (Collections of) Elements</b><br />
7162 * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7163 * @constructor Create a new Element directly.
7164 * @param {String/HTMLElement} element
7165 * @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).
7167 Roo.Element = function(element, forceNew)
7169 var dom = typeof element == "string" ?
7170 document.getElementById(element) : element;
7172 this.listeners = {};
7174 if(!dom){ // invalid id/element
7178 if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7179 return Roo.Element.cache[id];
7189 * The DOM element ID
7192 this.id = id || Roo.id(dom);
7194 return this; // assumed for cctor?
7197 var El = Roo.Element;
7201 * The element's default display mode (defaults to "")
7204 originalDisplay : "",
7207 // note this is overridden in BS version..
7210 * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7216 * Sets the element's visibility mode. When setVisible() is called it
7217 * will use this to determine whether to set the visibility or the display property.
7218 * @param visMode Element.VISIBILITY or Element.DISPLAY
7219 * @return {Roo.Element} this
7221 setVisibilityMode : function(visMode){
7222 this.visibilityMode = visMode;
7226 * Convenience method for setVisibilityMode(Element.DISPLAY)
7227 * @param {String} display (optional) What to set display to when visible
7228 * @return {Roo.Element} this
7230 enableDisplayMode : function(display){
7231 this.setVisibilityMode(El.DISPLAY);
7232 if(typeof display != "undefined") { this.originalDisplay = display; }
7237 * 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)
7238 * @param {String} selector The simple selector to test
7239 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7240 search as a number or element (defaults to 10 || document.body)
7241 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7242 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7244 findParent : function(simpleSelector, maxDepth, returnEl){
7245 var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7246 maxDepth = maxDepth || 50;
7247 if(typeof maxDepth != "number"){
7248 stopEl = Roo.getDom(maxDepth);
7251 while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7252 if(dq.is(p, simpleSelector)){
7253 return returnEl ? Roo.get(p) : p;
7263 * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7264 * @param {String} selector The simple selector to test
7265 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7266 search as a number or element (defaults to 10 || document.body)
7267 * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7268 * @return {HTMLElement} The matching DOM node (or null if no match was found)
7270 findParentNode : function(simpleSelector, maxDepth, returnEl){
7271 var p = Roo.fly(this.dom.parentNode, '_internal');
7272 return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7276 * Looks at the scrollable parent element
7278 findScrollableParent : function()
7280 var overflowRegex = /(auto|scroll)/;
7282 if(this.getStyle('position') === 'fixed'){
7283 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7286 var excludeStaticParent = this.getStyle('position') === "absolute";
7288 for (var parent = this; (parent = Roo.get(parent.dom.parentNode));){
7290 if (excludeStaticParent && parent.getStyle('position') === "static") {
7294 if (overflowRegex.test(parent.getStyle('overflow') + parent.getStyle('overflow-x') + parent.getStyle('overflow-y'))){
7298 if(parent.dom.nodeName.toLowerCase() == 'body'){
7299 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7303 return Roo.isAndroid ? Roo.get(document.documentElement) : Roo.get(document.body);
7307 * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7308 * This is a shortcut for findParentNode() that always returns an Roo.Element.
7309 * @param {String} selector The simple selector to test
7310 * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7311 search as a number or element (defaults to 10 || document.body)
7312 * @return {Roo.Element} The matching DOM node (or null if no match was found)
7314 up : function(simpleSelector, maxDepth){
7315 return this.findParentNode(simpleSelector, maxDepth, true);
7321 * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7322 * @param {String} selector The simple selector to test
7323 * @return {Boolean} True if this element matches the selector, else false
7325 is : function(simpleSelector){
7326 return Roo.DomQuery.is(this.dom, simpleSelector);
7330 * Perform animation on this element.
7331 * @param {Object} args The YUI animation control args
7332 * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7333 * @param {Function} onComplete (optional) Function to call when animation completes
7334 * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7335 * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7336 * @return {Roo.Element} this
7338 animate : function(args, duration, onComplete, easing, animType){
7339 this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7344 * @private Internal animation call
7346 anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7347 animType = animType || 'run';
7349 var anim = Roo.lib.Anim[animType](
7351 (opt.duration || defaultDur) || .35,
7352 (opt.easing || defaultEase) || 'easeOut',
7354 Roo.callback(cb, this);
7355 Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7363 // private legacy anim prep
7364 preanim : function(a, i){
7365 return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7369 * Removes worthless text nodes
7370 * @param {Boolean} forceReclean (optional) By default the element
7371 * keeps track if it has been cleaned already so
7372 * you can call this over and over. However, if you update the element and
7373 * need to force a reclean, you can pass true.
7375 clean : function(forceReclean){
7376 if(this.isCleaned && forceReclean !== true){
7380 var d = this.dom, n = d.firstChild, ni = -1;
7382 var nx = n.nextSibling;
7383 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7390 this.isCleaned = true;
7395 calcOffsetsTo : function(el){
7398 var restorePos = false;
7399 if(el.getStyle('position') == 'static'){
7400 el.position('relative');
7405 while(op && op != d && op.tagName != 'HTML'){
7408 op = op.offsetParent;
7411 el.position('static');
7417 * Scrolls this element into view within the passed container.
7418 * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7419 * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7420 * @return {Roo.Element} this
7422 scrollIntoView : function(container, hscroll){
7423 var c = Roo.getDom(container) || document.body;
7426 var o = this.calcOffsetsTo(c),
7429 b = t+el.offsetHeight,
7430 r = l+el.offsetWidth;
7432 var ch = c.clientHeight;
7433 var ct = parseInt(c.scrollTop, 10);
7434 var cl = parseInt(c.scrollLeft, 10);
7436 var cr = cl + c.clientWidth;
7444 if(hscroll !== false){
7448 c.scrollLeft = r-c.clientWidth;
7455 scrollChildIntoView : function(child, hscroll){
7456 Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7460 * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7461 * the new height may not be available immediately.
7462 * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7463 * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7464 * @param {Function} onComplete (optional) Function to call when animation completes
7465 * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7466 * @return {Roo.Element} this
7468 autoHeight : function(animate, duration, onComplete, easing){
7469 var oldHeight = this.getHeight();
7471 this.setHeight(1); // force clipping
7472 setTimeout(function(){
7473 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7475 this.setHeight(height);
7477 if(typeof onComplete == "function"){
7481 this.setHeight(oldHeight); // restore original height
7482 this.setHeight(height, animate, duration, function(){
7484 if(typeof onComplete == "function") { onComplete(); }
7485 }.createDelegate(this), easing);
7487 }.createDelegate(this), 0);
7492 * Returns true if this element is an ancestor of the passed element
7493 * @param {HTMLElement/String} el The element to check
7494 * @return {Boolean} True if this element is an ancestor of el, else false
7496 contains : function(el){
7497 if(!el){return false;}
7498 return D.isAncestor(this.dom, el.dom ? el.dom : el);
7502 * Checks whether the element is currently visible using both visibility and display properties.
7503 * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7504 * @return {Boolean} True if the element is currently visible, else false
7506 isVisible : function(deep) {
7507 var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7508 if(deep !== true || !vis){
7511 var p = this.dom.parentNode;
7512 while(p && p.tagName.toLowerCase() != "body"){
7513 if(!Roo.fly(p, '_isVisible').isVisible()){
7522 * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7523 * @param {String} selector The CSS selector
7524 * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7525 * @return {CompositeElement/CompositeElementLite} The composite element
7527 select : function(selector, unique){
7528 return El.select(selector, unique, this.dom);
7532 * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7533 * @param {String} selector The CSS selector
7534 * @return {Array} An array of the matched nodes
7536 query : function(selector, unique){
7537 return Roo.DomQuery.select(selector, this.dom);
7541 * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7542 * @param {String} selector The CSS selector
7543 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7544 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7546 child : function(selector, returnDom){
7547 var n = Roo.DomQuery.selectNode(selector, this.dom);
7548 return returnDom ? n : Roo.get(n);
7552 * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7553 * @param {String} selector The CSS selector
7554 * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7555 * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7557 down : function(selector, returnDom){
7558 var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7559 return returnDom ? n : Roo.get(n);
7563 * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7564 * @param {String} group The group the DD object is member of
7565 * @param {Object} config The DD config object
7566 * @param {Object} overrides An object containing methods to override/implement on the DD object
7567 * @return {Roo.dd.DD} The DD object
7569 initDD : function(group, config, overrides){
7570 var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7571 return Roo.apply(dd, overrides);
7575 * Initializes a {@link Roo.dd.DDProxy} object for this element.
7576 * @param {String} group The group the DDProxy object is member of
7577 * @param {Object} config The DDProxy config object
7578 * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7579 * @return {Roo.dd.DDProxy} The DDProxy object
7581 initDDProxy : function(group, config, overrides){
7582 var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7583 return Roo.apply(dd, overrides);
7587 * Initializes a {@link Roo.dd.DDTarget} object for this element.
7588 * @param {String} group The group the DDTarget object is member of
7589 * @param {Object} config The DDTarget config object
7590 * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7591 * @return {Roo.dd.DDTarget} The DDTarget object
7593 initDDTarget : function(group, config, overrides){
7594 var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7595 return Roo.apply(dd, overrides);
7599 * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7600 * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7601 * @param {Boolean} visible Whether the element is visible
7602 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7603 * @return {Roo.Element} this
7605 setVisible : function(visible, animate){
7607 if(this.visibilityMode == El.DISPLAY){
7608 this.setDisplayed(visible);
7611 this.dom.style.visibility = visible ? "visible" : "hidden";
7614 // closure for composites
7616 var visMode = this.visibilityMode;
7618 this.setOpacity(.01);
7619 this.setVisible(true);
7621 this.anim({opacity: { to: (visible?1:0) }},
7622 this.preanim(arguments, 1),
7623 null, .35, 'easeIn', function(){
7625 if(visMode == El.DISPLAY){
7626 dom.style.display = "none";
7628 dom.style.visibility = "hidden";
7630 Roo.get(dom).setOpacity(1);
7638 * Returns true if display is not "none"
7641 isDisplayed : function() {
7642 return this.getStyle("display") != "none";
7646 * Toggles the element's visibility or display, depending on visibility mode.
7647 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7648 * @return {Roo.Element} this
7650 toggle : function(animate){
7651 this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7656 * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7657 * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7658 * @return {Roo.Element} this
7660 setDisplayed : function(value) {
7661 if(typeof value == "boolean"){
7662 value = value ? this.originalDisplay : "none";
7664 this.setStyle("display", value);
7669 * Tries to focus the element. Any exceptions are caught and ignored.
7670 * @return {Roo.Element} this
7672 focus : function() {
7680 * Tries to blur the element. Any exceptions are caught and ignored.
7681 * @return {Roo.Element} this
7691 * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7692 * @param {String/Array} className The CSS class to add, or an array of classes
7693 * @return {Roo.Element} this
7695 addClass : function(className){
7696 if(className instanceof Array){
7697 for(var i = 0, len = className.length; i < len; i++) {
7698 this.addClass(className[i]);
7701 if(className && !this.hasClass(className)){
7702 if (this.dom instanceof SVGElement) {
7703 this.dom.className.baseVal =this.dom.className.baseVal + " " + className;
7705 this.dom.className = this.dom.className + " " + className;
7713 * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7714 * @param {String/Array} className The CSS class to add, or an array of classes
7715 * @return {Roo.Element} this
7717 radioClass : function(className){
7718 var siblings = this.dom.parentNode.childNodes;
7719 for(var i = 0; i < siblings.length; i++) {
7720 var s = siblings[i];
7721 if(s.nodeType == 1){
7722 Roo.get(s).removeClass(className);
7725 this.addClass(className);
7730 * Removes one or more CSS classes from the element.
7731 * @param {String/Array} className The CSS class to remove, or an array of classes
7732 * @return {Roo.Element} this
7734 removeClass : function(className){
7736 var cn = this.dom instanceof SVGElement ? this.dom.className.baseVal : this.dom.className;
7737 if(!className || !cn){
7740 if(className instanceof Array){
7741 for(var i = 0, len = className.length; i < len; i++) {
7742 this.removeClass(className[i]);
7745 if(this.hasClass(className)){
7746 var re = this.classReCache[className];
7748 re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7749 this.classReCache[className] = re;
7751 if (this.dom instanceof SVGElement) {
7752 this.dom.className.baseVal = cn.replace(re, " ");
7754 this.dom.className = cn.replace(re, " ");
7765 * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7766 * @param {String} className The CSS class to toggle
7767 * @return {Roo.Element} this
7769 toggleClass : function(className){
7770 if(this.hasClass(className)){
7771 this.removeClass(className);
7773 this.addClass(className);
7779 * Checks if the specified CSS class exists on this element's DOM node.
7780 * @param {String} className The CSS class to check for
7781 * @return {Boolean} True if the class exists, else false
7783 hasClass : function(className){
7784 if (this.dom instanceof SVGElement) {
7785 return className && (' '+this.dom.className.baseVal +' ').indexOf(' '+className+' ') != -1;
7787 return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7791 * Replaces a CSS class on the element with another. If the old name does not exist, the new name will simply be added.
7792 * @param {String} oldClassName The CSS class to replace
7793 * @param {String} newClassName The replacement CSS class
7794 * @return {Roo.Element} this
7796 replaceClass : function(oldClassName, newClassName){
7797 this.removeClass(oldClassName);
7798 this.addClass(newClassName);
7803 * Returns an object with properties matching the styles requested.
7804 * For example, el.getStyles('color', 'font-size', 'width') might return
7805 * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7806 * @param {String} style1 A style name
7807 * @param {String} style2 A style name
7808 * @param {String} etc.
7809 * @return {Object} The style object
7811 getStyles : function(){
7812 var a = arguments, len = a.length, r = {};
7813 for(var i = 0; i < len; i++){
7814 r[a[i]] = this.getStyle(a[i]);
7820 * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7821 * @param {String} property The style property whose value is returned.
7822 * @return {String} The current value of the style property for this element.
7824 getStyle : function(){
7825 return view && view.getComputedStyle ?
7827 var el = this.dom, v, cs, camel;
7828 if(prop == 'float'){
7831 if(el.style && (v = el.style[prop])){
7834 if(cs = view.getComputedStyle(el, "")){
7835 if(!(camel = propCache[prop])){
7836 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7843 var el = this.dom, v, cs, camel;
7844 if(prop == 'opacity'){
7845 if(typeof el.style.filter == 'string'){
7846 var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7848 var fv = parseFloat(m[1]);
7850 return fv ? fv / 100 : 0;
7855 }else if(prop == 'float'){
7856 prop = "styleFloat";
7858 if(!(camel = propCache[prop])){
7859 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7861 if(v = el.style[camel]){
7864 if(cs = el.currentStyle){
7872 * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7873 * @param {String/Object} property The style property to be set, or an object of multiple styles.
7874 * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7875 * @return {Roo.Element} this
7877 setStyle : function(prop, value){
7878 if(typeof prop == "string"){
7880 if (prop == 'float') {
7881 this.setStyle(Roo.isIE ? 'styleFloat' : 'cssFloat', value);
7886 if(!(camel = propCache[prop])){
7887 camel = propCache[prop] = prop.replace(camelRe, camelFn);
7890 if(camel == 'opacity') {
7891 this.setOpacity(value);
7893 this.dom.style[camel] = value;
7896 for(var style in prop){
7897 if(typeof prop[style] != "function"){
7898 this.setStyle(style, prop[style]);
7906 * More flexible version of {@link #setStyle} for setting style properties.
7907 * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7908 * a function which returns such a specification.
7909 * @return {Roo.Element} this
7911 applyStyles : function(style){
7912 Roo.DomHelper.applyStyles(this.dom, style);
7917 * 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).
7918 * @return {Number} The X position of the element
7921 return D.getX(this.dom);
7925 * 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).
7926 * @return {Number} The Y position of the element
7929 return D.getY(this.dom);
7933 * 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).
7934 * @return {Array} The XY position of the element
7937 return D.getXY(this.dom);
7941 * 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).
7942 * @param {Number} The X position of the element
7943 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7944 * @return {Roo.Element} this
7946 setX : function(x, animate){
7948 D.setX(this.dom, x);
7950 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7956 * 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).
7957 * @param {Number} The Y position of the element
7958 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7959 * @return {Roo.Element} this
7961 setY : function(y, animate){
7963 D.setY(this.dom, y);
7965 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7971 * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7972 * @param {String} left The left CSS property value
7973 * @return {Roo.Element} this
7975 setLeft : function(left){
7976 this.setStyle("left", this.addUnits(left));
7981 * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7982 * @param {String} top The top CSS property value
7983 * @return {Roo.Element} this
7985 setTop : function(top){
7986 this.setStyle("top", this.addUnits(top));
7991 * Sets the element's CSS right style.
7992 * @param {String} right The right CSS property value
7993 * @return {Roo.Element} this
7995 setRight : function(right){
7996 this.setStyle("right", this.addUnits(right));
8001 * Sets the element's CSS bottom style.
8002 * @param {String} bottom The bottom CSS property value
8003 * @return {Roo.Element} this
8005 setBottom : function(bottom){
8006 this.setStyle("bottom", this.addUnits(bottom));
8011 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8012 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8013 * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
8014 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8015 * @return {Roo.Element} this
8017 setXY : function(pos, animate){
8019 D.setXY(this.dom, pos);
8021 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
8027 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8028 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8029 * @param {Number} x X value for new position (coordinates are page-based)
8030 * @param {Number} y Y value for new position (coordinates are page-based)
8031 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8032 * @return {Roo.Element} this
8034 setLocation : function(x, y, animate){
8035 this.setXY([x, y], this.preanim(arguments, 2));
8040 * Sets the position of the element in page coordinates, regardless of how the element is positioned.
8041 * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
8042 * @param {Number} x X value for new position (coordinates are page-based)
8043 * @param {Number} y Y value for new position (coordinates are page-based)
8044 * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
8045 * @return {Roo.Element} this
8047 moveTo : function(x, y, animate){
8048 this.setXY([x, y], this.preanim(arguments, 2));
8053 * Returns the region of the given element.
8054 * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
8055 * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
8057 getRegion : function(){
8058 return D.getRegion(this.dom);
8062 * Returns the offset height of the element
8063 * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
8064 * @return {Number} The element's height
8066 getHeight : function(contentHeight){
8067 var h = this.dom.offsetHeight || 0;
8068 return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
8072 * Returns the offset width of the element
8073 * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
8074 * @return {Number} The element's width
8076 getWidth : function(contentWidth){
8077 var w = this.dom.offsetWidth || 0;
8078 return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
8082 * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
8083 * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
8084 * if a height has not been set using CSS.
8087 getComputedHeight : function(){
8088 var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
8090 h = parseInt(this.getStyle('height'), 10) || 0;
8091 if(!this.isBorderBox()){
8092 h += this.getFrameWidth('tb');
8099 * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
8100 * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
8101 * if a width has not been set using CSS.
8104 getComputedWidth : function(){
8105 var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
8107 w = parseInt(this.getStyle('width'), 10) || 0;
8108 if(!this.isBorderBox()){
8109 w += this.getFrameWidth('lr');
8116 * Returns the size of the element.
8117 * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
8118 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8120 getSize : function(contentSize){
8121 return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
8125 * Returns the width and height of the viewport.
8126 * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
8128 getViewSize : function(){
8129 var d = this.dom, doc = document, aw = 0, ah = 0;
8130 if(d == doc || d == doc.body){
8131 return {width : D.getViewWidth(), height: D.getViewHeight()};
8134 width : d.clientWidth,
8135 height: d.clientHeight
8141 * Returns the value of the "value" attribute
8142 * @param {Boolean} asNumber true to parse the value as a number
8143 * @return {String/Number}
8145 getValue : function(asNumber){
8146 return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
8150 adjustWidth : function(width){
8151 if(typeof width == "number"){
8152 if(this.autoBoxAdjust && !this.isBorderBox()){
8153 width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8163 adjustHeight : function(height){
8164 if(typeof height == "number"){
8165 if(this.autoBoxAdjust && !this.isBorderBox()){
8166 height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8176 * Set the width of the element
8177 * @param {Number} width The new width
8178 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8179 * @return {Roo.Element} this
8181 setWidth : function(width, animate){
8182 width = this.adjustWidth(width);
8184 this.dom.style.width = this.addUnits(width);
8186 this.anim({width: {to: width}}, this.preanim(arguments, 1));
8192 * Set the height of the element
8193 * @param {Number} height The new height
8194 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8195 * @return {Roo.Element} this
8197 setHeight : function(height, animate){
8198 height = this.adjustHeight(height);
8200 this.dom.style.height = this.addUnits(height);
8202 this.anim({height: {to: height}}, this.preanim(arguments, 1));
8208 * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8209 * @param {Number} width The new width
8210 * @param {Number} height The new height
8211 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8212 * @return {Roo.Element} this
8214 setSize : function(width, height, animate){
8215 if(typeof width == "object"){ // in case of object from getSize()
8216 height = width.height; width = width.width;
8218 width = this.adjustWidth(width); height = this.adjustHeight(height);
8220 this.dom.style.width = this.addUnits(width);
8221 this.dom.style.height = this.addUnits(height);
8223 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8229 * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8230 * @param {Number} x X value for new position (coordinates are page-based)
8231 * @param {Number} y Y value for new position (coordinates are page-based)
8232 * @param {Number} width The new width
8233 * @param {Number} height The new height
8234 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8235 * @return {Roo.Element} this
8237 setBounds : function(x, y, width, height, animate){
8239 this.setSize(width, height);
8240 this.setLocation(x, y);
8242 width = this.adjustWidth(width); height = this.adjustHeight(height);
8243 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8244 this.preanim(arguments, 4), 'motion');
8250 * 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.
8251 * @param {Roo.lib.Region} region The region to fill
8252 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8253 * @return {Roo.Element} this
8255 setRegion : function(region, animate){
8256 this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8261 * Appends an event handler
8263 * @param {String} eventName The type of event to append
8264 * @param {Function} fn The method the event invokes
8265 * @param {Object} scope (optional) The scope (this object) of the fn
8266 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
8268 addListener : function(eventName, fn, scope, options)
8270 if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch.
8271 this.addListener('touchstart', this.onTapHandler, this);
8274 // we need to handle a special case where dom element is a svg element.
8275 // in this case we do not actua
8280 if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) {
8281 if (typeof(this.listeners[eventName]) == 'undefined') {
8282 this.listeners[eventName] = new Roo.util.Event(this, eventName);
8284 this.listeners[eventName].addListener(fn, scope, options);
8289 Roo.EventManager.on(this.dom, eventName, fn, scope || this, options);
8294 onTapHandler : function(event)
8296 if(!this.tapedTwice) {
8297 this.tapedTwice = true;
8299 setTimeout( function() {
8300 s.tapedTwice = false;
8304 event.preventDefault();
8305 var revent = new MouseEvent('dblclick', {
8311 this.dom.dispatchEvent(revent);
8312 //action on double tap goes below
8317 * Removes an event handler from this element
8318 * @param {String} eventName the type of event to remove
8319 * @param {Function} fn the method the event invokes
8320 * @param {Function} scope (needed for svg fake listeners)
8321 * @return {Roo.Element} this
8323 removeListener : function(eventName, fn, scope){
8324 Roo.EventManager.removeListener(this.dom, eventName, fn);
8325 if (typeof(this.listeners) == 'undefined' || typeof(this.listeners[eventName]) == 'undefined') {
8328 this.listeners[eventName].removeListener(fn, scope);
8333 * Removes all previous added listeners from this element
8334 * @return {Roo.Element} this
8336 removeAllListeners : function(){
8337 E.purgeElement(this.dom);
8338 this.listeners = {};
8342 relayEvent : function(eventName, observable){
8343 this.on(eventName, function(e){
8344 observable.fireEvent(eventName, e);
8350 * Set the opacity of the element
8351 * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8352 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8353 * @return {Roo.Element} this
8355 setOpacity : function(opacity, animate){
8357 var s = this.dom.style;
8360 s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8361 (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8363 s.opacity = opacity;
8366 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8372 * Gets the left X coordinate
8373 * @param {Boolean} local True to get the local css position instead of page coordinate
8376 getLeft : function(local){
8380 return parseInt(this.getStyle("left"), 10) || 0;
8385 * Gets the right X coordinate of the element (element X position + element width)
8386 * @param {Boolean} local True to get the local css position instead of page coordinate
8389 getRight : function(local){
8391 return this.getX() + this.getWidth();
8393 return (this.getLeft(true) + this.getWidth()) || 0;
8398 * Gets the top Y coordinate
8399 * @param {Boolean} local True to get the local css position instead of page coordinate
8402 getTop : function(local) {
8406 return parseInt(this.getStyle("top"), 10) || 0;
8411 * Gets the bottom Y coordinate of the element (element Y position + element height)
8412 * @param {Boolean} local True to get the local css position instead of page coordinate
8415 getBottom : function(local){
8417 return this.getY() + this.getHeight();
8419 return (this.getTop(true) + this.getHeight()) || 0;
8424 * Initializes positioning on this element. If a desired position is not passed, it will make the
8425 * the element positioned relative IF it is not already positioned.
8426 * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8427 * @param {Number} zIndex (optional) The zIndex to apply
8428 * @param {Number} x (optional) Set the page X position
8429 * @param {Number} y (optional) Set the page Y position
8431 position : function(pos, zIndex, x, y){
8433 if(this.getStyle('position') == 'static'){
8434 this.setStyle('position', 'relative');
8437 this.setStyle("position", pos);
8440 this.setStyle("z-index", zIndex);
8442 if(x !== undefined && y !== undefined){
8444 }else if(x !== undefined){
8446 }else if(y !== undefined){
8452 * Clear positioning back to the default when the document was loaded
8453 * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8454 * @return {Roo.Element} this
8456 clearPositioning : function(value){
8464 "position" : "static"
8470 * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8471 * snapshot before performing an update and then restoring the element.
8474 getPositioning : function(){
8475 var l = this.getStyle("left");
8476 var t = this.getStyle("top");
8478 "position" : this.getStyle("position"),
8480 "right" : l ? "" : this.getStyle("right"),
8482 "bottom" : t ? "" : this.getStyle("bottom"),
8483 "z-index" : this.getStyle("z-index")
8488 * Gets the width of the border(s) for the specified side(s)
8489 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8490 * passing lr would get the border (l)eft width + the border (r)ight width.
8491 * @return {Number} The width of the sides passed added together
8493 getBorderWidth : function(side){
8494 return this.addStyles(side, El.borders);
8498 * Gets the width of the padding(s) for the specified side(s)
8499 * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8500 * passing lr would get the padding (l)eft + the padding (r)ight.
8501 * @return {Number} The padding of the sides passed added together
8503 getPadding : function(side){
8504 return this.addStyles(side, El.paddings);
8508 * Set positioning with an object returned by getPositioning().
8509 * @param {Object} posCfg
8510 * @return {Roo.Element} this
8512 setPositioning : function(pc){
8513 this.applyStyles(pc);
8514 if(pc.right == "auto"){
8515 this.dom.style.right = "";
8517 if(pc.bottom == "auto"){
8518 this.dom.style.bottom = "";
8524 fixDisplay : function(){
8525 if(this.getStyle("display") == "none"){
8526 this.setStyle("visibility", "hidden");
8527 this.setStyle("display", this.originalDisplay); // first try reverting to default
8528 if(this.getStyle("display") == "none"){ // if that fails, default to block
8529 this.setStyle("display", "block");
8535 * Quick set left and top adding default units
8536 * @param {String} left The left CSS property value
8537 * @param {String} top The top CSS property value
8538 * @return {Roo.Element} this
8540 setLeftTop : function(left, top){
8541 this.dom.style.left = this.addUnits(left);
8542 this.dom.style.top = this.addUnits(top);
8547 * Move this element relative to its current position.
8548 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8549 * @param {Number} distance How far to move the element in pixels
8550 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8551 * @return {Roo.Element} this
8553 move : function(direction, distance, animate){
8554 var xy = this.getXY();
8555 direction = direction.toLowerCase();
8559 this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8563 this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8568 this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8573 this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8580 * Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8581 * @return {Roo.Element} this
8584 if(!this.isClipped){
8585 this.isClipped = true;
8586 this.originalClip = {
8587 "o": this.getStyle("overflow"),
8588 "x": this.getStyle("overflow-x"),
8589 "y": this.getStyle("overflow-y")
8591 this.setStyle("overflow", "hidden");
8592 this.setStyle("overflow-x", "hidden");
8593 this.setStyle("overflow-y", "hidden");
8599 * Return clipping (overflow) to original clipping before clip() was called
8600 * @return {Roo.Element} this
8602 unclip : function(){
8604 this.isClipped = false;
8605 var o = this.originalClip;
8606 if(o.o){this.setStyle("overflow", o.o);}
8607 if(o.x){this.setStyle("overflow-x", o.x);}
8608 if(o.y){this.setStyle("overflow-y", o.y);}
8615 * Gets the x,y coordinates specified by the anchor position on the element.
8616 * @param {String} anchor (optional) The specified anchor position (defaults to "c"). See {@link #alignTo} for details on supported anchor positions.
8617 * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8618 * {width: (target width), height: (target height)} (defaults to the element's current size)
8619 * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8620 * @return {Array} [x, y] An array containing the element's x and y coordinates
8622 getAnchorXY : function(anchor, local, s){
8623 //Passing a different size is useful for pre-calculating anchors,
8624 //especially for anchored animations that change the el size.
8626 var w, h, vp = false;
8629 if(d == document.body || d == document){
8631 w = D.getViewWidth(); h = D.getViewHeight();
8633 w = this.getWidth(); h = this.getHeight();
8636 w = s.width; h = s.height;
8638 var x = 0, y = 0, r = Math.round;
8639 switch((anchor || "tl").toLowerCase()){
8681 var sc = this.getScroll();
8682 return [x + sc.left, y + sc.top];
8684 //Add the element's offset xy
8685 var o = this.getXY();
8686 return [x+o[0], y+o[1]];
8690 * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8691 * supported position values.
8692 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8693 * @param {String} position The position to align to.
8694 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8695 * @return {Array} [x, y]
8697 getAlignToXY : function(el, p, o)
8702 throw "Element.alignTo with an element that doesn't exist";
8704 var c = false; //constrain to viewport
8705 var p1 = "", p2 = "";
8712 }else if(p.indexOf("-") == -1){
8715 p = p.toLowerCase();
8716 var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8718 throw "Element.alignTo with an invalid alignment " + p;
8720 p1 = m[1]; p2 = m[2]; c = !!m[3];
8722 //Subtract the aligned el's internal xy from the target's offset xy
8723 //plus custom offset to get the aligned el's new offset xy
8724 var a1 = this.getAnchorXY(p1, true);
8725 var a2 = el.getAnchorXY(p2, false);
8726 var x = a2[0] - a1[0] + o[0];
8727 var y = a2[1] - a1[1] + o[1];
8729 //constrain the aligned el to viewport if necessary
8730 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8731 // 5px of margin for ie
8732 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8734 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8735 //perpendicular to the vp border, allow the aligned el to slide on that border,
8736 //otherwise swap the aligned el to the opposite border of the target.
8737 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8738 var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8739 var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t") );
8740 var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8743 var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8744 var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8746 if((x+w) > dw + scrollX){
8747 x = swapX ? r.left-w : dw+scrollX-w;
8750 x = swapX ? r.right : scrollX;
8752 if((y+h) > dh + scrollY){
8753 y = swapY ? r.top-h : dh+scrollY-h;
8756 y = swapY ? r.bottom : scrollY;
8763 getConstrainToXY : function(){
8764 var os = {top:0, left:0, bottom:0, right: 0};
8766 return function(el, local, offsets, proposedXY){
8768 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8770 var vw, vh, vx = 0, vy = 0;
8771 if(el.dom == document.body || el.dom == document){
8772 vw = Roo.lib.Dom.getViewWidth();
8773 vh = Roo.lib.Dom.getViewHeight();
8775 vw = el.dom.clientWidth;
8776 vh = el.dom.clientHeight;
8778 var vxy = el.getXY();
8784 var s = el.getScroll();
8786 vx += offsets.left + s.left;
8787 vy += offsets.top + s.top;
8789 vw -= offsets.right;
8790 vh -= offsets.bottom;
8795 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8796 var x = xy[0], y = xy[1];
8797 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8799 // only move it if it needs it
8802 // first validate right/bottom
8811 // then make sure top/left isn't negative
8820 return moved ? [x, y] : false;
8825 adjustForConstraints : function(xy, parent, offsets){
8826 return this.getConstrainToXY(parent || document, false, offsets, xy) || xy;
8830 * Aligns this element with another element relative to the specified anchor points. If the other element is the
8831 * document it aligns it to the viewport.
8832 * The position parameter is optional, and can be specified in any one of the following formats:
8834 * <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8835 * <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8836 * The element being aligned will position its top-left corner (tl) to that point. <i>This method has been
8837 * deprecated in favor of the newer two anchor syntax below</i>.</li>
8838 * <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
8839 * element's anchor point, and the second value is used as the target's anchor point.</li>
8841 * In addition to the anchor points, the position parameter also supports the "?" character. If "?" is passed at the end of
8842 * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8843 * the viewport if necessary. Note that the element being aligned might be swapped to align to a different position than
8844 * that specified in order to enforce the viewport constraints.
8845 * Following are all of the supported anchor positions:
8848 ----- -----------------------------
8849 tl The top left corner (default)
8850 t The center of the top edge
8851 tr The top right corner
8852 l The center of the left edge
8853 c In the center of the element
8854 r The center of the right edge
8855 bl The bottom left corner
8856 b The center of the bottom edge
8857 br The bottom right corner
8861 // align el to other-el using the default positioning ("tl-bl", non-constrained)
8862 el.alignTo("other-el");
8864 // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8865 el.alignTo("other-el", "tr?");
8867 // align the bottom right corner of el with the center left edge of other-el
8868 el.alignTo("other-el", "br-l?");
8870 // align the center of el with the bottom left corner of other-el and
8871 // adjust the x position by -6 pixels (and the y position by 0)
8872 el.alignTo("other-el", "c-bl", [-6, 0]);
8874 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8875 * @param {String} position The position to align to.
8876 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8877 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8878 * @return {Roo.Element} this
8880 alignTo : function(element, position, offsets, animate){
8881 var xy = this.getAlignToXY(element, position, offsets);
8882 this.setXY(xy, this.preanim(arguments, 3));
8887 * Anchors an element to another element and realigns it when the window is resized.
8888 * @param {String/HTMLElement/Roo.Element} element The element to align to.
8889 * @param {String} position The position to align to.
8890 * @param {Array} offsets (optional) Offset the positioning by [x, y]
8891 * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8892 * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8893 * is a number, it is used as the buffer delay (defaults to 50ms).
8894 * @param {Function} callback The function to call after the animation finishes
8895 * @return {Roo.Element} this
8897 anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8898 var action = function(){
8899 this.alignTo(el, alignment, offsets, animate);
8900 Roo.callback(callback, this);
8902 Roo.EventManager.onWindowResize(action, this);
8903 var tm = typeof monitorScroll;
8904 if(tm != 'undefined'){
8905 Roo.EventManager.on(window, 'scroll', action, this,
8906 {buffer: tm == 'number' ? monitorScroll : 50});
8908 action.call(this); // align immediately
8912 * Clears any opacity settings from this element. Required in some cases for IE.
8913 * @return {Roo.Element} this
8915 clearOpacity : function(){
8916 if (window.ActiveXObject) {
8917 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8918 this.dom.style.filter = "";
8921 this.dom.style.opacity = "";
8922 this.dom.style["-moz-opacity"] = "";
8923 this.dom.style["-khtml-opacity"] = "";
8929 * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8930 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8931 * @return {Roo.Element} this
8933 hide : function(animate){
8934 this.setVisible(false, this.preanim(arguments, 0));
8939 * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8940 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8941 * @return {Roo.Element} this
8943 show : function(animate){
8944 this.setVisible(true, this.preanim(arguments, 0));
8949 * @private Test if size has a unit, otherwise appends the default
8951 addUnits : function(size){
8952 return Roo.Element.addUnits(size, this.defaultUnit);
8956 * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8957 * @return {Roo.Element} this
8959 beginMeasure : function(){
8961 if(el.offsetWidth || el.offsetHeight){
8962 return this; // offsets work already
8965 var p = this.dom, b = document.body; // start with this element
8966 while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8967 var pe = Roo.get(p);
8968 if(pe.getStyle('display') == 'none'){
8969 changed.push({el: p, visibility: pe.getStyle("visibility")});
8970 p.style.visibility = "hidden";
8971 p.style.display = "block";
8975 this._measureChanged = changed;
8981 * Restores displays to before beginMeasure was called
8982 * @return {Roo.Element} this
8984 endMeasure : function(){
8985 var changed = this._measureChanged;
8987 for(var i = 0, len = changed.length; i < len; i++) {
8989 r.el.style.visibility = r.visibility;
8990 r.el.style.display = "none";
8992 this._measureChanged = null;
8998 * Update the innerHTML of this element, optionally searching for and processing scripts
8999 * @param {String} html The new HTML
9000 * @param {Boolean} loadScripts (optional) true to look for and process scripts
9001 * @param {Function} callback For async script loading you can be noticed when the update completes
9002 * @return {Roo.Element} this
9004 update : function(html, loadScripts, callback){
9005 if(typeof html == "undefined"){
9008 if(loadScripts !== true){
9009 this.dom.innerHTML = html;
9010 if(typeof callback == "function"){
9018 html += '<span id="' + id + '"></span>';
9020 E.onAvailable(id, function(){
9021 var hd = document.getElementsByTagName("head")[0];
9022 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
9023 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
9024 var typeRe = /\stype=([\'\"])(.*?)\1/i;
9027 while(match = re.exec(html)){
9028 var attrs = match[1];
9029 var srcMatch = attrs ? attrs.match(srcRe) : false;
9030 if(srcMatch && srcMatch[2]){
9031 var s = document.createElement("script");
9032 s.src = srcMatch[2];
9033 var typeMatch = attrs.match(typeRe);
9034 if(typeMatch && typeMatch[2]){
9035 s.type = typeMatch[2];
9038 }else if(match[2] && match[2].length > 0){
9039 if(window.execScript) {
9040 window.execScript(match[2]);
9048 window.eval(match[2]);
9052 var el = document.getElementById(id);
9053 if(el){el.parentNode.removeChild(el);}
9054 if(typeof callback == "function"){
9058 dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
9063 * Direct access to the UpdateManager update() method (takes the same parameters).
9064 * @param {String/Function} url The url for this request or a function to call to get the url
9065 * @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}
9066 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9067 * @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.
9068 * @return {Roo.Element} this
9071 var um = this.getUpdateManager();
9072 um.update.apply(um, arguments);
9077 * Gets this element's UpdateManager
9078 * @return {Roo.UpdateManager} The UpdateManager
9080 getUpdateManager : function(){
9081 if(!this.updateManager){
9082 this.updateManager = new Roo.UpdateManager(this);
9084 return this.updateManager;
9088 * Disables text selection for this element (normalized across browsers)
9089 * @return {Roo.Element} this
9091 unselectable : function(){
9092 this.dom.unselectable = "on";
9093 this.swallowEvent("selectstart", true);
9094 this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
9095 this.addClass("x-unselectable");
9100 * Calculates the x, y to center this element on the screen
9101 * @return {Array} The x, y values [x, y]
9103 getCenterXY : function(){
9104 return this.getAlignToXY(document, 'c-c');
9108 * Centers the Element in either the viewport, or another Element.
9109 * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
9111 center : function(centerIn){
9112 this.alignTo(centerIn || document, 'c-c');
9117 * Tests various css rules/browsers to determine if this element uses a border box
9120 isBorderBox : function(){
9121 return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
9125 * Return a box {x, y, width, height} that can be used to set another elements
9126 * size/location to match this element.
9127 * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
9128 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
9129 * @return {Object} box An object in the format {x, y, width, height}
9131 getBox : function(contentBox, local){
9136 var left = parseInt(this.getStyle("left"), 10) || 0;
9137 var top = parseInt(this.getStyle("top"), 10) || 0;
9140 var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
9142 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
9144 var l = this.getBorderWidth("l")+this.getPadding("l");
9145 var r = this.getBorderWidth("r")+this.getPadding("r");
9146 var t = this.getBorderWidth("t")+this.getPadding("t");
9147 var b = this.getBorderWidth("b")+this.getPadding("b");
9148 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)};
9150 bx.right = bx.x + bx.width;
9151 bx.bottom = bx.y + bx.height;
9156 * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
9157 for more information about the sides.
9158 * @param {String} sides
9161 getFrameWidth : function(sides, onlyContentBox){
9162 return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
9166 * 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.
9167 * @param {Object} box The box to fill {x, y, width, height}
9168 * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
9169 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9170 * @return {Roo.Element} this
9172 setBox : function(box, adjust, animate){
9173 var w = box.width, h = box.height;
9174 if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
9175 w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
9176 h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
9178 this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
9183 * Forces the browser to repaint this element
9184 * @return {Roo.Element} this
9186 repaint : function(){
9188 this.addClass("x-repaint");
9189 setTimeout(function(){
9190 Roo.get(dom).removeClass("x-repaint");
9196 * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
9197 * then it returns the calculated width of the sides (see getPadding)
9198 * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
9199 * @return {Object/Number}
9201 getMargins : function(side){
9204 top: parseInt(this.getStyle("margin-top"), 10) || 0,
9205 left: parseInt(this.getStyle("margin-left"), 10) || 0,
9206 bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
9207 right: parseInt(this.getStyle("margin-right"), 10) || 0
9210 return this.addStyles(side, El.margins);
9215 addStyles : function(sides, styles){
9217 for(var i = 0, len = sides.length; i < len; i++){
9218 v = this.getStyle(styles[sides.charAt(i)]);
9220 w = parseInt(v, 10);
9228 * Creates a proxy element of this element
9229 * @param {String/Object} config The class name of the proxy element or a DomHelper config object
9230 * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
9231 * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
9232 * @return {Roo.Element} The new proxy element
9234 createProxy : function(config, renderTo, matchBox){
9236 renderTo = Roo.getDom(renderTo);
9238 renderTo = document.body;
9240 config = typeof config == "object" ?
9241 config : {tag : "div", cls: config};
9242 var proxy = Roo.DomHelper.append(renderTo, config, true);
9244 proxy.setBox(this.getBox());
9250 * Puts a mask over this element to disable user interaction. Requires core.css.
9251 * This method can only be applied to elements which accept child nodes.
9252 * @param {String} msg (optional) A message to display in the mask
9253 * @param {String} msgCls (optional) A css class to apply to the msg element
9254 * @return {Element} The mask element
9256 mask : function(msg, msgCls)
9258 if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9259 this.setStyle("position", "relative");
9262 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9265 this.addClass("x-masked");
9266 this._mask.setDisplayed(true);
9271 while (dom && dom.style) {
9272 if (!isNaN(parseInt(dom.style.zIndex))) {
9273 z = Math.max(z, parseInt(dom.style.zIndex));
9275 dom = dom.parentNode;
9277 // if we are masking the body - then it hides everything..
9278 if (this.dom == document.body) {
9280 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9281 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9284 if(typeof msg == 'string'){
9286 this._maskMsg = Roo.DomHelper.append(this.dom, {
9287 cls: "roo-el-mask-msg",
9291 cls: 'fa fa-spinner fa-spin'
9299 var mm = this._maskMsg;
9300 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9301 if (mm.dom.lastChild) { // weird IE issue?
9302 mm.dom.lastChild.innerHTML = msg;
9304 mm.setDisplayed(true);
9306 mm.setStyle('z-index', z + 102);
9308 if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9309 this._mask.setHeight(this.getHeight());
9311 this._mask.setStyle('z-index', z + 100);
9317 * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9318 * it is cached for reuse.
9320 unmask : function(removeEl){
9322 if(removeEl === true){
9323 this._mask.remove();
9326 this._maskMsg.remove();
9327 delete this._maskMsg;
9330 this._mask.setDisplayed(false);
9332 this._maskMsg.setDisplayed(false);
9336 this.removeClass("x-masked");
9340 * Returns true if this element is masked
9343 isMasked : function(){
9344 return this._mask && this._mask.isVisible();
9348 * Creates an iframe shim for this element to keep selects and other windowed objects from
9350 * @return {Roo.Element} The new shim element
9352 createShim : function(){
9353 var el = document.createElement('iframe');
9354 el.frameBorder = 'no';
9355 el.className = 'roo-shim';
9356 if(Roo.isIE && Roo.isSecure){
9357 el.src = Roo.SSL_SECURE_URL;
9359 var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9360 shim.autoBoxAdjust = false;
9365 * Removes this element from the DOM and deletes it from the cache
9367 remove : function(){
9368 if(this.dom.parentNode){
9369 this.dom.parentNode.removeChild(this.dom);
9371 delete El.cache[this.dom.id];
9375 * Sets up event handlers to add and remove a css class when the mouse is over this element
9376 * @param {String} className
9377 * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9378 * mouseout events for children elements
9379 * @return {Roo.Element} this
9381 addClassOnOver : function(className, preventFlicker){
9382 this.on("mouseover", function(){
9383 Roo.fly(this, '_internal').addClass(className);
9385 var removeFn = function(e){
9386 if(preventFlicker !== true || !e.within(this, true)){
9387 Roo.fly(this, '_internal').removeClass(className);
9390 this.on("mouseout", removeFn, this.dom);
9395 * Sets up event handlers to add and remove a css class when this element has the focus
9396 * @param {String} className
9397 * @return {Roo.Element} this
9399 addClassOnFocus : function(className){
9400 this.on("focus", function(){
9401 Roo.fly(this, '_internal').addClass(className);
9403 this.on("blur", function(){
9404 Roo.fly(this, '_internal').removeClass(className);
9409 * 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)
9410 * @param {String} className
9411 * @return {Roo.Element} this
9413 addClassOnClick : function(className){
9415 this.on("mousedown", function(){
9416 Roo.fly(dom, '_internal').addClass(className);
9417 var d = Roo.get(document);
9418 var fn = function(){
9419 Roo.fly(dom, '_internal').removeClass(className);
9420 d.removeListener("mouseup", fn);
9422 d.on("mouseup", fn);
9428 * Stops the specified event from bubbling and optionally prevents the default action
9429 * @param {String} eventName
9430 * @param {Boolean} preventDefault (optional) true to prevent the default action too
9431 * @return {Roo.Element} this
9433 swallowEvent : function(eventName, preventDefault){
9434 var fn = function(e){
9435 e.stopPropagation();
9440 if(eventName instanceof Array){
9441 for(var i = 0, len = eventName.length; i < len; i++){
9442 this.on(eventName[i], fn);
9446 this.on(eventName, fn);
9453 fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9456 * Sizes this element to its parent element's dimensions performing
9457 * neccessary box adjustments.
9458 * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9459 * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9460 * @return {Roo.Element} this
9462 fitToParent : function(monitorResize, targetParent) {
9463 Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9464 this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9465 if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9468 var p = Roo.get(targetParent || this.dom.parentNode);
9469 this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9470 if (monitorResize === true) {
9471 this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9472 Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9478 * Gets the next sibling, skipping text nodes
9479 * @return {HTMLElement} The next sibling or null
9481 getNextSibling : function(){
9482 var n = this.dom.nextSibling;
9483 while(n && n.nodeType != 1){
9490 * Gets the previous sibling, skipping text nodes
9491 * @return {HTMLElement} The previous sibling or null
9493 getPrevSibling : function(){
9494 var n = this.dom.previousSibling;
9495 while(n && n.nodeType != 1){
9496 n = n.previousSibling;
9503 * Appends the passed element(s) to this element
9504 * @param {String/HTMLElement/Array/Element/CompositeElement} el
9505 * @return {Roo.Element} this
9507 appendChild: function(el){
9514 * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9515 * @param {Object} config DomHelper element config object. If no tag is specified (e.g., {tag:'input'}) then a div will be
9516 * automatically generated with the specified attributes.
9517 * @param {HTMLElement} insertBefore (optional) a child element of this element
9518 * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9519 * @return {Roo.Element} The new child element
9521 createChild: function(config, insertBefore, returnDom){
9522 config = config || {tag:'div'};
9524 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9526 return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config, returnDom !== true);
9530 * Appends this element to the passed element
9531 * @param {String/HTMLElement/Element} el The new parent element
9532 * @return {Roo.Element} this
9534 appendTo: function(el){
9535 el = Roo.getDom(el);
9536 el.appendChild(this.dom);
9541 * Inserts this element before the passed element in the DOM
9542 * @param {String/HTMLElement/Element} el The element to insert before
9543 * @return {Roo.Element} this
9545 insertBefore: function(el){
9546 el = Roo.getDom(el);
9547 el.parentNode.insertBefore(this.dom, el);
9552 * Inserts this element after the passed element in the DOM
9553 * @param {String/HTMLElement/Element} el The element to insert after
9554 * @return {Roo.Element} this
9556 insertAfter: function(el){
9557 el = Roo.getDom(el);
9558 el.parentNode.insertBefore(this.dom, el.nextSibling);
9563 * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9564 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9565 * @return {Roo.Element} The new child
9567 insertFirst: function(el, returnDom){
9569 if(typeof el == 'object' && !el.nodeType){ // dh config
9570 return this.createChild(el, this.dom.firstChild, returnDom);
9572 el = Roo.getDom(el);
9573 this.dom.insertBefore(el, this.dom.firstChild);
9574 return !returnDom ? Roo.get(el) : el;
9579 * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9580 * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9581 * @param {String} where (optional) 'before' or 'after' defaults to before
9582 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9583 * @return {Roo.Element} the inserted Element
9585 insertSibling: function(el, where, returnDom){
9586 where = where ? where.toLowerCase() : 'before';
9588 var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9590 if(typeof el == 'object' && !el.nodeType){ // dh config
9591 if(where == 'after' && !this.dom.nextSibling){
9592 rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9594 rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9598 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9599 where == 'before' ? this.dom : this.dom.nextSibling);
9608 * Creates and wraps this element with another element
9609 * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9610 * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9611 * @return {HTMLElement/Element} The newly created wrapper element
9613 wrap: function(config, returnDom){
9615 config = {tag: "div"};
9617 var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9618 newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9623 * Replaces the passed element with this element
9624 * @param {String/HTMLElement/Element} el The element to replace
9625 * @return {Roo.Element} this
9627 replace: function(el){
9629 this.insertBefore(el);
9635 * Inserts an html fragment into this element
9636 * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9637 * @param {String} html The HTML fragment
9638 * @param {Boolean} returnEl True to return an Roo.Element
9639 * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9641 insertHtml : function(where, html, returnEl){
9642 var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9643 return returnEl ? Roo.get(el) : el;
9647 * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9648 * @param {Object} o The object with the attributes
9649 * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9650 * @return {Roo.Element} this
9652 set : function(o, useSet){
9654 useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9656 if(attr == "style" || typeof o[attr] == "function") { continue; }
9658 el.className = o["cls"];
9661 el.setAttribute(attr, o[attr]);
9668 Roo.DomHelper.applyStyles(el, o.style);
9674 * Convenience method for constructing a KeyMap
9675 * @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:
9676 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9677 * @param {Function} fn The function to call
9678 * @param {Object} scope (optional) The scope of the function
9679 * @return {Roo.KeyMap} The KeyMap created
9681 addKeyListener : function(key, fn, scope){
9683 if(typeof key != "object" || key instanceof Array){
9699 return new Roo.KeyMap(this, config);
9703 * Creates a KeyMap for this element
9704 * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9705 * @return {Roo.KeyMap} The KeyMap created
9707 addKeyMap : function(config){
9708 return new Roo.KeyMap(this, config);
9712 * Returns true if this element is scrollable.
9715 isScrollable : function(){
9717 return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9721 * 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().
9722 * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9723 * @param {Number} value The new scroll value
9724 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9725 * @return {Element} this
9728 scrollTo : function(side, value, animate){
9729 var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9731 this.dom[prop] = value;
9733 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9734 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9740 * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9741 * within this element's scrollable range.
9742 * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9743 * @param {Number} distance How far to scroll the element in pixels
9744 * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9745 * @return {Boolean} Returns true if a scroll was triggered or false if the element
9746 * was scrolled as far as it could go.
9748 scroll : function(direction, distance, animate){
9749 if(!this.isScrollable()){
9753 var l = el.scrollLeft, t = el.scrollTop;
9754 var w = el.scrollWidth, h = el.scrollHeight;
9755 var cw = el.clientWidth, ch = el.clientHeight;
9756 direction = direction.toLowerCase();
9757 var scrolled = false;
9758 var a = this.preanim(arguments, 2);
9763 var v = Math.min(l + distance, w-cw);
9764 this.scrollTo("left", v, a);
9771 var v = Math.max(l - distance, 0);
9772 this.scrollTo("left", v, a);
9780 var v = Math.max(t - distance, 0);
9781 this.scrollTo("top", v, a);
9789 var v = Math.min(t + distance, h-ch);
9790 this.scrollTo("top", v, a);
9799 * Translates the passed page coordinates into left/top css values for this element
9800 * @param {Number/Array} x The page x or an array containing [x, y]
9801 * @param {Number} y The page y
9802 * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9804 translatePoints : function(x, y){
9805 if(typeof x == 'object' || x instanceof Array){
9808 var p = this.getStyle('position');
9809 var o = this.getXY();
9811 var l = parseInt(this.getStyle('left'), 10);
9812 var t = parseInt(this.getStyle('top'), 10);
9815 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9818 t = (p == "relative") ? 0 : this.dom.offsetTop;
9821 return {left: (x - o[0] + l), top: (y - o[1] + t)};
9825 * Returns the current scroll position of the element.
9826 * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9828 getScroll : function(){
9829 var d = this.dom, doc = document;
9830 if(d == doc || d == doc.body){
9831 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9832 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9833 return {left: l, top: t};
9835 return {left: d.scrollLeft, top: d.scrollTop};
9840 * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9841 * are convert to standard 6 digit hex color.
9842 * @param {String} attr The css attribute
9843 * @param {String} defaultValue The default value to use when a valid color isn't found
9844 * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9847 getColor : function(attr, defaultValue, prefix){
9848 var v = this.getStyle(attr);
9849 if(!v || v == "transparent" || v == "inherit") {
9850 return defaultValue;
9852 var color = typeof prefix == "undefined" ? "#" : prefix;
9853 if(v.substr(0, 4) == "rgb("){
9854 var rvs = v.slice(4, v.length -1).split(",");
9855 for(var i = 0; i < 3; i++){
9856 var h = parseInt(rvs[i]).toString(16);
9863 if(v.substr(0, 1) == "#"){
9865 for(var i = 1; i < 4; i++){
9866 var c = v.charAt(i);
9869 }else if(v.length == 7){
9870 color += v.substr(1);
9874 return(color.length > 5 ? color.toLowerCase() : defaultValue);
9878 * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9879 * gradient background, rounded corners and a 4-way shadow.
9880 * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9881 * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9882 * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9883 * @return {Roo.Element} this
9885 boxWrap : function(cls){
9886 cls = cls || 'x-box';
9887 var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9888 el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9893 * Returns the value of a namespaced attribute from the element's underlying DOM node.
9894 * @param {String} namespace The namespace in which to look for the attribute
9895 * @param {String} name The attribute name
9896 * @return {String} The attribute value
9898 getAttributeNS : Roo.isIE ? function(ns, name){
9900 var type = typeof d[ns+":"+name];
9901 if(type != 'undefined' && type != 'unknown'){
9902 return d[ns+":"+name];
9905 } : function(ns, name){
9907 return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9912 * Sets or Returns the value the dom attribute value
9913 * @param {String|Object} name The attribute name (or object to set multiple attributes)
9914 * @param {String} value (optional) The value to set the attribute to
9915 * @return {String} The attribute value
9917 attr : function(name){
9918 if (arguments.length > 1) {
9919 this.dom.setAttribute(name, arguments[1]);
9920 return arguments[1];
9922 if (typeof(name) == 'object') {
9923 for(var i in name) {
9924 this.attr(i, name[i]);
9930 if (!this.dom.hasAttribute(name)) {
9933 return this.dom.getAttribute(name);
9940 var ep = El.prototype;
9943 * Appends an event handler (Shorthand for addListener)
9944 * @param {String} eventName The type of event to append
9945 * @param {Function} fn The method the event invokes
9946 * @param {Object} scope (optional) The scope (this object) of the fn
9947 * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options
9950 ep.on = ep.addListener;
9952 ep.mon = ep.addListener;
9955 * Removes an event handler from this element (shorthand for removeListener)
9956 * @param {String} eventName the type of event to remove
9957 * @param {Function} fn the method the event invokes
9958 * @return {Roo.Element} this
9961 ep.un = ep.removeListener;
9964 * true to automatically adjust width and height settings for box-model issues (default to true)
9966 ep.autoBoxAdjust = true;
9969 El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9972 El.addUnits = function(v, defaultUnit){
9973 if(v === "" || v == "auto"){
9976 if(v === undefined){
9979 if(typeof v == "number" || !El.unitPattern.test(v)){
9980 return v + (defaultUnit || 'px');
9985 // special markup used throughout Roo when box wrapping elements
9986 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>';
9988 * Visibility mode constant - Use visibility to hide element
9994 * Visibility mode constant - Use display to hide element
10000 El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
10001 El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
10002 El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
10014 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10015 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10016 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10017 * @return {Element} The Element object
10020 El.get = function(el){
10022 if(!el){ return null; }
10023 if(typeof el == "string"){ // element id
10024 if(!(elm = document.getElementById(el))){
10027 if(ex = El.cache[el]){
10030 ex = El.cache[el] = new El(elm);
10033 }else if(el.tagName){ // dom element
10037 if(ex = El.cache[id]){
10040 ex = El.cache[id] = new El(el);
10043 }else if(el instanceof El){
10045 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
10046 // catch case where it hasn't been appended
10047 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
10050 }else if(el.isComposite){
10052 }else if(el instanceof Array){
10053 return El.select(el);
10054 }else if(el == document){
10055 // create a bogus element object representing the document object
10057 var f = function(){};
10058 f.prototype = El.prototype;
10060 docEl.dom = document;
10068 El.uncache = function(el){
10069 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
10071 delete El.cache[a[i].id || a[i]];
10077 // Garbage collection - uncache elements/purge listeners on orphaned elements
10078 // so we don't hold a reference and cause the browser to retain them
10079 El.garbageCollect = function(){
10080 if(!Roo.enableGarbageCollector){
10081 clearInterval(El.collectorThread);
10084 for(var eid in El.cache){
10085 var el = El.cache[eid], d = el.dom;
10086 // -------------------------------------------------------
10087 // Determining what is garbage:
10088 // -------------------------------------------------------
10090 // dom node is null, definitely garbage
10091 // -------------------------------------------------------
10093 // no parentNode == direct orphan, definitely garbage
10094 // -------------------------------------------------------
10095 // !d.offsetParent && !document.getElementById(eid)
10096 // display none elements have no offsetParent so we will
10097 // also try to look it up by it's id. However, check
10098 // offsetParent first so we don't do unneeded lookups.
10099 // This enables collection of elements that are not orphans
10100 // directly, but somewhere up the line they have an orphan
10102 // -------------------------------------------------------
10103 if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
10104 delete El.cache[eid];
10105 if(d && Roo.enableListenerCollection){
10111 El.collectorThreadId = setInterval(El.garbageCollect, 30000);
10115 El.Flyweight = function(dom){
10118 El.Flyweight.prototype = El.prototype;
10120 El._flyweights = {};
10122 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10123 * the dom node can be overwritten by other code.
10124 * @param {String/HTMLElement} el The dom node or id
10125 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10126 * prevent conflicts (e.g. internally Roo uses "_internal")
10128 * @return {Element} The shared Element object
10130 El.fly = function(el, named){
10131 named = named || '_global';
10132 el = Roo.getDom(el);
10136 if(!El._flyweights[named]){
10137 El._flyweights[named] = new El.Flyweight();
10139 El._flyweights[named].dom = el;
10140 return El._flyweights[named];
10144 * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
10145 * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
10146 * Shorthand of {@link Roo.Element#get}
10147 * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
10148 * @return {Element} The Element object
10154 * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
10155 * the dom node can be overwritten by other code.
10156 * Shorthand of {@link Roo.Element#fly}
10157 * @param {String/HTMLElement} el The dom node or id
10158 * @param {String} named (optional) Allows for creation of named reusable flyweights to
10159 * prevent conflicts (e.g. internally Roo uses "_internal")
10161 * @return {Element} The shared Element object
10167 // speedy lookup for elements never to box adjust
10168 var noBoxAdjust = Roo.isStrict ? {
10171 input:1, select:1, textarea:1
10173 if(Roo.isIE || Roo.isGecko){
10174 noBoxAdjust['button'] = 1;
10178 Roo.EventManager.on(window, 'unload', function(){
10180 delete El._flyweights;
10188 Roo.Element.selectorFunction = Roo.DomQuery.select;
10191 Roo.Element.select = function(selector, unique, root){
10193 if(typeof selector == "string"){
10194 els = Roo.Element.selectorFunction(selector, root);
10195 }else if(selector.length !== undefined){
10198 throw "Invalid selector";
10200 if(unique === true){
10201 return new Roo.CompositeElement(els);
10203 return new Roo.CompositeElementLite(els);
10207 * Selects elements based on the passed CSS selector to enable working on them as 1.
10208 * @param {String/Array} selector The CSS selector or an array of elements
10209 * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
10210 * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
10211 * @return {CompositeElementLite/CompositeElement}
10215 Roo.select = Roo.Element.select;
10232 * Ext JS Library 1.1.1
10233 * Copyright(c) 2006-2007, Ext JS, LLC.
10235 * Originally Released Under LGPL - original licence link has changed is not relivant.
10238 * <script type="text/javascript">
10243 //Notifies Element that fx methods are available
10244 Roo.enableFx = true;
10248 * <p>A class to provide basic animation and visual effects support. <b>Note:</b> This class is automatically applied
10249 * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
10250 * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the
10251 * Element effects to work.</p><br/>
10253 * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10254 * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10255 * method chain. The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10256 * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately. For this reason,
10257 * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10258 * expected results and should be done with care.</p><br/>
10260 * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10261 * that will serve as either the start or end point of the animation. Following are all of the supported anchor positions:</p>
10264 ----- -----------------------------
10265 tl The top left corner
10266 t The center of the top edge
10267 tr The top right corner
10268 l The center of the left edge
10269 r The center of the right edge
10270 bl The bottom left corner
10271 b The center of the bottom edge
10272 br The bottom right corner
10274 * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10275 * below are common options that can be passed to any Fx method.</b>
10276 * @cfg {Function} callback A function called when the effect is finished
10277 * @cfg {Object} scope The scope of the effect function
10278 * @cfg {String} easing A valid Easing value for the effect
10279 * @cfg {String} afterCls A css class to apply after the effect
10280 * @cfg {Number} duration The length of time (in seconds) that the effect should last
10281 * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10282 * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to
10283 * effects that end with the element being visually hidden, ignored otherwise)
10284 * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10285 * a function which returns such a specification that will be applied to the Element after the effect finishes
10286 * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10287 * @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
10288 * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10292 * Slides the element into view. An anchor point can be optionally passed to set the point of
10293 * origin for the slide effect. This function automatically handles wrapping the element with
10294 * a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10297 // default: slide the element in from the top
10300 // custom: slide the element in from the right with a 2-second duration
10301 el.slideIn('r', { duration: 2 });
10303 // common config options shown with default values
10309 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10310 * @param {Object} options (optional) Object literal with any of the Fx config options
10311 * @return {Roo.Element} The Element
10313 slideIn : function(anchor, o){
10314 var el = this.getFxEl();
10317 el.queueFx(o, function(){
10319 anchor = anchor || "t";
10321 // fix display to visibility
10324 // restore values after effect
10325 var r = this.getFxRestore();
10326 var b = this.getBox();
10327 // fixed size for slide
10331 var wrap = this.fxWrap(r.pos, o, "hidden");
10333 var st = this.dom.style;
10334 st.visibility = "visible";
10335 st.position = "absolute";
10337 // clear out temp styles after slide and unwrap
10338 var after = function(){
10339 el.fxUnwrap(wrap, r.pos, o);
10340 st.width = r.width;
10341 st.height = r.height;
10344 // time to calc the positions
10345 var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10347 switch(anchor.toLowerCase()){
10349 wrap.setSize(b.width, 0);
10350 st.left = st.bottom = "0";
10354 wrap.setSize(0, b.height);
10355 st.right = st.top = "0";
10359 wrap.setSize(0, b.height);
10360 wrap.setX(b.right);
10361 st.left = st.top = "0";
10362 a = {width: bw, points: pt};
10365 wrap.setSize(b.width, 0);
10366 wrap.setY(b.bottom);
10367 st.left = st.top = "0";
10368 a = {height: bh, points: pt};
10371 wrap.setSize(0, 0);
10372 st.right = st.bottom = "0";
10373 a = {width: bw, height: bh};
10376 wrap.setSize(0, 0);
10377 wrap.setY(b.y+b.height);
10378 st.right = st.top = "0";
10379 a = {width: bw, height: bh, points: pt};
10382 wrap.setSize(0, 0);
10383 wrap.setXY([b.right, b.bottom]);
10384 st.left = st.top = "0";
10385 a = {width: bw, height: bh, points: pt};
10388 wrap.setSize(0, 0);
10389 wrap.setX(b.x+b.width);
10390 st.left = st.bottom = "0";
10391 a = {width: bw, height: bh, points: pt};
10394 this.dom.style.visibility = "visible";
10397 arguments.callee.anim = wrap.fxanim(a,
10407 * Slides the element out of view. An anchor point can be optionally passed to set the end point
10408 * for the slide effect. When the effect is completed, the element will be hidden (visibility =
10409 * 'hidden') but block elements will still take up space in the document. The element must be removed
10410 * from the DOM using the 'remove' config option if desired. This function automatically handles
10411 * wrapping the element with a fixed-size container if needed. See the Fx class overview for valid anchor point options.
10414 // default: slide the element out to the top
10417 // custom: slide the element out to the right with a 2-second duration
10418 el.slideOut('r', { duration: 2 });
10420 // common config options shown with default values
10428 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10429 * @param {Object} options (optional) Object literal with any of the Fx config options
10430 * @return {Roo.Element} The Element
10432 slideOut : function(anchor, o){
10433 var el = this.getFxEl();
10436 el.queueFx(o, function(){
10438 anchor = anchor || "t";
10440 // restore values after effect
10441 var r = this.getFxRestore();
10443 var b = this.getBox();
10444 // fixed size for slide
10448 var wrap = this.fxWrap(r.pos, o, "visible");
10450 var st = this.dom.style;
10451 st.visibility = "visible";
10452 st.position = "absolute";
10456 var after = function(){
10458 el.setDisplayed(false);
10463 el.fxUnwrap(wrap, r.pos, o);
10465 st.width = r.width;
10466 st.height = r.height;
10471 var a, zero = {to: 0};
10472 switch(anchor.toLowerCase()){
10474 st.left = st.bottom = "0";
10475 a = {height: zero};
10478 st.right = st.top = "0";
10482 st.left = st.top = "0";
10483 a = {width: zero, points: {to:[b.right, b.y]}};
10486 st.left = st.top = "0";
10487 a = {height: zero, points: {to:[b.x, b.bottom]}};
10490 st.right = st.bottom = "0";
10491 a = {width: zero, height: zero};
10494 st.right = st.top = "0";
10495 a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10498 st.left = st.top = "0";
10499 a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10502 st.left = st.bottom = "0";
10503 a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10507 arguments.callee.anim = wrap.fxanim(a,
10517 * Fades the element out while slowly expanding it in all directions. When the effect is completed, the
10518 * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document.
10519 * The element must be removed from the DOM using the 'remove' config option if desired.
10525 // common config options shown with default values
10533 * @param {Object} options (optional) Object literal with any of the Fx config options
10534 * @return {Roo.Element} The Element
10536 puff : function(o){
10537 var el = this.getFxEl();
10540 el.queueFx(o, function(){
10541 this.clearOpacity();
10544 // restore values after effect
10545 var r = this.getFxRestore();
10546 var st = this.dom.style;
10548 var after = function(){
10550 el.setDisplayed(false);
10557 el.setPositioning(r.pos);
10558 st.width = r.width;
10559 st.height = r.height;
10564 var width = this.getWidth();
10565 var height = this.getHeight();
10567 arguments.callee.anim = this.fxanim({
10568 width : {to: this.adjustWidth(width * 2)},
10569 height : {to: this.adjustHeight(height * 2)},
10570 points : {by: [-(width * .5), -(height * .5)]},
10572 fontSize: {to:200, unit: "%"}
10583 * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10584 * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still
10585 * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10591 // all config options shown with default values
10599 * @param {Object} options (optional) Object literal with any of the Fx config options
10600 * @return {Roo.Element} The Element
10602 switchOff : function(o){
10603 var el = this.getFxEl();
10606 el.queueFx(o, function(){
10607 this.clearOpacity();
10610 // restore values after effect
10611 var r = this.getFxRestore();
10612 var st = this.dom.style;
10614 var after = function(){
10616 el.setDisplayed(false);
10622 el.setPositioning(r.pos);
10623 st.width = r.width;
10624 st.height = r.height;
10629 this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10630 this.clearOpacity();
10634 points:{by:[0, this.getHeight() * .5]}
10635 }, o, 'motion', 0.3, 'easeIn', after);
10636 }).defer(100, this);
10643 * Highlights the Element by setting a color (applies to the background-color by default, but can be
10644 * changed using the "attr" config option) and then fading back to the original color. If no original
10645 * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10648 // default: highlight background to yellow
10651 // custom: highlight foreground text to blue for 2 seconds
10652 el.highlight("0000ff", { attr: 'color', duration: 2 });
10654 // common config options shown with default values
10655 el.highlight("ffff9c", {
10656 attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10657 endColor: (current color) or "ffffff",
10662 * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10663 * @param {Object} options (optional) Object literal with any of the Fx config options
10664 * @return {Roo.Element} The Element
10666 highlight : function(color, o){
10667 var el = this.getFxEl();
10670 el.queueFx(o, function(){
10671 color = color || "ffff9c";
10672 attr = o.attr || "backgroundColor";
10674 this.clearOpacity();
10677 var origColor = this.getColor(attr);
10678 var restoreColor = this.dom.style[attr];
10679 endColor = (o.endColor || origColor) || "ffffff";
10681 var after = function(){
10682 el.dom.style[attr] = restoreColor;
10687 a[attr] = {from: color, to: endColor};
10688 arguments.callee.anim = this.fxanim(a,
10698 * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10701 // default: a single light blue ripple
10704 // custom: 3 red ripples lasting 3 seconds total
10705 el.frame("ff0000", 3, { duration: 3 });
10707 // common config options shown with default values
10708 el.frame("C3DAF9", 1, {
10709 duration: 1 //duration of entire animation (not each individual ripple)
10710 // Note: Easing is not configurable and will be ignored if included
10713 * @param {String} color (optional) The color of the border. Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10714 * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10715 * @param {Object} options (optional) Object literal with any of the Fx config options
10716 * @return {Roo.Element} The Element
10718 frame : function(color, count, o){
10719 var el = this.getFxEl();
10722 el.queueFx(o, function(){
10723 color = color || "#C3DAF9";
10724 if(color.length == 6){
10725 color = "#" + color;
10727 count = count || 1;
10728 duration = o.duration || 1;
10731 var b = this.getBox();
10732 var animFn = function(){
10733 var proxy = this.createProxy({
10736 visbility:"hidden",
10737 position:"absolute",
10738 "z-index":"35000", // yee haw
10739 border:"0px solid " + color
10742 var scale = Roo.isBorderBox ? 2 : 1;
10744 top:{from:b.y, to:b.y - 20},
10745 left:{from:b.x, to:b.x - 20},
10746 borderWidth:{from:0, to:10},
10747 opacity:{from:1, to:0},
10748 height:{from:b.height, to:(b.height + (20*scale))},
10749 width:{from:b.width, to:(b.width + (20*scale))}
10750 }, duration, function(){
10754 animFn.defer((duration/2)*1000, this);
10765 * Creates a pause before any subsequent queued effects begin. If there are
10766 * no effects queued after the pause it will have no effect.
10771 * @param {Number} seconds The length of time to pause (in seconds)
10772 * @return {Roo.Element} The Element
10774 pause : function(seconds){
10775 var el = this.getFxEl();
10778 el.queueFx(o, function(){
10779 setTimeout(function(){
10781 }, seconds * 1000);
10787 * Fade an element in (from transparent to opaque). The ending opacity can be specified
10788 * using the "endOpacity" config option.
10791 // default: fade in from opacity 0 to 100%
10794 // custom: fade in from opacity 0 to 75% over 2 seconds
10795 el.fadeIn({ endOpacity: .75, duration: 2});
10797 // common config options shown with default values
10799 endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10804 * @param {Object} options (optional) Object literal with any of the Fx config options
10805 * @return {Roo.Element} The Element
10807 fadeIn : function(o){
10808 var el = this.getFxEl();
10810 el.queueFx(o, function(){
10811 this.setOpacity(0);
10813 this.dom.style.visibility = 'visible';
10814 var to = o.endOpacity || 1;
10815 arguments.callee.anim = this.fxanim({opacity:{to:to}},
10816 o, null, .5, "easeOut", function(){
10818 this.clearOpacity();
10827 * Fade an element out (from opaque to transparent). The ending opacity can be specified
10828 * using the "endOpacity" config option.
10831 // default: fade out from the element's current opacity to 0
10834 // custom: fade out from the element's current opacity to 25% over 2 seconds
10835 el.fadeOut({ endOpacity: .25, duration: 2});
10837 // common config options shown with default values
10839 endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10846 * @param {Object} options (optional) Object literal with any of the Fx config options
10847 * @return {Roo.Element} The Element
10849 fadeOut : function(o){
10850 var el = this.getFxEl();
10852 el.queueFx(o, function(){
10853 arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10854 o, null, .5, "easeOut", function(){
10855 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10856 this.dom.style.display = "none";
10858 this.dom.style.visibility = "hidden";
10860 this.clearOpacity();
10868 * Animates the transition of an element's dimensions from a starting height/width
10869 * to an ending height/width.
10872 // change height and width to 100x100 pixels
10873 el.scale(100, 100);
10875 // common config options shown with default values. The height and width will default to
10876 // the element's existing values if passed as null.
10879 [element's height], {
10884 * @param {Number} width The new width (pass undefined to keep the original width)
10885 * @param {Number} height The new height (pass undefined to keep the original height)
10886 * @param {Object} options (optional) Object literal with any of the Fx config options
10887 * @return {Roo.Element} The Element
10889 scale : function(w, h, o){
10890 this.shift(Roo.apply({}, o, {
10898 * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10899 * Any of these properties not specified in the config object will not be changed. This effect
10900 * requires that at least one new dimension, position or opacity setting must be passed in on
10901 * the config object in order for the function to have any effect.
10904 // slide the element horizontally to x position 200 while changing the height and opacity
10905 el.shift({ x: 200, height: 50, opacity: .8 });
10907 // common config options shown with default values.
10909 width: [element's width],
10910 height: [element's height],
10911 x: [element's x position],
10912 y: [element's y position],
10913 opacity: [element's opacity],
10918 * @param {Object} options Object literal with any of the Fx config options
10919 * @return {Roo.Element} The Element
10921 shift : function(o){
10922 var el = this.getFxEl();
10924 el.queueFx(o, function(){
10925 var a = {}, w = o.width, h = o.height, x = o.x, y = o.y, op = o.opacity;
10926 if(w !== undefined){
10927 a.width = {to: this.adjustWidth(w)};
10929 if(h !== undefined){
10930 a.height = {to: this.adjustHeight(h)};
10932 if(x !== undefined || y !== undefined){
10934 x !== undefined ? x : this.getX(),
10935 y !== undefined ? y : this.getY()
10938 if(op !== undefined){
10939 a.opacity = {to: op};
10941 if(o.xy !== undefined){
10942 a.points = {to: o.xy};
10944 arguments.callee.anim = this.fxanim(a,
10945 o, 'motion', .35, "easeOut", function(){
10953 * Slides the element while fading it out of view. An anchor point can be optionally passed to set the
10954 * ending point of the effect.
10957 // default: slide the element downward while fading out
10960 // custom: slide the element out to the right with a 2-second duration
10961 el.ghost('r', { duration: 2 });
10963 // common config options shown with default values
10971 * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10972 * @param {Object} options (optional) Object literal with any of the Fx config options
10973 * @return {Roo.Element} The Element
10975 ghost : function(anchor, o){
10976 var el = this.getFxEl();
10979 el.queueFx(o, function(){
10980 anchor = anchor || "b";
10982 // restore values after effect
10983 var r = this.getFxRestore();
10984 var w = this.getWidth(),
10985 h = this.getHeight();
10987 var st = this.dom.style;
10989 var after = function(){
10991 el.setDisplayed(false);
10997 el.setPositioning(r.pos);
10998 st.width = r.width;
10999 st.height = r.height;
11004 var a = {opacity: {to: 0}, points: {}}, pt = a.points;
11005 switch(anchor.toLowerCase()){
11032 arguments.callee.anim = this.fxanim(a,
11042 * Ensures that all effects queued after syncFx is called on the element are
11043 * run concurrently. This is the opposite of {@link #sequenceFx}.
11044 * @return {Roo.Element} The Element
11046 syncFx : function(){
11047 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11056 * Ensures that all effects queued after sequenceFx is called on the element are
11057 * run in sequence. This is the opposite of {@link #syncFx}.
11058 * @return {Roo.Element} The Element
11060 sequenceFx : function(){
11061 this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
11063 concurrent : false,
11070 nextFx : function(){
11071 var ef = this.fxQueue[0];
11078 * Returns true if the element has any effects actively running or queued, else returns false.
11079 * @return {Boolean} True if element has active effects, else false
11081 hasActiveFx : function(){
11082 return this.fxQueue && this.fxQueue[0];
11086 * Stops any running effects and clears the element's internal effects queue if it contains
11087 * any additional effects that haven't started yet.
11088 * @return {Roo.Element} The Element
11090 stopFx : function(){
11091 if(this.hasActiveFx()){
11092 var cur = this.fxQueue[0];
11093 if(cur && cur.anim && cur.anim.isAnimated()){
11094 this.fxQueue = [cur]; // clear out others
11095 cur.anim.stop(true);
11102 beforeFx : function(o){
11103 if(this.hasActiveFx() && !o.concurrent){
11114 * Returns true if the element is currently blocking so that no other effect can be queued
11115 * until this effect is finished, else returns false if blocking is not set. This is commonly
11116 * used to ensure that an effect initiated by a user action runs to completion prior to the
11117 * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
11118 * @return {Boolean} True if blocking, else false
11120 hasFxBlock : function(){
11121 var q = this.fxQueue;
11122 return q && q[0] && q[0].block;
11126 queueFx : function(o, fn){
11130 if(!this.hasFxBlock()){
11131 Roo.applyIf(o, this.fxDefaults);
11133 var run = this.beforeFx(o);
11134 fn.block = o.block;
11135 this.fxQueue.push(fn);
11147 fxWrap : function(pos, o, vis){
11149 if(!o.wrap || !(wrap = Roo.get(o.wrap))){
11152 wrapXY = this.getXY();
11154 var div = document.createElement("div");
11155 div.style.visibility = vis;
11156 wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
11157 wrap.setPositioning(pos);
11158 if(wrap.getStyle("position") == "static"){
11159 wrap.position("relative");
11161 this.clearPositioning('auto');
11163 wrap.dom.appendChild(this.dom);
11165 wrap.setXY(wrapXY);
11172 fxUnwrap : function(wrap, pos, o){
11173 this.clearPositioning();
11174 this.setPositioning(pos);
11176 wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
11182 getFxRestore : function(){
11183 var st = this.dom.style;
11184 return {pos: this.getPositioning(), width: st.width, height : st.height};
11188 afterFx : function(o){
11190 this.applyStyles(o.afterStyle);
11193 this.addClass(o.afterCls);
11195 if(o.remove === true){
11198 Roo.callback(o.callback, o.scope, [this]);
11200 this.fxQueue.shift();
11206 getFxEl : function(){ // support for composite element fx
11207 return Roo.get(this.dom);
11211 fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
11212 animType = animType || 'run';
11214 var anim = Roo.lib.Anim[animType](
11216 (opt.duration || defaultDur) || .35,
11217 (opt.easing || defaultEase) || 'easeOut',
11219 Roo.callback(cb, this);
11228 // backwords compat
11229 Roo.Fx.resize = Roo.Fx.scale;
11231 //When included, Roo.Fx is automatically applied to Element so that all basic
11232 //effects are available directly via the Element API
11233 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
11235 * Ext JS Library 1.1.1
11236 * Copyright(c) 2006-2007, Ext JS, LLC.
11238 * Originally Released Under LGPL - original licence link has changed is not relivant.
11241 * <script type="text/javascript">
11246 * @class Roo.CompositeElement
11247 * Standard composite class. Creates a Roo.Element for every element in the collection.
11249 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11250 * actions will be performed on all the elements in this collection.</b>
11252 * All methods return <i>this</i> and can be chained.
11254 var els = Roo.select("#some-el div.some-class", true);
11255 // or select directly from an existing element
11256 var el = Roo.get('some-el');
11257 el.select('div.some-class', true);
11259 els.setWidth(100); // all elements become 100 width
11260 els.hide(true); // all elements fade out and hide
11262 els.setWidth(100).hide(true);
11265 Roo.CompositeElement = function(els){
11266 this.elements = [];
11267 this.addElements(els);
11269 Roo.CompositeElement.prototype = {
11271 addElements : function(els){
11275 if(typeof els == "string"){
11276 els = Roo.Element.selectorFunction(els);
11278 var yels = this.elements;
11279 var index = yels.length-1;
11280 for(var i = 0, len = els.length; i < len; i++) {
11281 yels[++index] = Roo.get(els[i]);
11287 * Clears this composite and adds the elements returned by the passed selector.
11288 * @param {String/Array} els A string CSS selector, an array of elements or an element
11289 * @return {CompositeElement} this
11291 fill : function(els){
11292 this.elements = [];
11298 * Filters this composite to only elements that match the passed selector.
11299 * @param {String} selector A string CSS selector
11300 * @param {Boolean} inverse return inverse filter (not matches)
11301 * @return {CompositeElement} this
11303 filter : function(selector, inverse){
11305 inverse = inverse || false;
11306 this.each(function(el){
11307 var match = inverse ? !el.is(selector) : el.is(selector);
11309 els[els.length] = el.dom;
11316 invoke : function(fn, args){
11317 var els = this.elements;
11318 for(var i = 0, len = els.length; i < len; i++) {
11319 Roo.Element.prototype[fn].apply(els[i], args);
11324 * Adds elements to this composite.
11325 * @param {String/Array} els A string CSS selector, an array of elements or an element
11326 * @return {CompositeElement} this
11328 add : function(els){
11329 if(typeof els == "string"){
11330 this.addElements(Roo.Element.selectorFunction(els));
11331 }else if(els.length !== undefined){
11332 this.addElements(els);
11334 this.addElements([els]);
11339 * Calls the passed function passing (el, this, index) for each element in this composite.
11340 * @param {Function} fn The function to call
11341 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11342 * @return {CompositeElement} this
11344 each : function(fn, scope){
11345 var els = this.elements;
11346 for(var i = 0, len = els.length; i < len; i++){
11347 if(fn.call(scope || els[i], els[i], this, i) === false) {
11355 * Returns the Element object at the specified index
11356 * @param {Number} index
11357 * @return {Roo.Element}
11359 item : function(index){
11360 return this.elements[index] || null;
11364 * Returns the first Element
11365 * @return {Roo.Element}
11367 first : function(){
11368 return this.item(0);
11372 * Returns the last Element
11373 * @return {Roo.Element}
11376 return this.item(this.elements.length-1);
11380 * Returns the number of elements in this composite
11383 getCount : function(){
11384 return this.elements.length;
11388 * Returns true if this composite contains the passed element
11391 contains : function(el){
11392 return this.indexOf(el) !== -1;
11396 * Returns true if this composite contains the passed element
11399 indexOf : function(el){
11400 return this.elements.indexOf(Roo.get(el));
11405 * Removes the specified element(s).
11406 * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11407 * or an array of any of those.
11408 * @param {Boolean} removeDom (optional) True to also remove the element from the document
11409 * @return {CompositeElement} this
11411 removeElement : function(el, removeDom){
11412 if(el instanceof Array){
11413 for(var i = 0, len = el.length; i < len; i++){
11414 this.removeElement(el[i]);
11418 var index = typeof el == 'number' ? el : this.indexOf(el);
11421 var d = this.elements[index];
11425 d.parentNode.removeChild(d);
11428 this.elements.splice(index, 1);
11434 * Replaces the specified element with the passed element.
11435 * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11437 * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11438 * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11439 * @return {CompositeElement} this
11441 replaceElement : function(el, replacement, domReplace){
11442 var index = typeof el == 'number' ? el : this.indexOf(el);
11445 this.elements[index].replaceWith(replacement);
11447 this.elements.splice(index, 1, Roo.get(replacement))
11454 * Removes all elements.
11456 clear : function(){
11457 this.elements = [];
11461 Roo.CompositeElement.createCall = function(proto, fnName){
11462 if(!proto[fnName]){
11463 proto[fnName] = function(){
11464 return this.invoke(fnName, arguments);
11468 for(var fnName in Roo.Element.prototype){
11469 if(typeof Roo.Element.prototype[fnName] == "function"){
11470 Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11476 * Ext JS Library 1.1.1
11477 * Copyright(c) 2006-2007, Ext JS, LLC.
11479 * Originally Released Under LGPL - original licence link has changed is not relivant.
11482 * <script type="text/javascript">
11486 * @class Roo.CompositeElementLite
11487 * @extends Roo.CompositeElement
11488 * Flyweight composite class. Reuses the same Roo.Element for element operations.
11490 var els = Roo.select("#some-el div.some-class");
11491 // or select directly from an existing element
11492 var el = Roo.get('some-el');
11493 el.select('div.some-class');
11495 els.setWidth(100); // all elements become 100 width
11496 els.hide(true); // all elements fade out and hide
11498 els.setWidth(100).hide(true);
11499 </code></pre><br><br>
11500 * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11501 * actions will be performed on all the elements in this collection.</b>
11503 Roo.CompositeElementLite = function(els){
11504 Roo.CompositeElementLite.superclass.constructor.call(this, els);
11505 this.el = new Roo.Element.Flyweight();
11507 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11508 addElements : function(els){
11510 if(els instanceof Array){
11511 this.elements = this.elements.concat(els);
11513 var yels = this.elements;
11514 var index = yels.length-1;
11515 for(var i = 0, len = els.length; i < len; i++) {
11516 yels[++index] = els[i];
11522 invoke : function(fn, args){
11523 var els = this.elements;
11525 for(var i = 0, len = els.length; i < len; i++) {
11527 Roo.Element.prototype[fn].apply(el, args);
11532 * Returns a flyweight Element of the dom element object at the specified index
11533 * @param {Number} index
11534 * @return {Roo.Element}
11536 item : function(index){
11537 if(!this.elements[index]){
11540 this.el.dom = this.elements[index];
11544 // fixes scope with flyweight
11545 addListener : function(eventName, handler, scope, opt){
11546 var els = this.elements;
11547 for(var i = 0, len = els.length; i < len; i++) {
11548 Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11554 * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11555 * passed is the flyweight (shared) Roo.Element instance, so if you require a
11556 * a reference to the dom node, use el.dom.</b>
11557 * @param {Function} fn The function to call
11558 * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11559 * @return {CompositeElement} this
11561 each : function(fn, scope){
11562 var els = this.elements;
11564 for(var i = 0, len = els.length; i < len; i++){
11566 if(fn.call(scope || el, el, this, i) === false){
11573 indexOf : function(el){
11574 return this.elements.indexOf(Roo.getDom(el));
11577 replaceElement : function(el, replacement, domReplace){
11578 var index = typeof el == 'number' ? el : this.indexOf(el);
11580 replacement = Roo.getDom(replacement);
11582 var d = this.elements[index];
11583 d.parentNode.insertBefore(replacement, d);
11584 d.parentNode.removeChild(d);
11586 this.elements.splice(index, 1, replacement);
11591 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11595 * Ext JS Library 1.1.1
11596 * Copyright(c) 2006-2007, Ext JS, LLC.
11598 * Originally Released Under LGPL - original licence link has changed is not relivant.
11601 * <script type="text/javascript">
11607 * @class Roo.data.Connection
11608 * @extends Roo.util.Observable
11609 * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11610 * either to a configured URL, or to a URL specified at request time.
11612 * Requests made by this class are asynchronous, and will return immediately. No data from
11613 * the server will be available to the statement immediately following the {@link #request} call.
11614 * To process returned data, use a callback in the request options object, or an event listener.
11616 * Note: If you are doing a file upload, you will not get a normal response object sent back to
11617 * your callback or event handler. Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11618 * The response object is created using the innerHTML of the IFRAME's document as the responseText
11619 * property and, if present, the IFRAME's XML document as the responseXML property.
11621 * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11622 * that it be placed either inside a <textarea> in an HTML document and retrieved from the responseText
11623 * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11624 * standard DOM methods.
11626 * @param {Object} config a configuration object.
11628 Roo.data.Connection = function(config){
11629 Roo.apply(this, config);
11632 * @event beforerequest
11633 * Fires before a network request is made to retrieve a data object.
11634 * @param {Connection} conn This Connection object.
11635 * @param {Object} options The options config object passed to the {@link #request} method.
11637 "beforerequest" : true,
11639 * @event requestcomplete
11640 * Fires if the request was successfully completed.
11641 * @param {Connection} conn This Connection object.
11642 * @param {Object} response The XHR object containing the response data.
11643 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11644 * @param {Object} options The options config object passed to the {@link #request} method.
11646 "requestcomplete" : true,
11648 * @event requestexception
11649 * Fires if an error HTTP status was returned from the server.
11650 * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11651 * @param {Connection} conn This Connection object.
11652 * @param {Object} response The XHR object containing the response data.
11653 * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11654 * @param {Object} options The options config object passed to the {@link #request} method.
11656 "requestexception" : true
11658 Roo.data.Connection.superclass.constructor.call(this);
11661 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11663 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11666 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11667 * extra parameters to each request made by this object. (defaults to undefined)
11670 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11671 * to each request made by this object. (defaults to undefined)
11674 * @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)
11677 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11681 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11687 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11690 disableCaching: true,
11693 * Sends an HTTP request to a remote server.
11694 * @param {Object} options An object which may contain the following properties:<ul>
11695 * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11696 * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11697 * request, a url encoded string or a function to call to get either.</li>
11698 * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11699 * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11700 * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11701 * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11702 * <li>options {Object} The parameter to the request call.</li>
11703 * <li>success {Boolean} True if the request succeeded.</li>
11704 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11706 * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11707 * The callback is passed the following parameters:<ul>
11708 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11709 * <li>options {Object} The parameter to the request call.</li>
11711 * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11712 * The callback is passed the following parameters:<ul>
11713 * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11714 * <li>options {Object} The parameter to the request call.</li>
11716 * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11717 * for the callback function. Defaults to the browser window.</li>
11718 * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11719 * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11720 * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11721 * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11722 * params for the post data. Any params will be appended to the URL.</li>
11723 * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11725 * @return {Number} transactionId
11727 request : function(o){
11728 if(this.fireEvent("beforerequest", this, o) !== false){
11731 if(typeof p == "function"){
11732 p = p.call(o.scope||window, o);
11734 if(typeof p == "object"){
11735 p = Roo.urlEncode(o.params);
11737 if(this.extraParams){
11738 var extras = Roo.urlEncode(this.extraParams);
11739 p = p ? (p + '&' + extras) : extras;
11742 var url = o.url || this.url;
11743 if(typeof url == 'function'){
11744 url = url.call(o.scope||window, o);
11748 var form = Roo.getDom(o.form);
11749 url = url || form.action;
11751 var enctype = form.getAttribute("enctype");
11754 return this.doFormDataUpload(o, url);
11757 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11758 return this.doFormUpload(o, p, url);
11760 var f = Roo.lib.Ajax.serializeForm(form);
11761 p = p ? (p + '&' + f) : f;
11764 if (!o.form && o.formData) {
11765 o.formData = o.formData === true ? new FormData() : o.formData;
11766 for (var k in o.params) {
11767 o.formData.append(k,o.params[k]);
11770 return this.doFormDataUpload(o, url);
11774 var hs = o.headers;
11775 if(this.defaultHeaders){
11776 hs = Roo.apply(hs || {}, this.defaultHeaders);
11783 success: this.handleResponse,
11784 failure: this.handleFailure,
11786 argument: {options: o},
11787 timeout : o.timeout || this.timeout
11790 var method = o.method||this.method||(p ? "POST" : "GET");
11792 if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11793 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11796 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11800 }else if(this.autoAbort !== false){
11804 if((method == 'GET' && p) || o.xmlData){
11805 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11808 Roo.lib.Ajax.useDefaultHeader = typeof(o.headers) == 'undefined' || typeof(o.headers['Content-Type']) == 'undefined';
11809 this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11810 Roo.lib.Ajax.useDefaultHeader == true;
11811 return this.transId;
11813 Roo.callback(o.callback, o.scope, [o, null, null]);
11819 * Determine whether this object has a request outstanding.
11820 * @param {Number} transactionId (Optional) defaults to the last transaction
11821 * @return {Boolean} True if there is an outstanding request.
11823 isLoading : function(transId){
11825 return Roo.lib.Ajax.isCallInProgress(transId);
11827 return this.transId ? true : false;
11832 * Aborts any outstanding request.
11833 * @param {Number} transactionId (Optional) defaults to the last transaction
11835 abort : function(transId){
11836 if(transId || this.isLoading()){
11837 Roo.lib.Ajax.abort(transId || this.transId);
11842 handleResponse : function(response){
11843 this.transId = false;
11844 var options = response.argument.options;
11845 response.argument = options ? options.argument : null;
11846 this.fireEvent("requestcomplete", this, response, options);
11847 Roo.callback(options.success, options.scope, [response, options]);
11848 Roo.callback(options.callback, options.scope, [options, true, response]);
11852 handleFailure : function(response, e){
11853 this.transId = false;
11854 var options = response.argument.options;
11855 response.argument = options ? options.argument : null;
11856 this.fireEvent("requestexception", this, response, options, e);
11857 Roo.callback(options.failure, options.scope, [response, options]);
11858 Roo.callback(options.callback, options.scope, [options, false, response]);
11862 doFormUpload : function(o, ps, url){
11864 var frame = document.createElement('iframe');
11867 frame.className = 'x-hidden';
11869 frame.src = Roo.SSL_SECURE_URL;
11871 document.body.appendChild(frame);
11874 document.frames[id].name = id;
11877 var form = Roo.getDom(o.form);
11879 form.method = 'POST';
11880 form.enctype = form.encoding = 'multipart/form-data';
11886 if(ps){ // add dynamic params
11888 ps = Roo.urlDecode(ps, false);
11890 if(ps.hasOwnProperty(k)){
11891 hd = document.createElement('input');
11892 hd.type = 'hidden';
11895 form.appendChild(hd);
11902 var r = { // bogus response object
11907 r.argument = o ? o.argument : null;
11912 doc = frame.contentWindow.document;
11914 doc = (frame.contentDocument || window.frames[id].document);
11916 if(doc && doc.body){
11917 r.responseText = doc.body.innerHTML;
11919 if(doc && doc.XMLDocument){
11920 r.responseXML = doc.XMLDocument;
11922 r.responseXML = doc;
11929 Roo.EventManager.removeListener(frame, 'load', cb, this);
11931 this.fireEvent("requestcomplete", this, r, o);
11932 Roo.callback(o.success, o.scope, [r, o]);
11933 Roo.callback(o.callback, o.scope, [o, true, r]);
11935 setTimeout(function(){document.body.removeChild(frame);}, 100);
11938 Roo.EventManager.on(frame, 'load', cb, this);
11941 if(hiddens){ // remove dynamic params
11942 for(var i = 0, len = hiddens.length; i < len; i++){
11943 form.removeChild(hiddens[i]);
11947 // this is a 'formdata version???'
11950 doFormDataUpload : function(o, url)
11954 var form = Roo.getDom(o.form);
11955 form.enctype = form.encoding = 'multipart/form-data';
11956 formData = o.formData === true ? new FormData(form) : o.formData;
11958 formData = o.formData === true ? new FormData() : o.formData;
11963 success: this.handleResponse,
11964 failure: this.handleFailure,
11966 argument: {options: o},
11967 timeout : o.timeout || this.timeout
11970 if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11974 }else if(this.autoAbort !== false){
11978 //Roo.lib.Ajax.defaultPostHeader = null;
11979 Roo.lib.Ajax.useDefaultHeader = false;
11980 this.transId = Roo.lib.Ajax.request( "POST", url, cb, formData, o);
11981 Roo.lib.Ajax.useDefaultHeader = true;
11989 * Ext JS Library 1.1.1
11990 * Copyright(c) 2006-2007, Ext JS, LLC.
11992 * Originally Released Under LGPL - original licence link has changed is not relivant.
11995 * <script type="text/javascript">
11999 * Global Ajax request class.
12002 * @extends Roo.data.Connection
12005 * @cfg {String} url The default URL to be used for requests to the server. (defaults to undefined)
12006 * @cfg {Object} extraParams An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
12007 * @cfg {Object} defaultHeaders An object containing request headers which are added to each request made by this object. (defaults to undefined)
12008 * @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)
12009 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
12010 * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
12011 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
12013 Roo.Ajax = new Roo.data.Connection({
12022 * Serialize the passed form into a url encoded string
12024 * @param {String/HTMLElement} form
12027 serializeForm : function(form){
12028 return Roo.lib.Ajax.serializeForm(form);
12032 * Ext JS Library 1.1.1
12033 * Copyright(c) 2006-2007, Ext JS, LLC.
12035 * Originally Released Under LGPL - original licence link has changed is not relivant.
12038 * <script type="text/javascript">
12043 * @class Roo.UpdateManager
12044 * @extends Roo.util.Observable
12045 * Provides AJAX-style update for Element object.<br><br>
12048 * // Get it from a Roo.Element object
12049 * var el = Roo.get("foo");
12050 * var mgr = el.getUpdateManager();
12051 * mgr.update("http://myserver.com/index.php", "param1=1&param2=2");
12053 * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
12055 * // or directly (returns the same UpdateManager instance)
12056 * var mgr = new Roo.UpdateManager("myElementId");
12057 * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
12058 * mgr.on("update", myFcnNeedsToKnow);
12060 // short handed call directly from the element object
12061 Roo.get("foo").load({
12065 text: "Loading Foo..."
12069 * Create new UpdateManager directly.
12070 * @param {String/HTMLElement/Roo.Element} el The element to update
12071 * @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).
12073 Roo.UpdateManager = function(el, forceNew){
12075 if(!forceNew && el.updateManager){
12076 return el.updateManager;
12079 * The Element object
12080 * @type Roo.Element
12084 * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
12087 this.defaultUrl = null;
12091 * @event beforeupdate
12092 * Fired before an update is made, return false from your handler and the update is cancelled.
12093 * @param {Roo.Element} el
12094 * @param {String/Object/Function} url
12095 * @param {String/Object} params
12097 "beforeupdate": true,
12100 * Fired after successful update is made.
12101 * @param {Roo.Element} el
12102 * @param {Object} oResponseObject The response Object
12107 * Fired on update failure.
12108 * @param {Roo.Element} el
12109 * @param {Object} oResponseObject The response Object
12113 var d = Roo.UpdateManager.defaults;
12115 * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
12118 this.sslBlankUrl = d.sslBlankUrl;
12120 * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
12123 this.disableCaching = d.disableCaching;
12125 * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '<div class="loading-indicator">Loading...</div>').
12128 this.indicatorText = d.indicatorText;
12130 * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
12133 this.showLoadIndicator = d.showLoadIndicator;
12135 * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
12138 this.timeout = d.timeout;
12141 * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
12144 this.loadScripts = d.loadScripts;
12147 * Transaction object of current executing transaction
12149 this.transaction = null;
12154 this.autoRefreshProcId = null;
12156 * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
12159 this.refreshDelegate = this.refresh.createDelegate(this);
12161 * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
12164 this.updateDelegate = this.update.createDelegate(this);
12166 * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
12169 this.formUpdateDelegate = this.formUpdate.createDelegate(this);
12173 this.successDelegate = this.processSuccess.createDelegate(this);
12177 this.failureDelegate = this.processFailure.createDelegate(this);
12179 if(!this.renderer){
12181 * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
12183 this.renderer = new Roo.UpdateManager.BasicRenderer();
12186 Roo.UpdateManager.superclass.constructor.call(this);
12189 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
12191 * Get the Element this UpdateManager is bound to
12192 * @return {Roo.Element} The element
12194 getEl : function(){
12198 * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
12199 * @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:
12202 url: "your-url.php",<br/>
12203 params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
12204 callback: yourFunction,<br/>
12205 scope: yourObject, //(optional scope) <br/>
12206 discardUrl: false, <br/>
12207 nocache: false,<br/>
12208 text: "Loading...",<br/>
12210 scripts: false<br/>
12213 * The only required property is url. The optional properties nocache, text and scripts
12214 * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
12215 * @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}
12216 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12217 * @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.
12219 update : function(url, params, callback, discardUrl){
12220 if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
12221 var method = this.method,
12223 if(typeof url == "object"){ // must be config object
12226 params = params || cfg.params;
12227 callback = callback || cfg.callback;
12228 discardUrl = discardUrl || cfg.discardUrl;
12229 if(callback && cfg.scope){
12230 callback = callback.createDelegate(cfg.scope);
12232 if(typeof cfg.method != "undefined"){method = cfg.method;};
12233 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
12234 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
12235 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
12236 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
12238 this.showLoading();
12240 this.defaultUrl = url;
12242 if(typeof url == "function"){
12243 url = url.call(this);
12246 method = method || (params ? "POST" : "GET");
12247 if(method == "GET"){
12248 url = this.prepareUrl(url);
12251 var o = Roo.apply(cfg ||{}, {
12254 success: this.successDelegate,
12255 failure: this.failureDelegate,
12256 callback: undefined,
12257 timeout: (this.timeout*1000),
12258 argument: {"url": url, "form": null, "callback": callback, "params": params}
12260 Roo.log("updated manager called with timeout of " + o.timeout);
12261 this.transaction = Roo.Ajax.request(o);
12266 * 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.
12267 * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
12268 * @param {String/HTMLElement} form The form Id or form element
12269 * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
12270 * @param {Boolean} reset (optional) Whether to try to reset the form after the update
12271 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
12273 formUpdate : function(form, url, reset, callback){
12274 if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
12275 if(typeof url == "function"){
12276 url = url.call(this);
12278 form = Roo.getDom(form);
12279 this.transaction = Roo.Ajax.request({
12282 success: this.successDelegate,
12283 failure: this.failureDelegate,
12284 timeout: (this.timeout*1000),
12285 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
12287 this.showLoading.defer(1, this);
12292 * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
12293 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12295 refresh : function(callback){
12296 if(this.defaultUrl == null){
12299 this.update(this.defaultUrl, null, callback, true);
12303 * Set this element to auto refresh.
12304 * @param {Number} interval How often to update (in seconds).
12305 * @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)
12306 * @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}
12307 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
12308 * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
12310 startAutoRefresh : function(interval, url, params, callback, refreshNow){
12312 this.update(url || this.defaultUrl, params, callback, true);
12314 if(this.autoRefreshProcId){
12315 clearInterval(this.autoRefreshProcId);
12317 this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12321 * Stop auto refresh on this element.
12323 stopAutoRefresh : function(){
12324 if(this.autoRefreshProcId){
12325 clearInterval(this.autoRefreshProcId);
12326 delete this.autoRefreshProcId;
12330 isAutoRefreshing : function(){
12331 return this.autoRefreshProcId ? true : false;
12334 * Called to update the element to "Loading" state. Override to perform custom action.
12336 showLoading : function(){
12337 if(this.showLoadIndicator){
12338 this.el.update(this.indicatorText);
12343 * Adds unique parameter to query string if disableCaching = true
12346 prepareUrl : function(url){
12347 if(this.disableCaching){
12348 var append = "_dc=" + (new Date().getTime());
12349 if(url.indexOf("?") !== -1){
12350 url += "&" + append;
12352 url += "?" + append;
12361 processSuccess : function(response){
12362 this.transaction = null;
12363 if(response.argument.form && response.argument.reset){
12364 try{ // put in try/catch since some older FF releases had problems with this
12365 response.argument.form.reset();
12368 if(this.loadScripts){
12369 this.renderer.render(this.el, response, this,
12370 this.updateComplete.createDelegate(this, [response]));
12372 this.renderer.render(this.el, response, this);
12373 this.updateComplete(response);
12377 updateComplete : function(response){
12378 this.fireEvent("update", this.el, response);
12379 if(typeof response.argument.callback == "function"){
12380 response.argument.callback(this.el, true, response);
12387 processFailure : function(response){
12388 this.transaction = null;
12389 this.fireEvent("failure", this.el, response);
12390 if(typeof response.argument.callback == "function"){
12391 response.argument.callback(this.el, false, response);
12396 * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12397 * @param {Object} renderer The object implementing the render() method
12399 setRenderer : function(renderer){
12400 this.renderer = renderer;
12403 getRenderer : function(){
12404 return this.renderer;
12408 * Set the defaultUrl used for updates
12409 * @param {String/Function} defaultUrl The url or a function to call to get the url
12411 setDefaultUrl : function(defaultUrl){
12412 this.defaultUrl = defaultUrl;
12416 * Aborts the executing transaction
12418 abort : function(){
12419 if(this.transaction){
12420 Roo.Ajax.abort(this.transaction);
12425 * Returns true if an update is in progress
12426 * @return {Boolean}
12428 isUpdating : function(){
12429 if(this.transaction){
12430 return Roo.Ajax.isLoading(this.transaction);
12437 * @class Roo.UpdateManager.defaults
12438 * @static (not really - but it helps the doc tool)
12439 * The defaults collection enables customizing the default properties of UpdateManager
12441 Roo.UpdateManager.defaults = {
12443 * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12449 * True to process scripts by default (Defaults to false).
12452 loadScripts : false,
12455 * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12458 sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12460 * Whether to append unique parameter on get request to disable caching (Defaults to false).
12463 disableCaching : false,
12465 * Whether to show indicatorText when loading (Defaults to true).
12468 showLoadIndicator : true,
12470 * Text for loading indicator (Defaults to '<div class="loading-indicator">Loading...</div>').
12473 indicatorText : '<div class="loading-indicator">Loading...</div>'
12477 * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12479 * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12480 * @param {String/HTMLElement/Roo.Element} el The element to update
12481 * @param {String} url The url
12482 * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12483 * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12486 * @member Roo.UpdateManager
12488 Roo.UpdateManager.updateElement = function(el, url, params, options){
12489 var um = Roo.get(el, true).getUpdateManager();
12490 Roo.apply(um, options);
12491 um.update(url, params, options ? options.callback : null);
12493 // alias for backwards compat
12494 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12496 * @class Roo.UpdateManager.BasicRenderer
12497 * Default Content renderer. Updates the elements innerHTML with the responseText.
12499 Roo.UpdateManager.BasicRenderer = function(){};
12501 Roo.UpdateManager.BasicRenderer.prototype = {
12503 * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12504 * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12505 * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12506 * @param {Roo.Element} el The element being rendered
12507 * @param {Object} response The YUI Connect response object
12508 * @param {UpdateManager} updateManager The calling update manager
12509 * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12511 render : function(el, response, updateManager, callback){
12512 el.update(response.responseText, updateManager.loadScripts, callback);
12518 * (c)) Alan Knowles
12524 * @class Roo.DomTemplate
12525 * @extends Roo.Template
12526 * An effort at a dom based template engine..
12528 * Similar to XTemplate, except it uses dom parsing to create the template..
12530 * Supported features:
12535 {a_variable} - output encoded.
12536 {a_variable.format:("Y-m-d")} - call a method on the variable
12537 {a_variable:raw} - unencoded output
12538 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12539 {a_variable:this.method_on_template(...)} - call a method on the template object.
12544 <div roo-for="a_variable or condition.."></div>
12545 <div roo-if="a_variable or condition"></div>
12546 <div roo-exec="some javascript"></div>
12547 <div roo-name="named_template"></div>
12552 Roo.DomTemplate = function()
12554 Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12561 Roo.extend(Roo.DomTemplate, Roo.Template, {
12563 * id counter for sub templates.
12567 * flag to indicate if dom parser is inside a pre,
12568 * it will strip whitespace if not.
12573 * The various sub templates
12581 * basic tag replacing syntax
12584 * // you can fake an object call by doing this
12588 re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12589 //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12591 iterChild : function (node, method) {
12593 var oldPre = this.inPre;
12594 if (node.tagName == 'PRE') {
12597 for( var i = 0; i < node.childNodes.length; i++) {
12598 method.call(this, node.childNodes[i]);
12600 this.inPre = oldPre;
12606 * compile the template
12608 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12611 compile: function()
12615 // covert the html into DOM...
12619 doc = document.implementation.createHTMLDocument("");
12620 doc.documentElement.innerHTML = this.html ;
12621 div = doc.documentElement;
12623 // old IE... - nasty -- it causes all sorts of issues.. with
12624 // images getting pulled from server..
12625 div = document.createElement('div');
12626 div.innerHTML = this.html;
12628 //doc.documentElement.innerHTML = htmlBody
12634 this.iterChild(div, function(n) {_t.compileNode(n, true); });
12636 var tpls = this.tpls;
12638 // create a top level template from the snippet..
12640 //Roo.log(div.innerHTML);
12647 body : div.innerHTML,
12660 Roo.each(tpls, function(tp){
12661 this.compileTpl(tp);
12662 this.tpls[tp.id] = tp;
12665 this.master = tpls[0];
12671 compileNode : function(node, istop) {
12676 // skip anything not a tag..
12677 if (node.nodeType != 1) {
12678 if (node.nodeType == 3 && !this.inPre) {
12679 // reduce white space..
12680 node.nodeValue = node.nodeValue.replace(/\s+/g, ' ');
12703 case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12704 case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12705 case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12706 case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12712 // just itterate children..
12713 this.iterChild(node,this.compileNode);
12716 tpl.uid = this.id++;
12717 tpl.value = node.getAttribute('roo-' + tpl.attr);
12718 node.removeAttribute('roo-'+ tpl.attr);
12719 if (tpl.attr != 'name') {
12720 var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12721 node.parentNode.replaceChild(placeholder, node);
12724 var placeholder = document.createElement('span');
12725 placeholder.className = 'roo-tpl-' + tpl.value;
12726 node.parentNode.replaceChild(placeholder, node);
12729 // parent now sees '{domtplXXXX}
12730 this.iterChild(node,this.compileNode);
12732 // we should now have node body...
12733 var div = document.createElement('div');
12734 div.appendChild(node);
12736 // this has the unfortunate side effect of converting tagged attributes
12737 // eg. href="{...}" into %7C...%7D
12738 // this has been fixed by searching for those combo's although it's a bit hacky..
12741 tpl.body = div.innerHTML;
12748 switch (tpl.value) {
12749 case '.': tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12750 case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12751 default: tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12756 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12760 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12764 tpl.id = tpl.value; // replace non characters???
12770 this.tpls.push(tpl);
12780 * Compile a segment of the template into a 'sub-template'
12786 compileTpl : function(tpl)
12788 var fm = Roo.util.Format;
12789 var useF = this.disableFormats !== true;
12791 var sep = Roo.isGecko ? "+\n" : ",\n";
12793 var undef = function(str) {
12794 Roo.debug && Roo.log("Property not found :" + str);
12798 //Roo.log(tpl.body);
12802 var fn = function(m, lbrace, name, format, args)
12805 //Roo.log(arguments);
12806 args = args ? args.replace(/\\'/g,"'") : args;
12807 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12808 if (typeof(format) == 'undefined') {
12809 format = 'htmlEncode';
12811 if (format == 'raw' ) {
12815 if(name.substr(0, 6) == 'domtpl'){
12816 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12819 // build an array of options to determine if value is undefined..
12821 // basically get 'xxxx.yyyy' then do
12822 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12823 // (function () { Roo.log("Property not found"); return ''; })() :
12828 Roo.each(name.split('.'), function(st) {
12829 lookfor += (lookfor.length ? '.': '') + st;
12830 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
12833 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12836 if(format && useF){
12838 args = args ? ',' + args : "";
12840 if(format.substr(0, 5) != "this."){
12841 format = "fm." + format + '(';
12843 format = 'this.call("'+ format.substr(5) + '", ';
12847 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
12850 if (args && args.length) {
12851 // called with xxyx.yuu:(test,test)
12853 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
12855 // raw.. - :raw modifier..
12856 return "'"+ sep + udef_st + name + ")"+sep+"'";
12860 // branched to use + in gecko and [].join() in others
12862 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
12863 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12866 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
12867 body.push(tpl.body.replace(/(\r\n|\n)/g,
12868 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12869 body.push("'].join('');};};");
12870 body = body.join('');
12873 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12875 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
12882 * same as applyTemplate, except it's done to one of the subTemplates
12883 * when using named templates, you can do:
12885 * var str = pl.applySubTemplate('your-name', values);
12888 * @param {Number} id of the template
12889 * @param {Object} values to apply to template
12890 * @param {Object} parent (normaly the instance of this object)
12892 applySubTemplate : function(id, values, parent)
12896 var t = this.tpls[id];
12900 if(t.ifCall && !t.ifCall.call(this, values, parent)){
12901 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12905 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12912 if(t.execCall && t.execCall.call(this, values, parent)){
12916 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12922 var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12923 parent = t.target ? values : parent;
12924 if(t.forCall && vs instanceof Array){
12926 for(var i = 0, len = vs.length; i < len; i++){
12928 buf[buf.length] = t.compiled.call(this, vs[i], parent);
12930 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12932 //Roo.log(t.compiled);
12936 return buf.join('');
12939 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12944 return t.compiled.call(this, vs, parent);
12946 Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12948 //Roo.log(t.compiled);
12956 applyTemplate : function(values){
12957 return this.master.compiled.call(this, values, {});
12958 //var s = this.subs;
12961 apply : function(){
12962 return this.applyTemplate.apply(this, arguments);
12967 Roo.DomTemplate.from = function(el){
12968 el = Roo.getDom(el);
12969 return new Roo.Domtemplate(el.value || el.innerHTML);
12972 * Ext JS Library 1.1.1
12973 * Copyright(c) 2006-2007, Ext JS, LLC.
12975 * Originally Released Under LGPL - original licence link has changed is not relivant.
12978 * <script type="text/javascript">
12982 * @class Roo.util.DelayedTask
12983 * Provides a convenient method of performing setTimeout where a new
12984 * timeout cancels the old timeout. An example would be performing validation on a keypress.
12985 * You can use this class to buffer
12986 * the keypress events for a certain number of milliseconds, and perform only if they stop
12987 * for that amount of time.
12988 * @constructor The parameters to this constructor serve as defaults and are not required.
12989 * @param {Function} fn (optional) The default function to timeout
12990 * @param {Object} scope (optional) The default scope of that timeout
12991 * @param {Array} args (optional) The default Array of arguments
12993 Roo.util.DelayedTask = function(fn, scope, args){
12994 var id = null, d, t;
12996 var call = function(){
12997 var now = new Date().getTime();
13001 fn.apply(scope, args || []);
13005 * Cancels any pending timeout and queues a new one
13006 * @param {Number} delay The milliseconds to delay
13007 * @param {Function} newFn (optional) Overrides function passed to constructor
13008 * @param {Object} newScope (optional) Overrides scope passed to constructor
13009 * @param {Array} newArgs (optional) Overrides args passed to constructor
13011 this.delay = function(delay, newFn, newScope, newArgs){
13012 if(id && delay != d){
13016 t = new Date().getTime();
13018 scope = newScope || scope;
13019 args = newArgs || args;
13021 id = setInterval(call, d);
13026 * Cancel the last queued timeout
13028 this.cancel = function(){
13036 * Ext JS Library 1.1.1
13037 * Copyright(c) 2006-2007, Ext JS, LLC.
13039 * Originally Released Under LGPL - original licence link has changed is not relivant.
13042 * <script type="text/javascript">
13046 Roo.util.TaskRunner = function(interval){
13047 interval = interval || 10;
13048 var tasks = [], removeQueue = [];
13050 var running = false;
13052 var stopThread = function(){
13058 var startThread = function(){
13061 id = setInterval(runTasks, interval);
13065 var removeTask = function(task){
13066 removeQueue.push(task);
13072 var runTasks = function(){
13073 if(removeQueue.length > 0){
13074 for(var i = 0, len = removeQueue.length; i < len; i++){
13075 tasks.remove(removeQueue[i]);
13078 if(tasks.length < 1){
13083 var now = new Date().getTime();
13084 for(var i = 0, len = tasks.length; i < len; ++i){
13086 var itime = now - t.taskRunTime;
13087 if(t.interval <= itime){
13088 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
13089 t.taskRunTime = now;
13090 if(rt === false || t.taskRunCount === t.repeat){
13095 if(t.duration && t.duration <= (now - t.taskStartTime)){
13102 * Queues a new task.
13103 * @param {Object} task
13105 this.start = function(task){
13107 task.taskStartTime = new Date().getTime();
13108 task.taskRunTime = 0;
13109 task.taskRunCount = 0;
13114 this.stop = function(task){
13119 this.stopAll = function(){
13121 for(var i = 0, len = tasks.length; i < len; i++){
13122 if(tasks[i].onStop){
13131 Roo.TaskMgr = new Roo.util.TaskRunner();/*
13133 * Ext JS Library 1.1.1
13134 * Copyright(c) 2006-2007, Ext JS, LLC.
13136 * Originally Released Under LGPL - original licence link has changed is not relivant.
13139 * <script type="text/javascript">
13144 * @class Roo.util.MixedCollection
13145 * @extends Roo.util.Observable
13146 * A Collection class that maintains both numeric indexes and keys and exposes events.
13148 * @param {Boolean} allowFunctions True if the addAll function should add function references to the
13149 * collection (defaults to false)
13150 * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
13151 * and return the key value for that item. This is used when available to look up the key on items that
13152 * were passed without an explicit key parameter to a MixedCollection method. Passing this parameter is
13153 * equivalent to providing an implementation for the {@link #getKey} method.
13155 Roo.util.MixedCollection = function(allowFunctions, keyFn){
13163 * Fires when the collection is cleared.
13168 * Fires when an item is added to the collection.
13169 * @param {Number} index The index at which the item was added.
13170 * @param {Object} o The item added.
13171 * @param {String} key The key associated with the added item.
13176 * Fires when an item is replaced in the collection.
13177 * @param {String} key he key associated with the new added.
13178 * @param {Object} old The item being replaced.
13179 * @param {Object} new The new item.
13184 * Fires when an item is removed from the collection.
13185 * @param {Object} o The item being removed.
13186 * @param {String} key (optional) The key associated with the removed item.
13191 this.allowFunctions = allowFunctions === true;
13193 this.getKey = keyFn;
13195 Roo.util.MixedCollection.superclass.constructor.call(this);
13198 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
13199 allowFunctions : false,
13202 * Adds an item to the collection.
13203 * @param {String} key The key to associate with the item
13204 * @param {Object} o The item to add.
13205 * @return {Object} The item added.
13207 add : function(key, o){
13208 if(arguments.length == 1){
13210 key = this.getKey(o);
13212 if(typeof key == "undefined" || key === null){
13214 this.items.push(o);
13215 this.keys.push(null);
13217 var old = this.map[key];
13219 return this.replace(key, o);
13222 this.items.push(o);
13224 this.keys.push(key);
13226 this.fireEvent("add", this.length-1, o, key);
13231 * MixedCollection has a generic way to fetch keys if you implement getKey.
13234 var mc = new Roo.util.MixedCollection();
13235 mc.add(someEl.dom.id, someEl);
13236 mc.add(otherEl.dom.id, otherEl);
13240 var mc = new Roo.util.MixedCollection();
13241 mc.getKey = function(el){
13247 // or via the constructor
13248 var mc = new Roo.util.MixedCollection(false, function(el){
13254 * @param o {Object} The item for which to find the key.
13255 * @return {Object} The key for the passed item.
13257 getKey : function(o){
13262 * Replaces an item in the collection.
13263 * @param {String} key The key associated with the item to replace, or the item to replace.
13264 * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
13265 * @return {Object} The new item.
13267 replace : function(key, o){
13268 if(arguments.length == 1){
13270 key = this.getKey(o);
13272 var old = this.item(key);
13273 if(typeof key == "undefined" || key === null || typeof old == "undefined"){
13274 return this.add(key, o);
13276 var index = this.indexOfKey(key);
13277 this.items[index] = o;
13279 this.fireEvent("replace", key, old, o);
13284 * Adds all elements of an Array or an Object to the collection.
13285 * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
13286 * an Array of values, each of which are added to the collection.
13288 addAll : function(objs){
13289 if(arguments.length > 1 || objs instanceof Array){
13290 var args = arguments.length > 1 ? arguments : objs;
13291 for(var i = 0, len = args.length; i < len; i++){
13295 for(var key in objs){
13296 if(this.allowFunctions || typeof objs[key] != "function"){
13297 this.add(key, objs[key]);
13304 * Executes the specified function once for every item in the collection, passing each
13305 * item as the first and only parameter. returning false from the function will stop the iteration.
13306 * @param {Function} fn The function to execute for each item.
13307 * @param {Object} scope (optional) The scope in which to execute the function.
13309 each : function(fn, scope){
13310 var items = [].concat(this.items); // each safe for removal
13311 for(var i = 0, len = items.length; i < len; i++){
13312 if(fn.call(scope || items[i], items[i], i, len) === false){
13319 * Executes the specified function once for every key in the collection, passing each
13320 * key, and its associated item as the first two parameters.
13321 * @param {Function} fn The function to execute for each item.
13322 * @param {Object} scope (optional) The scope in which to execute the function.
13324 eachKey : function(fn, scope){
13325 for(var i = 0, len = this.keys.length; i < len; i++){
13326 fn.call(scope || window, this.keys[i], this.items[i], i, len);
13331 * Returns the first item in the collection which elicits a true return value from the
13332 * passed selection function.
13333 * @param {Function} fn The selection function to execute for each item.
13334 * @param {Object} scope (optional) The scope in which to execute the function.
13335 * @return {Object} The first item in the collection which returned true from the selection function.
13337 find : function(fn, scope){
13338 for(var i = 0, len = this.items.length; i < len; i++){
13339 if(fn.call(scope || window, this.items[i], this.keys[i])){
13340 return this.items[i];
13347 * Inserts an item at the specified index in the collection.
13348 * @param {Number} index The index to insert the item at.
13349 * @param {String} key The key to associate with the new item, or the item itself.
13350 * @param {Object} o (optional) If the second parameter was a key, the new item.
13351 * @return {Object} The item inserted.
13353 insert : function(index, key, o){
13354 if(arguments.length == 2){
13356 key = this.getKey(o);
13358 if(index >= this.length){
13359 return this.add(key, o);
13362 this.items.splice(index, 0, o);
13363 if(typeof key != "undefined" && key != null){
13366 this.keys.splice(index, 0, key);
13367 this.fireEvent("add", index, o, key);
13372 * Removed an item from the collection.
13373 * @param {Object} o The item to remove.
13374 * @return {Object} The item removed.
13376 remove : function(o){
13377 return this.removeAt(this.indexOf(o));
13381 * Remove an item from a specified index in the collection.
13382 * @param {Number} index The index within the collection of the item to remove.
13384 removeAt : function(index){
13385 if(index < this.length && index >= 0){
13387 var o = this.items[index];
13388 this.items.splice(index, 1);
13389 var key = this.keys[index];
13390 if(typeof key != "undefined"){
13391 delete this.map[key];
13393 this.keys.splice(index, 1);
13394 this.fireEvent("remove", o, key);
13399 * Removed an item associated with the passed key fom the collection.
13400 * @param {String} key The key of the item to remove.
13402 removeKey : function(key){
13403 return this.removeAt(this.indexOfKey(key));
13407 * Returns the number of items in the collection.
13408 * @return {Number} the number of items in the collection.
13410 getCount : function(){
13411 return this.length;
13415 * Returns index within the collection of the passed Object.
13416 * @param {Object} o The item to find the index of.
13417 * @return {Number} index of the item.
13419 indexOf : function(o){
13420 if(!this.items.indexOf){
13421 for(var i = 0, len = this.items.length; i < len; i++){
13422 if(this.items[i] == o) {
13428 return this.items.indexOf(o);
13433 * Returns index within the collection of the passed key.
13434 * @param {String} key The key to find the index of.
13435 * @return {Number} index of the key.
13437 indexOfKey : function(key){
13438 if(!this.keys.indexOf){
13439 for(var i = 0, len = this.keys.length; i < len; i++){
13440 if(this.keys[i] == key) {
13446 return this.keys.indexOf(key);
13451 * Returns the item associated with the passed key OR index. Key has priority over index.
13452 * @param {String/Number} key The key or index of the item.
13453 * @return {Object} The item associated with the passed key.
13455 item : function(key){
13456 if (key === 'length') {
13459 var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13460 return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13464 * Returns the item at the specified index.
13465 * @param {Number} index The index of the item.
13468 itemAt : function(index){
13469 return this.items[index];
13473 * Returns the item associated with the passed key.
13474 * @param {String/Number} key The key of the item.
13475 * @return {Object} The item associated with the passed key.
13477 key : function(key){
13478 return this.map[key];
13482 * Returns true if the collection contains the passed Object as an item.
13483 * @param {Object} o The Object to look for in the collection.
13484 * @return {Boolean} True if the collection contains the Object as an item.
13486 contains : function(o){
13487 return this.indexOf(o) != -1;
13491 * Returns true if the collection contains the passed Object as a key.
13492 * @param {String} key The key to look for in the collection.
13493 * @return {Boolean} True if the collection contains the Object as a key.
13495 containsKey : function(key){
13496 return typeof this.map[key] != "undefined";
13500 * Removes all items from the collection.
13502 clear : function(){
13507 this.fireEvent("clear");
13511 * Returns the first item in the collection.
13512 * @return {Object} the first item in the collection..
13514 first : function(){
13515 return this.items[0];
13519 * Returns the last item in the collection.
13520 * @return {Object} the last item in the collection..
13523 return this.items[this.length-1];
13526 _sort : function(property, dir, fn){
13527 var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13528 fn = fn || function(a, b){
13531 var c = [], k = this.keys, items = this.items;
13532 for(var i = 0, len = items.length; i < len; i++){
13533 c[c.length] = {key: k[i], value: items[i], index: i};
13535 c.sort(function(a, b){
13536 var v = fn(a[property], b[property]) * dsc;
13538 v = (a.index < b.index ? -1 : 1);
13542 for(var i = 0, len = c.length; i < len; i++){
13543 items[i] = c[i].value;
13546 this.fireEvent("sort", this);
13550 * Sorts this collection with the passed comparison function
13551 * @param {String} direction (optional) "ASC" or "DESC"
13552 * @param {Function} fn (optional) comparison function
13554 sort : function(dir, fn){
13555 this._sort("value", dir, fn);
13559 * Sorts this collection by keys
13560 * @param {String} direction (optional) "ASC" or "DESC"
13561 * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13563 keySort : function(dir, fn){
13564 this._sort("key", dir, fn || function(a, b){
13565 return String(a).toUpperCase()-String(b).toUpperCase();
13570 * Returns a range of items in this collection
13571 * @param {Number} startIndex (optional) defaults to 0
13572 * @param {Number} endIndex (optional) default to the last item
13573 * @return {Array} An array of items
13575 getRange : function(start, end){
13576 var items = this.items;
13577 if(items.length < 1){
13580 start = start || 0;
13581 end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13584 for(var i = start; i <= end; i++) {
13585 r[r.length] = items[i];
13588 for(var i = start; i >= end; i--) {
13589 r[r.length] = items[i];
13596 * Filter the <i>objects</i> in this collection by a specific property.
13597 * Returns a new collection that has been filtered.
13598 * @param {String} property A property on your objects
13599 * @param {String/RegExp} value Either string that the property values
13600 * should start with or a RegExp to test against the property
13601 * @return {MixedCollection} The new filtered collection
13603 filter : function(property, value){
13604 if(!value.exec){ // not a regex
13605 value = String(value);
13606 if(value.length == 0){
13607 return this.clone();
13609 value = new RegExp("^" + Roo.escapeRe(value), "i");
13611 return this.filterBy(function(o){
13612 return o && value.test(o[property]);
13617 * Filter by a function. * Returns a new collection that has been filtered.
13618 * The passed function will be called with each
13619 * object in the collection. If the function returns true, the value is included
13620 * otherwise it is filtered.
13621 * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13622 * @param {Object} scope (optional) The scope of the function (defaults to this)
13623 * @return {MixedCollection} The new filtered collection
13625 filterBy : function(fn, scope){
13626 var r = new Roo.util.MixedCollection();
13627 r.getKey = this.getKey;
13628 var k = this.keys, it = this.items;
13629 for(var i = 0, len = it.length; i < len; i++){
13630 if(fn.call(scope||this, it[i], k[i])){
13631 r.add(k[i], it[i]);
13638 * Creates a duplicate of this collection
13639 * @return {MixedCollection}
13641 clone : function(){
13642 var r = new Roo.util.MixedCollection();
13643 var k = this.keys, it = this.items;
13644 for(var i = 0, len = it.length; i < len; i++){
13645 r.add(k[i], it[i]);
13647 r.getKey = this.getKey;
13652 * Returns the item associated with the passed key or index.
13654 * @param {String/Number} key The key or index of the item.
13655 * @return {Object} The item associated with the passed key.
13657 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13659 * Ext JS Library 1.1.1
13660 * Copyright(c) 2006-2007, Ext JS, LLC.
13662 * Originally Released Under LGPL - original licence link has changed is not relivant.
13665 * <script type="text/javascript">
13668 * @class Roo.util.JSON
13669 * Modified version of Douglas Crockford"s json.js that doesn"t
13670 * mess with the Object prototype
13671 * http://www.json.org/js.html
13674 Roo.util.JSON = new (function(){
13675 var useHasOwn = {}.hasOwnProperty ? true : false;
13677 // crashes Safari in some instances
13678 //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13680 var pad = function(n) {
13681 return n < 10 ? "0" + n : n;
13694 var encodeString = function(s){
13695 if (/["\\\x00-\x1f]/.test(s)) {
13696 return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13701 c = b.charCodeAt();
13703 Math.floor(c / 16).toString(16) +
13704 (c % 16).toString(16);
13707 return '"' + s + '"';
13710 var encodeArray = function(o){
13711 var a = ["["], b, i, l = o.length, v;
13712 for (i = 0; i < l; i += 1) {
13714 switch (typeof v) {
13723 a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13731 var encodeDate = function(o){
13732 return '"' + o.getFullYear() + "-" +
13733 pad(o.getMonth() + 1) + "-" +
13734 pad(o.getDate()) + "T" +
13735 pad(o.getHours()) + ":" +
13736 pad(o.getMinutes()) + ":" +
13737 pad(o.getSeconds()) + '"';
13741 * Encodes an Object, Array or other value
13742 * @param {Mixed} o The variable to encode
13743 * @return {String} The JSON string
13745 this.encode = function(o)
13747 // should this be extended to fully wrap stringify..
13749 if(typeof o == "undefined" || o === null){
13751 }else if(o instanceof Array){
13752 return encodeArray(o);
13753 }else if(o instanceof Date){
13754 return encodeDate(o);
13755 }else if(typeof o == "string"){
13756 return encodeString(o);
13757 }else if(typeof o == "number"){
13758 return isFinite(o) ? String(o) : "null";
13759 }else if(typeof o == "boolean"){
13762 var a = ["{"], b, i, v;
13764 if(!useHasOwn || o.hasOwnProperty(i)) {
13766 switch (typeof v) {
13775 a.push(this.encode(i), ":",
13776 v === null ? "null" : this.encode(v));
13787 * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13788 * @param {String} json The JSON string
13789 * @return {Object} The resulting object
13791 this.decode = function(json){
13793 return /** eval:var:json */ eval("(" + json + ')');
13797 * Shorthand for {@link Roo.util.JSON#encode}
13798 * @member Roo encode
13800 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13802 * Shorthand for {@link Roo.util.JSON#decode}
13803 * @member Roo decode
13805 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13808 * Ext JS Library 1.1.1
13809 * Copyright(c) 2006-2007, Ext JS, LLC.
13811 * Originally Released Under LGPL - original licence link has changed is not relivant.
13814 * <script type="text/javascript">
13818 * @class Roo.util.Format
13819 * Reusable data formatting functions
13822 Roo.util.Format = function(){
13823 var trimRe = /^\s+|\s+$/g;
13826 * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13827 * @param {String} value The string to truncate
13828 * @param {Number} length The maximum length to allow before truncating
13829 * @return {String} The converted text
13831 ellipsis : function(value, len){
13832 if(value && value.length > len){
13833 return value.substr(0, len-3)+"...";
13839 * Checks a reference and converts it to empty string if it is undefined
13840 * @param {Mixed} value Reference to check
13841 * @return {Mixed} Empty string if converted, otherwise the original value
13843 undef : function(value){
13844 return typeof value != "undefined" ? value : "";
13848 * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13849 * @param {String} value The string to encode
13850 * @return {String} The encoded text
13852 htmlEncode : function(value){
13853 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
13857 * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13858 * @param {String} value The string to decode
13859 * @return {String} The decoded text
13861 htmlDecode : function(value){
13862 return !value ? value : String(value).replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, '"');
13866 * Trims any whitespace from either side of a string
13867 * @param {String} value The text to trim
13868 * @return {String} The trimmed text
13870 trim : function(value){
13871 return String(value).replace(trimRe, "");
13875 * Returns a substring from within an original string
13876 * @param {String} value The original text
13877 * @param {Number} start The start index of the substring
13878 * @param {Number} length The length of the substring
13879 * @return {String} The substring
13881 substr : function(value, start, length){
13882 return String(value).substr(start, length);
13886 * Converts a string to all lower case letters
13887 * @param {String} value The text to convert
13888 * @return {String} The converted text
13890 lowercase : function(value){
13891 return String(value).toLowerCase();
13895 * Converts a string to all upper case letters
13896 * @param {String} value The text to convert
13897 * @return {String} The converted text
13899 uppercase : function(value){
13900 return String(value).toUpperCase();
13904 * Converts the first character only of a string to upper case
13905 * @param {String} value The text to convert
13906 * @return {String} The converted text
13908 capitalize : function(value){
13909 return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13913 call : function(value, fn){
13914 if(arguments.length > 2){
13915 var args = Array.prototype.slice.call(arguments, 2);
13916 args.unshift(value);
13918 return /** eval:var:value */ eval(fn).apply(window, args);
13920 /** eval:var:value */
13921 return /** eval:var:value */ eval(fn).call(window, value);
13927 * safer version of Math.toFixed..??/
13928 * @param {Number/String} value The numeric value to format
13929 * @param {Number/String} value Decimal places
13930 * @return {String} The formatted currency string
13932 toFixed : function(v, n)
13934 // why not use to fixed - precision is buggered???
13936 return Math.round(v-0);
13938 var fact = Math.pow(10,n+1);
13939 v = (Math.round((v-0)*fact))/fact;
13940 var z = (''+fact).substring(2);
13941 if (v == Math.floor(v)) {
13942 return Math.floor(v) + '.' + z;
13945 // now just padd decimals..
13946 var ps = String(v).split('.');
13947 var fd = (ps[1] + z);
13948 var r = fd.substring(0,n);
13949 var rm = fd.substring(n);
13951 return ps[0] + '.' + r;
13953 r*=1; // turn it into a number;
13955 if (String(r).length != n) {
13958 r = String(r).substring(1); // chop the end off.
13961 return ps[0] + '.' + r;
13966 * Format a number as US currency
13967 * @param {Number/String} value The numeric value to format
13968 * @return {String} The formatted currency string
13970 usMoney : function(v){
13971 return '$' + Roo.util.Format.number(v);
13976 * eventually this should probably emulate php's number_format
13977 * @param {Number/String} value The numeric value to format
13978 * @param {Number} decimals number of decimal places
13979 * @param {String} delimiter for thousands (default comma)
13980 * @return {String} The formatted currency string
13982 number : function(v, decimals, thousandsDelimiter)
13984 // multiply and round.
13985 decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13986 thousandsDelimiter = typeof(thousandsDelimiter) == 'undefined' ? ',' : thousandsDelimiter;
13988 var mul = Math.pow(10, decimals);
13989 var zero = String(mul).substring(1);
13990 v = (Math.round((v-0)*mul))/mul;
13992 // if it's '0' number.. then
13994 //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13996 var ps = v.split('.');
13999 var r = /(\d+)(\d{3})/;
14002 if(thousandsDelimiter.length != 0) {
14003 whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, thousandsDelimiter );
14008 (decimals ? ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
14009 // does not have decimals
14010 (decimals ? ('.' + zero) : '');
14013 return whole + sub ;
14017 * Parse a value into a formatted date using the specified format pattern.
14018 * @param {Mixed} value The value to format
14019 * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
14020 * @return {String} The formatted date string
14022 date : function(v, format){
14026 if(!(v instanceof Date)){
14027 v = new Date(Date.parse(v));
14029 return v.dateFormat(format || Roo.util.Format.defaults.date);
14033 * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
14034 * @param {String} format Any valid date format string
14035 * @return {Function} The date formatting function
14037 dateRenderer : function(format){
14038 return function(v){
14039 return Roo.util.Format.date(v, format);
14044 stripTagsRE : /<\/?[^>]+>/gi,
14047 * Strips all HTML tags
14048 * @param {Mixed} value The text from which to strip tags
14049 * @return {String} The stripped text
14051 stripTags : function(v){
14052 return !v ? v : String(v).replace(this.stripTagsRE, "");
14056 * Size in Mb,Gb etc.
14057 * @param {Number} value The number to be formated
14058 * @param {number} decimals how many decimal places
14059 * @return {String} the formated string
14061 size : function(value, decimals)
14063 var sizes = ['b', 'k', 'M', 'G', 'T'];
14067 var i = parseInt(Math.floor(Math.log(value) / Math.log(1024)));
14068 return Roo.util.Format.number(value/ Math.pow(1024, i) ,decimals) + sizes[i];
14075 Roo.util.Format.defaults = {
14079 * Ext JS Library 1.1.1
14080 * Copyright(c) 2006-2007, Ext JS, LLC.
14082 * Originally Released Under LGPL - original licence link has changed is not relivant.
14085 * <script type="text/javascript">
14092 * @class Roo.MasterTemplate
14093 * @extends Roo.Template
14094 * Provides a template that can have child templates. The syntax is:
14096 var t = new Roo.MasterTemplate(
14097 '<select name="{name}">',
14098 '<tpl name="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
14101 t.add('options', {value: 'foo', text: 'bar'});
14102 // or you can add multiple child elements in one shot
14103 t.addAll('options', [
14104 {value: 'foo', text: 'bar'},
14105 {value: 'foo2', text: 'bar2'},
14106 {value: 'foo3', text: 'bar3'}
14108 // then append, applying the master template values
14109 t.append('my-form', {name: 'my-select'});
14111 * A name attribute for the child template is not required if you have only one child
14112 * template or you want to refer to them by index.
14114 Roo.MasterTemplate = function(){
14115 Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
14116 this.originalHtml = this.html;
14118 var m, re = this.subTemplateRe;
14121 while(m = re.exec(this.html)){
14122 var name = m[1], content = m[2];
14127 tpl : new Roo.Template(content)
14130 st[name] = st[subIndex];
14132 st[subIndex].tpl.compile();
14133 st[subIndex].tpl.call = this.call.createDelegate(this);
14136 this.subCount = subIndex;
14139 Roo.extend(Roo.MasterTemplate, Roo.Template, {
14141 * The regular expression used to match sub templates
14145 subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
14148 * Applies the passed values to a child template.
14149 * @param {String/Number} name (optional) The name or index of the child template
14150 * @param {Array/Object} values The values to be applied to the template
14151 * @return {MasterTemplate} this
14153 add : function(name, values){
14154 if(arguments.length == 1){
14155 values = arguments[0];
14158 var s = this.subs[name];
14159 s.buffer[s.buffer.length] = s.tpl.apply(values);
14164 * Applies all the passed values to a child template.
14165 * @param {String/Number} name (optional) The name or index of the child template
14166 * @param {Array} values The values to be applied to the template, this should be an array of objects.
14167 * @param {Boolean} reset (optional) True to reset the template first
14168 * @return {MasterTemplate} this
14170 fill : function(name, values, reset){
14172 if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
14180 for(var i = 0, len = values.length; i < len; i++){
14181 this.add(name, values[i]);
14187 * Resets the template for reuse
14188 * @return {MasterTemplate} this
14190 reset : function(){
14192 for(var i = 0; i < this.subCount; i++){
14198 applyTemplate : function(values){
14200 var replaceIndex = -1;
14201 this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
14202 return s[++replaceIndex].buffer.join("");
14204 return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
14207 apply : function(){
14208 return this.applyTemplate.apply(this, arguments);
14211 compile : function(){return this;}
14215 * Alias for fill().
14218 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
14220 * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
14221 * var tpl = Roo.MasterTemplate.from('element-id');
14222 * @param {String/HTMLElement} el
14223 * @param {Object} config
14226 Roo.MasterTemplate.from = function(el, config){
14227 el = Roo.getDom(el);
14228 return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
14231 * Ext JS Library 1.1.1
14232 * Copyright(c) 2006-2007, Ext JS, LLC.
14234 * Originally Released Under LGPL - original licence link has changed is not relivant.
14237 * <script type="text/javascript">
14242 * @class Roo.util.CSS
14243 * Utility class for manipulating CSS rules
14246 Roo.util.CSS = function(){
14248 var doc = document;
14250 var camelRe = /(-[a-z])/gi;
14251 var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
14255 * Very simple dynamic creation of stylesheets from a text blob of rules. The text will wrapped in a style
14256 * tag and appended to the HEAD of the document.
14257 * @param {String|Object} cssText The text containing the css rules
14258 * @param {String} id An id to add to the stylesheet for later removal
14259 * @return {StyleSheet}
14261 createStyleSheet : function(cssText, id){
14263 var head = doc.getElementsByTagName("head")[0];
14264 var nrules = doc.createElement("style");
14265 nrules.setAttribute("type", "text/css");
14267 nrules.setAttribute("id", id);
14269 if (typeof(cssText) != 'string') {
14270 // support object maps..
14271 // not sure if this a good idea..
14272 // perhaps it should be merged with the general css handling
14273 // and handle js style props.
14274 var cssTextNew = [];
14275 for(var n in cssText) {
14277 for(var k in cssText[n]) {
14278 citems.push( k + ' : ' +cssText[n][k] + ';' );
14280 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
14283 cssText = cssTextNew.join("\n");
14289 head.appendChild(nrules);
14290 ss = nrules.styleSheet;
14291 ss.cssText = cssText;
14294 nrules.appendChild(doc.createTextNode(cssText));
14296 nrules.cssText = cssText;
14298 head.appendChild(nrules);
14299 ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
14301 this.cacheStyleSheet(ss);
14306 * Removes a style or link tag by id
14307 * @param {String} id The id of the tag
14309 removeStyleSheet : function(id){
14310 var existing = doc.getElementById(id);
14312 existing.parentNode.removeChild(existing);
14317 * Dynamically swaps an existing stylesheet reference for a new one
14318 * @param {String} id The id of an existing link tag to remove
14319 * @param {String} url The href of the new stylesheet to include
14321 swapStyleSheet : function(id, url){
14322 this.removeStyleSheet(id);
14323 var ss = doc.createElement("link");
14324 ss.setAttribute("rel", "stylesheet");
14325 ss.setAttribute("type", "text/css");
14326 ss.setAttribute("id", id);
14327 ss.setAttribute("href", url);
14328 doc.getElementsByTagName("head")[0].appendChild(ss);
14332 * Refresh the rule cache if you have dynamically added stylesheets
14333 * @return {Object} An object (hash) of rules indexed by selector
14335 refreshCache : function(){
14336 return this.getRules(true);
14340 cacheStyleSheet : function(stylesheet){
14344 try{// try catch for cross domain access issue
14345 var ssRules = stylesheet.cssRules || stylesheet.rules;
14346 for(var j = ssRules.length-1; j >= 0; --j){
14347 rules[ssRules[j].selectorText] = ssRules[j];
14353 * Gets all css rules for the document
14354 * @param {Boolean} refreshCache true to refresh the internal cache
14355 * @return {Object} An object (hash) of rules indexed by selector
14357 getRules : function(refreshCache){
14358 if(rules == null || refreshCache){
14360 var ds = doc.styleSheets;
14361 for(var i =0, len = ds.length; i < len; i++){
14363 this.cacheStyleSheet(ds[i]);
14371 * Gets an an individual CSS rule by selector(s)
14372 * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14373 * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14374 * @return {CSSRule} The CSS rule or null if one is not found
14376 getRule : function(selector, refreshCache){
14377 var rs = this.getRules(refreshCache);
14378 if(!(selector instanceof Array)){
14379 return rs[selector];
14381 for(var i = 0; i < selector.length; i++){
14382 if(rs[selector[i]]){
14383 return rs[selector[i]];
14391 * Updates a rule property
14392 * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14393 * @param {String} property The css property
14394 * @param {String} value The new value for the property
14395 * @return {Boolean} true If a rule was found and updated
14397 updateRule : function(selector, property, value){
14398 if(!(selector instanceof Array)){
14399 var rule = this.getRule(selector);
14401 rule.style[property.replace(camelRe, camelFn)] = value;
14405 for(var i = 0; i < selector.length; i++){
14406 if(this.updateRule(selector[i], property, value)){
14416 * Ext JS Library 1.1.1
14417 * Copyright(c) 2006-2007, Ext JS, LLC.
14419 * Originally Released Under LGPL - original licence link has changed is not relivant.
14422 * <script type="text/javascript">
14428 * @class Roo.util.ClickRepeater
14429 * @extends Roo.util.Observable
14431 * A wrapper class which can be applied to any element. Fires a "click" event while the
14432 * mouse is pressed. The interval between firings may be specified in the config but
14433 * defaults to 10 milliseconds.
14435 * Optionally, a CSS class may be applied to the element during the time it is pressed.
14437 * @cfg {String/HTMLElement/Element} el The element to act as a button.
14438 * @cfg {Number} delay The initial delay before the repeating event begins firing.
14439 * Similar to an autorepeat key delay.
14440 * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14441 * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14442 * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14443 * "interval" and "delay" are ignored. "immediate" is honored.
14444 * @cfg {Boolean} preventDefault True to prevent the default click event
14445 * @cfg {Boolean} stopDefault True to stop the default click event
14448 * 2007-02-02 jvs Original code contributed by Nige "Animal" White
14449 * 2007-02-02 jvs Renamed to ClickRepeater
14450 * 2007-02-03 jvs Modifications for FF Mac and Safari
14453 * @param {String/HTMLElement/Element} el The element to listen on
14454 * @param {Object} config
14456 Roo.util.ClickRepeater = function(el, config)
14458 this.el = Roo.get(el);
14459 this.el.unselectable();
14461 Roo.apply(this, config);
14466 * Fires when the mouse button is depressed.
14467 * @param {Roo.util.ClickRepeater} this
14469 "mousedown" : true,
14472 * Fires on a specified interval during the time the element is pressed.
14473 * @param {Roo.util.ClickRepeater} this
14478 * Fires when the mouse key is released.
14479 * @param {Roo.util.ClickRepeater} this
14484 this.el.on("mousedown", this.handleMouseDown, this);
14485 if(this.preventDefault || this.stopDefault){
14486 this.el.on("click", function(e){
14487 if(this.preventDefault){
14488 e.preventDefault();
14490 if(this.stopDefault){
14496 // allow inline handler
14498 this.on("click", this.handler, this.scope || this);
14501 Roo.util.ClickRepeater.superclass.constructor.call(this);
14504 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14507 preventDefault : true,
14508 stopDefault : false,
14512 handleMouseDown : function(){
14513 clearTimeout(this.timer);
14515 if(this.pressClass){
14516 this.el.addClass(this.pressClass);
14518 this.mousedownTime = new Date();
14520 Roo.get(document).on("mouseup", this.handleMouseUp, this);
14521 this.el.on("mouseout", this.handleMouseOut, this);
14523 this.fireEvent("mousedown", this);
14524 this.fireEvent("click", this);
14526 this.timer = this.click.defer(this.delay || this.interval, this);
14530 click : function(){
14531 this.fireEvent("click", this);
14532 this.timer = this.click.defer(this.getInterval(), this);
14536 getInterval: function(){
14537 if(!this.accelerate){
14538 return this.interval;
14540 var pressTime = this.mousedownTime.getElapsed();
14541 if(pressTime < 500){
14543 }else if(pressTime < 1700){
14545 }else if(pressTime < 2600){
14547 }else if(pressTime < 3500){
14549 }else if(pressTime < 4400){
14551 }else if(pressTime < 5300){
14553 }else if(pressTime < 6200){
14561 handleMouseOut : function(){
14562 clearTimeout(this.timer);
14563 if(this.pressClass){
14564 this.el.removeClass(this.pressClass);
14566 this.el.on("mouseover", this.handleMouseReturn, this);
14570 handleMouseReturn : function(){
14571 this.el.un("mouseover", this.handleMouseReturn);
14572 if(this.pressClass){
14573 this.el.addClass(this.pressClass);
14579 handleMouseUp : function(){
14580 clearTimeout(this.timer);
14581 this.el.un("mouseover", this.handleMouseReturn);
14582 this.el.un("mouseout", this.handleMouseOut);
14583 Roo.get(document).un("mouseup", this.handleMouseUp);
14584 this.el.removeClass(this.pressClass);
14585 this.fireEvent("mouseup", this);
14588 * @class Roo.util.Clipboard
14594 Roo.util.Clipboard = {
14596 * Writes a string to the clipboard - using the Clipboard API if https, otherwise using text area.
14597 * @param {String} text to copy to clipboard
14599 write : function(text) {
14600 // navigator clipboard api needs a secure context (https)
14601 if (navigator.clipboard && window.isSecureContext) {
14602 // navigator clipboard api method'
14603 navigator.clipboard.writeText(text);
14606 // text area method
14607 var ta = document.createElement("textarea");
14609 // make the textarea out of viewport
14610 ta.style.position = "fixed";
14611 ta.style.left = "-999999px";
14612 ta.style.top = "-999999px";
14613 document.body.appendChild(ta);
14616 document.execCommand('copy');
14626 * Ext JS Library 1.1.1
14627 * Copyright(c) 2006-2007, Ext JS, LLC.
14629 * Originally Released Under LGPL - original licence link has changed is not relivant.
14632 * <script type="text/javascript">
14637 * @class Roo.KeyNav
14638 * <p>Provides a convenient wrapper for normalized keyboard navigation. KeyNav allows you to bind
14639 * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14640 * way to implement custom navigation schemes for any UI component.</p>
14641 * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14642 * pageUp, pageDown, del, home, end. Usage:</p>
14644 var nav = new Roo.KeyNav("my-element", {
14645 "left" : function(e){
14646 this.moveLeft(e.ctrlKey);
14648 "right" : function(e){
14649 this.moveRight(e.ctrlKey);
14651 "enter" : function(e){
14658 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14659 * @param {Object} config The config
14661 Roo.KeyNav = function(el, config){
14662 this.el = Roo.get(el);
14663 Roo.apply(this, config);
14664 if(!this.disabled){
14665 this.disabled = true;
14670 Roo.KeyNav.prototype = {
14672 * @cfg {Boolean} disabled
14673 * True to disable this KeyNav instance (defaults to false)
14677 * @cfg {String} defaultEventAction
14678 * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key. Valid values are
14679 * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14680 * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14682 defaultEventAction: "stopEvent",
14684 * @cfg {Boolean} forceKeyDown
14685 * Handle the keydown event instead of keypress (defaults to false). KeyNav automatically does this for IE since
14686 * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14687 * handle keydown instead of keypress.
14689 forceKeyDown : false,
14692 prepareEvent : function(e){
14693 var k = e.getKey();
14694 var h = this.keyToHandler[k];
14695 //if(h && this[h]){
14696 // e.stopPropagation();
14698 if(Roo.isSafari && h && k >= 37 && k <= 40){
14704 relay : function(e){
14705 var k = e.getKey();
14706 var h = this.keyToHandler[k];
14708 if(this.doRelay(e, this[h], h) !== true){
14709 e[this.defaultEventAction]();
14715 doRelay : function(e, h, hname){
14716 return h.call(this.scope || this, e);
14719 // possible handlers
14733 // quick lookup hash
14750 * Enable this KeyNav
14752 enable: function(){
14754 // ie won't do special keys on keypress, no one else will repeat keys with keydown
14755 // the EventObject will normalize Safari automatically
14756 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14757 this.el.on("keydown", this.relay, this);
14759 this.el.on("keydown", this.prepareEvent, this);
14760 this.el.on("keypress", this.relay, this);
14762 this.disabled = false;
14767 * Disable this KeyNav
14769 disable: function(){
14770 if(!this.disabled){
14771 if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14772 this.el.un("keydown", this.relay);
14774 this.el.un("keydown", this.prepareEvent);
14775 this.el.un("keypress", this.relay);
14777 this.disabled = true;
14782 * Ext JS Library 1.1.1
14783 * Copyright(c) 2006-2007, Ext JS, LLC.
14785 * Originally Released Under LGPL - original licence link has changed is not relivant.
14788 * <script type="text/javascript">
14793 * @class Roo.KeyMap
14794 * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14795 * The constructor accepts the same config object as defined by {@link #addBinding}.
14796 * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14797 * combination it will call the function with this signature (if the match is a multi-key
14798 * combination the callback will still be called only once): (String key, Roo.EventObject e)
14799 * A KeyMap can also handle a string representation of keys.<br />
14802 // map one key by key code
14803 var map = new Roo.KeyMap("my-element", {
14804 key: 13, // or Roo.EventObject.ENTER
14809 // map multiple keys to one action by string
14810 var map = new Roo.KeyMap("my-element", {
14816 // map multiple keys to multiple actions by strings and array of codes
14817 var map = new Roo.KeyMap("my-element", [
14820 fn: function(){ alert("Return was pressed"); }
14823 fn: function(){ alert('a, b or c was pressed'); }
14828 fn: function(){ alert('Control + shift + tab was pressed.'); }
14832 * <b>Note: A KeyMap starts enabled</b>
14834 * @param {String/HTMLElement/Roo.Element} el The element to bind to
14835 * @param {Object} config The config (see {@link #addBinding})
14836 * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14838 Roo.KeyMap = function(el, config, eventName){
14839 this.el = Roo.get(el);
14840 this.eventName = eventName || "keydown";
14841 this.bindings = [];
14843 this.addBinding(config);
14848 Roo.KeyMap.prototype = {
14850 * True to stop the event from bubbling and prevent the default browser action if the
14851 * key was handled by the KeyMap (defaults to false)
14857 * Add a new binding to this KeyMap. The following config object properties are supported:
14859 Property Type Description
14860 ---------- --------------- ----------------------------------------------------------------------
14861 key String/Array A single keycode or an array of keycodes to handle
14862 shift Boolean True to handle key only when shift is pressed (defaults to false)
14863 ctrl Boolean True to handle key only when ctrl is pressed (defaults to false)
14864 alt Boolean True to handle key only when alt is pressed (defaults to false)
14865 fn Function The function to call when KeyMap finds the expected key combination
14866 scope Object The scope of the callback function
14872 var map = new Roo.KeyMap(document, {
14873 key: Roo.EventObject.ENTER,
14878 //Add a new binding to the existing KeyMap later
14886 * @param {Object/Array} config A single KeyMap config or an array of configs
14888 addBinding : function(config){
14889 if(config instanceof Array){
14890 for(var i = 0, len = config.length; i < len; i++){
14891 this.addBinding(config[i]);
14895 var keyCode = config.key,
14896 shift = config.shift,
14897 ctrl = config.ctrl,
14900 scope = config.scope;
14901 if(typeof keyCode == "string"){
14903 var keyString = keyCode.toUpperCase();
14904 for(var j = 0, len = keyString.length; j < len; j++){
14905 ks.push(keyString.charCodeAt(j));
14909 var keyArray = keyCode instanceof Array;
14910 var handler = function(e){
14911 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14912 var k = e.getKey();
14914 for(var i = 0, len = keyCode.length; i < len; i++){
14915 if(keyCode[i] == k){
14916 if(this.stopEvent){
14919 fn.call(scope || window, k, e);
14925 if(this.stopEvent){
14928 fn.call(scope || window, k, e);
14933 this.bindings.push(handler);
14937 * Shorthand for adding a single key listener
14938 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14939 * following options:
14940 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14941 * @param {Function} fn The function to call
14942 * @param {Object} scope (optional) The scope of the function
14944 on : function(key, fn, scope){
14945 var keyCode, shift, ctrl, alt;
14946 if(typeof key == "object" && !(key instanceof Array)){
14965 handleKeyDown : function(e){
14966 if(this.enabled){ //just in case
14967 var b = this.bindings;
14968 for(var i = 0, len = b.length; i < len; i++){
14969 b[i].call(this, e);
14975 * Returns true if this KeyMap is enabled
14976 * @return {Boolean}
14978 isEnabled : function(){
14979 return this.enabled;
14983 * Enables this KeyMap
14985 enable: function(){
14987 this.el.on(this.eventName, this.handleKeyDown, this);
14988 this.enabled = true;
14993 * Disable this KeyMap
14995 disable: function(){
14997 this.el.removeListener(this.eventName, this.handleKeyDown, this);
14998 this.enabled = false;
15003 * Ext JS Library 1.1.1
15004 * Copyright(c) 2006-2007, Ext JS, LLC.
15006 * Originally Released Under LGPL - original licence link has changed is not relivant.
15009 * <script type="text/javascript">
15014 * @class Roo.util.TextMetrics
15015 * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
15016 * wide, in pixels, a given block of text will be.
15019 Roo.util.TextMetrics = function(){
15023 * Measures the size of the specified text
15024 * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
15025 * that can affect the size of the rendered text
15026 * @param {String} text The text to measure
15027 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15028 * in order to accurately measure the text height
15029 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15031 measure : function(el, text, fixedWidth){
15033 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
15036 shared.setFixedWidth(fixedWidth || 'auto');
15037 return shared.getSize(text);
15041 * Return a unique TextMetrics instance that can be bound directly to an element and reused. This reduces
15042 * the overhead of multiple calls to initialize the style properties on each measurement.
15043 * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
15044 * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
15045 * in order to accurately measure the text height
15046 * @return {Roo.util.TextMetrics.Instance} instance The new instance
15048 createInstance : function(el, fixedWidth){
15049 return Roo.util.TextMetrics.Instance(el, fixedWidth);
15056 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
15057 var ml = new Roo.Element(document.createElement('div'));
15058 document.body.appendChild(ml.dom);
15059 ml.position('absolute');
15060 ml.setLeftTop(-1000, -1000);
15064 ml.setWidth(fixedWidth);
15069 * Returns the size of the specified text based on the internal element's style and width properties
15070 * @memberOf Roo.util.TextMetrics.Instance#
15071 * @param {String} text The text to measure
15072 * @return {Object} An object containing the text's size {width: (width), height: (height)}
15074 getSize : function(text){
15076 var s = ml.getSize();
15082 * Binds this TextMetrics instance to an element from which to copy existing CSS styles
15083 * that can affect the size of the rendered text
15084 * @memberOf Roo.util.TextMetrics.Instance#
15085 * @param {String/HTMLElement} el The element, dom node or id
15087 bind : function(el){
15089 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
15094 * Sets a fixed width on the internal measurement element. If the text will be multiline, you have
15095 * to set a fixed width in order to accurately measure the text height.
15096 * @memberOf Roo.util.TextMetrics.Instance#
15097 * @param {Number} width The width to set on the element
15099 setFixedWidth : function(width){
15100 ml.setWidth(width);
15104 * Returns the measured width of the specified text
15105 * @memberOf Roo.util.TextMetrics.Instance#
15106 * @param {String} text The text to measure
15107 * @return {Number} width The width in pixels
15109 getWidth : function(text){
15110 ml.dom.style.width = 'auto';
15111 return this.getSize(text).width;
15115 * Returns the measured height of the specified text. For multiline text, be sure to call
15116 * {@link #setFixedWidth} if necessary.
15117 * @memberOf Roo.util.TextMetrics.Instance#
15118 * @param {String} text The text to measure
15119 * @return {Number} height The height in pixels
15121 getHeight : function(text){
15122 return this.getSize(text).height;
15126 instance.bind(bindTo);
15131 // backwards compat
15132 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
15134 * Ext JS Library 1.1.1
15135 * Copyright(c) 2006-2007, Ext JS, LLC.
15137 * Originally Released Under LGPL - original licence link has changed is not relivant.
15140 * <script type="text/javascript">
15144 * @class Roo.state.Provider
15145 * Abstract base class for state provider implementations. This class provides methods
15146 * for encoding and decoding <b>typed</b> variables including dates and defines the
15147 * Provider interface.
15149 Roo.state.Provider = function(){
15151 * @event statechange
15152 * Fires when a state change occurs.
15153 * @param {Provider} this This state provider
15154 * @param {String} key The state key which was changed
15155 * @param {String} value The encoded value for the state
15158 "statechange": true
15161 Roo.state.Provider.superclass.constructor.call(this);
15163 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
15165 * Returns the current value for a key
15166 * @param {String} name The key name
15167 * @param {Mixed} defaultValue A default value to return if the key's value is not found
15168 * @return {Mixed} The state data
15170 get : function(name, defaultValue){
15171 return typeof this.state[name] == "undefined" ?
15172 defaultValue : this.state[name];
15176 * Clears a value from the state
15177 * @param {String} name The key name
15179 clear : function(name){
15180 delete this.state[name];
15181 this.fireEvent("statechange", this, name, null);
15185 * Sets the value for a key
15186 * @param {String} name The key name
15187 * @param {Mixed} value The value to set
15189 set : function(name, value){
15190 this.state[name] = value;
15191 this.fireEvent("statechange", this, name, value);
15195 * Decodes a string previously encoded with {@link #encodeValue}.
15196 * @param {String} value The value to decode
15197 * @return {Mixed} The decoded value
15199 decodeValue : function(cookie){
15200 var re = /^(a|n|d|b|s|o)\:(.*)$/;
15201 var matches = re.exec(unescape(cookie));
15202 if(!matches || !matches[1]) {
15203 return; // non state cookie
15205 var type = matches[1];
15206 var v = matches[2];
15209 return parseFloat(v);
15211 return new Date(Date.parse(v));
15216 var values = v.split("^");
15217 for(var i = 0, len = values.length; i < len; i++){
15218 all.push(this.decodeValue(values[i]));
15223 var values = v.split("^");
15224 for(var i = 0, len = values.length; i < len; i++){
15225 var kv = values[i].split("=");
15226 all[kv[0]] = this.decodeValue(kv[1]);
15235 * Encodes a value including type information. Decode with {@link #decodeValue}.
15236 * @param {Mixed} value The value to encode
15237 * @return {String} The encoded value
15239 encodeValue : function(v){
15241 if(typeof v == "number"){
15243 }else if(typeof v == "boolean"){
15244 enc = "b:" + (v ? "1" : "0");
15245 }else if(v instanceof Date){
15246 enc = "d:" + v.toGMTString();
15247 }else if(v instanceof Array){
15249 for(var i = 0, len = v.length; i < len; i++){
15250 flat += this.encodeValue(v[i]);
15256 }else if(typeof v == "object"){
15259 if(typeof v[key] != "function"){
15260 flat += key + "=" + this.encodeValue(v[key]) + "^";
15263 enc = "o:" + flat.substring(0, flat.length-1);
15267 return escape(enc);
15273 * Ext JS Library 1.1.1
15274 * Copyright(c) 2006-2007, Ext JS, LLC.
15276 * Originally Released Under LGPL - original licence link has changed is not relivant.
15279 * <script type="text/javascript">
15282 * @class Roo.state.Manager
15283 * This is the global state manager. By default all components that are "state aware" check this class
15284 * for state information if you don't pass them a custom state provider. In order for this class
15285 * to be useful, it must be initialized with a provider when your application initializes.
15287 // in your initialization function
15289 Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
15291 // supposed you have a {@link Roo.BorderLayout}
15292 var layout = new Roo.BorderLayout(...);
15293 layout.restoreState();
15294 // or a {Roo.BasicDialog}
15295 var dialog = new Roo.BasicDialog(...);
15296 dialog.restoreState();
15300 Roo.state.Manager = function(){
15301 var provider = new Roo.state.Provider();
15305 * Configures the default state provider for your application
15306 * @param {Provider} stateProvider The state provider to set
15308 setProvider : function(stateProvider){
15309 provider = stateProvider;
15313 * Returns the current value for a key
15314 * @param {String} name The key name
15315 * @param {Mixed} defaultValue The default value to return if the key lookup does not match
15316 * @return {Mixed} The state data
15318 get : function(key, defaultValue){
15319 return provider.get(key, defaultValue);
15323 * Sets the value for a key
15324 * @param {String} name The key name
15325 * @param {Mixed} value The state data
15327 set : function(key, value){
15328 provider.set(key, value);
15332 * Clears a value from the state
15333 * @param {String} name The key name
15335 clear : function(key){
15336 provider.clear(key);
15340 * Gets the currently configured state provider
15341 * @return {Provider} The state provider
15343 getProvider : function(){
15350 * Ext JS Library 1.1.1
15351 * Copyright(c) 2006-2007, Ext JS, LLC.
15353 * Originally Released Under LGPL - original licence link has changed is not relivant.
15356 * <script type="text/javascript">
15359 * @class Roo.state.CookieProvider
15360 * @extends Roo.state.Provider
15361 * The default Provider implementation which saves state via cookies.
15364 var cp = new Roo.state.CookieProvider({
15366 expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
15367 domain: "roojs.com"
15369 Roo.state.Manager.setProvider(cp);
15371 * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
15372 * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
15373 * @cfg {String} domain The domain to save the cookie for. Note that you cannot specify a different domain than
15374 * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
15375 * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
15376 * domain the page is running on including the 'www' like 'www.roojs.com')
15377 * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
15379 * Create a new CookieProvider
15380 * @param {Object} config The configuration object
15382 Roo.state.CookieProvider = function(config){
15383 Roo.state.CookieProvider.superclass.constructor.call(this);
15385 this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15386 this.domain = null;
15387 this.secure = false;
15388 Roo.apply(this, config);
15389 this.state = this.readCookies();
15392 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15394 set : function(name, value){
15395 if(typeof value == "undefined" || value === null){
15399 this.setCookie(name, value);
15400 Roo.state.CookieProvider.superclass.set.call(this, name, value);
15404 clear : function(name){
15405 this.clearCookie(name);
15406 Roo.state.CookieProvider.superclass.clear.call(this, name);
15410 readCookies : function(){
15412 var c = document.cookie + ";";
15413 var re = /\s?(.*?)=(.*?);/g;
15415 while((matches = re.exec(c)) != null){
15416 var name = matches[1];
15417 var value = matches[2];
15418 if(name && name.substring(0,3) == "ys-"){
15419 cookies[name.substr(3)] = this.decodeValue(value);
15426 setCookie : function(name, value){
15427 document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15428 ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15429 ((this.path == null) ? "" : ("; path=" + this.path)) +
15430 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15431 ((this.secure == true) ? "; secure" : "");
15435 clearCookie : function(name){
15436 document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15437 ((this.path == null) ? "" : ("; path=" + this.path)) +
15438 ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15439 ((this.secure == true) ? "; secure" : "");
15443 * Ext JS Library 1.1.1
15444 * Copyright(c) 2006-2007, Ext JS, LLC.
15446 * Originally Released Under LGPL - original licence link has changed is not relivant.
15449 * <script type="text/javascript">
15454 * @class Roo.ComponentMgr
15455 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15458 Roo.ComponentMgr = function(){
15459 var all = new Roo.util.MixedCollection();
15463 * Registers a component.
15464 * @param {Roo.Component} c The component
15466 register : function(c){
15471 * Unregisters a component.
15472 * @param {Roo.Component} c The component
15474 unregister : function(c){
15479 * Returns a component by id
15480 * @param {String} id The component id
15482 get : function(id){
15483 return all.get(id);
15487 * Registers a function that will be called when a specified component is added to ComponentMgr
15488 * @param {String} id The component id
15489 * @param {Funtction} fn The callback function
15490 * @param {Object} scope The scope of the callback
15492 onAvailable : function(id, fn, scope){
15493 all.on("add", function(index, o){
15495 fn.call(scope || o, o);
15496 all.un("add", fn, scope);
15503 * Ext JS Library 1.1.1
15504 * Copyright(c) 2006-2007, Ext JS, LLC.
15506 * Originally Released Under LGPL - original licence link has changed is not relivant.
15509 * <script type="text/javascript">
15513 * @class Roo.Component
15514 * @extends Roo.util.Observable
15515 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
15516 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
15517 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15518 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15519 * All visual components (widgets) that require rendering into a layout should subclass Component.
15521 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
15522 * 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
15523 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
15525 Roo.Component = function(config){
15526 config = config || {};
15527 if(config.tagName || config.dom || typeof config == "string"){ // element object
15528 config = {el: config, id: config.id || config};
15530 this.initialConfig = config;
15532 Roo.apply(this, config);
15536 * Fires after the component is disabled.
15537 * @param {Roo.Component} this
15542 * Fires after the component is enabled.
15543 * @param {Roo.Component} this
15547 * @event beforeshow
15548 * Fires before the component is shown. Return false to stop the show.
15549 * @param {Roo.Component} this
15554 * Fires after the component is shown.
15555 * @param {Roo.Component} this
15559 * @event beforehide
15560 * Fires before the component is hidden. Return false to stop the hide.
15561 * @param {Roo.Component} this
15566 * Fires after the component is hidden.
15567 * @param {Roo.Component} this
15571 * @event beforerender
15572 * Fires before the component is rendered. Return false to stop the render.
15573 * @param {Roo.Component} this
15575 beforerender : true,
15578 * Fires after the component is rendered.
15579 * @param {Roo.Component} this
15583 * @event beforedestroy
15584 * Fires before the component is destroyed. Return false to stop the destroy.
15585 * @param {Roo.Component} this
15587 beforedestroy : true,
15590 * Fires after the component is destroyed.
15591 * @param {Roo.Component} this
15596 this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15598 Roo.ComponentMgr.register(this);
15599 Roo.Component.superclass.constructor.call(this);
15600 this.initComponent();
15601 if(this.renderTo){ // not supported by all components yet. use at your own risk!
15602 this.render(this.renderTo);
15603 delete this.renderTo;
15608 Roo.Component.AUTO_ID = 1000;
15610 Roo.extend(Roo.Component, Roo.util.Observable, {
15612 * @scope Roo.Component.prototype
15614 * true if this component is hidden. Read-only.
15619 * true if this component is disabled. Read-only.
15624 * true if this component has been rendered. Read-only.
15628 /** @cfg {String} disableClass
15629 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15631 disabledClass : "x-item-disabled",
15632 /** @cfg {Boolean} allowDomMove
15633 * Whether the component can move the Dom node when rendering (defaults to true).
15635 allowDomMove : true,
15636 /** @cfg {String} hideMode (display|visibility)
15637 * How this component should hidden. Supported values are
15638 * "visibility" (css visibility), "offsets" (negative offset position) and
15639 * "display" (css display) - defaults to "display".
15641 hideMode: 'display',
15644 ctype : "Roo.Component",
15647 * @cfg {String} actionMode
15648 * which property holds the element that used for hide() / show() / disable() / enable()
15649 * default is 'el' for forms you probably want to set this to fieldEl
15654 getActionEl : function(){
15655 return this[this.actionMode];
15658 initComponent : Roo.emptyFn,
15660 * If this is a lazy rendering component, render it to its container element.
15661 * @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.
15663 render : function(container, position){
15669 if(this.fireEvent("beforerender", this) === false){
15673 if(!container && this.el){
15674 this.el = Roo.get(this.el);
15675 container = this.el.dom.parentNode;
15676 this.allowDomMove = false;
15678 this.container = Roo.get(container);
15679 this.rendered = true;
15680 if(position !== undefined){
15681 if(typeof position == 'number'){
15682 position = this.container.dom.childNodes[position];
15684 position = Roo.getDom(position);
15687 this.onRender(this.container, position || null);
15689 this.el.addClass(this.cls);
15693 this.el.applyStyles(this.style);
15696 this.fireEvent("render", this);
15697 this.afterRender(this.container);
15710 // default function is not really useful
15711 onRender : function(ct, position){
15713 this.el = Roo.get(this.el);
15714 if(this.allowDomMove !== false){
15715 ct.dom.insertBefore(this.el.dom, position);
15721 getAutoCreate : function(){
15722 var cfg = typeof this.autoCreate == "object" ?
15723 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15724 if(this.id && !cfg.id){
15731 afterRender : Roo.emptyFn,
15734 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15735 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15737 destroy : function(){
15738 if(this.fireEvent("beforedestroy", this) !== false){
15739 this.purgeListeners();
15740 this.beforeDestroy();
15742 this.el.removeAllListeners();
15744 if(this.actionMode == "container"){
15745 this.container.remove();
15749 Roo.ComponentMgr.unregister(this);
15750 this.fireEvent("destroy", this);
15755 beforeDestroy : function(){
15760 onDestroy : function(){
15765 * Returns the underlying {@link Roo.Element}.
15766 * @return {Roo.Element} The element
15768 getEl : function(){
15773 * Returns the id of this component.
15776 getId : function(){
15781 * Try to focus this component.
15782 * @param {Boolean} selectText True to also select the text in this component (if applicable)
15783 * @return {Roo.Component} this
15785 focus : function(selectText){
15788 if(selectText === true){
15789 this.el.dom.select();
15804 * Disable this component.
15805 * @return {Roo.Component} this
15807 disable : function(){
15811 this.disabled = true;
15812 this.fireEvent("disable", this);
15817 onDisable : function(){
15818 this.getActionEl().addClass(this.disabledClass);
15819 this.el.dom.disabled = true;
15823 * Enable this component.
15824 * @return {Roo.Component} this
15826 enable : function(){
15830 this.disabled = false;
15831 this.fireEvent("enable", this);
15836 onEnable : function(){
15837 this.getActionEl().removeClass(this.disabledClass);
15838 this.el.dom.disabled = false;
15842 * Convenience function for setting disabled/enabled by boolean.
15843 * @param {Boolean} disabled
15845 setDisabled : function(disabled){
15846 this[disabled ? "disable" : "enable"]();
15850 * Show this component.
15851 * @return {Roo.Component} this
15854 if(this.fireEvent("beforeshow", this) !== false){
15855 this.hidden = false;
15859 this.fireEvent("show", this);
15865 onShow : function(){
15866 var ae = this.getActionEl();
15867 if(this.hideMode == 'visibility'){
15868 ae.dom.style.visibility = "visible";
15869 }else if(this.hideMode == 'offsets'){
15870 ae.removeClass('x-hidden');
15872 ae.dom.style.display = "";
15877 * Hide this component.
15878 * @return {Roo.Component} this
15881 if(this.fireEvent("beforehide", this) !== false){
15882 this.hidden = true;
15886 this.fireEvent("hide", this);
15892 onHide : function(){
15893 var ae = this.getActionEl();
15894 if(this.hideMode == 'visibility'){
15895 ae.dom.style.visibility = "hidden";
15896 }else if(this.hideMode == 'offsets'){
15897 ae.addClass('x-hidden');
15899 ae.dom.style.display = "none";
15904 * Convenience function to hide or show this component by boolean.
15905 * @param {Boolean} visible True to show, false to hide
15906 * @return {Roo.Component} this
15908 setVisible: function(visible){
15918 * Returns true if this component is visible.
15920 isVisible : function(){
15921 return this.getActionEl().isVisible();
15924 cloneConfig : function(overrides){
15925 overrides = overrides || {};
15926 var id = overrides.id || Roo.id();
15927 var cfg = Roo.applyIf(overrides, this.initialConfig);
15928 cfg.id = id; // prevent dup id
15929 return new this.constructor(cfg);
15933 * Ext JS Library 1.1.1
15934 * Copyright(c) 2006-2007, Ext JS, LLC.
15936 * Originally Released Under LGPL - original licence link has changed is not relivant.
15939 * <script type="text/javascript">
15943 * @class Roo.BoxComponent
15944 * @extends Roo.Component
15945 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
15946 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
15947 * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo
15948 * layout containers.
15950 * @param {Roo.Element/String/Object} config The configuration options.
15952 Roo.BoxComponent = function(config){
15953 Roo.Component.call(this, config);
15957 * Fires after the component is resized.
15958 * @param {Roo.Component} this
15959 * @param {Number} adjWidth The box-adjusted width that was set
15960 * @param {Number} adjHeight The box-adjusted height that was set
15961 * @param {Number} rawWidth The width that was originally specified
15962 * @param {Number} rawHeight The height that was originally specified
15967 * Fires after the component is moved.
15968 * @param {Roo.Component} this
15969 * @param {Number} x The new x position
15970 * @param {Number} y The new y position
15976 Roo.extend(Roo.BoxComponent, Roo.Component, {
15977 // private, set in afterRender to signify that the component has been rendered
15979 // private, used to defer height settings to subclasses
15980 deferHeight: false,
15981 /** @cfg {Number} width
15982 * width (optional) size of component
15984 /** @cfg {Number} height
15985 * height (optional) size of component
15989 * Sets the width and height of the component. This method fires the resize event. This method can accept
15990 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15991 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15992 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15993 * @return {Roo.BoxComponent} this
15995 setSize : function(w, h){
15996 // support for standard size objects
15997 if(typeof w == 'object'){
16002 if(!this.boxReady){
16008 // prevent recalcs when not needed
16009 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
16012 this.lastSize = {width: w, height: h};
16014 var adj = this.adjustSize(w, h);
16015 var aw = adj.width, ah = adj.height;
16016 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
16017 var rz = this.getResizeEl();
16018 if(!this.deferHeight && aw !== undefined && ah !== undefined){
16019 rz.setSize(aw, ah);
16020 }else if(!this.deferHeight && ah !== undefined){
16022 }else if(aw !== undefined){
16025 this.onResize(aw, ah, w, h);
16026 this.fireEvent('resize', this, aw, ah, w, h);
16032 * Gets the current size of the component's underlying element.
16033 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
16035 getSize : function(){
16036 return this.el.getSize();
16040 * Gets the current XY position of the component's underlying element.
16041 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16042 * @return {Array} The XY position of the element (e.g., [100, 200])
16044 getPosition : function(local){
16045 if(local === true){
16046 return [this.el.getLeft(true), this.el.getTop(true)];
16048 return this.xy || this.el.getXY();
16052 * Gets the current box measurements of the component's underlying element.
16053 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
16054 * @returns {Object} box An object in the format {x, y, width, height}
16056 getBox : function(local){
16057 var s = this.el.getSize();
16059 s.x = this.el.getLeft(true);
16060 s.y = this.el.getTop(true);
16062 var xy = this.xy || this.el.getXY();
16070 * Sets the current box measurements of the component's underlying element.
16071 * @param {Object} box An object in the format {x, y, width, height}
16072 * @returns {Roo.BoxComponent} this
16074 updateBox : function(box){
16075 this.setSize(box.width, box.height);
16076 this.setPagePosition(box.x, box.y);
16081 getResizeEl : function(){
16082 return this.resizeEl || this.el;
16086 getPositionEl : function(){
16087 return this.positionEl || this.el;
16091 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
16092 * This method fires the move event.
16093 * @param {Number} left The new left
16094 * @param {Number} top The new top
16095 * @returns {Roo.BoxComponent} this
16097 setPosition : function(x, y){
16100 if(!this.boxReady){
16103 var adj = this.adjustPosition(x, y);
16104 var ax = adj.x, ay = adj.y;
16106 var el = this.getPositionEl();
16107 if(ax !== undefined || ay !== undefined){
16108 if(ax !== undefined && ay !== undefined){
16109 el.setLeftTop(ax, ay);
16110 }else if(ax !== undefined){
16112 }else if(ay !== undefined){
16115 this.onPosition(ax, ay);
16116 this.fireEvent('move', this, ax, ay);
16122 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
16123 * This method fires the move event.
16124 * @param {Number} x The new x position
16125 * @param {Number} y The new y position
16126 * @returns {Roo.BoxComponent} this
16128 setPagePosition : function(x, y){
16131 if(!this.boxReady){
16134 if(x === undefined || y === undefined){ // cannot translate undefined points
16137 var p = this.el.translatePoints(x, y);
16138 this.setPosition(p.left, p.top);
16143 onRender : function(ct, position){
16144 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
16146 this.resizeEl = Roo.get(this.resizeEl);
16148 if(this.positionEl){
16149 this.positionEl = Roo.get(this.positionEl);
16154 afterRender : function(){
16155 Roo.BoxComponent.superclass.afterRender.call(this);
16156 this.boxReady = true;
16157 this.setSize(this.width, this.height);
16158 if(this.x || this.y){
16159 this.setPosition(this.x, this.y);
16161 if(this.pageX || this.pageY){
16162 this.setPagePosition(this.pageX, this.pageY);
16167 * Force the component's size to recalculate based on the underlying element's current height and width.
16168 * @returns {Roo.BoxComponent} this
16170 syncSize : function(){
16171 delete this.lastSize;
16172 this.setSize(this.el.getWidth(), this.el.getHeight());
16177 * Called after the component is resized, this method is empty by default but can be implemented by any
16178 * subclass that needs to perform custom logic after a resize occurs.
16179 * @param {Number} adjWidth The box-adjusted width that was set
16180 * @param {Number} adjHeight The box-adjusted height that was set
16181 * @param {Number} rawWidth The width that was originally specified
16182 * @param {Number} rawHeight The height that was originally specified
16184 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
16189 * Called after the component is moved, this method is empty by default but can be implemented by any
16190 * subclass that needs to perform custom logic after a move occurs.
16191 * @param {Number} x The new x position
16192 * @param {Number} y The new y position
16194 onPosition : function(x, y){
16199 adjustSize : function(w, h){
16200 if(this.autoWidth){
16203 if(this.autoHeight){
16206 return {width : w, height: h};
16210 adjustPosition : function(x, y){
16211 return {x : x, y: y};
16215 * Ext JS Library 1.1.1
16216 * Copyright(c) 2006-2007, Ext JS, LLC.
16218 * Originally Released Under LGPL - original licence link has changed is not relivant.
16221 * <script type="text/javascript">
16226 * @extends Roo.Element
16227 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
16228 * automatic maintaining of shadow/shim positions.
16229 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
16230 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
16231 * you can pass a string with a CSS class name. False turns off the shadow.
16232 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
16233 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
16234 * @cfg {String} cls CSS class to add to the element
16235 * @cfg {Number} zindex Starting z-index (defaults to 11000)
16236 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
16238 * @param {Object} config An object with config options.
16239 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
16242 Roo.Layer = function(config, existingEl){
16243 config = config || {};
16244 var dh = Roo.DomHelper;
16245 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
16247 this.dom = Roo.getDom(existingEl);
16250 var o = config.dh || {tag: "div", cls: "x-layer"};
16251 this.dom = dh.append(pel, o);
16254 this.addClass(config.cls);
16256 this.constrain = config.constrain !== false;
16257 this.visibilityMode = Roo.Element.VISIBILITY;
16259 this.id = this.dom.id = config.id;
16261 this.id = Roo.id(this.dom);
16263 this.zindex = config.zindex || this.getZIndex();
16264 this.position("absolute", this.zindex);
16266 this.shadowOffset = config.shadowOffset || 4;
16267 this.shadow = new Roo.Shadow({
16268 offset : this.shadowOffset,
16269 mode : config.shadow
16272 this.shadowOffset = 0;
16274 this.useShim = config.shim !== false && Roo.useShims;
16275 this.useDisplay = config.useDisplay;
16279 var supr = Roo.Element.prototype;
16281 // shims are shared among layer to keep from having 100 iframes
16284 Roo.extend(Roo.Layer, Roo.Element, {
16286 getZIndex : function(){
16287 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
16290 getShim : function(){
16297 var shim = shims.shift();
16299 shim = this.createShim();
16300 shim.enableDisplayMode('block');
16301 shim.dom.style.display = 'none';
16302 shim.dom.style.visibility = 'visible';
16304 var pn = this.dom.parentNode;
16305 if(shim.dom.parentNode != pn){
16306 pn.insertBefore(shim.dom, this.dom);
16308 shim.setStyle('z-index', this.getZIndex()-2);
16313 hideShim : function(){
16315 this.shim.setDisplayed(false);
16316 shims.push(this.shim);
16321 disableShadow : function(){
16323 this.shadowDisabled = true;
16324 this.shadow.hide();
16325 this.lastShadowOffset = this.shadowOffset;
16326 this.shadowOffset = 0;
16330 enableShadow : function(show){
16332 this.shadowDisabled = false;
16333 this.shadowOffset = this.lastShadowOffset;
16334 delete this.lastShadowOffset;
16342 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
16343 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
16344 sync : function(doShow){
16345 var sw = this.shadow;
16346 if(!this.updating && this.isVisible() && (sw || this.useShim)){
16347 var sh = this.getShim();
16349 var w = this.getWidth(),
16350 h = this.getHeight();
16352 var l = this.getLeft(true),
16353 t = this.getTop(true);
16355 if(sw && !this.shadowDisabled){
16356 if(doShow && !sw.isVisible()){
16359 sw.realign(l, t, w, h);
16365 // fit the shim behind the shadow, so it is shimmed too
16366 var a = sw.adjusts, s = sh.dom.style;
16367 s.left = (Math.min(l, l+a.l))+"px";
16368 s.top = (Math.min(t, t+a.t))+"px";
16369 s.width = (w+a.w)+"px";
16370 s.height = (h+a.h)+"px";
16377 sh.setLeftTop(l, t);
16384 destroy : function(){
16387 this.shadow.hide();
16389 this.removeAllListeners();
16390 var pn = this.dom.parentNode;
16392 pn.removeChild(this.dom);
16394 Roo.Element.uncache(this.id);
16397 remove : function(){
16402 beginUpdate : function(){
16403 this.updating = true;
16407 endUpdate : function(){
16408 this.updating = false;
16413 hideUnders : function(negOffset){
16415 this.shadow.hide();
16421 constrainXY : function(){
16422 if(this.constrain){
16423 var vw = Roo.lib.Dom.getViewWidth(),
16424 vh = Roo.lib.Dom.getViewHeight();
16425 var s = Roo.get(document).getScroll();
16427 var xy = this.getXY();
16428 var x = xy[0], y = xy[1];
16429 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
16430 // only move it if it needs it
16432 // first validate right/bottom
16433 if((x + w) > vw+s.left){
16434 x = vw - w - this.shadowOffset;
16437 if((y + h) > vh+s.top){
16438 y = vh - h - this.shadowOffset;
16441 // then make sure top/left isn't negative
16452 var ay = this.avoidY;
16453 if(y <= ay && (y+h) >= ay){
16459 supr.setXY.call(this, xy);
16465 isVisible : function(){
16466 return this.visible;
16470 showAction : function(){
16471 this.visible = true; // track visibility to prevent getStyle calls
16472 if(this.useDisplay === true){
16473 this.setDisplayed("");
16474 }else if(this.lastXY){
16475 supr.setXY.call(this, this.lastXY);
16476 }else if(this.lastLT){
16477 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
16482 hideAction : function(){
16483 this.visible = false;
16484 if(this.useDisplay === true){
16485 this.setDisplayed(false);
16487 this.setLeftTop(-10000,-10000);
16491 // overridden Element method
16492 setVisible : function(v, a, d, c, e){
16497 var cb = function(){
16502 }.createDelegate(this);
16503 supr.setVisible.call(this, true, true, d, cb, e);
16506 this.hideUnders(true);
16515 }.createDelegate(this);
16517 supr.setVisible.call(this, v, a, d, cb, e);
16526 storeXY : function(xy){
16527 delete this.lastLT;
16531 storeLeftTop : function(left, top){
16532 delete this.lastXY;
16533 this.lastLT = [left, top];
16537 beforeFx : function(){
16538 this.beforeAction();
16539 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
16543 afterFx : function(){
16544 Roo.Layer.superclass.afterFx.apply(this, arguments);
16545 this.sync(this.isVisible());
16549 beforeAction : function(){
16550 if(!this.updating && this.shadow){
16551 this.shadow.hide();
16555 // overridden Element method
16556 setLeft : function(left){
16557 this.storeLeftTop(left, this.getTop(true));
16558 supr.setLeft.apply(this, arguments);
16562 setTop : function(top){
16563 this.storeLeftTop(this.getLeft(true), top);
16564 supr.setTop.apply(this, arguments);
16568 setLeftTop : function(left, top){
16569 this.storeLeftTop(left, top);
16570 supr.setLeftTop.apply(this, arguments);
16574 setXY : function(xy, a, d, c, e){
16576 this.beforeAction();
16578 var cb = this.createCB(c);
16579 supr.setXY.call(this, xy, a, d, cb, e);
16586 createCB : function(c){
16597 // overridden Element method
16598 setX : function(x, a, d, c, e){
16599 this.setXY([x, this.getY()], a, d, c, e);
16602 // overridden Element method
16603 setY : function(y, a, d, c, e){
16604 this.setXY([this.getX(), y], a, d, c, e);
16607 // overridden Element method
16608 setSize : function(w, h, a, d, c, e){
16609 this.beforeAction();
16610 var cb = this.createCB(c);
16611 supr.setSize.call(this, w, h, a, d, cb, e);
16617 // overridden Element method
16618 setWidth : function(w, a, d, c, e){
16619 this.beforeAction();
16620 var cb = this.createCB(c);
16621 supr.setWidth.call(this, w, a, d, cb, e);
16627 // overridden Element method
16628 setHeight : function(h, a, d, c, e){
16629 this.beforeAction();
16630 var cb = this.createCB(c);
16631 supr.setHeight.call(this, h, a, d, cb, e);
16637 // overridden Element method
16638 setBounds : function(x, y, w, h, a, d, c, e){
16639 this.beforeAction();
16640 var cb = this.createCB(c);
16642 this.storeXY([x, y]);
16643 supr.setXY.call(this, [x, y]);
16644 supr.setSize.call(this, w, h, a, d, cb, e);
16647 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
16653 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
16654 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
16655 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
16656 * @param {Number} zindex The new z-index to set
16657 * @return {this} The Layer
16659 setZIndex : function(zindex){
16660 this.zindex = zindex;
16661 this.setStyle("z-index", zindex + 2);
16663 this.shadow.setZIndex(zindex + 1);
16666 this.shim.setStyle("z-index", zindex);
16671 * Original code for Roojs - LGPL
16672 * <script type="text/javascript">
16676 * @class Roo.XComponent
16677 * A delayed Element creator...
16678 * Or a way to group chunks of interface together.
16679 * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
16680 * used in conjunction with XComponent.build() it will create an instance of each element,
16681 * then call addxtype() to build the User interface.
16683 * Mypart.xyx = new Roo.XComponent({
16685 parent : 'Mypart.xyz', // empty == document.element.!!
16689 disabled : function() {}
16691 tree : function() { // return an tree of xtype declared components
16695 xtype : 'NestedLayoutPanel',
16702 * It can be used to build a big heiracy, with parent etc.
16703 * or you can just use this to render a single compoent to a dom element
16704 * MYPART.render(Roo.Element | String(id) | dom_element )
16711 * Roo is designed primarily as a single page application, so the UI build for a standard interface will
16712 * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
16714 * Each sub module is expected to have a parent pointing to the class name of it's parent module.
16716 * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
16717 * - if mulitple topModules exist, the last one is defined as the top module.
16721 * When the top level or multiple modules are to embedded into a existing HTML page,
16722 * the parent element can container '#id' of the element where the module will be drawn.
16726 * Unlike classic Roo, the bootstrap tends not to be used as a single page.
16727 * it relies more on a include mechanism, where sub modules are included into an outer page.
16728 * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
16730 * Bootstrap Roo Included elements
16732 * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
16733 * hence confusing the component builder as it thinks there are multiple top level elements.
16735 * String Over-ride & Translations
16737 * Our builder application writes all the strings as _strings and _named_strings. This is to enable the translation of elements,
16738 * and also the 'overlaying of string values - needed when different versions of the same application with different text content
16739 * are needed. @see Roo.XComponent.overlayString
16743 * @extends Roo.util.Observable
16745 * @param cfg {Object} configuration of component
16748 Roo.XComponent = function(cfg) {
16749 Roo.apply(this, cfg);
16753 * Fires when this the componnt is built
16754 * @param {Roo.XComponent} c the component
16759 this.region = this.region || 'center'; // default..
16760 Roo.XComponent.register(this);
16761 this.modules = false;
16762 this.el = false; // where the layout goes..
16766 Roo.extend(Roo.XComponent, Roo.util.Observable, {
16769 * The created element (with Roo.factory())
16770 * @type {Roo.Layout}
16776 * for BC - use el in new code
16777 * @type {Roo.Layout}
16783 * for BC - use el in new code
16784 * @type {Roo.Layout}
16789 * @cfg {Function|boolean} disabled
16790 * If this module is disabled by some rule, return true from the funtion
16795 * @cfg {String} parent
16796 * Name of parent element which it get xtype added to..
16801 * @cfg {String} order
16802 * Used to set the order in which elements are created (usefull for multiple tabs)
16807 * @cfg {String} name
16808 * String to display while loading.
16812 * @cfg {String} region
16813 * Region to render component to (defaults to center)
16818 * @cfg {Array} items
16819 * A single item array - the first element is the root of the tree..
16820 * It's done this way to stay compatible with the Xtype system...
16826 * The method that retuns the tree of parts that make up this compoennt
16833 * render element to dom or tree
16834 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
16837 render : function(el)
16841 var hp = this.parent ? 1 : 0;
16842 Roo.debug && Roo.log(this);
16844 var tree = this._tree ? this._tree() : this.tree();
16847 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
16848 // if parent is a '#.....' string, then let's use that..
16849 var ename = this.parent.substr(1);
16850 this.parent = false;
16851 Roo.debug && Roo.log(ename);
16853 case 'bootstrap-body':
16854 if (typeof(tree.el) != 'undefined' && tree.el == document.body) {
16855 // this is the BorderLayout standard?
16856 this.parent = { el : true };
16859 if (["Nest", "Content", "Grid", "Tree"].indexOf(tree.xtype) > -1) {
16860 // need to insert stuff...
16862 el : new Roo.bootstrap.layout.Border({
16863 el : document.body,
16869 tabPosition: 'top',
16870 //resizeTabs: true,
16871 alwaysShowTabs: true,
16881 if (typeof(Roo.bootstrap.Body) != 'undefined' ) {
16882 this.parent = { el : new Roo.bootstrap.Body() };
16883 Roo.debug && Roo.log("setting el to doc body");
16886 throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16890 this.parent = { el : true};
16893 el = Roo.get(ename);
16894 if (typeof(Roo.bootstrap) != 'undefined' && tree['|xns'] == 'Roo.bootstrap') {
16895 this.parent = { el : true};
16902 if (!el && !this.parent) {
16903 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16908 Roo.debug && Roo.log("EL:");
16909 Roo.debug && Roo.log(el);
16910 Roo.debug && Roo.log("this.parent.el:");
16911 Roo.debug && Roo.log(this.parent.el);
16914 // altertive root elements ??? - we need a better way to indicate these.
16915 var is_alt = Roo.XComponent.is_alt ||
16916 (typeof(tree.el) != 'undefined' && tree.el == document.body) ||
16917 (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16918 (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16922 if (!this.parent && is_alt) {
16923 //el = Roo.get(document.body);
16924 this.parent = { el : true };
16929 if (!this.parent) {
16931 Roo.debug && Roo.log("no parent - creating one");
16933 el = el ? Roo.get(el) : false;
16935 if (typeof(Roo.BorderLayout) == 'undefined' ) {
16938 el : new Roo.bootstrap.layout.Border({
16939 el: el || document.body,
16945 tabPosition: 'top',
16946 //resizeTabs: true,
16947 alwaysShowTabs: false,
16950 overflow: 'visible'
16956 // it's a top level one..
16958 el : new Roo.BorderLayout(el || document.body, {
16963 tabPosition: 'top',
16964 //resizeTabs: true,
16965 alwaysShowTabs: el && hp? false : true,
16966 hideTabs: el || !hp ? true : false,
16974 if (!this.parent.el) {
16975 // probably an old style ctor, which has been disabled.
16979 // The 'tree' method is '_tree now'
16981 tree.region = tree.region || this.region;
16982 var is_body = false;
16983 if (this.parent.el === true) {
16984 // bootstrap... - body..
16988 this.parent.el = Roo.factory(tree);
16992 this.el = this.parent.el.addxtype(tree, undefined, is_body);
16993 this.fireEvent('built', this);
16995 this.panel = this.el;
16996 this.layout = this.panel.layout;
16997 this.parentLayout = this.parent.layout || false;
17003 Roo.apply(Roo.XComponent, {
17005 * @property hideProgress
17006 * true to disable the building progress bar.. usefull on single page renders.
17009 hideProgress : false,
17011 * @property buildCompleted
17012 * True when the builder has completed building the interface.
17015 buildCompleted : false,
17018 * @property topModule
17019 * the upper most module - uses document.element as it's constructor.
17026 * @property modules
17027 * array of modules to be created by registration system.
17028 * @type {Array} of Roo.XComponent
17033 * @property elmodules
17034 * array of modules to be created by which use #ID
17035 * @type {Array} of Roo.XComponent
17042 * Is an alternative Root - normally used by bootstrap or other systems,
17043 * where the top element in the tree can wrap 'body'
17044 * @type {boolean} (default false)
17049 * @property build_from_html
17050 * Build elements from html - used by bootstrap HTML stuff
17051 * - this is cleared after build is completed
17052 * @type {boolean} (default false)
17055 build_from_html : false,
17057 * Register components to be built later.
17059 * This solves the following issues
17060 * - Building is not done on page load, but after an authentication process has occured.
17061 * - Interface elements are registered on page load
17062 * - Parent Interface elements may not be loaded before child, so this handles that..
17069 module : 'Pman.Tab.projectMgr',
17071 parent : 'Pman.layout',
17072 disabled : false, // or use a function..
17075 * * @param {Object} details about module
17077 register : function(obj) {
17079 Roo.XComponent.event.fireEvent('register', obj);
17080 switch(typeof(obj.disabled) ) {
17086 if ( obj.disabled() ) {
17092 if (obj.disabled || obj.region == '#disabled') {
17098 this.modules.push(obj);
17102 * convert a string to an object..
17103 * eg. 'AAA.BBB' -> finds AAA.BBB
17107 toObject : function(str)
17109 if (!str || typeof(str) == 'object') {
17112 if (str.substring(0,1) == '#') {
17116 var ar = str.split('.');
17121 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
17123 throw "Module not found : " + str;
17127 throw "Module not found : " + str;
17129 Roo.each(ar, function(e) {
17130 if (typeof(o[e]) == 'undefined') {
17131 throw "Module not found : " + str;
17142 * move modules into their correct place in the tree..
17145 preBuild : function ()
17148 Roo.each(this.modules , function (obj)
17150 Roo.XComponent.event.fireEvent('beforebuild', obj);
17152 var opar = obj.parent;
17154 obj.parent = this.toObject(opar);
17156 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
17161 Roo.debug && Roo.log("GOT top level module");
17162 Roo.debug && Roo.log(obj);
17163 obj.modules = new Roo.util.MixedCollection(false,
17164 function(o) { return o.order + '' }
17166 this.topModule = obj;
17169 // parent is a string (usually a dom element name..)
17170 if (typeof(obj.parent) == 'string') {
17171 this.elmodules.push(obj);
17174 if (obj.parent.constructor != Roo.XComponent) {
17175 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
17177 if (!obj.parent.modules) {
17178 obj.parent.modules = new Roo.util.MixedCollection(false,
17179 function(o) { return o.order + '' }
17182 if (obj.parent.disabled) {
17183 obj.disabled = true;
17185 obj.parent.modules.add(obj);
17190 * make a list of modules to build.
17191 * @return {Array} list of modules.
17194 buildOrder : function()
17197 var cmp = function(a,b) {
17198 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
17200 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
17201 throw "No top level modules to build";
17204 // make a flat list in order of modules to build.
17205 var mods = this.topModule ? [ this.topModule ] : [];
17208 // elmodules (is a list of DOM based modules )
17209 Roo.each(this.elmodules, function(e) {
17211 if (!this.topModule &&
17212 typeof(e.parent) == 'string' &&
17213 e.parent.substring(0,1) == '#' &&
17214 Roo.get(e.parent.substr(1))
17217 _this.topModule = e;
17223 // add modules to their parents..
17224 var addMod = function(m) {
17225 Roo.debug && Roo.log("build Order: add: " + m.name);
17228 if (m.modules && !m.disabled) {
17229 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
17230 m.modules.keySort('ASC', cmp );
17231 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
17233 m.modules.each(addMod);
17235 Roo.debug && Roo.log("build Order: no child modules");
17237 // not sure if this is used any more..
17239 m.finalize.name = m.name + " (clean up) ";
17240 mods.push(m.finalize);
17244 if (this.topModule && this.topModule.modules) {
17245 this.topModule.modules.keySort('ASC', cmp );
17246 this.topModule.modules.each(addMod);
17252 * Build the registered modules.
17253 * @param {Object} parent element.
17254 * @param {Function} optional method to call after module has been added.
17258 build : function(opts)
17261 if (typeof(opts) != 'undefined') {
17262 Roo.apply(this,opts);
17266 var mods = this.buildOrder();
17268 //this.allmods = mods;
17269 //Roo.debug && Roo.log(mods);
17271 if (!mods.length) { // should not happen
17272 throw "NO modules!!!";
17276 var msg = "Building Interface...";
17277 // flash it up as modal - so we store the mask!?
17278 if (!this.hideProgress && Roo.MessageBox) {
17279 Roo.MessageBox.show({ title: 'loading' });
17280 Roo.MessageBox.show({
17281 title: "Please wait...",
17291 var total = mods.length;
17294 var progressRun = function() {
17295 if (!mods.length) {
17296 Roo.debug && Roo.log('hide?');
17297 if (!this.hideProgress && Roo.MessageBox) {
17298 Roo.MessageBox.hide();
17300 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
17302 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
17308 var m = mods.shift();
17311 Roo.debug && Roo.log(m);
17312 // not sure if this is supported any more.. - modules that are are just function
17313 if (typeof(m) == 'function') {
17315 return progressRun.defer(10, _this);
17319 msg = "Building Interface " + (total - mods.length) +
17321 (m.name ? (' - ' + m.name) : '');
17322 Roo.debug && Roo.log(msg);
17323 if (!_this.hideProgress && Roo.MessageBox) {
17324 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
17328 // is the module disabled?
17329 var disabled = (typeof(m.disabled) == 'function') ?
17330 m.disabled.call(m.module.disabled) : m.disabled;
17334 return progressRun(); // we do not update the display!
17342 // it's 10 on top level, and 1 on others??? why...
17343 return progressRun.defer(10, _this);
17346 progressRun.defer(1, _this);
17352 * Overlay a set of modified strings onto a component
17353 * This is dependant on our builder exporting the strings and 'named strings' elements.
17355 * @param {Object} element to overlay on - eg. Pman.Dialog.Login
17356 * @param {Object} associative array of 'named' string and it's new value.
17359 overlayStrings : function( component, strings )
17361 if (typeof(component['_named_strings']) == 'undefined') {
17362 throw "ERROR: component does not have _named_strings";
17364 for ( var k in strings ) {
17365 var md = typeof(component['_named_strings'][k]) == 'undefined' ? false : component['_named_strings'][k];
17366 if (md !== false) {
17367 component['_strings'][md] = strings[k];
17369 Roo.log('could not find named string: ' + k + ' in');
17370 Roo.log(component);
17385 * wrapper for event.on - aliased later..
17386 * Typically use to register a event handler for register:
17388 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
17397 Roo.XComponent.event = new Roo.util.Observable({
17401 * Fires when an Component is registered,
17402 * set the disable property on the Component to stop registration.
17403 * @param {Roo.XComponent} c the component being registerd.
17408 * @event beforebuild
17409 * Fires before each Component is built
17410 * can be used to apply permissions.
17411 * @param {Roo.XComponent} c the component being registerd.
17414 'beforebuild' : true,
17416 * @event buildcomplete
17417 * Fires on the top level element when all elements have been built
17418 * @param {Roo.XComponent} the top level component.
17420 'buildcomplete' : true
17425 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);
17428 * marked - a markdown parser
17429 * Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
17430 * https://github.com/chjj/marked
17436 * Roo.Markdown - is a very crude wrapper around marked..
17440 * alert( Roo.Markdown.toHtml("Markdown *rocks*.") );
17442 * Note: move the sample code to the bottom of this
17443 * file before uncommenting it.
17448 Roo.Markdown.toHtml = function(text) {
17450 var c = new Roo.Markdown.marked.setOptions({
17451 renderer: new Roo.Markdown.marked.Renderer(),
17462 text = text.replace(/\\\n/g,' ');
17463 return Roo.Markdown.marked(text);
17468 // Wraps all "globals" so that the only thing
17469 // exposed is makeHtml().
17475 * eval:var:unescape
17483 var escape = function (html, encode) {
17485 .replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&')
17486 .replace(/</g, '<')
17487 .replace(/>/g, '>')
17488 .replace(/"/g, '"')
17489 .replace(/'/g, ''');
17492 var unescape = function (html) {
17493 // explicitly match decimal, hex, and named HTML entities
17494 return html.replace(/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/g, function(_, n) {
17495 n = n.toLowerCase();
17496 if (n === 'colon') { return ':'; }
17497 if (n.charAt(0) === '#') {
17498 return n.charAt(1) === 'x'
17499 ? String.fromCharCode(parseInt(n.substring(2), 16))
17500 : String.fromCharCode(+n.substring(1));
17506 var replace = function (regex, opt) {
17507 regex = regex.source;
17509 return function self(name, val) {
17510 if (!name) { return new RegExp(regex, opt); }
17511 val = val.source || val;
17512 val = val.replace(/(^|[^\[])\^/g, '$1');
17513 regex = regex.replace(name, val);
17522 var noop = function () {}
17528 var merge = function (obj) {
17533 for (; i < arguments.length; i++) {
17534 target = arguments[i];
17535 for (key in target) {
17536 if (Object.prototype.hasOwnProperty.call(target, key)) {
17537 obj[key] = target[key];
17547 * Block-Level Grammar
17555 code: /^( {4}[^\n]+\n*)+/,
17557 hr: /^( *[-*_]){3,} *(?:\n+|$)/,
17558 heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
17560 lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
17561 blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
17562 list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
17563 html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
17564 def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
17566 paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
17570 block.bullet = /(?:[*+-]|\d+\.)/;
17571 block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
17572 block.item = replace(block.item, 'gm')
17573 (/bull/g, block.bullet)
17576 block.list = replace(block.list)
17577 (/bull/g, block.bullet)
17578 ('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
17579 ('def', '\\n+(?=' + block.def.source + ')')
17582 block.blockquote = replace(block.blockquote)
17586 block._tag = '(?!(?:'
17587 + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
17588 + '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
17589 + '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
17591 block.html = replace(block.html)
17592 ('comment', /<!--[\s\S]*?-->/)
17593 ('closed', /<(tag)[\s\S]+?<\/\1>/)
17594 ('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
17595 (/tag/g, block._tag)
17598 block.paragraph = replace(block.paragraph)
17600 ('heading', block.heading)
17601 ('lheading', block.lheading)
17602 ('blockquote', block.blockquote)
17603 ('tag', '<' + block._tag)
17608 * Normal Block Grammar
17611 block.normal = merge({}, block);
17614 * GFM Block Grammar
17617 block.gfm = merge({}, block.normal, {
17618 fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
17620 heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
17623 block.gfm.paragraph = replace(block.paragraph)
17625 + block.gfm.fences.source.replace('\\1', '\\2') + '|'
17626 + block.list.source.replace('\\1', '\\3') + '|')
17630 * GFM + Tables Block Grammar
17633 block.tables = merge({}, block.gfm, {
17634 nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
17635 table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
17642 var Lexer = function (options) {
17644 this.tokens.links = {};
17645 this.options = options || marked.defaults;
17646 this.rules = block.normal;
17648 if (this.options.gfm) {
17649 if (this.options.tables) {
17650 this.rules = block.tables;
17652 this.rules = block.gfm;
17658 * Expose Block Rules
17661 Lexer.rules = block;
17664 * Static Lex Method
17667 Lexer.lex = function(src, options) {
17668 var lexer = new Lexer(options);
17669 return lexer.lex(src);
17676 Lexer.prototype.lex = function(src) {
17678 .replace(/\r\n|\r/g, '\n')
17679 .replace(/\t/g, ' ')
17680 .replace(/\u00a0/g, ' ')
17681 .replace(/\u2424/g, '\n');
17683 return this.token(src, true);
17690 Lexer.prototype.token = function(src, top, bq) {
17691 var src = src.replace(/^ +$/gm, '')
17704 if (cap = this.rules.newline.exec(src)) {
17705 src = src.substring(cap[0].length);
17706 if (cap[0].length > 1) {
17714 if (cap = this.rules.code.exec(src)) {
17715 src = src.substring(cap[0].length);
17716 cap = cap[0].replace(/^ {4}/gm, '');
17719 text: !this.options.pedantic
17720 ? cap.replace(/\n+$/, '')
17727 if (cap = this.rules.fences.exec(src)) {
17728 src = src.substring(cap[0].length);
17738 if (cap = this.rules.heading.exec(src)) {
17739 src = src.substring(cap[0].length);
17742 depth: cap[1].length,
17748 // table no leading pipe (gfm)
17749 if (top && (cap = this.rules.nptable.exec(src))) {
17750 src = src.substring(cap[0].length);
17754 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17755 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17756 cells: cap[3].replace(/\n$/, '').split('\n')
17759 for (i = 0; i < item.align.length; i++) {
17760 if (/^ *-+: *$/.test(item.align[i])) {
17761 item.align[i] = 'right';
17762 } else if (/^ *:-+: *$/.test(item.align[i])) {
17763 item.align[i] = 'center';
17764 } else if (/^ *:-+ *$/.test(item.align[i])) {
17765 item.align[i] = 'left';
17767 item.align[i] = null;
17771 for (i = 0; i < item.cells.length; i++) {
17772 item.cells[i] = item.cells[i].split(/ *\| */);
17775 this.tokens.push(item);
17781 if (cap = this.rules.lheading.exec(src)) {
17782 src = src.substring(cap[0].length);
17785 depth: cap[2] === '=' ? 1 : 2,
17792 if (cap = this.rules.hr.exec(src)) {
17793 src = src.substring(cap[0].length);
17801 if (cap = this.rules.blockquote.exec(src)) {
17802 src = src.substring(cap[0].length);
17805 type: 'blockquote_start'
17808 cap = cap[0].replace(/^ *> ?/gm, '');
17810 // Pass `top` to keep the current
17811 // "toplevel" state. This is exactly
17812 // how markdown.pl works.
17813 this.token(cap, top, true);
17816 type: 'blockquote_end'
17823 if (cap = this.rules.list.exec(src)) {
17824 src = src.substring(cap[0].length);
17828 type: 'list_start',
17829 ordered: bull.length > 1
17832 // Get each top-level item.
17833 cap = cap[0].match(this.rules.item);
17839 for (; i < l; i++) {
17842 // Remove the list item's bullet
17843 // so it is seen as the next token.
17844 space = item.length;
17845 item = item.replace(/^ *([*+-]|\d+\.) +/, '');
17847 // Outdent whatever the
17848 // list item contains. Hacky.
17849 if (~item.indexOf('\n ')) {
17850 space -= item.length;
17851 item = !this.options.pedantic
17852 ? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
17853 : item.replace(/^ {1,4}/gm, '');
17856 // Determine whether the next list item belongs here.
17857 // Backpedal if it does not belong in this list.
17858 if (this.options.smartLists && i !== l - 1) {
17859 b = block.bullet.exec(cap[i + 1])[0];
17860 if (bull !== b && !(bull.length > 1 && b.length > 1)) {
17861 src = cap.slice(i + 1).join('\n') + src;
17866 // Determine whether item is loose or not.
17867 // Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
17868 // for discount behavior.
17869 loose = next || /\n\n(?!\s*$)/.test(item);
17871 next = item.charAt(item.length - 1) === '\n';
17872 if (!loose) { loose = next; }
17877 ? 'loose_item_start'
17878 : 'list_item_start'
17882 this.token(item, false, bq);
17885 type: 'list_item_end'
17897 if (cap = this.rules.html.exec(src)) {
17898 src = src.substring(cap[0].length);
17900 type: this.options.sanitize
17903 pre: !this.options.sanitizer
17904 && (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
17911 if ((!bq && top) && (cap = this.rules.def.exec(src))) {
17912 src = src.substring(cap[0].length);
17913 this.tokens.links[cap[1].toLowerCase()] = {
17921 if (top && (cap = this.rules.table.exec(src))) {
17922 src = src.substring(cap[0].length);
17926 header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
17927 align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
17928 cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
17931 for (i = 0; i < item.align.length; i++) {
17932 if (/^ *-+: *$/.test(item.align[i])) {
17933 item.align[i] = 'right';
17934 } else if (/^ *:-+: *$/.test(item.align[i])) {
17935 item.align[i] = 'center';
17936 } else if (/^ *:-+ *$/.test(item.align[i])) {
17937 item.align[i] = 'left';
17939 item.align[i] = null;
17943 for (i = 0; i < item.cells.length; i++) {
17944 item.cells[i] = item.cells[i]
17945 .replace(/^ *\| *| *\| *$/g, '')
17949 this.tokens.push(item);
17954 // top-level paragraph
17955 if (top && (cap = this.rules.paragraph.exec(src))) {
17956 src = src.substring(cap[0].length);
17959 text: cap[1].charAt(cap[1].length - 1) === '\n'
17960 ? cap[1].slice(0, -1)
17967 if (cap = this.rules.text.exec(src)) {
17968 // Top-level should never reach here.
17969 src = src.substring(cap[0].length);
17979 Error('Infinite loop on byte: ' + src.charCodeAt(0));
17983 return this.tokens;
17987 * Inline-Level Grammar
17991 escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
17992 autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
17994 tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
17995 link: /^!?\[(inside)\]\(href\)/,
17996 reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
17997 nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
17998 strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
17999 em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
18000 code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
18001 br: /^ {2,}\n(?!\s*$)/,
18003 text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
18006 inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
18007 inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
18009 inline.link = replace(inline.link)
18010 ('inside', inline._inside)
18011 ('href', inline._href)
18014 inline.reflink = replace(inline.reflink)
18015 ('inside', inline._inside)
18019 * Normal Inline Grammar
18022 inline.normal = merge({}, inline);
18025 * Pedantic Inline Grammar
18028 inline.pedantic = merge({}, inline.normal, {
18029 strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
18030 em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
18034 * GFM Inline Grammar
18037 inline.gfm = merge({}, inline.normal, {
18038 escape: replace(inline.escape)('])', '~|])')(),
18039 url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
18040 del: /^~~(?=\S)([\s\S]*?\S)~~/,
18041 text: replace(inline.text)
18043 ('|', '|https?://|')
18048 * GFM + Line Breaks Inline Grammar
18051 inline.breaks = merge({}, inline.gfm, {
18052 br: replace(inline.br)('{2,}', '*')(),
18053 text: replace(inline.gfm.text)('{2,}', '*')()
18057 * Inline Lexer & Compiler
18060 var InlineLexer = function (links, options) {
18061 this.options = options || marked.defaults;
18062 this.links = links;
18063 this.rules = inline.normal;
18064 this.renderer = this.options.renderer || new Renderer;
18065 this.renderer.options = this.options;
18069 Error('Tokens array requires a `links` property.');
18072 if (this.options.gfm) {
18073 if (this.options.breaks) {
18074 this.rules = inline.breaks;
18076 this.rules = inline.gfm;
18078 } else if (this.options.pedantic) {
18079 this.rules = inline.pedantic;
18084 * Expose Inline Rules
18087 InlineLexer.rules = inline;
18090 * Static Lexing/Compiling Method
18093 InlineLexer.output = function(src, links, options) {
18094 var inline = new InlineLexer(links, options);
18095 return inline.output(src);
18102 InlineLexer.prototype.output = function(src) {
18111 if (cap = this.rules.escape.exec(src)) {
18112 src = src.substring(cap[0].length);
18118 if (cap = this.rules.autolink.exec(src)) {
18119 src = src.substring(cap[0].length);
18120 if (cap[2] === '@') {
18121 text = cap[1].charAt(6) === ':'
18122 ? this.mangle(cap[1].substring(7))
18123 : this.mangle(cap[1]);
18124 href = this.mangle('mailto:') + text;
18126 text = escape(cap[1]);
18129 out += this.renderer.link(href, null, text);
18134 if (!this.inLink && (cap = this.rules.url.exec(src))) {
18135 src = src.substring(cap[0].length);
18136 text = escape(cap[1]);
18138 out += this.renderer.link(href, null, text);
18143 if (cap = this.rules.tag.exec(src)) {
18144 if (!this.inLink && /^<a /i.test(cap[0])) {
18145 this.inLink = true;
18146 } else if (this.inLink && /^<\/a>/i.test(cap[0])) {
18147 this.inLink = false;
18149 src = src.substring(cap[0].length);
18150 out += this.options.sanitize
18151 ? this.options.sanitizer
18152 ? this.options.sanitizer(cap[0])
18159 if (cap = this.rules.link.exec(src)) {
18160 src = src.substring(cap[0].length);
18161 this.inLink = true;
18162 out += this.outputLink(cap, {
18166 this.inLink = false;
18171 if ((cap = this.rules.reflink.exec(src))
18172 || (cap = this.rules.nolink.exec(src))) {
18173 src = src.substring(cap[0].length);
18174 link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
18175 link = this.links[link.toLowerCase()];
18176 if (!link || !link.href) {
18177 out += cap[0].charAt(0);
18178 src = cap[0].substring(1) + src;
18181 this.inLink = true;
18182 out += this.outputLink(cap, link);
18183 this.inLink = false;
18188 if (cap = this.rules.strong.exec(src)) {
18189 src = src.substring(cap[0].length);
18190 out += this.renderer.strong(this.output(cap[2] || cap[1]));
18195 if (cap = this.rules.em.exec(src)) {
18196 src = src.substring(cap[0].length);
18197 out += this.renderer.em(this.output(cap[2] || cap[1]));
18202 if (cap = this.rules.code.exec(src)) {
18203 src = src.substring(cap[0].length);
18204 out += this.renderer.codespan(escape(cap[2], true));
18209 if (cap = this.rules.br.exec(src)) {
18210 src = src.substring(cap[0].length);
18211 out += this.renderer.br();
18216 if (cap = this.rules.del.exec(src)) {
18217 src = src.substring(cap[0].length);
18218 out += this.renderer.del(this.output(cap[1]));
18223 if (cap = this.rules.text.exec(src)) {
18224 src = src.substring(cap[0].length);
18225 out += this.renderer.text(escape(this.smartypants(cap[0])));
18231 Error('Infinite loop on byte: ' + src.charCodeAt(0));
18242 InlineLexer.prototype.outputLink = function(cap, link) {
18243 var href = escape(link.href)
18244 , title = link.title ? escape(link.title) : null;
18246 return cap[0].charAt(0) !== '!'
18247 ? this.renderer.link(href, title, this.output(cap[1]))
18248 : this.renderer.image(href, title, escape(cap[1]));
18252 * Smartypants Transformations
18255 InlineLexer.prototype.smartypants = function(text) {
18256 if (!this.options.smartypants) { return text; }
18259 .replace(/---/g, '\u2014')
18261 .replace(/--/g, '\u2013')
18263 .replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
18264 // closing singles & apostrophes
18265 .replace(/'/g, '\u2019')
18267 .replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
18269 .replace(/"/g, '\u201d')
18271 .replace(/\.{3}/g, '\u2026');
18278 InlineLexer.prototype.mangle = function(text) {
18279 if (!this.options.mangle) { return text; }
18285 for (; i < l; i++) {
18286 ch = text.charCodeAt(i);
18287 if (Math.random() > 0.5) {
18288 ch = 'x' + ch.toString(16);
18290 out += '&#' + ch + ';';
18301 * eval:var:Renderer
18304 var Renderer = function (options) {
18305 this.options = options || {};
18308 Renderer.prototype.code = function(code, lang, escaped) {
18309 if (this.options.highlight) {
18310 var out = this.options.highlight(code, lang);
18311 if (out != null && out !== code) {
18316 // hack!!! - it's already escapeD?
18321 return '<pre><code>'
18322 + (escaped ? code : escape(code, true))
18323 + '\n</code></pre>';
18326 return '<pre><code class="'
18327 + this.options.langPrefix
18328 + escape(lang, true)
18330 + (escaped ? code : escape(code, true))
18331 + '\n</code></pre>\n';
18334 Renderer.prototype.blockquote = function(quote) {
18335 return '<blockquote>\n' + quote + '</blockquote>\n';
18338 Renderer.prototype.html = function(html) {
18342 Renderer.prototype.heading = function(text, level, raw) {
18346 + this.options.headerPrefix
18347 + raw.toLowerCase().replace(/[^\w]+/g, '-')
18355 Renderer.prototype.hr = function() {
18356 return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
18359 Renderer.prototype.list = function(body, ordered) {
18360 var type = ordered ? 'ol' : 'ul';
18361 return '<' + type + '>\n' + body + '</' + type + '>\n';
18364 Renderer.prototype.listitem = function(text) {
18365 return '<li>' + text + '</li>\n';
18368 Renderer.prototype.paragraph = function(text) {
18369 return '<p>' + text + '</p>\n';
18372 Renderer.prototype.table = function(header, body) {
18373 return '<table class="table table-striped">\n'
18383 Renderer.prototype.tablerow = function(content) {
18384 return '<tr>\n' + content + '</tr>\n';
18387 Renderer.prototype.tablecell = function(content, flags) {
18388 var type = flags.header ? 'th' : 'td';
18389 var tag = flags.align
18390 ? '<' + type + ' style="text-align:' + flags.align + '">'
18391 : '<' + type + '>';
18392 return tag + content + '</' + type + '>\n';
18395 // span level renderer
18396 Renderer.prototype.strong = function(text) {
18397 return '<strong>' + text + '</strong>';
18400 Renderer.prototype.em = function(text) {
18401 return '<em>' + text + '</em>';
18404 Renderer.prototype.codespan = function(text) {
18405 return '<code>' + text + '</code>';
18408 Renderer.prototype.br = function() {
18409 return this.options.xhtml ? '<br/>' : '<br>';
18412 Renderer.prototype.del = function(text) {
18413 return '<del>' + text + '</del>';
18416 Renderer.prototype.link = function(href, title, text) {
18417 if (this.options.sanitize) {
18419 var prot = decodeURIComponent(unescape(href))
18420 .replace(/[^\w:]/g, '')
18425 if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
18429 var out = '<a href="' + href + '"';
18431 out += ' title="' + title + '"';
18433 out += '>' + text + '</a>';
18437 Renderer.prototype.image = function(href, title, text) {
18438 var out = '<img src="' + href + '" alt="' + text + '"';
18440 out += ' title="' + title + '"';
18442 out += this.options.xhtml ? '/>' : '>';
18446 Renderer.prototype.text = function(text) {
18451 * Parsing & Compiling
18457 var Parser= function (options) {
18460 this.options = options || marked.defaults;
18461 this.options.renderer = this.options.renderer || new Renderer;
18462 this.renderer = this.options.renderer;
18463 this.renderer.options = this.options;
18467 * Static Parse Method
18470 Parser.parse = function(src, options, renderer) {
18471 var parser = new Parser(options, renderer);
18472 return parser.parse(src);
18479 Parser.prototype.parse = function(src) {
18480 this.inline = new InlineLexer(src.links, this.options, this.renderer);
18481 this.tokens = src.reverse();
18484 while (this.next()) {
18495 Parser.prototype.next = function() {
18496 return this.token = this.tokens.pop();
18500 * Preview Next Token
18503 Parser.prototype.peek = function() {
18504 return this.tokens[this.tokens.length - 1] || 0;
18508 * Parse Text Tokens
18511 Parser.prototype.parseText = function() {
18512 var body = this.token.text;
18514 while (this.peek().type === 'text') {
18515 body += '\n' + this.next().text;
18518 return this.inline.output(body);
18522 * Parse Current Token
18525 Parser.prototype.tok = function() {
18526 switch (this.token.type) {
18531 return this.renderer.hr();
18534 return this.renderer.heading(
18535 this.inline.output(this.token.text),
18540 return this.renderer.code(this.token.text,
18542 this.token.escaped);
18555 for (i = 0; i < this.token.header.length; i++) {
18556 flags = { header: true, align: this.token.align[i] };
18557 cell += this.renderer.tablecell(
18558 this.inline.output(this.token.header[i]),
18559 { header: true, align: this.token.align[i] }
18562 header += this.renderer.tablerow(cell);
18564 for (i = 0; i < this.token.cells.length; i++) {
18565 row = this.token.cells[i];
18568 for (j = 0; j < row.length; j++) {
18569 cell += this.renderer.tablecell(
18570 this.inline.output(row[j]),
18571 { header: false, align: this.token.align[j] }
18575 body += this.renderer.tablerow(cell);
18577 return this.renderer.table(header, body);
18579 case 'blockquote_start': {
18582 while (this.next().type !== 'blockquote_end') {
18583 body += this.tok();
18586 return this.renderer.blockquote(body);
18588 case 'list_start': {
18590 , ordered = this.token.ordered;
18592 while (this.next().type !== 'list_end') {
18593 body += this.tok();
18596 return this.renderer.list(body, ordered);
18598 case 'list_item_start': {
18601 while (this.next().type !== 'list_item_end') {
18602 body += this.token.type === 'text'
18607 return this.renderer.listitem(body);
18609 case 'loose_item_start': {
18612 while (this.next().type !== 'list_item_end') {
18613 body += this.tok();
18616 return this.renderer.listitem(body);
18619 var html = !this.token.pre && !this.options.pedantic
18620 ? this.inline.output(this.token.text)
18622 return this.renderer.html(html);
18624 case 'paragraph': {
18625 return this.renderer.paragraph(this.inline.output(this.token.text));
18628 return this.renderer.paragraph(this.parseText());
18640 var marked = function (src, opt, callback) {
18641 if (callback || typeof opt === 'function') {
18647 opt = merge({}, marked.defaults, opt || {});
18649 var highlight = opt.highlight
18655 tokens = Lexer.lex(src, opt)
18657 return callback(e);
18660 pending = tokens.length;
18664 var done = function(err) {
18666 opt.highlight = highlight;
18667 return callback(err);
18673 out = Parser.parse(tokens, opt);
18678 opt.highlight = highlight;
18682 : callback(null, out);
18685 if (!highlight || highlight.length < 3) {
18689 delete opt.highlight;
18691 if (!pending) { return done(); }
18693 for (; i < tokens.length; i++) {
18695 if (token.type !== 'code') {
18696 return --pending || done();
18698 return highlight(token.text, token.lang, function(err, code) {
18699 if (err) { return done(err); }
18700 if (code == null || code === token.text) {
18701 return --pending || done();
18704 token.escaped = true;
18705 --pending || done();
18713 if (opt) { opt = merge({}, marked.defaults, opt); }
18714 return Parser.parse(Lexer.lex(src, opt), opt);
18716 e.message += '\nPlease report this to https://github.com/chjj/marked.';
18717 if ((opt || marked.defaults).silent) {
18718 return '<p>An error occured:</p><pre>'
18719 + escape(e.message + '', true)
18731 marked.setOptions = function(opt) {
18732 merge(marked.defaults, opt);
18736 marked.defaults = {
18747 langPrefix: 'lang-',
18748 smartypants: false,
18750 renderer: new Renderer,
18758 marked.Parser = Parser;
18759 marked.parser = Parser.parse;
18761 marked.Renderer = Renderer;
18763 marked.Lexer = Lexer;
18764 marked.lexer = Lexer.lex;
18766 marked.InlineLexer = InlineLexer;
18767 marked.inlineLexer = InlineLexer.output;
18769 marked.parse = marked;
18771 Roo.Markdown.marked = marked;
18775 * Ext JS Library 1.1.1
18776 * Copyright(c) 2006-2007, Ext JS, LLC.
18778 * Originally Released Under LGPL - original licence link has changed is not relivant.
18781 * <script type="text/javascript">
18787 * These classes are derivatives of the similarly named classes in the YUI Library.
18788 * The original license:
18789 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18790 * Code licensed under the BSD License:
18791 * http://developer.yahoo.net/yui/license.txt
18796 var Event=Roo.EventManager;
18797 var Dom=Roo.lib.Dom;
18800 * @class Roo.dd.DragDrop
18801 * @extends Roo.util.Observable
18802 * Defines the interface and base operation of items that that can be
18803 * dragged or can be drop targets. It was designed to be extended, overriding
18804 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
18805 * Up to three html elements can be associated with a DragDrop instance:
18807 * <li>linked element: the element that is passed into the constructor.
18808 * This is the element which defines the boundaries for interaction with
18809 * other DragDrop objects.</li>
18810 * <li>handle element(s): The drag operation only occurs if the element that
18811 * was clicked matches a handle element. By default this is the linked
18812 * element, but there are times that you will want only a portion of the
18813 * linked element to initiate the drag operation, and the setHandleElId()
18814 * method provides a way to define this.</li>
18815 * <li>drag element: this represents the element that would be moved along
18816 * with the cursor during a drag operation. By default, this is the linked
18817 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
18818 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
18821 * This class should not be instantiated until the onload event to ensure that
18822 * the associated elements are available.
18823 * The following would define a DragDrop obj that would interact with any
18824 * other DragDrop obj in the "group1" group:
18826 * dd = new Roo.dd.DragDrop("div1", "group1");
18828 * Since none of the event handlers have been implemented, nothing would
18829 * actually happen if you were to run the code above. Normally you would
18830 * override this class or one of the default implementations, but you can
18831 * also override the methods you want on an instance of the class...
18833 * dd.onDragDrop = function(e, id) {
18834 * alert("dd was dropped on " + id);
18838 * @param {String} id of the element that is linked to this instance
18839 * @param {String} sGroup the group of related DragDrop objects
18840 * @param {object} config an object containing configurable attributes
18841 * Valid properties for DragDrop:
18842 * padding, isTarget, maintainOffset, primaryButtonOnly
18844 Roo.dd.DragDrop = function(id, sGroup, config) {
18846 this.init(id, sGroup, config);
18851 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
18854 * The id of the element associated with this object. This is what we
18855 * refer to as the "linked element" because the size and position of
18856 * this element is used to determine when the drag and drop objects have
18864 * Configuration attributes passed into the constructor
18871 * The id of the element that will be dragged. By default this is same
18872 * as the linked element , but could be changed to another element. Ex:
18874 * @property dragElId
18881 * the id of the element that initiates the drag operation. By default
18882 * this is the linked element, but could be changed to be a child of this
18883 * element. This lets us do things like only starting the drag when the
18884 * header element within the linked html element is clicked.
18885 * @property handleElId
18892 * An associative array of HTML tags that will be ignored if clicked.
18893 * @property invalidHandleTypes
18894 * @type {string: string}
18896 invalidHandleTypes: null,
18899 * An associative array of ids for elements that will be ignored if clicked
18900 * @property invalidHandleIds
18901 * @type {string: string}
18903 invalidHandleIds: null,
18906 * An indexted array of css class names for elements that will be ignored
18908 * @property invalidHandleClasses
18911 invalidHandleClasses: null,
18914 * The linked element's absolute X position at the time the drag was
18916 * @property startPageX
18923 * The linked element's absolute X position at the time the drag was
18925 * @property startPageY
18932 * The group defines a logical collection of DragDrop objects that are
18933 * related. Instances only get events when interacting with other
18934 * DragDrop object in the same group. This lets us define multiple
18935 * groups using a single DragDrop subclass if we want.
18937 * @type {string: string}
18942 * Individual drag/drop instances can be locked. This will prevent
18943 * onmousedown start drag.
18951 * Lock this instance
18954 lock: function() { this.locked = true; },
18957 * Unlock this instace
18960 unlock: function() { this.locked = false; },
18963 * By default, all insances can be a drop target. This can be disabled by
18964 * setting isTarget to false.
18971 * The padding configured for this drag and drop object for calculating
18972 * the drop zone intersection with this object.
18979 * Cached reference to the linked element
18980 * @property _domRef
18986 * Internal typeof flag
18987 * @property __ygDragDrop
18990 __ygDragDrop: true,
18993 * Set to true when horizontal contraints are applied
18994 * @property constrainX
19001 * Set to true when vertical contraints are applied
19002 * @property constrainY
19009 * The left constraint
19017 * The right constraint
19025 * The up constraint
19034 * The down constraint
19042 * Maintain offsets when we resetconstraints. Set to true when you want
19043 * the position of the element relative to its parent to stay the same
19044 * when the page changes
19046 * @property maintainOffset
19049 maintainOffset: false,
19052 * Array of pixel locations the element will snap to if we specified a
19053 * horizontal graduation/interval. This array is generated automatically
19054 * when you define a tick interval.
19061 * Array of pixel locations the element will snap to if we specified a
19062 * vertical graduation/interval. This array is generated automatically
19063 * when you define a tick interval.
19070 * By default the drag and drop instance will only respond to the primary
19071 * button click (left button for a right-handed mouse). Set to true to
19072 * allow drag and drop to start with any mouse click that is propogated
19074 * @property primaryButtonOnly
19077 primaryButtonOnly: true,
19080 * The availabe property is false until the linked dom element is accessible.
19081 * @property available
19087 * By default, drags can only be initiated if the mousedown occurs in the
19088 * region the linked element is. This is done in part to work around a
19089 * bug in some browsers that mis-report the mousedown if the previous
19090 * mouseup happened outside of the window. This property is set to true
19091 * if outer handles are defined.
19093 * @property hasOuterHandles
19097 hasOuterHandles: false,
19100 * Code that executes immediately before the startDrag event
19101 * @method b4StartDrag
19104 b4StartDrag: function(x, y) { },
19107 * Abstract method called after a drag/drop object is clicked
19108 * and the drag or mousedown time thresholds have beeen met.
19109 * @method startDrag
19110 * @param {int} X click location
19111 * @param {int} Y click location
19113 startDrag: function(x, y) { /* override this */ },
19116 * Code that executes immediately before the onDrag event
19120 b4Drag: function(e) { },
19123 * Abstract method called during the onMouseMove event while dragging an
19126 * @param {Event} e the mousemove event
19128 onDrag: function(e) { /* override this */ },
19131 * Abstract method called when this element fist begins hovering over
19132 * another DragDrop obj
19133 * @method onDragEnter
19134 * @param {Event} e the mousemove event
19135 * @param {String|DragDrop[]} id In POINT mode, the element
19136 * id this is hovering over. In INTERSECT mode, an array of one or more
19137 * dragdrop items being hovered over.
19139 onDragEnter: function(e, id) { /* override this */ },
19142 * Code that executes immediately before the onDragOver event
19143 * @method b4DragOver
19146 b4DragOver: function(e) { },
19149 * Abstract method called when this element is hovering over another
19151 * @method onDragOver
19152 * @param {Event} e the mousemove event
19153 * @param {String|DragDrop[]} id In POINT mode, the element
19154 * id this is hovering over. In INTERSECT mode, an array of dd items
19155 * being hovered over.
19157 onDragOver: function(e, id) { /* override this */ },
19160 * Code that executes immediately before the onDragOut event
19161 * @method b4DragOut
19164 b4DragOut: function(e) { },
19167 * Abstract method called when we are no longer hovering over an element
19168 * @method onDragOut
19169 * @param {Event} e the mousemove event
19170 * @param {String|DragDrop[]} id In POINT mode, the element
19171 * id this was hovering over. In INTERSECT mode, an array of dd items
19172 * that the mouse is no longer over.
19174 onDragOut: function(e, id) { /* override this */ },
19177 * Code that executes immediately before the onDragDrop event
19178 * @method b4DragDrop
19181 b4DragDrop: function(e) { },
19184 * Abstract method called when this item is dropped on another DragDrop
19186 * @method onDragDrop
19187 * @param {Event} e the mouseup event
19188 * @param {String|DragDrop[]} id In POINT mode, the element
19189 * id this was dropped on. In INTERSECT mode, an array of dd items this
19192 onDragDrop: function(e, id) { /* override this */ },
19195 * Abstract method called when this item is dropped on an area with no
19197 * @method onInvalidDrop
19198 * @param {Event} e the mouseup event
19200 onInvalidDrop: function(e) { /* override this */ },
19203 * Code that executes immediately before the endDrag event
19204 * @method b4EndDrag
19207 b4EndDrag: function(e) { },
19210 * Fired when we are done dragging the object
19212 * @param {Event} e the mouseup event
19214 endDrag: function(e) { /* override this */ },
19217 * Code executed immediately before the onMouseDown event
19218 * @method b4MouseDown
19219 * @param {Event} e the mousedown event
19222 b4MouseDown: function(e) { },
19225 * Event handler that fires when a drag/drop obj gets a mousedown
19226 * @method onMouseDown
19227 * @param {Event} e the mousedown event
19229 onMouseDown: function(e) { /* override this */ },
19232 * Event handler that fires when a drag/drop obj gets a mouseup
19233 * @method onMouseUp
19234 * @param {Event} e the mouseup event
19236 onMouseUp: function(e) { /* override this */ },
19239 * Override the onAvailable method to do what is needed after the initial
19240 * position was determined.
19241 * @method onAvailable
19243 onAvailable: function () {
19247 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
19250 defaultPadding : {left:0, right:0, top:0, bottom:0},
19253 * Initializes the drag drop object's constraints to restrict movement to a certain element.
19257 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
19258 { dragElId: "existingProxyDiv" });
19259 dd.startDrag = function(){
19260 this.constrainTo("parent-id");
19263 * Or you can initalize it using the {@link Roo.Element} object:
19265 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
19266 startDrag : function(){
19267 this.constrainTo("parent-id");
19271 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
19272 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
19273 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
19274 * an object containing the sides to pad. For example: {right:10, bottom:10}
19275 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
19277 constrainTo : function(constrainTo, pad, inContent){
19278 if(typeof pad == "number"){
19279 pad = {left: pad, right:pad, top:pad, bottom:pad};
19281 pad = pad || this.defaultPadding;
19282 var b = Roo.get(this.getEl()).getBox();
19283 var ce = Roo.get(constrainTo);
19284 var s = ce.getScroll();
19285 var c, cd = ce.dom;
19286 if(cd == document.body){
19287 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
19290 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
19294 var topSpace = b.y - c.y;
19295 var leftSpace = b.x - c.x;
19297 this.resetConstraints();
19298 this.setXConstraint(leftSpace - (pad.left||0), // left
19299 c.width - leftSpace - b.width - (pad.right||0) //right
19301 this.setYConstraint(topSpace - (pad.top||0), //top
19302 c.height - topSpace - b.height - (pad.bottom||0) //bottom
19307 * Returns a reference to the linked element
19309 * @return {HTMLElement} the html element
19311 getEl: function() {
19312 if (!this._domRef) {
19313 this._domRef = Roo.getDom(this.id);
19316 return this._domRef;
19320 * Returns a reference to the actual element to drag. By default this is
19321 * the same as the html element, but it can be assigned to another
19322 * element. An example of this can be found in Roo.dd.DDProxy
19323 * @method getDragEl
19324 * @return {HTMLElement} the html element
19326 getDragEl: function() {
19327 return Roo.getDom(this.dragElId);
19331 * Sets up the DragDrop object. Must be called in the constructor of any
19332 * Roo.dd.DragDrop subclass
19334 * @param id the id of the linked element
19335 * @param {String} sGroup the group of related items
19336 * @param {object} config configuration attributes
19338 init: function(id, sGroup, config) {
19339 this.initTarget(id, sGroup, config);
19340 if (!Roo.isTouch) {
19341 Event.on(this.id, "mousedown", this.handleMouseDown, this);
19343 Event.on(this.id, "touchstart", this.handleMouseDown, this);
19344 // Event.on(this.id, "selectstart", Event.preventDefault);
19348 * Initializes Targeting functionality only... the object does not
19349 * get a mousedown handler.
19350 * @method initTarget
19351 * @param id the id of the linked element
19352 * @param {String} sGroup the group of related items
19353 * @param {object} config configuration attributes
19355 initTarget: function(id, sGroup, config) {
19357 // configuration attributes
19358 this.config = config || {};
19360 // create a local reference to the drag and drop manager
19361 this.DDM = Roo.dd.DDM;
19362 // initialize the groups array
19365 // assume that we have an element reference instead of an id if the
19366 // parameter is not a string
19367 if (typeof id !== "string") {
19374 // add to an interaction group
19375 this.addToGroup((sGroup) ? sGroup : "default");
19377 // We don't want to register this as the handle with the manager
19378 // so we just set the id rather than calling the setter.
19379 this.handleElId = id;
19381 // the linked element is the element that gets dragged by default
19382 this.setDragElId(id);
19384 // by default, clicked anchors will not start drag operations.
19385 this.invalidHandleTypes = { A: "A" };
19386 this.invalidHandleIds = {};
19387 this.invalidHandleClasses = [];
19389 this.applyConfig();
19391 this.handleOnAvailable();
19395 * Applies the configuration parameters that were passed into the constructor.
19396 * This is supposed to happen at each level through the inheritance chain. So
19397 * a DDProxy implentation will execute apply config on DDProxy, DD, and
19398 * DragDrop in order to get all of the parameters that are available in
19400 * @method applyConfig
19402 applyConfig: function() {
19404 // configurable properties:
19405 // padding, isTarget, maintainOffset, primaryButtonOnly
19406 this.padding = this.config.padding || [0, 0, 0, 0];
19407 this.isTarget = (this.config.isTarget !== false);
19408 this.maintainOffset = (this.config.maintainOffset);
19409 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
19414 * Executed when the linked element is available
19415 * @method handleOnAvailable
19418 handleOnAvailable: function() {
19419 this.available = true;
19420 this.resetConstraints();
19421 this.onAvailable();
19425 * Configures the padding for the target zone in px. Effectively expands
19426 * (or reduces) the virtual object size for targeting calculations.
19427 * Supports css-style shorthand; if only one parameter is passed, all sides
19428 * will have that padding, and if only two are passed, the top and bottom
19429 * will have the first param, the left and right the second.
19430 * @method setPadding
19431 * @param {int} iTop Top pad
19432 * @param {int} iRight Right pad
19433 * @param {int} iBot Bot pad
19434 * @param {int} iLeft Left pad
19436 setPadding: function(iTop, iRight, iBot, iLeft) {
19437 // this.padding = [iLeft, iRight, iTop, iBot];
19438 if (!iRight && 0 !== iRight) {
19439 this.padding = [iTop, iTop, iTop, iTop];
19440 } else if (!iBot && 0 !== iBot) {
19441 this.padding = [iTop, iRight, iTop, iRight];
19443 this.padding = [iTop, iRight, iBot, iLeft];
19448 * Stores the initial placement of the linked element.
19449 * @method setInitialPosition
19450 * @param {int} diffX the X offset, default 0
19451 * @param {int} diffY the Y offset, default 0
19453 setInitPosition: function(diffX, diffY) {
19454 var el = this.getEl();
19456 if (!this.DDM.verifyEl(el)) {
19460 var dx = diffX || 0;
19461 var dy = diffY || 0;
19463 var p = Dom.getXY( el );
19465 this.initPageX = p[0] - dx;
19466 this.initPageY = p[1] - dy;
19468 this.lastPageX = p[0];
19469 this.lastPageY = p[1];
19472 this.setStartPosition(p);
19476 * Sets the start position of the element. This is set when the obj
19477 * is initialized, the reset when a drag is started.
19478 * @method setStartPosition
19479 * @param pos current position (from previous lookup)
19482 setStartPosition: function(pos) {
19483 var p = pos || Dom.getXY( this.getEl() );
19484 this.deltaSetXY = null;
19486 this.startPageX = p[0];
19487 this.startPageY = p[1];
19491 * Add this instance to a group of related drag/drop objects. All
19492 * instances belong to at least one group, and can belong to as many
19493 * groups as needed.
19494 * @method addToGroup
19495 * @param sGroup {string} the name of the group
19497 addToGroup: function(sGroup) {
19498 this.groups[sGroup] = true;
19499 this.DDM.regDragDrop(this, sGroup);
19503 * Remove's this instance from the supplied interaction group
19504 * @method removeFromGroup
19505 * @param {string} sGroup The group to drop
19507 removeFromGroup: function(sGroup) {
19508 if (this.groups[sGroup]) {
19509 delete this.groups[sGroup];
19512 this.DDM.removeDDFromGroup(this, sGroup);
19516 * Allows you to specify that an element other than the linked element
19517 * will be moved with the cursor during a drag
19518 * @method setDragElId
19519 * @param id {string} the id of the element that will be used to initiate the drag
19521 setDragElId: function(id) {
19522 this.dragElId = id;
19526 * Allows you to specify a child of the linked element that should be
19527 * used to initiate the drag operation. An example of this would be if
19528 * you have a content div with text and links. Clicking anywhere in the
19529 * content area would normally start the drag operation. Use this method
19530 * to specify that an element inside of the content div is the element
19531 * that starts the drag operation.
19532 * @method setHandleElId
19533 * @param id {string} the id of the element that will be used to
19534 * initiate the drag.
19536 setHandleElId: function(id) {
19537 if (typeof id !== "string") {
19540 this.handleElId = id;
19541 this.DDM.regHandle(this.id, id);
19545 * Allows you to set an element outside of the linked element as a drag
19547 * @method setOuterHandleElId
19548 * @param id the id of the element that will be used to initiate the drag
19550 setOuterHandleElId: function(id) {
19551 if (typeof id !== "string") {
19554 Event.on(id, "mousedown",
19555 this.handleMouseDown, this);
19556 this.setHandleElId(id);
19558 this.hasOuterHandles = true;
19562 * Remove all drag and drop hooks for this element
19565 unreg: function() {
19566 Event.un(this.id, "mousedown",
19567 this.handleMouseDown);
19568 Event.un(this.id, "touchstart",
19569 this.handleMouseDown);
19570 this._domRef = null;
19571 this.DDM._remove(this);
19574 destroy : function(){
19579 * Returns true if this instance is locked, or the drag drop mgr is locked
19580 * (meaning that all drag/drop is disabled on the page.)
19582 * @return {boolean} true if this obj or all drag/drop is locked, else
19585 isLocked: function() {
19586 return (this.DDM.isLocked() || this.locked);
19590 * Fired when this object is clicked
19591 * @method handleMouseDown
19593 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
19596 handleMouseDown: function(e, oDD){
19598 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
19599 //Roo.log('not touch/ button !=0');
19602 if (e.browserEvent.touches && e.browserEvent.touches.length != 1) {
19603 return; // double touch..
19607 if (this.isLocked()) {
19608 //Roo.log('locked');
19612 this.DDM.refreshCache(this.groups);
19613 // Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
19614 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
19615 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
19616 //Roo.log('no outer handes or not over target');
19619 // Roo.log('check validator');
19620 if (this.clickValidator(e)) {
19621 // Roo.log('validate success');
19622 // set the initial element position
19623 this.setStartPosition();
19626 this.b4MouseDown(e);
19627 this.onMouseDown(e);
19629 this.DDM.handleMouseDown(e, this);
19631 this.DDM.stopEvent(e);
19639 clickValidator: function(e) {
19640 var target = e.getTarget();
19641 return ( this.isValidHandleChild(target) &&
19642 (this.id == this.handleElId ||
19643 this.DDM.handleWasClicked(target, this.id)) );
19647 * Allows you to specify a tag name that should not start a drag operation
19648 * when clicked. This is designed to facilitate embedding links within a
19649 * drag handle that do something other than start the drag.
19650 * @method addInvalidHandleType
19651 * @param {string} tagName the type of element to exclude
19653 addInvalidHandleType: function(tagName) {
19654 var type = tagName.toUpperCase();
19655 this.invalidHandleTypes[type] = type;
19659 * Lets you to specify an element id for a child of a drag handle
19660 * that should not initiate a drag
19661 * @method addInvalidHandleId
19662 * @param {string} id the element id of the element you wish to ignore
19664 addInvalidHandleId: function(id) {
19665 if (typeof id !== "string") {
19668 this.invalidHandleIds[id] = id;
19672 * Lets you specify a css class of elements that will not initiate a drag
19673 * @method addInvalidHandleClass
19674 * @param {string} cssClass the class of the elements you wish to ignore
19676 addInvalidHandleClass: function(cssClass) {
19677 this.invalidHandleClasses.push(cssClass);
19681 * Unsets an excluded tag name set by addInvalidHandleType
19682 * @method removeInvalidHandleType
19683 * @param {string} tagName the type of element to unexclude
19685 removeInvalidHandleType: function(tagName) {
19686 var type = tagName.toUpperCase();
19687 // this.invalidHandleTypes[type] = null;
19688 delete this.invalidHandleTypes[type];
19692 * Unsets an invalid handle id
19693 * @method removeInvalidHandleId
19694 * @param {string} id the id of the element to re-enable
19696 removeInvalidHandleId: function(id) {
19697 if (typeof id !== "string") {
19700 delete this.invalidHandleIds[id];
19704 * Unsets an invalid css class
19705 * @method removeInvalidHandleClass
19706 * @param {string} cssClass the class of the element(s) you wish to
19709 removeInvalidHandleClass: function(cssClass) {
19710 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
19711 if (this.invalidHandleClasses[i] == cssClass) {
19712 delete this.invalidHandleClasses[i];
19718 * Checks the tag exclusion list to see if this click should be ignored
19719 * @method isValidHandleChild
19720 * @param {HTMLElement} node the HTMLElement to evaluate
19721 * @return {boolean} true if this is a valid tag type, false if not
19723 isValidHandleChild: function(node) {
19726 // var n = (node.nodeName == "#text") ? node.parentNode : node;
19729 nodeName = node.nodeName.toUpperCase();
19731 nodeName = node.nodeName;
19733 valid = valid && !this.invalidHandleTypes[nodeName];
19734 valid = valid && !this.invalidHandleIds[node.id];
19736 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
19737 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
19746 * Create the array of horizontal tick marks if an interval was specified
19747 * in setXConstraint().
19748 * @method setXTicks
19751 setXTicks: function(iStartX, iTickSize) {
19753 this.xTickSize = iTickSize;
19757 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
19759 this.xTicks[this.xTicks.length] = i;
19764 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
19766 this.xTicks[this.xTicks.length] = i;
19771 this.xTicks.sort(this.DDM.numericSort) ;
19775 * Create the array of vertical tick marks if an interval was specified in
19776 * setYConstraint().
19777 * @method setYTicks
19780 setYTicks: function(iStartY, iTickSize) {
19782 this.yTickSize = iTickSize;
19786 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
19788 this.yTicks[this.yTicks.length] = i;
19793 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
19795 this.yTicks[this.yTicks.length] = i;
19800 this.yTicks.sort(this.DDM.numericSort) ;
19804 * By default, the element can be dragged any place on the screen. Use
19805 * this method to limit the horizontal travel of the element. Pass in
19806 * 0,0 for the parameters if you want to lock the drag to the y axis.
19807 * @method setXConstraint
19808 * @param {int} iLeft the number of pixels the element can move to the left
19809 * @param {int} iRight the number of pixels the element can move to the
19811 * @param {int} iTickSize optional parameter for specifying that the
19813 * should move iTickSize pixels at a time.
19815 setXConstraint: function(iLeft, iRight, iTickSize) {
19816 this.leftConstraint = iLeft;
19817 this.rightConstraint = iRight;
19819 this.minX = this.initPageX - iLeft;
19820 this.maxX = this.initPageX + iRight;
19821 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
19823 this.constrainX = true;
19827 * Clears any constraints applied to this instance. Also clears ticks
19828 * since they can't exist independent of a constraint at this time.
19829 * @method clearConstraints
19831 clearConstraints: function() {
19832 this.constrainX = false;
19833 this.constrainY = false;
19838 * Clears any tick interval defined for this instance
19839 * @method clearTicks
19841 clearTicks: function() {
19842 this.xTicks = null;
19843 this.yTicks = null;
19844 this.xTickSize = 0;
19845 this.yTickSize = 0;
19849 * By default, the element can be dragged any place on the screen. Set
19850 * this to limit the vertical travel of the element. Pass in 0,0 for the
19851 * parameters if you want to lock the drag to the x axis.
19852 * @method setYConstraint
19853 * @param {int} iUp the number of pixels the element can move up
19854 * @param {int} iDown the number of pixels the element can move down
19855 * @param {int} iTickSize optional parameter for specifying that the
19856 * element should move iTickSize pixels at a time.
19858 setYConstraint: function(iUp, iDown, iTickSize) {
19859 this.topConstraint = iUp;
19860 this.bottomConstraint = iDown;
19862 this.minY = this.initPageY - iUp;
19863 this.maxY = this.initPageY + iDown;
19864 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
19866 this.constrainY = true;
19871 * resetConstraints must be called if you manually reposition a dd element.
19872 * @method resetConstraints
19873 * @param {boolean} maintainOffset
19875 resetConstraints: function() {
19878 // Maintain offsets if necessary
19879 if (this.initPageX || this.initPageX === 0) {
19880 // figure out how much this thing has moved
19881 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
19882 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
19884 this.setInitPosition(dx, dy);
19886 // This is the first time we have detected the element's position
19888 this.setInitPosition();
19891 if (this.constrainX) {
19892 this.setXConstraint( this.leftConstraint,
19893 this.rightConstraint,
19897 if (this.constrainY) {
19898 this.setYConstraint( this.topConstraint,
19899 this.bottomConstraint,
19905 * Normally the drag element is moved pixel by pixel, but we can specify
19906 * that it move a number of pixels at a time. This method resolves the
19907 * location when we have it set up like this.
19909 * @param {int} val where we want to place the object
19910 * @param {int[]} tickArray sorted array of valid points
19911 * @return {int} the closest tick
19914 getTick: function(val, tickArray) {
19917 // If tick interval is not defined, it is effectively 1 pixel,
19918 // so we return the value passed to us.
19920 } else if (tickArray[0] >= val) {
19921 // The value is lower than the first tick, so we return the first
19923 return tickArray[0];
19925 for (var i=0, len=tickArray.length; i<len; ++i) {
19927 if (tickArray[next] && tickArray[next] >= val) {
19928 var diff1 = val - tickArray[i];
19929 var diff2 = tickArray[next] - val;
19930 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
19934 // The value is larger than the last tick, so we return the last
19936 return tickArray[tickArray.length - 1];
19943 * @return {string} string representation of the dd obj
19945 toString: function() {
19946 return ("DragDrop " + this.id);
19954 * Ext JS Library 1.1.1
19955 * Copyright(c) 2006-2007, Ext JS, LLC.
19957 * Originally Released Under LGPL - original licence link has changed is not relivant.
19960 * <script type="text/javascript">
19965 * The drag and drop utility provides a framework for building drag and drop
19966 * applications. In addition to enabling drag and drop for specific elements,
19967 * the drag and drop elements are tracked by the manager class, and the
19968 * interactions between the various elements are tracked during the drag and
19969 * the implementing code is notified about these important moments.
19972 // Only load the library once. Rewriting the manager class would orphan
19973 // existing drag and drop instances.
19974 if (!Roo.dd.DragDropMgr) {
19977 * @class Roo.dd.DragDropMgr
19978 * DragDropMgr is a singleton that tracks the element interaction for
19979 * all DragDrop items in the window. Generally, you will not call
19980 * this class directly, but it does have helper methods that could
19981 * be useful in your DragDrop implementations.
19984 Roo.dd.DragDropMgr = function() {
19986 var Event = Roo.EventManager;
19991 * Two dimensional Array of registered DragDrop objects. The first
19992 * dimension is the DragDrop item group, the second the DragDrop
19995 * @type {string: string}
20002 * Array of element ids defined as drag handles. Used to determine
20003 * if the element that generated the mousedown event is actually the
20004 * handle and not the html element itself.
20005 * @property handleIds
20006 * @type {string: string}
20013 * the DragDrop object that is currently being dragged
20014 * @property dragCurrent
20022 * the DragDrop object(s) that are being hovered over
20023 * @property dragOvers
20031 * the X distance between the cursor and the object being dragged
20040 * the Y distance between the cursor and the object being dragged
20049 * Flag to determine if we should prevent the default behavior of the
20050 * events we define. By default this is true, but this can be set to
20051 * false if you need the default behavior (not recommended)
20052 * @property preventDefault
20056 preventDefault: true,
20059 * Flag to determine if we should stop the propagation of the events
20060 * we generate. This is true by default but you may want to set it to
20061 * false if the html element contains other features that require the
20063 * @property stopPropagation
20067 stopPropagation: true,
20070 * Internal flag that is set to true when drag and drop has been
20072 * @property initialized
20079 * All drag and drop can be disabled.
20087 * Called the first time an element is registered.
20093 this.initialized = true;
20097 * In point mode, drag and drop interaction is defined by the
20098 * location of the cursor during the drag/drop
20106 * In intersect mode, drag and drop interactio nis defined by the
20107 * overlap of two or more drag and drop objects.
20108 * @property INTERSECT
20115 * The current drag and drop mode. Default: POINT
20123 * Runs method on all drag and drop objects
20124 * @method _execOnAll
20128 _execOnAll: function(sMethod, args) {
20129 for (var i in this.ids) {
20130 for (var j in this.ids[i]) {
20131 var oDD = this.ids[i][j];
20132 if (! this.isTypeOfDD(oDD)) {
20135 oDD[sMethod].apply(oDD, args);
20141 * Drag and drop initialization. Sets up the global event handlers
20146 _onLoad: function() {
20150 if (!Roo.isTouch) {
20151 Event.on(document, "mouseup", this.handleMouseUp, this, true);
20152 Event.on(document, "mousemove", this.handleMouseMove, this, true);
20154 Event.on(document, "touchend", this.handleMouseUp, this, true);
20155 Event.on(document, "touchmove", this.handleMouseMove, this, true);
20157 Event.on(window, "unload", this._onUnload, this, true);
20158 Event.on(window, "resize", this._onResize, this, true);
20159 // Event.on(window, "mouseout", this._test);
20164 * Reset constraints on all drag and drop objs
20165 * @method _onResize
20169 _onResize: function(e) {
20170 this._execOnAll("resetConstraints", []);
20174 * Lock all drag and drop functionality
20178 lock: function() { this.locked = true; },
20181 * Unlock all drag and drop functionality
20185 unlock: function() { this.locked = false; },
20188 * Is drag and drop locked?
20190 * @return {boolean} True if drag and drop is locked, false otherwise.
20193 isLocked: function() { return this.locked; },
20196 * Location cache that is set for all drag drop objects when a drag is
20197 * initiated, cleared when the drag is finished.
20198 * @property locationCache
20205 * Set useCache to false if you want to force object the lookup of each
20206 * drag and drop linked element constantly during a drag.
20207 * @property useCache
20214 * The number of pixels that the mouse needs to move after the
20215 * mousedown before the drag is initiated. Default=3;
20216 * @property clickPixelThresh
20220 clickPixelThresh: 3,
20223 * The number of milliseconds after the mousedown event to initiate the
20224 * drag if we don't get a mouseup event. Default=1000
20225 * @property clickTimeThresh
20229 clickTimeThresh: 350,
20232 * Flag that indicates that either the drag pixel threshold or the
20233 * mousdown time threshold has been met
20234 * @property dragThreshMet
20239 dragThreshMet: false,
20242 * Timeout used for the click time threshold
20243 * @property clickTimeout
20248 clickTimeout: null,
20251 * The X position of the mousedown event stored for later use when a
20252 * drag threshold is met.
20261 * The Y position of the mousedown event stored for later use when a
20262 * drag threshold is met.
20271 * Each DragDrop instance must be registered with the DragDropMgr.
20272 * This is executed in DragDrop.init()
20273 * @method regDragDrop
20274 * @param {DragDrop} oDD the DragDrop object to register
20275 * @param {String} sGroup the name of the group this element belongs to
20278 regDragDrop: function(oDD, sGroup) {
20279 if (!this.initialized) { this.init(); }
20281 if (!this.ids[sGroup]) {
20282 this.ids[sGroup] = {};
20284 this.ids[sGroup][oDD.id] = oDD;
20288 * Removes the supplied dd instance from the supplied group. Executed
20289 * by DragDrop.removeFromGroup, so don't call this function directly.
20290 * @method removeDDFromGroup
20294 removeDDFromGroup: function(oDD, sGroup) {
20295 if (!this.ids[sGroup]) {
20296 this.ids[sGroup] = {};
20299 var obj = this.ids[sGroup];
20300 if (obj && obj[oDD.id]) {
20301 delete obj[oDD.id];
20306 * Unregisters a drag and drop item. This is executed in
20307 * DragDrop.unreg, use that method instead of calling this directly.
20312 _remove: function(oDD) {
20313 for (var g in oDD.groups) {
20314 if (g && this.ids[g][oDD.id]) {
20315 delete this.ids[g][oDD.id];
20318 delete this.handleIds[oDD.id];
20322 * Each DragDrop handle element must be registered. This is done
20323 * automatically when executing DragDrop.setHandleElId()
20324 * @method regHandle
20325 * @param {String} sDDId the DragDrop id this element is a handle for
20326 * @param {String} sHandleId the id of the element that is the drag
20330 regHandle: function(sDDId, sHandleId) {
20331 if (!this.handleIds[sDDId]) {
20332 this.handleIds[sDDId] = {};
20334 this.handleIds[sDDId][sHandleId] = sHandleId;
20338 * Utility function to determine if a given element has been
20339 * registered as a drag drop item.
20340 * @method isDragDrop
20341 * @param {String} id the element id to check
20342 * @return {boolean} true if this element is a DragDrop item,
20346 isDragDrop: function(id) {
20347 return ( this.getDDById(id) ) ? true : false;
20351 * Returns the drag and drop instances that are in all groups the
20352 * passed in instance belongs to.
20353 * @method getRelated
20354 * @param {DragDrop} p_oDD the obj to get related data for
20355 * @param {boolean} bTargetsOnly if true, only return targetable objs
20356 * @return {DragDrop[]} the related instances
20359 getRelated: function(p_oDD, bTargetsOnly) {
20361 for (var i in p_oDD.groups) {
20362 for (j in this.ids[i]) {
20363 var dd = this.ids[i][j];
20364 if (! this.isTypeOfDD(dd)) {
20367 if (!bTargetsOnly || dd.isTarget) {
20368 oDDs[oDDs.length] = dd;
20377 * Returns true if the specified dd target is a legal target for
20378 * the specifice drag obj
20379 * @method isLegalTarget
20380 * @param {DragDrop} the drag obj
20381 * @param {DragDrop} the target
20382 * @return {boolean} true if the target is a legal target for the
20386 isLegalTarget: function (oDD, oTargetDD) {
20387 var targets = this.getRelated(oDD, true);
20388 for (var i=0, len=targets.length;i<len;++i) {
20389 if (targets[i].id == oTargetDD.id) {
20398 * My goal is to be able to transparently determine if an object is
20399 * typeof DragDrop, and the exact subclass of DragDrop. typeof
20400 * returns "object", oDD.constructor.toString() always returns
20401 * "DragDrop" and not the name of the subclass. So for now it just
20402 * evaluates a well-known variable in DragDrop.
20403 * @method isTypeOfDD
20404 * @param {Object} the object to evaluate
20405 * @return {boolean} true if typeof oDD = DragDrop
20408 isTypeOfDD: function (oDD) {
20409 return (oDD && oDD.__ygDragDrop);
20413 * Utility function to determine if a given element has been
20414 * registered as a drag drop handle for the given Drag Drop object.
20416 * @param {String} id the element id to check
20417 * @return {boolean} true if this element is a DragDrop handle, false
20421 isHandle: function(sDDId, sHandleId) {
20422 return ( this.handleIds[sDDId] &&
20423 this.handleIds[sDDId][sHandleId] );
20427 * Returns the DragDrop instance for a given id
20428 * @method getDDById
20429 * @param {String} id the id of the DragDrop object
20430 * @return {DragDrop} the drag drop object, null if it is not found
20433 getDDById: function(id) {
20434 for (var i in this.ids) {
20435 if (this.ids[i][id]) {
20436 return this.ids[i][id];
20443 * Fired after a registered DragDrop object gets the mousedown event.
20444 * Sets up the events required to track the object being dragged
20445 * @method handleMouseDown
20446 * @param {Event} e the event
20447 * @param oDD the DragDrop object being dragged
20451 handleMouseDown: function(e, oDD) {
20453 Roo.QuickTips.disable();
20455 this.currentTarget = e.getTarget();
20457 this.dragCurrent = oDD;
20459 var el = oDD.getEl();
20461 // track start position
20462 this.startX = e.getPageX();
20463 this.startY = e.getPageY();
20465 this.deltaX = this.startX - el.offsetLeft;
20466 this.deltaY = this.startY - el.offsetTop;
20468 this.dragThreshMet = false;
20470 this.clickTimeout = setTimeout(
20472 var DDM = Roo.dd.DDM;
20473 DDM.startDrag(DDM.startX, DDM.startY);
20475 this.clickTimeThresh );
20479 * Fired when either the drag pixel threshol or the mousedown hold
20480 * time threshold has been met.
20481 * @method startDrag
20482 * @param x {int} the X position of the original mousedown
20483 * @param y {int} the Y position of the original mousedown
20486 startDrag: function(x, y) {
20487 clearTimeout(this.clickTimeout);
20488 if (this.dragCurrent) {
20489 this.dragCurrent.b4StartDrag(x, y);
20490 this.dragCurrent.startDrag(x, y);
20492 this.dragThreshMet = true;
20496 * Internal function to handle the mouseup event. Will be invoked
20497 * from the context of the document.
20498 * @method handleMouseUp
20499 * @param {Event} e the event
20503 handleMouseUp: function(e) {
20506 Roo.QuickTips.enable();
20508 if (! this.dragCurrent) {
20512 clearTimeout(this.clickTimeout);
20514 if (this.dragThreshMet) {
20515 this.fireEvents(e, true);
20525 * Utility to stop event propagation and event default, if these
20526 * features are turned on.
20527 * @method stopEvent
20528 * @param {Event} e the event as returned by this.getEvent()
20531 stopEvent: function(e){
20532 if(this.stopPropagation) {
20533 e.stopPropagation();
20536 if (this.preventDefault) {
20537 e.preventDefault();
20542 * Internal function to clean up event handlers after the drag
20543 * operation is complete
20545 * @param {Event} e the event
20549 stopDrag: function(e) {
20550 // Fire the drag end event for the item that was dragged
20551 if (this.dragCurrent) {
20552 if (this.dragThreshMet) {
20553 this.dragCurrent.b4EndDrag(e);
20554 this.dragCurrent.endDrag(e);
20557 this.dragCurrent.onMouseUp(e);
20560 this.dragCurrent = null;
20561 this.dragOvers = {};
20565 * Internal function to handle the mousemove event. Will be invoked
20566 * from the context of the html element.
20568 * @TODO figure out what we can do about mouse events lost when the
20569 * user drags objects beyond the window boundary. Currently we can
20570 * detect this in internet explorer by verifying that the mouse is
20571 * down during the mousemove event. Firefox doesn't give us the
20572 * button state on the mousemove event.
20573 * @method handleMouseMove
20574 * @param {Event} e the event
20578 handleMouseMove: function(e) {
20579 if (! this.dragCurrent) {
20583 // var button = e.which || e.button;
20585 // check for IE mouseup outside of page boundary
20586 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
20588 return this.handleMouseUp(e);
20591 if (!this.dragThreshMet) {
20592 var diffX = Math.abs(this.startX - e.getPageX());
20593 var diffY = Math.abs(this.startY - e.getPageY());
20594 if (diffX > this.clickPixelThresh ||
20595 diffY > this.clickPixelThresh) {
20596 this.startDrag(this.startX, this.startY);
20600 if (this.dragThreshMet) {
20601 this.dragCurrent.b4Drag(e);
20602 this.dragCurrent.onDrag(e);
20603 if(!this.dragCurrent.moveOnly){
20604 this.fireEvents(e, false);
20614 * Iterates over all of the DragDrop elements to find ones we are
20615 * hovering over or dropping on
20616 * @method fireEvents
20617 * @param {Event} e the event
20618 * @param {boolean} isDrop is this a drop op or a mouseover op?
20622 fireEvents: function(e, isDrop) {
20623 var dc = this.dragCurrent;
20625 // If the user did the mouse up outside of the window, we could
20626 // get here even though we have ended the drag.
20627 if (!dc || dc.isLocked()) {
20631 var pt = e.getPoint();
20633 // cache the previous dragOver array
20639 var enterEvts = [];
20641 // Check to see if the object(s) we were hovering over is no longer
20642 // being hovered over so we can fire the onDragOut event
20643 for (var i in this.dragOvers) {
20645 var ddo = this.dragOvers[i];
20647 if (! this.isTypeOfDD(ddo)) {
20651 if (! this.isOverTarget(pt, ddo, this.mode)) {
20652 outEvts.push( ddo );
20655 oldOvers[i] = true;
20656 delete this.dragOvers[i];
20659 for (var sGroup in dc.groups) {
20661 if ("string" != typeof sGroup) {
20665 for (i in this.ids[sGroup]) {
20666 var oDD = this.ids[sGroup][i];
20667 if (! this.isTypeOfDD(oDD)) {
20671 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
20672 if (this.isOverTarget(pt, oDD, this.mode)) {
20673 // look for drop interactions
20675 dropEvts.push( oDD );
20676 // look for drag enter and drag over interactions
20679 // initial drag over: dragEnter fires
20680 if (!oldOvers[oDD.id]) {
20681 enterEvts.push( oDD );
20682 // subsequent drag overs: dragOver fires
20684 overEvts.push( oDD );
20687 this.dragOvers[oDD.id] = oDD;
20695 if (outEvts.length) {
20696 dc.b4DragOut(e, outEvts);
20697 dc.onDragOut(e, outEvts);
20700 if (enterEvts.length) {
20701 dc.onDragEnter(e, enterEvts);
20704 if (overEvts.length) {
20705 dc.b4DragOver(e, overEvts);
20706 dc.onDragOver(e, overEvts);
20709 if (dropEvts.length) {
20710 dc.b4DragDrop(e, dropEvts);
20711 dc.onDragDrop(e, dropEvts);
20715 // fire dragout events
20717 for (i=0, len=outEvts.length; i<len; ++i) {
20718 dc.b4DragOut(e, outEvts[i].id);
20719 dc.onDragOut(e, outEvts[i].id);
20722 // fire enter events
20723 for (i=0,len=enterEvts.length; i<len; ++i) {
20724 // dc.b4DragEnter(e, oDD.id);
20725 dc.onDragEnter(e, enterEvts[i].id);
20728 // fire over events
20729 for (i=0,len=overEvts.length; i<len; ++i) {
20730 dc.b4DragOver(e, overEvts[i].id);
20731 dc.onDragOver(e, overEvts[i].id);
20734 // fire drop events
20735 for (i=0, len=dropEvts.length; i<len; ++i) {
20736 dc.b4DragDrop(e, dropEvts[i].id);
20737 dc.onDragDrop(e, dropEvts[i].id);
20742 // notify about a drop that did not find a target
20743 if (isDrop && !dropEvts.length) {
20744 dc.onInvalidDrop(e);
20750 * Helper function for getting the best match from the list of drag
20751 * and drop objects returned by the drag and drop events when we are
20752 * in INTERSECT mode. It returns either the first object that the
20753 * cursor is over, or the object that has the greatest overlap with
20754 * the dragged element.
20755 * @method getBestMatch
20756 * @param {DragDrop[]} dds The array of drag and drop objects
20758 * @return {DragDrop} The best single match
20761 getBestMatch: function(dds) {
20763 // Return null if the input is not what we expect
20764 //if (!dds || !dds.length || dds.length == 0) {
20766 // If there is only one item, it wins
20767 //} else if (dds.length == 1) {
20769 var len = dds.length;
20774 // Loop through the targeted items
20775 for (var i=0; i<len; ++i) {
20777 // If the cursor is over the object, it wins. If the
20778 // cursor is over multiple matches, the first one we come
20780 if (dd.cursorIsOver) {
20783 // Otherwise the object with the most overlap wins
20786 winner.overlap.getArea() < dd.overlap.getArea()) {
20797 * Refreshes the cache of the top-left and bottom-right points of the
20798 * drag and drop objects in the specified group(s). This is in the
20799 * format that is stored in the drag and drop instance, so typical
20802 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
20806 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
20808 * @TODO this really should be an indexed array. Alternatively this
20809 * method could accept both.
20810 * @method refreshCache
20811 * @param {Object} groups an associative array of groups to refresh
20814 refreshCache: function(groups) {
20815 for (var sGroup in groups) {
20816 if ("string" != typeof sGroup) {
20819 for (var i in this.ids[sGroup]) {
20820 var oDD = this.ids[sGroup][i];
20822 if (this.isTypeOfDD(oDD)) {
20823 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
20824 var loc = this.getLocation(oDD);
20826 this.locationCache[oDD.id] = loc;
20828 delete this.locationCache[oDD.id];
20829 // this will unregister the drag and drop object if
20830 // the element is not in a usable state
20839 * This checks to make sure an element exists and is in the DOM. The
20840 * main purpose is to handle cases where innerHTML is used to remove
20841 * drag and drop objects from the DOM. IE provides an 'unspecified
20842 * error' when trying to access the offsetParent of such an element
20844 * @param {HTMLElement} el the element to check
20845 * @return {boolean} true if the element looks usable
20848 verifyEl: function(el) {
20853 parent = el.offsetParent;
20856 parent = el.offsetParent;
20867 * Returns a Region object containing the drag and drop element's position
20868 * and size, including the padding configured for it
20869 * @method getLocation
20870 * @param {DragDrop} oDD the drag and drop object to get the
20872 * @return {Roo.lib.Region} a Region object representing the total area
20873 * the element occupies, including any padding
20874 * the instance is configured for.
20877 getLocation: function(oDD) {
20878 if (! this.isTypeOfDD(oDD)) {
20882 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
20885 pos= Roo.lib.Dom.getXY(el);
20893 x2 = x1 + el.offsetWidth;
20895 y2 = y1 + el.offsetHeight;
20897 t = y1 - oDD.padding[0];
20898 r = x2 + oDD.padding[1];
20899 b = y2 + oDD.padding[2];
20900 l = x1 - oDD.padding[3];
20902 return new Roo.lib.Region( t, r, b, l );
20906 * Checks the cursor location to see if it over the target
20907 * @method isOverTarget
20908 * @param {Roo.lib.Point} pt The point to evaluate
20909 * @param {DragDrop} oTarget the DragDrop object we are inspecting
20910 * @return {boolean} true if the mouse is over the target
20914 isOverTarget: function(pt, oTarget, intersect) {
20915 // use cache if available
20916 var loc = this.locationCache[oTarget.id];
20917 if (!loc || !this.useCache) {
20918 loc = this.getLocation(oTarget);
20919 this.locationCache[oTarget.id] = loc;
20927 oTarget.cursorIsOver = loc.contains( pt );
20929 // DragDrop is using this as a sanity check for the initial mousedown
20930 // in this case we are done. In POINT mode, if the drag obj has no
20931 // contraints, we are also done. Otherwise we need to evaluate the
20932 // location of the target as related to the actual location of the
20933 // dragged element.
20934 var dc = this.dragCurrent;
20935 if (!dc || !dc.getTargetCoord ||
20936 (!intersect && !dc.constrainX && !dc.constrainY)) {
20937 return oTarget.cursorIsOver;
20940 oTarget.overlap = null;
20942 // Get the current location of the drag element, this is the
20943 // location of the mouse event less the delta that represents
20944 // where the original mousedown happened on the element. We
20945 // need to consider constraints and ticks as well.
20946 var pos = dc.getTargetCoord(pt.x, pt.y);
20948 var el = dc.getDragEl();
20949 var curRegion = new Roo.lib.Region( pos.y,
20950 pos.x + el.offsetWidth,
20951 pos.y + el.offsetHeight,
20954 var overlap = curRegion.intersect(loc);
20957 oTarget.overlap = overlap;
20958 return (intersect) ? true : oTarget.cursorIsOver;
20965 * unload event handler
20966 * @method _onUnload
20970 _onUnload: function(e, me) {
20971 Roo.dd.DragDropMgr.unregAll();
20975 * Cleans up the drag and drop events and objects.
20980 unregAll: function() {
20982 if (this.dragCurrent) {
20984 this.dragCurrent = null;
20987 this._execOnAll("unreg", []);
20989 for (i in this.elementCache) {
20990 delete this.elementCache[i];
20993 this.elementCache = {};
20998 * A cache of DOM elements
20999 * @property elementCache
21006 * Get the wrapper for the DOM element specified
21007 * @method getElWrapper
21008 * @param {String} id the id of the element to get
21009 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
21011 * @deprecated This wrapper isn't that useful
21014 getElWrapper: function(id) {
21015 var oWrapper = this.elementCache[id];
21016 if (!oWrapper || !oWrapper.el) {
21017 oWrapper = this.elementCache[id] =
21018 new this.ElementWrapper(Roo.getDom(id));
21024 * Returns the actual DOM element
21025 * @method getElement
21026 * @param {String} id the id of the elment to get
21027 * @return {Object} The element
21028 * @deprecated use Roo.getDom instead
21031 getElement: function(id) {
21032 return Roo.getDom(id);
21036 * Returns the style property for the DOM element (i.e.,
21037 * document.getElById(id).style)
21039 * @param {String} id the id of the elment to get
21040 * @return {Object} The style property of the element
21041 * @deprecated use Roo.getDom instead
21044 getCss: function(id) {
21045 var el = Roo.getDom(id);
21046 return (el) ? el.style : null;
21050 * Inner class for cached elements
21051 * @class DragDropMgr.ElementWrapper
21056 ElementWrapper: function(el) {
21061 this.el = el || null;
21066 this.id = this.el && el.id;
21068 * A reference to the style property
21071 this.css = this.el && el.style;
21075 * Returns the X position of an html element
21077 * @param el the element for which to get the position
21078 * @return {int} the X coordinate
21080 * @deprecated use Roo.lib.Dom.getX instead
21083 getPosX: function(el) {
21084 return Roo.lib.Dom.getX(el);
21088 * Returns the Y position of an html element
21090 * @param el the element for which to get the position
21091 * @return {int} the Y coordinate
21092 * @deprecated use Roo.lib.Dom.getY instead
21095 getPosY: function(el) {
21096 return Roo.lib.Dom.getY(el);
21100 * Swap two nodes. In IE, we use the native method, for others we
21101 * emulate the IE behavior
21103 * @param n1 the first node to swap
21104 * @param n2 the other node to swap
21107 swapNode: function(n1, n2) {
21111 var p = n2.parentNode;
21112 var s = n2.nextSibling;
21115 p.insertBefore(n1, n2);
21116 } else if (n2 == n1.nextSibling) {
21117 p.insertBefore(n2, n1);
21119 n1.parentNode.replaceChild(n2, n1);
21120 p.insertBefore(n1, s);
21126 * Returns the current scroll position
21127 * @method getScroll
21131 getScroll: function () {
21132 var t, l, dde=document.documentElement, db=document.body;
21133 if (dde && (dde.scrollTop || dde.scrollLeft)) {
21135 l = dde.scrollLeft;
21142 return { top: t, left: l };
21146 * Returns the specified element style property
21148 * @param {HTMLElement} el the element
21149 * @param {string} styleProp the style property
21150 * @return {string} The value of the style property
21151 * @deprecated use Roo.lib.Dom.getStyle
21154 getStyle: function(el, styleProp) {
21155 return Roo.fly(el).getStyle(styleProp);
21159 * Gets the scrollTop
21160 * @method getScrollTop
21161 * @return {int} the document's scrollTop
21164 getScrollTop: function () { return this.getScroll().top; },
21167 * Gets the scrollLeft
21168 * @method getScrollLeft
21169 * @return {int} the document's scrollTop
21172 getScrollLeft: function () { return this.getScroll().left; },
21175 * Sets the x/y position of an element to the location of the
21178 * @param {HTMLElement} moveEl The element to move
21179 * @param {HTMLElement} targetEl The position reference element
21182 moveToEl: function (moveEl, targetEl) {
21183 var aCoord = Roo.lib.Dom.getXY(targetEl);
21184 Roo.lib.Dom.setXY(moveEl, aCoord);
21188 * Numeric array sort function
21189 * @method numericSort
21192 numericSort: function(a, b) { return (a - b); },
21196 * @property _timeoutCount
21203 * Trying to make the load order less important. Without this we get
21204 * an error if this file is loaded before the Event Utility.
21205 * @method _addListeners
21209 _addListeners: function() {
21210 var DDM = Roo.dd.DDM;
21211 if ( Roo.lib.Event && document ) {
21214 if (DDM._timeoutCount > 2000) {
21216 setTimeout(DDM._addListeners, 10);
21217 if (document && document.body) {
21218 DDM._timeoutCount += 1;
21225 * Recursively searches the immediate parent and all child nodes for
21226 * the handle element in order to determine wheter or not it was
21228 * @method handleWasClicked
21229 * @param node the html element to inspect
21232 handleWasClicked: function(node, id) {
21233 if (this.isHandle(id, node.id)) {
21236 // check to see if this is a text node child of the one we want
21237 var p = node.parentNode;
21240 if (this.isHandle(id, p.id)) {
21255 // shorter alias, save a few bytes
21256 Roo.dd.DDM = Roo.dd.DragDropMgr;
21257 Roo.dd.DDM._addListeners();
21261 * Ext JS Library 1.1.1
21262 * Copyright(c) 2006-2007, Ext JS, LLC.
21264 * Originally Released Under LGPL - original licence link has changed is not relivant.
21267 * <script type="text/javascript">
21272 * A DragDrop implementation where the linked element follows the
21273 * mouse cursor during a drag.
21274 * @extends Roo.dd.DragDrop
21276 * @param {String} id the id of the linked element
21277 * @param {String} sGroup the group of related DragDrop items
21278 * @param {object} config an object containing configurable attributes
21279 * Valid properties for DD:
21282 Roo.dd.DD = function(id, sGroup, config) {
21284 this.init(id, sGroup, config);
21288 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
21291 * When set to true, the utility automatically tries to scroll the browser
21292 * window wehn a drag and drop element is dragged near the viewport boundary.
21293 * Defaults to true.
21300 * Sets the pointer offset to the distance between the linked element's top
21301 * left corner and the location the element was clicked
21302 * @method autoOffset
21303 * @param {int} iPageX the X coordinate of the click
21304 * @param {int} iPageY the Y coordinate of the click
21306 autoOffset: function(iPageX, iPageY) {
21307 var x = iPageX - this.startPageX;
21308 var y = iPageY - this.startPageY;
21309 this.setDelta(x, y);
21313 * Sets the pointer offset. You can call this directly to force the
21314 * offset to be in a particular location (e.g., pass in 0,0 to set it
21315 * to the center of the object)
21317 * @param {int} iDeltaX the distance from the left
21318 * @param {int} iDeltaY the distance from the top
21320 setDelta: function(iDeltaX, iDeltaY) {
21321 this.deltaX = iDeltaX;
21322 this.deltaY = iDeltaY;
21326 * Sets the drag element to the location of the mousedown or click event,
21327 * maintaining the cursor location relative to the location on the element
21328 * that was clicked. Override this if you want to place the element in a
21329 * location other than where the cursor is.
21330 * @method setDragElPos
21331 * @param {int} iPageX the X coordinate of the mousedown or drag event
21332 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21334 setDragElPos: function(iPageX, iPageY) {
21335 // the first time we do this, we are going to check to make sure
21336 // the element has css positioning
21338 var el = this.getDragEl();
21339 this.alignElWithMouse(el, iPageX, iPageY);
21343 * Sets the element to the location of the mousedown or click event,
21344 * maintaining the cursor location relative to the location on the element
21345 * that was clicked. Override this if you want to place the element in a
21346 * location other than where the cursor is.
21347 * @method alignElWithMouse
21348 * @param {HTMLElement} el the element to move
21349 * @param {int} iPageX the X coordinate of the mousedown or drag event
21350 * @param {int} iPageY the Y coordinate of the mousedown or drag event
21352 alignElWithMouse: function(el, iPageX, iPageY) {
21353 var oCoord = this.getTargetCoord(iPageX, iPageY);
21354 var fly = el.dom ? el : Roo.fly(el);
21355 if (!this.deltaSetXY) {
21356 var aCoord = [oCoord.x, oCoord.y];
21358 var newLeft = fly.getLeft(true);
21359 var newTop = fly.getTop(true);
21360 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
21362 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
21365 this.cachePosition(oCoord.x, oCoord.y);
21366 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
21371 * Saves the most recent position so that we can reset the constraints and
21372 * tick marks on-demand. We need to know this so that we can calculate the
21373 * number of pixels the element is offset from its original position.
21374 * @method cachePosition
21375 * @param iPageX the current x position (optional, this just makes it so we
21376 * don't have to look it up again)
21377 * @param iPageY the current y position (optional, this just makes it so we
21378 * don't have to look it up again)
21380 cachePosition: function(iPageX, iPageY) {
21382 this.lastPageX = iPageX;
21383 this.lastPageY = iPageY;
21385 var aCoord = Roo.lib.Dom.getXY(this.getEl());
21386 this.lastPageX = aCoord[0];
21387 this.lastPageY = aCoord[1];
21392 * Auto-scroll the window if the dragged object has been moved beyond the
21393 * visible window boundary.
21394 * @method autoScroll
21395 * @param {int} x the drag element's x position
21396 * @param {int} y the drag element's y position
21397 * @param {int} h the height of the drag element
21398 * @param {int} w the width of the drag element
21401 autoScroll: function(x, y, h, w) {
21404 // The client height
21405 var clientH = Roo.lib.Dom.getViewWidth();
21407 // The client width
21408 var clientW = Roo.lib.Dom.getViewHeight();
21410 // The amt scrolled down
21411 var st = this.DDM.getScrollTop();
21413 // The amt scrolled right
21414 var sl = this.DDM.getScrollLeft();
21416 // Location of the bottom of the element
21419 // Location of the right of the element
21422 // The distance from the cursor to the bottom of the visible area,
21423 // adjusted so that we don't scroll if the cursor is beyond the
21424 // element drag constraints
21425 var toBot = (clientH + st - y - this.deltaY);
21427 // The distance from the cursor to the right of the visible area
21428 var toRight = (clientW + sl - x - this.deltaX);
21431 // How close to the edge the cursor must be before we scroll
21432 // var thresh = (document.all) ? 100 : 40;
21435 // How many pixels to scroll per autoscroll op. This helps to reduce
21436 // clunky scrolling. IE is more sensitive about this ... it needs this
21437 // value to be higher.
21438 var scrAmt = (document.all) ? 80 : 30;
21440 // Scroll down if we are near the bottom of the visible page and the
21441 // obj extends below the crease
21442 if ( bot > clientH && toBot < thresh ) {
21443 window.scrollTo(sl, st + scrAmt);
21446 // Scroll up if the window is scrolled down and the top of the object
21447 // goes above the top border
21448 if ( y < st && st > 0 && y - st < thresh ) {
21449 window.scrollTo(sl, st - scrAmt);
21452 // Scroll right if the obj is beyond the right border and the cursor is
21453 // near the border.
21454 if ( right > clientW && toRight < thresh ) {
21455 window.scrollTo(sl + scrAmt, st);
21458 // Scroll left if the window has been scrolled to the right and the obj
21459 // extends past the left border
21460 if ( x < sl && sl > 0 && x - sl < thresh ) {
21461 window.scrollTo(sl - scrAmt, st);
21467 * Finds the location the element should be placed if we want to move
21468 * it to where the mouse location less the click offset would place us.
21469 * @method getTargetCoord
21470 * @param {int} iPageX the X coordinate of the click
21471 * @param {int} iPageY the Y coordinate of the click
21472 * @return an object that contains the coordinates (Object.x and Object.y)
21475 getTargetCoord: function(iPageX, iPageY) {
21478 var x = iPageX - this.deltaX;
21479 var y = iPageY - this.deltaY;
21481 if (this.constrainX) {
21482 if (x < this.minX) { x = this.minX; }
21483 if (x > this.maxX) { x = this.maxX; }
21486 if (this.constrainY) {
21487 if (y < this.minY) { y = this.minY; }
21488 if (y > this.maxY) { y = this.maxY; }
21491 x = this.getTick(x, this.xTicks);
21492 y = this.getTick(y, this.yTicks);
21499 * Sets up config options specific to this class. Overrides
21500 * Roo.dd.DragDrop, but all versions of this method through the
21501 * inheritance chain are called
21503 applyConfig: function() {
21504 Roo.dd.DD.superclass.applyConfig.call(this);
21505 this.scroll = (this.config.scroll !== false);
21509 * Event that fires prior to the onMouseDown event. Overrides
21512 b4MouseDown: function(e) {
21513 // this.resetConstraints();
21514 this.autoOffset(e.getPageX(),
21519 * Event that fires prior to the onDrag event. Overrides
21522 b4Drag: function(e) {
21523 this.setDragElPos(e.getPageX(),
21527 toString: function() {
21528 return ("DD " + this.id);
21531 //////////////////////////////////////////////////////////////////////////
21532 // Debugging ygDragDrop events that can be overridden
21533 //////////////////////////////////////////////////////////////////////////
21535 startDrag: function(x, y) {
21538 onDrag: function(e) {
21541 onDragEnter: function(e, id) {
21544 onDragOver: function(e, id) {
21547 onDragOut: function(e, id) {
21550 onDragDrop: function(e, id) {
21553 endDrag: function(e) {
21560 * Ext JS Library 1.1.1
21561 * Copyright(c) 2006-2007, Ext JS, LLC.
21563 * Originally Released Under LGPL - original licence link has changed is not relivant.
21566 * <script type="text/javascript">
21570 * @class Roo.dd.DDProxy
21571 * A DragDrop implementation that inserts an empty, bordered div into
21572 * the document that follows the cursor during drag operations. At the time of
21573 * the click, the frame div is resized to the dimensions of the linked html
21574 * element, and moved to the exact location of the linked element.
21576 * References to the "frame" element refer to the single proxy element that
21577 * was created to be dragged in place of all DDProxy elements on the
21580 * @extends Roo.dd.DD
21582 * @param {String} id the id of the linked html element
21583 * @param {String} sGroup the group of related DragDrop objects
21584 * @param {object} config an object containing configurable attributes
21585 * Valid properties for DDProxy in addition to those in DragDrop:
21586 * resizeFrame, centerFrame, dragElId
21588 Roo.dd.DDProxy = function(id, sGroup, config) {
21590 this.init(id, sGroup, config);
21596 * The default drag frame div id
21597 * @property Roo.dd.DDProxy.dragElId
21601 Roo.dd.DDProxy.dragElId = "ygddfdiv";
21603 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
21606 * By default we resize the drag frame to be the same size as the element
21607 * we want to drag (this is to get the frame effect). We can turn it off
21608 * if we want a different behavior.
21609 * @property resizeFrame
21615 * By default the frame is positioned exactly where the drag element is, so
21616 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
21617 * you do not have constraints on the obj is to have the drag frame centered
21618 * around the cursor. Set centerFrame to true for this effect.
21619 * @property centerFrame
21622 centerFrame: false,
21625 * Creates the proxy element if it does not yet exist
21626 * @method createFrame
21628 createFrame: function() {
21630 var body = document.body;
21632 if (!body || !body.firstChild) {
21633 setTimeout( function() { self.createFrame(); }, 50 );
21637 var div = this.getDragEl();
21640 div = document.createElement("div");
21641 div.id = this.dragElId;
21644 s.position = "absolute";
21645 s.visibility = "hidden";
21647 s.border = "2px solid #aaa";
21650 // appendChild can blow up IE if invoked prior to the window load event
21651 // while rendering a table. It is possible there are other scenarios
21652 // that would cause this to happen as well.
21653 body.insertBefore(div, body.firstChild);
21658 * Initialization for the drag frame element. Must be called in the
21659 * constructor of all subclasses
21660 * @method initFrame
21662 initFrame: function() {
21663 this.createFrame();
21666 applyConfig: function() {
21667 Roo.dd.DDProxy.superclass.applyConfig.call(this);
21669 this.resizeFrame = (this.config.resizeFrame !== false);
21670 this.centerFrame = (this.config.centerFrame);
21671 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
21675 * Resizes the drag frame to the dimensions of the clicked object, positions
21676 * it over the object, and finally displays it
21677 * @method showFrame
21678 * @param {int} iPageX X click position
21679 * @param {int} iPageY Y click position
21682 showFrame: function(iPageX, iPageY) {
21683 var el = this.getEl();
21684 var dragEl = this.getDragEl();
21685 var s = dragEl.style;
21687 this._resizeProxy();
21689 if (this.centerFrame) {
21690 this.setDelta( Math.round(parseInt(s.width, 10)/2),
21691 Math.round(parseInt(s.height, 10)/2) );
21694 this.setDragElPos(iPageX, iPageY);
21696 Roo.fly(dragEl).show();
21700 * The proxy is automatically resized to the dimensions of the linked
21701 * element when a drag is initiated, unless resizeFrame is set to false
21702 * @method _resizeProxy
21705 _resizeProxy: function() {
21706 if (this.resizeFrame) {
21707 var el = this.getEl();
21708 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
21712 // overrides Roo.dd.DragDrop
21713 b4MouseDown: function(e) {
21714 var x = e.getPageX();
21715 var y = e.getPageY();
21716 this.autoOffset(x, y);
21717 this.setDragElPos(x, y);
21720 // overrides Roo.dd.DragDrop
21721 b4StartDrag: function(x, y) {
21722 // show the drag frame
21723 this.showFrame(x, y);
21726 // overrides Roo.dd.DragDrop
21727 b4EndDrag: function(e) {
21728 Roo.fly(this.getDragEl()).hide();
21731 // overrides Roo.dd.DragDrop
21732 // By default we try to move the element to the last location of the frame.
21733 // This is so that the default behavior mirrors that of Roo.dd.DD.
21734 endDrag: function(e) {
21736 var lel = this.getEl();
21737 var del = this.getDragEl();
21739 // Show the drag frame briefly so we can get its position
21740 del.style.visibility = "";
21743 // Hide the linked element before the move to get around a Safari
21745 lel.style.visibility = "hidden";
21746 Roo.dd.DDM.moveToEl(lel, del);
21747 del.style.visibility = "hidden";
21748 lel.style.visibility = "";
21753 beforeMove : function(){
21757 afterDrag : function(){
21761 toString: function() {
21762 return ("DDProxy " + this.id);
21768 * Ext JS Library 1.1.1
21769 * Copyright(c) 2006-2007, Ext JS, LLC.
21771 * Originally Released Under LGPL - original licence link has changed is not relivant.
21774 * <script type="text/javascript">
21778 * @class Roo.dd.DDTarget
21779 * A DragDrop implementation that does not move, but can be a drop
21780 * target. You would get the same result by simply omitting implementation
21781 * for the event callbacks, but this way we reduce the processing cost of the
21782 * event listener and the callbacks.
21783 * @extends Roo.dd.DragDrop
21785 * @param {String} id the id of the element that is a drop target
21786 * @param {String} sGroup the group of related DragDrop objects
21787 * @param {object} config an object containing configurable attributes
21788 * Valid properties for DDTarget in addition to those in
21792 Roo.dd.DDTarget = function(id, sGroup, config) {
21794 this.initTarget(id, sGroup, config);
21796 if (config && (config.listeners || config.events)) {
21797 Roo.dd.DragDrop.superclass.constructor.call(this, {
21798 listeners : config.listeners || {},
21799 events : config.events || {}
21804 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
21805 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
21806 toString: function() {
21807 return ("DDTarget " + this.id);
21812 * Ext JS Library 1.1.1
21813 * Copyright(c) 2006-2007, Ext JS, LLC.
21815 * Originally Released Under LGPL - original licence link has changed is not relivant.
21818 * <script type="text/javascript">
21823 * @class Roo.dd.ScrollManager
21824 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
21825 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
21828 Roo.dd.ScrollManager = function(){
21829 var ddm = Roo.dd.DragDropMgr;
21836 var onStop = function(e){
21841 var triggerRefresh = function(){
21842 if(ddm.dragCurrent){
21843 ddm.refreshCache(ddm.dragCurrent.groups);
21847 var doScroll = function(){
21848 if(ddm.dragCurrent){
21849 var dds = Roo.dd.ScrollManager;
21851 if(proc.el.scroll(proc.dir, dds.increment)){
21855 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
21860 var clearProc = function(){
21862 clearInterval(proc.id);
21869 var startProc = function(el, dir){
21870 Roo.log('scroll startproc');
21874 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
21877 var onFire = function(e, isDrop){
21879 if(isDrop || !ddm.dragCurrent){ return; }
21880 var dds = Roo.dd.ScrollManager;
21881 if(!dragEl || dragEl != ddm.dragCurrent){
21882 dragEl = ddm.dragCurrent;
21883 // refresh regions on drag start
21884 dds.refreshCache();
21887 var xy = Roo.lib.Event.getXY(e);
21888 var pt = new Roo.lib.Point(xy[0], xy[1]);
21889 for(var id in els){
21890 var el = els[id], r = el._region;
21891 if(r && r.contains(pt) && el.isScrollable()){
21892 if(r.bottom - pt.y <= dds.thresh){
21894 startProc(el, "down");
21897 }else if(r.right - pt.x <= dds.thresh){
21899 startProc(el, "left");
21902 }else if(pt.y - r.top <= dds.thresh){
21904 startProc(el, "up");
21907 }else if(pt.x - r.left <= dds.thresh){
21909 startProc(el, "right");
21918 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
21919 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
21923 * Registers new overflow element(s) to auto scroll
21924 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
21926 register : function(el){
21927 if(el instanceof Array){
21928 for(var i = 0, len = el.length; i < len; i++) {
21929 this.register(el[i]);
21935 Roo.dd.ScrollManager.els = els;
21939 * Unregisters overflow element(s) so they are no longer scrolled
21940 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
21942 unregister : function(el){
21943 if(el instanceof Array){
21944 for(var i = 0, len = el.length; i < len; i++) {
21945 this.unregister(el[i]);
21954 * The number of pixels from the edge of a container the pointer needs to be to
21955 * trigger scrolling (defaults to 25)
21961 * The number of pixels to scroll in each scroll increment (defaults to 50)
21967 * The frequency of scrolls in milliseconds (defaults to 500)
21973 * True to animate the scroll (defaults to true)
21979 * The animation duration in seconds -
21980 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
21986 * Manually trigger a cache refresh.
21988 refreshCache : function(){
21989 for(var id in els){
21990 if(typeof els[id] == 'object'){ // for people extending the object prototype
21991 els[id]._region = els[id].getRegion();
21998 * Ext JS Library 1.1.1
21999 * Copyright(c) 2006-2007, Ext JS, LLC.
22001 * Originally Released Under LGPL - original licence link has changed is not relivant.
22004 * <script type="text/javascript">
22009 * @class Roo.dd.Registry
22010 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
22011 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
22014 Roo.dd.Registry = function(){
22017 var autoIdSeed = 0;
22019 var getId = function(el, autogen){
22020 if(typeof el == "string"){
22024 if(!id && autogen !== false){
22025 id = "roodd-" + (++autoIdSeed);
22033 * Register a drag drop element
22034 * @param {String|HTMLElement} element The id or DOM node to register
22035 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
22036 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
22037 * knows how to interpret, plus there are some specific properties known to the Registry that should be
22038 * populated in the data object (if applicable):
22040 Value Description<br />
22041 --------- ------------------------------------------<br />
22042 handles Array of DOM nodes that trigger dragging<br />
22043 for the element being registered<br />
22044 isHandle True if the element passed in triggers<br />
22045 dragging itself, else false
22048 register : function(el, data){
22050 if(typeof el == "string"){
22051 el = document.getElementById(el);
22054 elements[getId(el)] = data;
22055 if(data.isHandle !== false){
22056 handles[data.ddel.id] = data;
22059 var hs = data.handles;
22060 for(var i = 0, len = hs.length; i < len; i++){
22061 handles[getId(hs[i])] = data;
22067 * Unregister a drag drop element
22068 * @param {String|HTMLElement} element The id or DOM node to unregister
22070 unregister : function(el){
22071 var id = getId(el, false);
22072 var data = elements[id];
22074 delete elements[id];
22076 var hs = data.handles;
22077 for(var i = 0, len = hs.length; i < len; i++){
22078 delete handles[getId(hs[i], false)];
22085 * Returns the handle registered for a DOM Node by id
22086 * @param {String|HTMLElement} id The DOM node or id to look up
22087 * @return {Object} handle The custom handle data
22089 getHandle : function(id){
22090 if(typeof id != "string"){ // must be element?
22093 return handles[id];
22097 * Returns the handle that is registered for the DOM node that is the target of the event
22098 * @param {Event} e The event
22099 * @return {Object} handle The custom handle data
22101 getHandleFromEvent : function(e){
22102 var t = Roo.lib.Event.getTarget(e);
22103 return t ? handles[t.id] : null;
22107 * Returns a custom data object that is registered for a DOM node by id
22108 * @param {String|HTMLElement} id The DOM node or id to look up
22109 * @return {Object} data The custom data
22111 getTarget : function(id){
22112 if(typeof id != "string"){ // must be element?
22115 return elements[id];
22119 * Returns a custom data object that is registered for the DOM node that is the target of the event
22120 * @param {Event} e The event
22121 * @return {Object} data The custom data
22123 getTargetFromEvent : function(e){
22124 var t = Roo.lib.Event.getTarget(e);
22125 return t ? elements[t.id] || handles[t.id] : null;
22130 * Ext JS Library 1.1.1
22131 * Copyright(c) 2006-2007, Ext JS, LLC.
22133 * Originally Released Under LGPL - original licence link has changed is not relivant.
22136 * <script type="text/javascript">
22141 * @class Roo.dd.StatusProxy
22142 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
22143 * default drag proxy used by all Roo.dd components.
22145 * @param {Object} config
22147 Roo.dd.StatusProxy = function(config){
22148 Roo.apply(this, config);
22149 this.id = this.id || Roo.id();
22150 this.el = new Roo.Layer({
22152 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
22153 {tag: "div", cls: "x-dd-drop-icon"},
22154 {tag: "div", cls: "x-dd-drag-ghost"}
22157 shadow: !config || config.shadow !== false
22159 this.ghost = Roo.get(this.el.dom.childNodes[1]);
22160 this.dropStatus = this.dropNotAllowed;
22163 Roo.dd.StatusProxy.prototype = {
22165 * @cfg {String} dropAllowed
22166 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
22168 dropAllowed : "x-dd-drop-ok",
22170 * @cfg {String} dropNotAllowed
22171 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
22173 dropNotAllowed : "x-dd-drop-nodrop",
22176 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
22177 * over the current target element.
22178 * @param {String} cssClass The css class for the new drop status indicator image
22180 setStatus : function(cssClass){
22181 cssClass = cssClass || this.dropNotAllowed;
22182 if(this.dropStatus != cssClass){
22183 this.el.replaceClass(this.dropStatus, cssClass);
22184 this.dropStatus = cssClass;
22189 * Resets the status indicator to the default dropNotAllowed value
22190 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
22192 reset : function(clearGhost){
22193 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
22194 this.dropStatus = this.dropNotAllowed;
22196 this.ghost.update("");
22201 * Updates the contents of the ghost element
22202 * @param {String} html The html that will replace the current innerHTML of the ghost element
22204 update : function(html){
22205 if(typeof html == "string"){
22206 this.ghost.update(html);
22208 this.ghost.update("");
22209 html.style.margin = "0";
22210 this.ghost.dom.appendChild(html);
22212 // ensure float = none set?? cant remember why though.
22213 var el = this.ghost.dom.firstChild;
22215 Roo.fly(el).setStyle('float', 'none');
22220 * Returns the underlying proxy {@link Roo.Layer}
22221 * @return {Roo.Layer} el
22223 getEl : function(){
22228 * Returns the ghost element
22229 * @return {Roo.Element} el
22231 getGhost : function(){
22237 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
22239 hide : function(clear){
22247 * Stops the repair animation if it's currently running
22250 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
22256 * Displays this proxy
22263 * Force the Layer to sync its shadow and shim positions to the element
22270 * Causes the proxy to return to its position of origin via an animation. Should be called after an
22271 * invalid drop operation by the item being dragged.
22272 * @param {Array} xy The XY position of the element ([x, y])
22273 * @param {Function} callback The function to call after the repair is complete
22274 * @param {Object} scope The scope in which to execute the callback
22276 repair : function(xy, callback, scope){
22277 this.callback = callback;
22278 this.scope = scope;
22279 if(xy && this.animRepair !== false){
22280 this.el.addClass("x-dd-drag-repair");
22281 this.el.hideUnders(true);
22282 this.anim = this.el.shift({
22283 duration: this.repairDuration || .5,
22287 callback: this.afterRepair,
22291 this.afterRepair();
22296 afterRepair : function(){
22298 if(typeof this.callback == "function"){
22299 this.callback.call(this.scope || this);
22301 this.callback = null;
22306 * Ext JS Library 1.1.1
22307 * Copyright(c) 2006-2007, Ext JS, LLC.
22309 * Originally Released Under LGPL - original licence link has changed is not relivant.
22312 * <script type="text/javascript">
22316 * @class Roo.dd.DragSource
22317 * @extends Roo.dd.DDProxy
22318 * A simple class that provides the basic implementation needed to make any element draggable.
22320 * @param {String/HTMLElement/Element} el The container element
22321 * @param {Object} config
22323 Roo.dd.DragSource = function(el, config){
22324 this.el = Roo.get(el);
22325 this.dragData = {};
22327 Roo.apply(this, config);
22330 this.proxy = new Roo.dd.StatusProxy();
22333 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
22334 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
22336 this.dragging = false;
22339 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
22341 * @cfg {String} dropAllowed
22342 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22344 dropAllowed : "x-dd-drop-ok",
22346 * @cfg {String} dropNotAllowed
22347 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22349 dropNotAllowed : "x-dd-drop-nodrop",
22352 * Returns the data object associated with this drag source
22353 * @return {Object} data An object containing arbitrary data
22355 getDragData : function(e){
22356 return this.dragData;
22360 onDragEnter : function(e, id){
22361 var target = Roo.dd.DragDropMgr.getDDById(id);
22362 this.cachedTarget = target;
22363 if(this.beforeDragEnter(target, e, id) !== false){
22364 if(target.isNotifyTarget){
22365 var status = target.notifyEnter(this, e, this.dragData);
22366 this.proxy.setStatus(status);
22368 this.proxy.setStatus(this.dropAllowed);
22371 if(this.afterDragEnter){
22373 * An empty function by default, but provided so that you can perform a custom action
22374 * when the dragged item enters the drop target by providing an implementation.
22375 * @param {Roo.dd.DragDrop} target The drop target
22376 * @param {Event} e The event object
22377 * @param {String} id The id of the dragged element
22378 * @method afterDragEnter
22380 this.afterDragEnter(target, e, id);
22386 * An empty function by default, but provided so that you can perform a custom action
22387 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
22388 * @param {Roo.dd.DragDrop} target The drop target
22389 * @param {Event} e The event object
22390 * @param {String} id The id of the dragged element
22391 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22393 beforeDragEnter : function(target, e, id){
22398 alignElWithMouse: function() {
22399 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
22404 onDragOver : function(e, id){
22405 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22406 if(this.beforeDragOver(target, e, id) !== false){
22407 if(target.isNotifyTarget){
22408 var status = target.notifyOver(this, e, this.dragData);
22409 this.proxy.setStatus(status);
22412 if(this.afterDragOver){
22414 * An empty function by default, but provided so that you can perform a custom action
22415 * while the dragged item is over the drop target by providing an implementation.
22416 * @param {Roo.dd.DragDrop} target The drop target
22417 * @param {Event} e The event object
22418 * @param {String} id The id of the dragged element
22419 * @method afterDragOver
22421 this.afterDragOver(target, e, id);
22427 * An empty function by default, but provided so that you can perform a custom action
22428 * while the dragged item is over the drop target and optionally cancel the onDragOver.
22429 * @param {Roo.dd.DragDrop} target The drop target
22430 * @param {Event} e The event object
22431 * @param {String} id The id of the dragged element
22432 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22434 beforeDragOver : function(target, e, id){
22439 onDragOut : function(e, id){
22440 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22441 if(this.beforeDragOut(target, e, id) !== false){
22442 if(target.isNotifyTarget){
22443 target.notifyOut(this, e, this.dragData);
22445 this.proxy.reset();
22446 if(this.afterDragOut){
22448 * An empty function by default, but provided so that you can perform a custom action
22449 * after the dragged item is dragged out of the target without dropping.
22450 * @param {Roo.dd.DragDrop} target The drop target
22451 * @param {Event} e The event object
22452 * @param {String} id The id of the dragged element
22453 * @method afterDragOut
22455 this.afterDragOut(target, e, id);
22458 this.cachedTarget = null;
22462 * An empty function by default, but provided so that you can perform a custom action before the dragged
22463 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
22464 * @param {Roo.dd.DragDrop} target The drop target
22465 * @param {Event} e The event object
22466 * @param {String} id The id of the dragged element
22467 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22469 beforeDragOut : function(target, e, id){
22474 onDragDrop : function(e, id){
22475 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
22476 if(this.beforeDragDrop(target, e, id) !== false){
22477 if(target.isNotifyTarget){
22478 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
22479 this.onValidDrop(target, e, id);
22481 this.onInvalidDrop(target, e, id);
22484 this.onValidDrop(target, e, id);
22487 if(this.afterDragDrop){
22489 * An empty function by default, but provided so that you can perform a custom action
22490 * after a valid drag drop has occurred by providing an implementation.
22491 * @param {Roo.dd.DragDrop} target The drop target
22492 * @param {Event} e The event object
22493 * @param {String} id The id of the dropped element
22494 * @method afterDragDrop
22496 this.afterDragDrop(target, e, id);
22499 delete this.cachedTarget;
22503 * An empty function by default, but provided so that you can perform a custom action before the dragged
22504 * item is dropped onto the target and optionally cancel the onDragDrop.
22505 * @param {Roo.dd.DragDrop} target The drop target
22506 * @param {Event} e The event object
22507 * @param {String} id The id of the dragged element
22508 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
22510 beforeDragDrop : function(target, e, id){
22515 onValidDrop : function(target, e, id){
22517 if(this.afterValidDrop){
22519 * An empty function by default, but provided so that you can perform a custom action
22520 * after a valid drop has occurred by providing an implementation.
22521 * @param {Object} target The target DD
22522 * @param {Event} e The event object
22523 * @param {String} id The id of the dropped element
22524 * @method afterInvalidDrop
22526 this.afterValidDrop(target, e, id);
22531 getRepairXY : function(e, data){
22532 return this.el.getXY();
22536 onInvalidDrop : function(target, e, id){
22537 this.beforeInvalidDrop(target, e, id);
22538 if(this.cachedTarget){
22539 if(this.cachedTarget.isNotifyTarget){
22540 this.cachedTarget.notifyOut(this, e, this.dragData);
22542 this.cacheTarget = null;
22544 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
22546 if(this.afterInvalidDrop){
22548 * An empty function by default, but provided so that you can perform a custom action
22549 * after an invalid drop has occurred by providing an implementation.
22550 * @param {Event} e The event object
22551 * @param {String} id The id of the dropped element
22552 * @method afterInvalidDrop
22554 this.afterInvalidDrop(e, id);
22559 afterRepair : function(){
22561 this.el.highlight(this.hlColor || "c3daf9");
22563 this.dragging = false;
22567 * An empty function by default, but provided so that you can perform a custom action after an invalid
22568 * drop has occurred.
22569 * @param {Roo.dd.DragDrop} target The drop target
22570 * @param {Event} e The event object
22571 * @param {String} id The id of the dragged element
22572 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
22574 beforeInvalidDrop : function(target, e, id){
22579 handleMouseDown : function(e){
22580 if(this.dragging) {
22583 var data = this.getDragData(e);
22584 if(data && this.onBeforeDrag(data, e) !== false){
22585 this.dragData = data;
22587 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
22592 * An empty function by default, but provided so that you can perform a custom action before the initial
22593 * drag event begins and optionally cancel it.
22594 * @param {Object} data An object containing arbitrary data to be shared with drop targets
22595 * @param {Event} e The event object
22596 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
22598 onBeforeDrag : function(data, e){
22603 * An empty function by default, but provided so that you can perform a custom action once the initial
22604 * drag event has begun. The drag cannot be canceled from this function.
22605 * @param {Number} x The x position of the click on the dragged object
22606 * @param {Number} y The y position of the click on the dragged object
22608 onStartDrag : Roo.emptyFn,
22610 // private - YUI override
22611 startDrag : function(x, y){
22612 this.proxy.reset();
22613 this.dragging = true;
22614 this.proxy.update("");
22615 this.onInitDrag(x, y);
22620 onInitDrag : function(x, y){
22621 var clone = this.el.dom.cloneNode(true);
22622 clone.id = Roo.id(); // prevent duplicate ids
22623 this.proxy.update(clone);
22624 this.onStartDrag(x, y);
22629 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
22630 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
22632 getProxy : function(){
22637 * Hides the drag source's {@link Roo.dd.StatusProxy}
22639 hideProxy : function(){
22641 this.proxy.reset(true);
22642 this.dragging = false;
22646 triggerCacheRefresh : function(){
22647 Roo.dd.DDM.refreshCache(this.groups);
22650 // private - override to prevent hiding
22651 b4EndDrag: function(e) {
22654 // private - override to prevent moving
22655 endDrag : function(e){
22656 this.onEndDrag(this.dragData, e);
22660 onEndDrag : function(data, e){
22663 // private - pin to cursor
22664 autoOffset : function(x, y) {
22665 this.setDelta(-12, -20);
22669 * Ext JS Library 1.1.1
22670 * Copyright(c) 2006-2007, Ext JS, LLC.
22672 * Originally Released Under LGPL - original licence link has changed is not relivant.
22675 * <script type="text/javascript">
22680 * @class Roo.dd.DropTarget
22681 * @extends Roo.dd.DDTarget
22682 * A simple class that provides the basic implementation needed to make any element a drop target that can have
22683 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
22685 * @param {String/HTMLElement/Element} el The container element
22686 * @param {Object} config
22688 Roo.dd.DropTarget = function(el, config){
22689 this.el = Roo.get(el);
22691 var listeners = false; ;
22692 if (config && config.listeners) {
22693 listeners= config.listeners;
22694 delete config.listeners;
22696 Roo.apply(this, config);
22698 if(this.containerScroll){
22699 Roo.dd.ScrollManager.register(this.el);
22703 * @scope Roo.dd.DropTarget
22708 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
22709 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
22710 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
22712 * IMPORTANT : it should set this.valid to true|false
22714 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22715 * @param {Event} e The event
22716 * @param {Object} data An object containing arbitrary data supplied by the drag source
22722 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
22723 * This method will be called on every mouse movement while the drag source is over the drop target.
22724 * This default implementation simply returns the dropAllowed config value.
22726 * IMPORTANT : it should set this.valid to true|false
22728 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22729 * @param {Event} e The event
22730 * @param {Object} data An object containing arbitrary data supplied by the drag source
22736 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
22737 * out of the target without dropping. This default implementation simply removes the CSS class specified by
22738 * overClass (if any) from the drop element.
22741 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22742 * @param {Event} e The event
22743 * @param {Object} data An object containing arbitrary data supplied by the drag source
22749 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
22750 * been dropped on it. This method has no default implementation and returns false, so you must provide an
22751 * implementation that does something to process the drop event and returns true so that the drag source's
22752 * repair action does not run.
22754 * IMPORTANT : it should set this.success
22756 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
22757 * @param {Event} e The event
22758 * @param {Object} data An object containing arbitrary data supplied by the drag source
22764 Roo.dd.DropTarget.superclass.constructor.call( this,
22766 this.ddGroup || this.group,
22769 listeners : listeners || {}
22777 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
22779 * @cfg {String} overClass
22780 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
22783 * @cfg {String} ddGroup
22784 * The drag drop group to handle drop events for
22788 * @cfg {String} dropAllowed
22789 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
22791 dropAllowed : "x-dd-drop-ok",
22793 * @cfg {String} dropNotAllowed
22794 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
22796 dropNotAllowed : "x-dd-drop-nodrop",
22798 * @cfg {boolean} success
22799 * set this after drop listener..
22803 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
22804 * if the drop point is valid for over/enter..
22811 isNotifyTarget : true,
22816 notifyEnter : function(dd, e, data)
22819 this.fireEvent('enter', dd, e, data);
22820 if(this.overClass){
22821 this.el.addClass(this.overClass);
22823 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22824 this.valid ? this.dropAllowed : this.dropNotAllowed
22831 notifyOver : function(dd, e, data)
22834 this.fireEvent('over', dd, e, data);
22835 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
22836 this.valid ? this.dropAllowed : this.dropNotAllowed
22843 notifyOut : function(dd, e, data)
22845 this.fireEvent('out', dd, e, data);
22846 if(this.overClass){
22847 this.el.removeClass(this.overClass);
22854 notifyDrop : function(dd, e, data)
22856 this.success = false;
22857 this.fireEvent('drop', dd, e, data);
22858 return this.success;
22862 * Ext JS Library 1.1.1
22863 * Copyright(c) 2006-2007, Ext JS, LLC.
22865 * Originally Released Under LGPL - original licence link has changed is not relivant.
22868 * <script type="text/javascript">
22873 * @class Roo.dd.DragZone
22874 * @extends Roo.dd.DragSource
22875 * This class provides a container DD instance that proxies for multiple child node sources.<br />
22876 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
22878 * @param {String/HTMLElement/Element} el The container element
22879 * @param {Object} config
22881 Roo.dd.DragZone = function(el, config){
22882 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
22883 if(this.containerScroll){
22884 Roo.dd.ScrollManager.register(this.el);
22888 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
22890 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
22891 * for auto scrolling during drag operations.
22894 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
22895 * method after a failed drop (defaults to "c3daf9" - light blue)
22899 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
22900 * for a valid target to drag based on the mouse down. Override this method
22901 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
22902 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
22903 * @param {EventObject} e The mouse down event
22904 * @return {Object} The dragData
22906 getDragData : function(e){
22907 return Roo.dd.Registry.getHandleFromEvent(e);
22911 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
22912 * this.dragData.ddel
22913 * @param {Number} x The x position of the click on the dragged object
22914 * @param {Number} y The y position of the click on the dragged object
22915 * @return {Boolean} true to continue the drag, false to cancel
22917 onInitDrag : function(x, y){
22918 this.proxy.update(this.dragData.ddel.cloneNode(true));
22919 this.onStartDrag(x, y);
22924 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
22926 afterRepair : function(){
22928 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
22930 this.dragging = false;
22934 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
22935 * the XY of this.dragData.ddel
22936 * @param {EventObject} e The mouse up event
22937 * @return {Array} The xy location (e.g. [100, 200])
22939 getRepairXY : function(e){
22940 return Roo.Element.fly(this.dragData.ddel).getXY();
22944 * Ext JS Library 1.1.1
22945 * Copyright(c) 2006-2007, Ext JS, LLC.
22947 * Originally Released Under LGPL - original licence link has changed is not relivant.
22950 * <script type="text/javascript">
22953 * @class Roo.dd.DropZone
22954 * @extends Roo.dd.DropTarget
22955 * This class provides a container DD instance that proxies for multiple child node targets.<br />
22956 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
22958 * @param {String/HTMLElement/Element} el The container element
22959 * @param {Object} config
22961 Roo.dd.DropZone = function(el, config){
22962 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
22965 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
22967 * Returns a custom data object associated with the DOM node that is the target of the event. By default
22968 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
22969 * provide your own custom lookup.
22970 * @param {Event} e The event
22971 * @return {Object} data The custom data
22973 getTargetFromEvent : function(e){
22974 return Roo.dd.Registry.getTargetFromEvent(e);
22978 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
22979 * that it has registered. This method has no default implementation and should be overridden to provide
22980 * node-specific processing if necessary.
22981 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22982 * {@link #getTargetFromEvent} for this node)
22983 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22984 * @param {Event} e The event
22985 * @param {Object} data An object containing arbitrary data supplied by the drag source
22987 onNodeEnter : function(n, dd, e, data){
22992 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
22993 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
22994 * overridden to provide the proper feedback.
22995 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
22996 * {@link #getTargetFromEvent} for this node)
22997 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
22998 * @param {Event} e The event
22999 * @param {Object} data An object containing arbitrary data supplied by the drag source
23000 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23001 * underlying {@link Roo.dd.StatusProxy} can be updated
23003 onNodeOver : function(n, dd, e, data){
23004 return this.dropAllowed;
23008 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
23009 * the drop node without dropping. This method has no default implementation and should be overridden to provide
23010 * node-specific processing if necessary.
23011 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23012 * {@link #getTargetFromEvent} for this node)
23013 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23014 * @param {Event} e The event
23015 * @param {Object} data An object containing arbitrary data supplied by the drag source
23017 onNodeOut : function(n, dd, e, data){
23022 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
23023 * the drop node. The default implementation returns false, so it should be overridden to provide the
23024 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
23025 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
23026 * {@link #getTargetFromEvent} for this node)
23027 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23028 * @param {Event} e The event
23029 * @param {Object} data An object containing arbitrary data supplied by the drag source
23030 * @return {Boolean} True if the drop was valid, else false
23032 onNodeDrop : function(n, dd, e, data){
23037 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
23038 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
23039 * it should be overridden to provide the proper feedback if necessary.
23040 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23041 * @param {Event} e The event
23042 * @param {Object} data An object containing arbitrary data supplied by the drag source
23043 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23044 * underlying {@link Roo.dd.StatusProxy} can be updated
23046 onContainerOver : function(dd, e, data){
23047 return this.dropNotAllowed;
23051 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
23052 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
23053 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
23054 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
23055 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23056 * @param {Event} e The event
23057 * @param {Object} data An object containing arbitrary data supplied by the drag source
23058 * @return {Boolean} True if the drop was valid, else false
23060 onContainerDrop : function(dd, e, data){
23065 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
23066 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
23067 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
23068 * you should override this method and provide a custom implementation.
23069 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23070 * @param {Event} e The event
23071 * @param {Object} data An object containing arbitrary data supplied by the drag source
23072 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23073 * underlying {@link Roo.dd.StatusProxy} can be updated
23075 notifyEnter : function(dd, e, data){
23076 return this.dropNotAllowed;
23080 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
23081 * This method will be called on every mouse movement while the drag source is over the drop zone.
23082 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
23083 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
23084 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
23085 * registered node, it will call {@link #onContainerOver}.
23086 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23087 * @param {Event} e The event
23088 * @param {Object} data An object containing arbitrary data supplied by the drag source
23089 * @return {String} status The CSS class that communicates the drop status back to the source so that the
23090 * underlying {@link Roo.dd.StatusProxy} can be updated
23092 notifyOver : function(dd, e, data){
23093 var n = this.getTargetFromEvent(e);
23094 if(!n){ // not over valid drop target
23095 if(this.lastOverNode){
23096 this.onNodeOut(this.lastOverNode, dd, e, data);
23097 this.lastOverNode = null;
23099 return this.onContainerOver(dd, e, data);
23101 if(this.lastOverNode != n){
23102 if(this.lastOverNode){
23103 this.onNodeOut(this.lastOverNode, dd, e, data);
23105 this.onNodeEnter(n, dd, e, data);
23106 this.lastOverNode = n;
23108 return this.onNodeOver(n, dd, e, data);
23112 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
23113 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
23114 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
23115 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
23116 * @param {Event} e The event
23117 * @param {Object} data An object containing arbitrary data supplied by the drag zone
23119 notifyOut : function(dd, e, data){
23120 if(this.lastOverNode){
23121 this.onNodeOut(this.lastOverNode, dd, e, data);
23122 this.lastOverNode = null;
23127 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
23128 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
23129 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
23130 * otherwise it will call {@link #onContainerDrop}.
23131 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
23132 * @param {Event} e The event
23133 * @param {Object} data An object containing arbitrary data supplied by the drag source
23134 * @return {Boolean} True if the drop was valid, else false
23136 notifyDrop : function(dd, e, data){
23137 if(this.lastOverNode){
23138 this.onNodeOut(this.lastOverNode, dd, e, data);
23139 this.lastOverNode = null;
23141 var n = this.getTargetFromEvent(e);
23143 this.onNodeDrop(n, dd, e, data) :
23144 this.onContainerDrop(dd, e, data);
23148 triggerCacheRefresh : function(){
23149 Roo.dd.DDM.refreshCache(this.groups);
23153 * Ext JS Library 1.1.1
23154 * Copyright(c) 2006-2007, Ext JS, LLC.
23156 * Originally Released Under LGPL - original licence link has changed is not relivant.
23159 * <script type="text/javascript">
23164 * @class Roo.data.SortTypes
23166 * Defines the default sorting (casting?) comparison functions used when sorting data.
23168 Roo.data.SortTypes = {
23170 * Default sort that does nothing
23171 * @param {Mixed} s The value being converted
23172 * @return {Mixed} The comparison value
23174 none : function(s){
23179 * The regular expression used to strip tags
23183 stripTagsRE : /<\/?[^>]+>/gi,
23186 * Strips all HTML tags to sort on text only
23187 * @param {Mixed} s The value being converted
23188 * @return {String} The comparison value
23190 asText : function(s){
23191 return String(s).replace(this.stripTagsRE, "");
23195 * Strips all HTML tags to sort on text only - Case insensitive
23196 * @param {Mixed} s The value being converted
23197 * @return {String} The comparison value
23199 asUCText : function(s){
23200 return String(s).toUpperCase().replace(this.stripTagsRE, "");
23204 * Case insensitive string
23205 * @param {Mixed} s The value being converted
23206 * @return {String} The comparison value
23208 asUCString : function(s) {
23209 return String(s).toUpperCase();
23214 * @param {Mixed} s The value being converted
23215 * @return {Number} The comparison value
23217 asDate : function(s) {
23221 if(s instanceof Date){
23222 return s.getTime();
23224 return Date.parse(String(s));
23229 * @param {Mixed} s The value being converted
23230 * @return {Float} The comparison value
23232 asFloat : function(s) {
23233 var val = parseFloat(String(s).replace(/,/g, ""));
23242 * @param {Mixed} s The value being converted
23243 * @return {Number} The comparison value
23245 asInt : function(s) {
23246 var val = parseInt(String(s).replace(/,/g, ""));
23254 * Ext JS Library 1.1.1
23255 * Copyright(c) 2006-2007, Ext JS, LLC.
23257 * Originally Released Under LGPL - original licence link has changed is not relivant.
23260 * <script type="text/javascript">
23264 * @class Roo.data.Record
23265 * Instances of this class encapsulate both record <em>definition</em> information, and record
23266 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
23267 * to access Records cached in an {@link Roo.data.Store} object.<br>
23269 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
23270 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
23273 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
23275 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
23276 * {@link #create}. The parameters are the same.
23277 * @param {Array} data An associative Array of data values keyed by the field name.
23278 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
23279 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
23280 * not specified an integer id is generated.
23282 Roo.data.Record = function(data, id){
23283 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
23288 * Generate a constructor for a specific record layout.
23289 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
23290 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
23291 * Each field definition object may contain the following properties: <ul>
23292 * <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,
23293 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
23294 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
23295 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
23296 * is being used, then this is a string containing the javascript expression to reference the data relative to
23297 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
23298 * to the data item relative to the record element. If the mapping expression is the same as the field name,
23299 * this may be omitted.</p></li>
23300 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
23301 * <ul><li>auto (Default, implies no conversion)</li>
23306 * <li>date</li></ul></p></li>
23307 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
23308 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
23309 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
23310 * by the Reader into an object that will be stored in the Record. It is passed the
23311 * following parameters:<ul>
23312 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
23314 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
23316 * <br>usage:<br><pre><code>
23317 var TopicRecord = Roo.data.Record.create(
23318 {name: 'title', mapping: 'topic_title'},
23319 {name: 'author', mapping: 'username'},
23320 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
23321 {name: 'lastPost', mapping: 'post_time', type: 'date'},
23322 {name: 'lastPoster', mapping: 'user2'},
23323 {name: 'excerpt', mapping: 'post_text'}
23326 var myNewRecord = new TopicRecord({
23327 title: 'Do my job please',
23330 lastPost: new Date(),
23331 lastPoster: 'Animal',
23332 excerpt: 'No way dude!'
23334 myStore.add(myNewRecord);
23339 Roo.data.Record.create = function(o){
23340 var f = function(){
23341 f.superclass.constructor.apply(this, arguments);
23343 Roo.extend(f, Roo.data.Record);
23344 var p = f.prototype;
23345 p.fields = new Roo.util.MixedCollection(false, function(field){
23348 for(var i = 0, len = o.length; i < len; i++){
23349 p.fields.add(new Roo.data.Field(o[i]));
23351 f.getField = function(name){
23352 return p.fields.get(name);
23357 Roo.data.Record.AUTO_ID = 1000;
23358 Roo.data.Record.EDIT = 'edit';
23359 Roo.data.Record.REJECT = 'reject';
23360 Roo.data.Record.COMMIT = 'commit';
23362 Roo.data.Record.prototype = {
23364 * Readonly flag - true if this record has been modified.
23373 join : function(store){
23374 this.store = store;
23378 * Set the named field to the specified value.
23379 * @param {String} name The name of the field to set.
23380 * @param {Object} value The value to set the field to.
23382 set : function(name, value){
23383 if(this.data[name] == value){
23387 if(!this.modified){
23388 this.modified = {};
23390 if(typeof this.modified[name] == 'undefined'){
23391 this.modified[name] = this.data[name];
23393 this.data[name] = value;
23394 if(!this.editing && this.store){
23395 this.store.afterEdit(this);
23400 * Get the value of the named field.
23401 * @param {String} name The name of the field to get the value of.
23402 * @return {Object} The value of the field.
23404 get : function(name){
23405 return this.data[name];
23409 beginEdit : function(){
23410 this.editing = true;
23411 this.modified = {};
23415 cancelEdit : function(){
23416 this.editing = false;
23417 delete this.modified;
23421 endEdit : function(){
23422 this.editing = false;
23423 if(this.dirty && this.store){
23424 this.store.afterEdit(this);
23429 * Usually called by the {@link Roo.data.Store} which owns the Record.
23430 * Rejects all changes made to the Record since either creation, or the last commit operation.
23431 * Modified fields are reverted to their original values.
23433 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23434 * of reject operations.
23436 reject : function(){
23437 var m = this.modified;
23439 if(typeof m[n] != "function"){
23440 this.data[n] = m[n];
23443 this.dirty = false;
23444 delete this.modified;
23445 this.editing = false;
23447 this.store.afterReject(this);
23452 * Usually called by the {@link Roo.data.Store} which owns the Record.
23453 * Commits all changes made to the Record since either creation, or the last commit operation.
23455 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
23456 * of commit operations.
23458 commit : function(){
23459 this.dirty = false;
23460 delete this.modified;
23461 this.editing = false;
23463 this.store.afterCommit(this);
23468 hasError : function(){
23469 return this.error != null;
23473 clearError : function(){
23478 * Creates a copy of this record.
23479 * @param {String} id (optional) A new record id if you don't want to use this record's id
23482 copy : function(newId) {
23483 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
23487 * Ext JS Library 1.1.1
23488 * Copyright(c) 2006-2007, Ext JS, LLC.
23490 * Originally Released Under LGPL - original licence link has changed is not relivant.
23493 * <script type="text/javascript">
23499 * @class Roo.data.Store
23500 * @extends Roo.util.Observable
23501 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
23502 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
23504 * 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
23505 * has no knowledge of the format of the data returned by the Proxy.<br>
23507 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
23508 * instances from the data object. These records are cached and made available through accessor functions.
23510 * Creates a new Store.
23511 * @param {Object} config A config object containing the objects needed for the Store to access data,
23512 * and read the data into Records.
23514 Roo.data.Store = function(config){
23515 this.data = new Roo.util.MixedCollection(false);
23516 this.data.getKey = function(o){
23519 this.baseParams = {};
23521 this.paramNames = {
23526 "multisort" : "_multisort"
23529 if(config && config.data){
23530 this.inlineData = config.data;
23531 delete config.data;
23534 Roo.apply(this, config);
23536 if(this.reader){ // reader passed
23537 this.reader = Roo.factory(this.reader, Roo.data);
23538 this.reader.xmodule = this.xmodule || false;
23539 if(!this.recordType){
23540 this.recordType = this.reader.recordType;
23542 if(this.reader.onMetaChange){
23543 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
23547 if(this.recordType){
23548 this.fields = this.recordType.prototype.fields;
23550 this.modified = [];
23554 * @event datachanged
23555 * Fires when the data cache has changed, and a widget which is using this Store
23556 * as a Record cache should refresh its view.
23557 * @param {Store} this
23559 datachanged : true,
23561 * @event metachange
23562 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
23563 * @param {Store} this
23564 * @param {Object} meta The JSON metadata
23569 * Fires when Records have been added to the Store
23570 * @param {Store} this
23571 * @param {Roo.data.Record[]} records The array of Records added
23572 * @param {Number} index The index at which the record(s) were added
23577 * Fires when a Record has been removed from the Store
23578 * @param {Store} this
23579 * @param {Roo.data.Record} record The Record that was removed
23580 * @param {Number} index The index at which the record was removed
23585 * Fires when a Record has been updated
23586 * @param {Store} this
23587 * @param {Roo.data.Record} record The Record that was updated
23588 * @param {String} operation The update operation being performed. Value may be one of:
23590 Roo.data.Record.EDIT
23591 Roo.data.Record.REJECT
23592 Roo.data.Record.COMMIT
23598 * Fires when the data cache has been cleared.
23599 * @param {Store} this
23603 * @event beforeload
23604 * Fires before a request is made for a new data object. If the beforeload handler returns false
23605 * the load action will be canceled.
23606 * @param {Store} this
23607 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23611 * @event beforeloadadd
23612 * Fires after a new set of Records has been loaded.
23613 * @param {Store} this
23614 * @param {Roo.data.Record[]} records The Records that were loaded
23615 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23617 beforeloadadd : true,
23620 * Fires after a new set of Records has been loaded, before they are added to the store.
23621 * @param {Store} this
23622 * @param {Roo.data.Record[]} records The Records that were loaded
23623 * @param {Object} options The loading options that were specified (see {@link #load} for details)
23624 * @params {Object} return from reader
23628 * @event loadexception
23629 * Fires if an exception occurs in the Proxy during loading.
23630 * Called with the signature of the Proxy's "loadexception" event.
23631 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
23634 * @param {Object} return from JsonData.reader() - success, totalRecords, records
23635 * @param {Object} load options
23636 * @param {Object} jsonData from your request (normally this contains the Exception)
23638 loadexception : true
23642 this.proxy = Roo.factory(this.proxy, Roo.data);
23643 this.proxy.xmodule = this.xmodule || false;
23644 this.relayEvents(this.proxy, ["loadexception"]);
23646 this.sortToggle = {};
23647 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
23649 Roo.data.Store.superclass.constructor.call(this);
23651 if(this.inlineData){
23652 this.loadData(this.inlineData);
23653 delete this.inlineData;
23657 Roo.extend(Roo.data.Store, Roo.util.Observable, {
23659 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
23660 * without a remote query - used by combo/forms at present.
23664 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
23667 * @cfg {Array} data Inline data to be loaded when the store is initialized.
23670 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
23671 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
23674 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
23675 * on any HTTP request
23678 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
23681 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
23685 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
23686 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
23688 remoteSort : false,
23691 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
23692 * loaded or when a record is removed. (defaults to false).
23694 pruneModifiedRecords : false,
23697 lastOptions : null,
23700 * Add Records to the Store and fires the add event.
23701 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23703 add : function(records){
23704 records = [].concat(records);
23705 for(var i = 0, len = records.length; i < len; i++){
23706 records[i].join(this);
23708 var index = this.data.length;
23709 this.data.addAll(records);
23710 this.fireEvent("add", this, records, index);
23714 * Remove a Record from the Store and fires the remove event.
23715 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
23717 remove : function(record){
23718 var index = this.data.indexOf(record);
23719 this.data.removeAt(index);
23721 if(this.pruneModifiedRecords){
23722 this.modified.remove(record);
23724 this.fireEvent("remove", this, record, index);
23728 * Remove all Records from the Store and fires the clear event.
23730 removeAll : function(){
23732 if(this.pruneModifiedRecords){
23733 this.modified = [];
23735 this.fireEvent("clear", this);
23739 * Inserts Records to the Store at the given index and fires the add event.
23740 * @param {Number} index The start index at which to insert the passed Records.
23741 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
23743 insert : function(index, records){
23744 records = [].concat(records);
23745 for(var i = 0, len = records.length; i < len; i++){
23746 this.data.insert(index, records[i]);
23747 records[i].join(this);
23749 this.fireEvent("add", this, records, index);
23753 * Get the index within the cache of the passed Record.
23754 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
23755 * @return {Number} The index of the passed Record. Returns -1 if not found.
23757 indexOf : function(record){
23758 return this.data.indexOf(record);
23762 * Get the index within the cache of the Record with the passed id.
23763 * @param {String} id The id of the Record to find.
23764 * @return {Number} The index of the Record. Returns -1 if not found.
23766 indexOfId : function(id){
23767 return this.data.indexOfKey(id);
23771 * Get the Record with the specified id.
23772 * @param {String} id The id of the Record to find.
23773 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
23775 getById : function(id){
23776 return this.data.key(id);
23780 * Get the Record at the specified index.
23781 * @param {Number} index The index of the Record to find.
23782 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
23784 getAt : function(index){
23785 return this.data.itemAt(index);
23789 * Returns a range of Records between specified indices.
23790 * @param {Number} startIndex (optional) The starting index (defaults to 0)
23791 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
23792 * @return {Roo.data.Record[]} An array of Records
23794 getRange : function(start, end){
23795 return this.data.getRange(start, end);
23799 storeOptions : function(o){
23800 o = Roo.apply({}, o);
23803 this.lastOptions = o;
23807 * Loads the Record cache from the configured Proxy using the configured Reader.
23809 * If using remote paging, then the first load call must specify the <em>start</em>
23810 * and <em>limit</em> properties in the options.params property to establish the initial
23811 * position within the dataset, and the number of Records to cache on each read from the Proxy.
23813 * <strong>It is important to note that for remote data sources, loading is asynchronous,
23814 * and this call will return before the new data has been loaded. Perform any post-processing
23815 * in a callback function, or in a "load" event handler.</strong>
23817 * @param {Object} options An object containing properties which control loading options:<ul>
23818 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
23819 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
23820 * passed the following arguments:<ul>
23821 * <li>r : Roo.data.Record[]</li>
23822 * <li>options: Options object from the load call</li>
23823 * <li>success: Boolean success indicator</li></ul></li>
23824 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
23825 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
23828 load : function(options){
23829 options = options || {};
23830 if(this.fireEvent("beforeload", this, options) !== false){
23831 this.storeOptions(options);
23832 var p = Roo.apply(options.params || {}, this.baseParams);
23833 // if meta was not loaded from remote source.. try requesting it.
23834 if (!this.reader.metaFromRemote) {
23835 p._requestMeta = 1;
23837 if(this.sortInfo && this.remoteSort){
23838 var pn = this.paramNames;
23839 p[pn["sort"]] = this.sortInfo.field;
23840 p[pn["dir"]] = this.sortInfo.direction;
23842 if (this.multiSort) {
23843 var pn = this.paramNames;
23844 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
23847 this.proxy.load(p, this.reader, this.loadRecords, this, options);
23852 * Reloads the Record cache from the configured Proxy using the configured Reader and
23853 * the options from the last load operation performed.
23854 * @param {Object} options (optional) An object containing properties which may override the options
23855 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
23856 * the most recently used options are reused).
23858 reload : function(options){
23859 this.load(Roo.applyIf(options||{}, this.lastOptions));
23863 // Called as a callback by the Reader during a load operation.
23864 loadRecords : function(o, options, success){
23865 if(!o || success === false){
23866 if(success !== false){
23867 this.fireEvent("load", this, [], options, o);
23869 if(options.callback){
23870 options.callback.call(options.scope || this, [], options, false);
23874 // if data returned failure - throw an exception.
23875 if (o.success === false) {
23876 // show a message if no listener is registered.
23877 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
23878 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
23880 // loadmask wil be hooked into this..
23881 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
23884 var r = o.records, t = o.totalRecords || r.length;
23886 this.fireEvent("beforeloadadd", this, r, options, o);
23888 if(!options || options.add !== true){
23889 if(this.pruneModifiedRecords){
23890 this.modified = [];
23892 for(var i = 0, len = r.length; i < len; i++){
23896 this.data = this.snapshot;
23897 delete this.snapshot;
23900 this.data.addAll(r);
23901 this.totalLength = t;
23903 this.fireEvent("datachanged", this);
23905 this.totalLength = Math.max(t, this.data.length+r.length);
23909 if(this.parent && !Roo.isIOS && !this.useNativeIOS && this.parent.emptyTitle.length) {
23911 var e = new Roo.data.Record({});
23913 e.set(this.parent.displayField, this.parent.emptyTitle);
23914 e.set(this.parent.valueField, '');
23919 this.fireEvent("load", this, r, options, o);
23920 if(options.callback){
23921 options.callback.call(options.scope || this, r, options, true);
23927 * Loads data from a passed data block. A Reader which understands the format of the data
23928 * must have been configured in the constructor.
23929 * @param {Object} data The data block from which to read the Records. The format of the data expected
23930 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
23931 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
23933 loadData : function(o, append){
23934 var r = this.reader.readRecords(o);
23935 this.loadRecords(r, {add: append}, true);
23939 * using 'cn' the nested child reader read the child array into it's child stores.
23940 * @param {Object} rec The record with a 'children array
23942 loadDataFromChildren : function(rec)
23944 this.loadData(this.reader.toLoadData(rec));
23949 * Gets the number of cached records.
23951 * <em>If using paging, this may not be the total size of the dataset. If the data object
23952 * used by the Reader contains the dataset size, then the getTotalCount() function returns
23953 * the data set size</em>
23955 getCount : function(){
23956 return this.data.length || 0;
23960 * Gets the total number of records in the dataset as returned by the server.
23962 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
23963 * the dataset size</em>
23965 getTotalCount : function(){
23966 return this.totalLength || 0;
23970 * Returns the sort state of the Store as an object with two properties:
23972 field {String} The name of the field by which the Records are sorted
23973 direction {String} The sort order, "ASC" or "DESC"
23976 getSortState : function(){
23977 return this.sortInfo;
23981 applySort : function(){
23982 if(this.sortInfo && !this.remoteSort){
23983 var s = this.sortInfo, f = s.field;
23984 var st = this.fields.get(f).sortType;
23985 var fn = function(r1, r2){
23986 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
23987 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
23989 this.data.sort(s.direction, fn);
23990 if(this.snapshot && this.snapshot != this.data){
23991 this.snapshot.sort(s.direction, fn);
23997 * Sets the default sort column and order to be used by the next load operation.
23998 * @param {String} fieldName The name of the field to sort by.
23999 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24001 setDefaultSort : function(field, dir){
24002 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
24006 * Sort the Records.
24007 * If remote sorting is used, the sort is performed on the server, and the cache is
24008 * reloaded. If local sorting is used, the cache is sorted internally.
24009 * @param {String} fieldName The name of the field to sort by.
24010 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
24012 sort : function(fieldName, dir){
24013 var f = this.fields.get(fieldName);
24015 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
24017 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
24018 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
24023 this.sortToggle[f.name] = dir;
24024 this.sortInfo = {field: f.name, direction: dir};
24025 if(!this.remoteSort){
24027 this.fireEvent("datachanged", this);
24029 this.load(this.lastOptions);
24034 * Calls the specified function for each of the Records in the cache.
24035 * @param {Function} fn The function to call. The Record is passed as the first parameter.
24036 * Returning <em>false</em> aborts and exits the iteration.
24037 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
24039 each : function(fn, scope){
24040 this.data.each(fn, scope);
24044 * Gets all records modified since the last commit. Modified records are persisted across load operations
24045 * (e.g., during paging).
24046 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
24048 getModifiedRecords : function(){
24049 return this.modified;
24053 createFilterFn : function(property, value, anyMatch){
24054 if(!value.exec){ // not a regex
24055 value = String(value);
24056 if(value.length == 0){
24059 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
24061 return function(r){
24062 return value.test(r.data[property]);
24067 * Sums the value of <i>property</i> for each record between start and end and returns the result.
24068 * @param {String} property A field on your records
24069 * @param {Number} start The record index to start at (defaults to 0)
24070 * @param {Number} end The last record index to include (defaults to length - 1)
24071 * @return {Number} The sum
24073 sum : function(property, start, end){
24074 var rs = this.data.items, v = 0;
24075 start = start || 0;
24076 end = (end || end === 0) ? end : rs.length-1;
24078 for(var i = start; i <= end; i++){
24079 v += (rs[i].data[property] || 0);
24085 * Filter the records by a specified property.
24086 * @param {String} field A field on your records
24087 * @param {String/RegExp} value Either a string that the field
24088 * should start with or a RegExp to test against the field
24089 * @param {Boolean} anyMatch True to match any part not just the beginning
24091 filter : function(property, value, anyMatch){
24092 var fn = this.createFilterFn(property, value, anyMatch);
24093 return fn ? this.filterBy(fn) : this.clearFilter();
24097 * Filter by a function. The specified function will be called with each
24098 * record in this data source. If the function returns true the record is included,
24099 * otherwise it is filtered.
24100 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24101 * @param {Object} scope (optional) The scope of the function (defaults to this)
24103 filterBy : function(fn, scope){
24104 this.snapshot = this.snapshot || this.data;
24105 this.data = this.queryBy(fn, scope||this);
24106 this.fireEvent("datachanged", this);
24110 * Query the records by a specified property.
24111 * @param {String} field A field on your records
24112 * @param {String/RegExp} value Either a string that the field
24113 * should start with or a RegExp to test against the field
24114 * @param {Boolean} anyMatch True to match any part not just the beginning
24115 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24117 query : function(property, value, anyMatch){
24118 var fn = this.createFilterFn(property, value, anyMatch);
24119 return fn ? this.queryBy(fn) : this.data.clone();
24123 * Query by a function. The specified function will be called with each
24124 * record in this data source. If the function returns true the record is included
24126 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
24127 * @param {Object} scope (optional) The scope of the function (defaults to this)
24128 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
24130 queryBy : function(fn, scope){
24131 var data = this.snapshot || this.data;
24132 return data.filterBy(fn, scope||this);
24136 * Collects unique values for a particular dataIndex from this store.
24137 * @param {String} dataIndex The property to collect
24138 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
24139 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
24140 * @return {Array} An array of the unique values
24142 collect : function(dataIndex, allowNull, bypassFilter){
24143 var d = (bypassFilter === true && this.snapshot) ?
24144 this.snapshot.items : this.data.items;
24145 var v, sv, r = [], l = {};
24146 for(var i = 0, len = d.length; i < len; i++){
24147 v = d[i].data[dataIndex];
24149 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
24158 * Revert to a view of the Record cache with no filtering applied.
24159 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
24161 clearFilter : function(suppressEvent){
24162 if(this.snapshot && this.snapshot != this.data){
24163 this.data = this.snapshot;
24164 delete this.snapshot;
24165 if(suppressEvent !== true){
24166 this.fireEvent("datachanged", this);
24172 afterEdit : function(record){
24173 if(this.modified.indexOf(record) == -1){
24174 this.modified.push(record);
24176 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
24180 afterReject : function(record){
24181 this.modified.remove(record);
24182 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
24186 afterCommit : function(record){
24187 this.modified.remove(record);
24188 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
24192 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
24193 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
24195 commitChanges : function(){
24196 var m = this.modified.slice(0);
24197 this.modified = [];
24198 for(var i = 0, len = m.length; i < len; i++){
24204 * Cancel outstanding changes on all changed records.
24206 rejectChanges : function(){
24207 var m = this.modified.slice(0);
24208 this.modified = [];
24209 for(var i = 0, len = m.length; i < len; i++){
24214 onMetaChange : function(meta, rtype, o){
24215 this.recordType = rtype;
24216 this.fields = rtype.prototype.fields;
24217 delete this.snapshot;
24218 this.sortInfo = meta.sortInfo || this.sortInfo;
24219 this.modified = [];
24220 this.fireEvent('metachange', this, this.reader.meta);
24223 moveIndex : function(data, type)
24225 var index = this.indexOf(data);
24227 var newIndex = index + type;
24231 this.insert(newIndex, data);
24236 * Ext JS Library 1.1.1
24237 * Copyright(c) 2006-2007, Ext JS, LLC.
24239 * Originally Released Under LGPL - original licence link has changed is not relivant.
24242 * <script type="text/javascript">
24246 * @class Roo.data.SimpleStore
24247 * @extends Roo.data.Store
24248 * Small helper class to make creating Stores from Array data easier.
24249 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
24250 * @cfg {Array} fields An array of field definition objects, or field name strings.
24251 * @cfg {Object} an existing reader (eg. copied from another store)
24252 * @cfg {Array} data The multi-dimensional array of data
24254 * @param {Object} config
24256 Roo.data.SimpleStore = function(config)
24258 Roo.data.SimpleStore.superclass.constructor.call(this, {
24260 reader: typeof(config.reader) != 'undefined' ? config.reader : new Roo.data.ArrayReader({
24263 Roo.data.Record.create(config.fields)
24265 proxy : new Roo.data.MemoryProxy(config.data)
24269 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
24271 * Ext JS Library 1.1.1
24272 * Copyright(c) 2006-2007, Ext JS, LLC.
24274 * Originally Released Under LGPL - original licence link has changed is not relivant.
24277 * <script type="text/javascript">
24282 * @extends Roo.data.Store
24283 * @class Roo.data.JsonStore
24284 * Small helper class to make creating Stores for JSON data easier. <br/>
24286 var store = new Roo.data.JsonStore({
24287 url: 'get-images.php',
24289 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
24292 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
24293 * JsonReader and HttpProxy (unless inline data is provided).</b>
24294 * @cfg {Array} fields An array of field definition objects, or field name strings.
24296 * @param {Object} config
24298 Roo.data.JsonStore = function(c){
24299 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
24300 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
24301 reader: new Roo.data.JsonReader(c, c.fields)
24304 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
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 Roo.data.Field = function(config){
24317 if(typeof config == "string"){
24318 config = {name: config};
24320 Roo.apply(this, config);
24323 this.type = "auto";
24326 var st = Roo.data.SortTypes;
24327 // named sortTypes are supported, here we look them up
24328 if(typeof this.sortType == "string"){
24329 this.sortType = st[this.sortType];
24332 // set default sortType for strings and dates
24333 if(!this.sortType){
24336 this.sortType = st.asUCString;
24339 this.sortType = st.asDate;
24342 this.sortType = st.none;
24347 var stripRe = /[\$,%]/g;
24349 // prebuilt conversion function for this field, instead of
24350 // switching every time we're reading a value
24352 var cv, dateFormat = this.dateFormat;
24357 cv = function(v){ return v; };
24360 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
24364 return v !== undefined && v !== null && v !== '' ?
24365 parseInt(String(v).replace(stripRe, ""), 10) : '';
24370 return v !== undefined && v !== null && v !== '' ?
24371 parseFloat(String(v).replace(stripRe, ""), 10) : '';
24376 cv = function(v){ return v === true || v === "true" || v == 1; };
24383 if(v instanceof Date){
24387 if(dateFormat == "timestamp"){
24388 return new Date(v*1000);
24390 return Date.parseDate(v, dateFormat);
24392 var parsed = Date.parse(v);
24393 return parsed ? new Date(parsed) : null;
24402 Roo.data.Field.prototype = {
24410 * Ext JS Library 1.1.1
24411 * Copyright(c) 2006-2007, Ext JS, LLC.
24413 * Originally Released Under LGPL - original licence link has changed is not relivant.
24416 * <script type="text/javascript">
24419 // Base class for reading structured data from a data source. This class is intended to be
24420 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
24423 * @class Roo.data.DataReader
24424 * Base class for reading structured data from a data source. This class is intended to be
24425 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
24428 Roo.data.DataReader = function(meta, recordType){
24432 this.recordType = recordType instanceof Array ?
24433 Roo.data.Record.create(recordType) : recordType;
24436 Roo.data.DataReader.prototype = {
24439 readerType : 'Data',
24441 * Create an empty record
24442 * @param {Object} data (optional) - overlay some values
24443 * @return {Roo.data.Record} record created.
24445 newRow : function(d) {
24447 this.recordType.prototype.fields.each(function(c) {
24449 case 'int' : da[c.name] = 0; break;
24450 case 'date' : da[c.name] = new Date(); break;
24451 case 'float' : da[c.name] = 0.0; break;
24452 case 'boolean' : da[c.name] = false; break;
24453 default : da[c.name] = ""; break;
24457 return new this.recordType(Roo.apply(da, d));
24463 * Ext JS Library 1.1.1
24464 * Copyright(c) 2006-2007, Ext JS, LLC.
24466 * Originally Released Under LGPL - original licence link has changed is not relivant.
24469 * <script type="text/javascript">
24473 * @class Roo.data.DataProxy
24474 * @extends Roo.data.Observable
24475 * This class is an abstract base class for implementations which provide retrieval of
24476 * unformatted data objects.<br>
24478 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
24479 * (of the appropriate type which knows how to parse the data object) to provide a block of
24480 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
24482 * Custom implementations must implement the load method as described in
24483 * {@link Roo.data.HttpProxy#load}.
24485 Roo.data.DataProxy = function(){
24488 * @event beforeload
24489 * Fires before a network request is made to retrieve a data object.
24490 * @param {Object} This DataProxy object.
24491 * @param {Object} params The params parameter to the load function.
24496 * Fires before the load method's callback is called.
24497 * @param {Object} This DataProxy object.
24498 * @param {Object} o The data object.
24499 * @param {Object} arg The callback argument object passed to the load function.
24503 * @event loadexception
24504 * Fires if an Exception occurs during data retrieval.
24505 * @param {Object} This DataProxy object.
24506 * @param {Object} o The data object.
24507 * @param {Object} arg The callback argument object passed to the load function.
24508 * @param {Object} e The Exception.
24510 loadexception : true
24512 Roo.data.DataProxy.superclass.constructor.call(this);
24515 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
24518 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
24522 * Ext JS Library 1.1.1
24523 * Copyright(c) 2006-2007, Ext JS, LLC.
24525 * Originally Released Under LGPL - original licence link has changed is not relivant.
24528 * <script type="text/javascript">
24531 * @class Roo.data.MemoryProxy
24532 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
24533 * to the Reader when its load method is called.
24535 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
24537 Roo.data.MemoryProxy = function(data){
24541 Roo.data.MemoryProxy.superclass.constructor.call(this);
24545 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
24548 * Load data from the requested source (in this case an in-memory
24549 * data object passed to the constructor), read the data object into
24550 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24551 * process that block using the passed callback.
24552 * @param {Object} params This parameter is not used by the MemoryProxy class.
24553 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24554 * object into a block of Roo.data.Records.
24555 * @param {Function} callback The function into which to pass the block of Roo.data.records.
24556 * The function must be passed <ul>
24557 * <li>The Record block object</li>
24558 * <li>The "arg" argument from the load function</li>
24559 * <li>A boolean success indicator</li>
24561 * @param {Object} scope The scope in which to call the callback
24562 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24564 load : function(params, reader, callback, scope, arg){
24565 params = params || {};
24568 result = reader.readRecords(params.data ? params.data :this.data);
24570 this.fireEvent("loadexception", this, arg, null, e);
24571 callback.call(scope, null, arg, false);
24574 callback.call(scope, result, arg, true);
24578 update : function(params, records){
24583 * Ext JS Library 1.1.1
24584 * Copyright(c) 2006-2007, Ext JS, LLC.
24586 * Originally Released Under LGPL - original licence link has changed is not relivant.
24589 * <script type="text/javascript">
24592 * @class Roo.data.HttpProxy
24593 * @extends Roo.data.DataProxy
24594 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
24595 * configured to reference a certain URL.<br><br>
24597 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
24598 * from which the running page was served.<br><br>
24600 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
24602 * Be aware that to enable the browser to parse an XML document, the server must set
24603 * the Content-Type header in the HTTP response to "text/xml".
24605 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
24606 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
24607 * will be used to make the request.
24609 Roo.data.HttpProxy = function(conn){
24610 Roo.data.HttpProxy.superclass.constructor.call(this);
24611 // is conn a conn config or a real conn?
24613 this.useAjax = !conn || !conn.events;
24617 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
24618 // thse are take from connection...
24621 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
24624 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
24625 * extra parameters to each request made by this object. (defaults to undefined)
24628 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
24629 * to each request made by this object. (defaults to undefined)
24632 * @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)
24635 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
24638 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
24644 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
24648 * Return the {@link Roo.data.Connection} object being used by this Proxy.
24649 * @return {Connection} The Connection object. This object may be used to subscribe to events on
24650 * a finer-grained basis than the DataProxy events.
24652 getConnection : function(){
24653 return this.useAjax ? Roo.Ajax : this.conn;
24657 * Load data from the configured {@link Roo.data.Connection}, read the data object into
24658 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
24659 * process that block using the passed callback.
24660 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24661 * for the request to the remote server.
24662 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24663 * object into a block of Roo.data.Records.
24664 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24665 * The function must be passed <ul>
24666 * <li>The Record block object</li>
24667 * <li>The "arg" argument from the load function</li>
24668 * <li>A boolean success indicator</li>
24670 * @param {Object} scope The scope in which to call the callback
24671 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24673 load : function(params, reader, callback, scope, arg){
24674 if(this.fireEvent("beforeload", this, params) !== false){
24676 params : params || {},
24678 callback : callback,
24683 callback : this.loadResponse,
24687 Roo.applyIf(o, this.conn);
24688 if(this.activeRequest){
24689 Roo.Ajax.abort(this.activeRequest);
24691 this.activeRequest = Roo.Ajax.request(o);
24693 this.conn.request(o);
24696 callback.call(scope||this, null, arg, false);
24701 loadResponse : function(o, success, response){
24702 delete this.activeRequest;
24704 this.fireEvent("loadexception", this, o, response);
24705 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24710 result = o.reader.read(response);
24712 this.fireEvent("loadexception", this, o, response, e);
24713 o.request.callback.call(o.request.scope, null, o.request.arg, false);
24717 this.fireEvent("load", this, o, o.request.arg);
24718 o.request.callback.call(o.request.scope, result, o.request.arg, true);
24722 update : function(dataSet){
24727 updateResponse : function(dataSet){
24732 * Ext JS Library 1.1.1
24733 * Copyright(c) 2006-2007, Ext JS, LLC.
24735 * Originally Released Under LGPL - original licence link has changed is not relivant.
24738 * <script type="text/javascript">
24742 * @class Roo.data.ScriptTagProxy
24743 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
24744 * other than the originating domain of the running page.<br><br>
24746 * <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
24747 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
24749 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
24750 * source code that is used as the source inside a <script> tag.<br><br>
24752 * In order for the browser to process the returned data, the server must wrap the data object
24753 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
24754 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
24755 * depending on whether the callback name was passed:
24758 boolean scriptTag = false;
24759 String cb = request.getParameter("callback");
24762 response.setContentType("text/javascript");
24764 response.setContentType("application/x-json");
24766 Writer out = response.getWriter();
24768 out.write(cb + "(");
24770 out.print(dataBlock.toJsonString());
24777 * @param {Object} config A configuration object.
24779 Roo.data.ScriptTagProxy = function(config){
24780 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
24781 Roo.apply(this, config);
24782 this.head = document.getElementsByTagName("head")[0];
24785 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
24787 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
24789 * @cfg {String} url The URL from which to request the data object.
24792 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
24796 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
24797 * the server the name of the callback function set up by the load call to process the returned data object.
24798 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
24799 * javascript output which calls this named function passing the data object as its only parameter.
24801 callbackParam : "callback",
24803 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
24804 * name to the request.
24809 * Load data from the configured URL, read the data object into
24810 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
24811 * process that block using the passed callback.
24812 * @param {Object} params An object containing properties which are to be used as HTTP parameters
24813 * for the request to the remote server.
24814 * @param {Roo.data.DataReader} reader The Reader object which converts the data
24815 * object into a block of Roo.data.Records.
24816 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
24817 * The function must be passed <ul>
24818 * <li>The Record block object</li>
24819 * <li>The "arg" argument from the load function</li>
24820 * <li>A boolean success indicator</li>
24822 * @param {Object} scope The scope in which to call the callback
24823 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
24825 load : function(params, reader, callback, scope, arg){
24826 if(this.fireEvent("beforeload", this, params) !== false){
24828 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
24830 var url = this.url;
24831 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
24833 url += "&_dc=" + (new Date().getTime());
24835 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
24838 cb : "stcCallback"+transId,
24839 scriptId : "stcScript"+transId,
24843 callback : callback,
24849 window[trans.cb] = function(o){
24850 conn.handleResponse(o, trans);
24853 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
24855 if(this.autoAbort !== false){
24859 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
24861 var script = document.createElement("script");
24862 script.setAttribute("src", url);
24863 script.setAttribute("type", "text/javascript");
24864 script.setAttribute("id", trans.scriptId);
24865 this.head.appendChild(script);
24867 this.trans = trans;
24869 callback.call(scope||this, null, arg, false);
24874 isLoading : function(){
24875 return this.trans ? true : false;
24879 * Abort the current server request.
24881 abort : function(){
24882 if(this.isLoading()){
24883 this.destroyTrans(this.trans);
24888 destroyTrans : function(trans, isLoaded){
24889 this.head.removeChild(document.getElementById(trans.scriptId));
24890 clearTimeout(trans.timeoutId);
24892 window[trans.cb] = undefined;
24894 delete window[trans.cb];
24897 // if hasn't been loaded, wait for load to remove it to prevent script error
24898 window[trans.cb] = function(){
24899 window[trans.cb] = undefined;
24901 delete window[trans.cb];
24908 handleResponse : function(o, trans){
24909 this.trans = false;
24910 this.destroyTrans(trans, true);
24913 result = trans.reader.readRecords(o);
24915 this.fireEvent("loadexception", this, o, trans.arg, e);
24916 trans.callback.call(trans.scope||window, null, trans.arg, false);
24919 this.fireEvent("load", this, o, trans.arg);
24920 trans.callback.call(trans.scope||window, result, trans.arg, true);
24924 handleFailure : function(trans){
24925 this.trans = false;
24926 this.destroyTrans(trans, false);
24927 this.fireEvent("loadexception", this, null, trans.arg);
24928 trans.callback.call(trans.scope||window, null, trans.arg, false);
24932 * Ext JS Library 1.1.1
24933 * Copyright(c) 2006-2007, Ext JS, LLC.
24935 * Originally Released Under LGPL - original licence link has changed is not relivant.
24938 * <script type="text/javascript">
24942 * @class Roo.data.JsonReader
24943 * @extends Roo.data.DataReader
24944 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
24945 * based on mappings in a provided Roo.data.Record constructor.
24947 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
24948 * in the reply previously.
24953 var RecordDef = Roo.data.Record.create([
24954 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
24955 {name: 'occupation'} // This field will use "occupation" as the mapping.
24957 var myReader = new Roo.data.JsonReader({
24958 totalProperty: "results", // The property which contains the total dataset size (optional)
24959 root: "rows", // The property which contains an Array of row objects
24960 id: "id" // The property within each row object that provides an ID for the record (optional)
24964 * This would consume a JSON file like this:
24966 { 'results': 2, 'rows': [
24967 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
24968 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
24971 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
24972 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
24973 * paged from the remote server.
24974 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
24975 * @cfg {String} root name of the property which contains the Array of row objects.
24976 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
24977 * @cfg {Array} fields Array of field definition objects
24979 * Create a new JsonReader
24980 * @param {Object} meta Metadata configuration options
24981 * @param {Object} recordType Either an Array of field definition objects,
24982 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
24984 Roo.data.JsonReader = function(meta, recordType){
24987 // set some defaults:
24988 Roo.applyIf(meta, {
24989 totalProperty: 'total',
24990 successProperty : 'success',
24995 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
24997 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
24999 readerType : 'Json',
25002 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
25003 * Used by Store query builder to append _requestMeta to params.
25006 metaFromRemote : false,
25008 * This method is only used by a DataProxy which has retrieved data from a remote server.
25009 * @param {Object} response The XHR object which contains the JSON data in its responseText.
25010 * @return {Object} data A data block which is used by an Roo.data.Store object as
25011 * a cache of Roo.data.Records.
25013 read : function(response){
25014 var json = response.responseText;
25016 var o = /* eval:var:o */ eval("("+json+")");
25018 throw {message: "JsonReader.read: Json object not found"};
25024 this.metaFromRemote = true;
25025 this.meta = o.metaData;
25026 this.recordType = Roo.data.Record.create(o.metaData.fields);
25027 this.onMetaChange(this.meta, this.recordType, o);
25029 return this.readRecords(o);
25032 // private function a store will implement
25033 onMetaChange : function(meta, recordType, o){
25040 simpleAccess: function(obj, subsc) {
25047 getJsonAccessor: function(){
25049 return function(expr) {
25051 return(re.test(expr))
25052 ? new Function("obj", "return obj." + expr)
25057 return Roo.emptyFn;
25062 * Create a data block containing Roo.data.Records from an XML document.
25063 * @param {Object} o An object which contains an Array of row objects in the property specified
25064 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
25065 * which contains the total size of the dataset.
25066 * @return {Object} data A data block which is used by an Roo.data.Store object as
25067 * a cache of Roo.data.Records.
25069 readRecords : function(o){
25071 * After any data loads, the raw JSON data is available for further custom processing.
25075 var s = this.meta, Record = this.recordType,
25076 f = Record ? Record.prototype.fields : null, fi = f ? f.items : [], fl = f ? f.length : 0;
25078 // Generate extraction functions for the totalProperty, the root, the id, and for each field
25080 if(s.totalProperty) {
25081 this.getTotal = this.getJsonAccessor(s.totalProperty);
25083 if(s.successProperty) {
25084 this.getSuccess = this.getJsonAccessor(s.successProperty);
25086 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
25088 var g = this.getJsonAccessor(s.id);
25089 this.getId = function(rec) {
25091 return (r === undefined || r === "") ? null : r;
25094 this.getId = function(){return null;};
25097 for(var jj = 0; jj < fl; jj++){
25099 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
25100 this.ef[jj] = this.getJsonAccessor(map);
25104 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
25105 if(s.totalProperty){
25106 var vt = parseInt(this.getTotal(o), 10);
25111 if(s.successProperty){
25112 var vs = this.getSuccess(o);
25113 if(vs === false || vs === 'false'){
25118 for(var i = 0; i < c; i++){
25121 var id = this.getId(n);
25122 for(var j = 0; j < fl; j++){
25124 var v = this.ef[j](n);
25126 Roo.log('missing convert for ' + f.name);
25130 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
25132 var record = new Record(values, id);
25134 records[i] = record;
25140 totalRecords : totalRecords
25143 // used when loading children.. @see loadDataFromChildren
25144 toLoadData: function(rec)
25146 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25147 var data = typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25148 return { data : data, total : data.length };
25153 * Ext JS Library 1.1.1
25154 * Copyright(c) 2006-2007, Ext JS, LLC.
25156 * Originally Released Under LGPL - original licence link has changed is not relivant.
25159 * <script type="text/javascript">
25163 * @class Roo.data.XmlReader
25164 * @extends Roo.data.DataReader
25165 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
25166 * based on mappings in a provided Roo.data.Record constructor.<br><br>
25168 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
25169 * header in the HTTP response must be set to "text/xml".</em>
25173 var RecordDef = Roo.data.Record.create([
25174 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
25175 {name: 'occupation'} // This field will use "occupation" as the mapping.
25177 var myReader = new Roo.data.XmlReader({
25178 totalRecords: "results", // The element which contains the total dataset size (optional)
25179 record: "row", // The repeated element which contains row information
25180 id: "id" // The element within the row that provides an ID for the record (optional)
25184 * This would consume an XML file like this:
25188 <results>2</results>
25191 <name>Bill</name>
25192 <occupation>Gardener</occupation>
25196 <name>Ben</name>
25197 <occupation>Horticulturalist</occupation>
25201 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
25202 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
25203 * paged from the remote server.
25204 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
25205 * @cfg {String} success The DomQuery path to the success attribute used by forms.
25206 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
25207 * a record identifier value.
25209 * Create a new XmlReader
25210 * @param {Object} meta Metadata configuration options
25211 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
25212 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
25213 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
25215 Roo.data.XmlReader = function(meta, recordType){
25217 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25219 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
25221 readerType : 'Xml',
25224 * This method is only used by a DataProxy which has retrieved data from a remote server.
25225 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
25226 * to contain a method called 'responseXML' that returns an XML document object.
25227 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25228 * a cache of Roo.data.Records.
25230 read : function(response){
25231 var doc = response.responseXML;
25233 throw {message: "XmlReader.read: XML Document not available"};
25235 return this.readRecords(doc);
25239 * Create a data block containing Roo.data.Records from an XML document.
25240 * @param {Object} doc A parsed XML document.
25241 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
25242 * a cache of Roo.data.Records.
25244 readRecords : function(doc){
25246 * After any data loads/reads, the raw XML Document is available for further custom processing.
25247 * @type XMLDocument
25249 this.xmlData = doc;
25250 var root = doc.documentElement || doc;
25251 var q = Roo.DomQuery;
25252 var recordType = this.recordType, fields = recordType.prototype.fields;
25253 var sid = this.meta.id;
25254 var totalRecords = 0, success = true;
25255 if(this.meta.totalRecords){
25256 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
25259 if(this.meta.success){
25260 var sv = q.selectValue(this.meta.success, root, true);
25261 success = sv !== false && sv !== 'false';
25264 var ns = q.select(this.meta.record, root);
25265 for(var i = 0, len = ns.length; i < len; i++) {
25268 var id = sid ? q.selectValue(sid, n) : undefined;
25269 for(var j = 0, jlen = fields.length; j < jlen; j++){
25270 var f = fields.items[j];
25271 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
25273 values[f.name] = v;
25275 var record = new recordType(values, id);
25277 records[records.length] = record;
25283 totalRecords : totalRecords || records.length
25288 * Ext JS Library 1.1.1
25289 * Copyright(c) 2006-2007, Ext JS, LLC.
25291 * Originally Released Under LGPL - original licence link has changed is not relivant.
25294 * <script type="text/javascript">
25298 * @class Roo.data.ArrayReader
25299 * @extends Roo.data.DataReader
25300 * Data reader class to create an Array of Roo.data.Record objects from an Array.
25301 * Each element of that Array represents a row of data fields. The
25302 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
25303 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
25307 var RecordDef = Roo.data.Record.create([
25308 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
25309 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
25311 var myReader = new Roo.data.ArrayReader({
25312 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
25316 * This would consume an Array like this:
25318 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
25322 * Create a new JsonReader
25323 * @param {Object} meta Metadata configuration options.
25324 * @param {Object|Array} recordType Either an Array of field definition objects
25326 * @cfg {Array} fields Array of field definition objects
25327 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
25328 * as specified to {@link Roo.data.Record#create},
25329 * or an {@link Roo.data.Record} object
25332 * created using {@link Roo.data.Record#create}.
25334 Roo.data.ArrayReader = function(meta, recordType)
25336 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType||meta.fields);
25339 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
25342 * Create a data block containing Roo.data.Records from an XML document.
25343 * @param {Object} o An Array of row objects which represents the dataset.
25344 * @return {Object} A data block which is used by an {@link Roo.data.Store} object as
25345 * a cache of Roo.data.Records.
25347 readRecords : function(o)
25349 var sid = this.meta ? this.meta.id : null;
25350 var recordType = this.recordType, fields = recordType.prototype.fields;
25353 for(var i = 0; i < root.length; i++){
25356 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
25357 for(var j = 0, jlen = fields.length; j < jlen; j++){
25358 var f = fields.items[j];
25359 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
25360 var v = n[k] !== undefined ? n[k] : f.defaultValue;
25362 values[f.name] = v;
25364 var record = new recordType(values, id);
25366 records[records.length] = record;
25370 totalRecords : records.length
25373 // used when loading children.. @see loadDataFromChildren
25374 toLoadData: function(rec)
25376 // expect rec just to be an array.. eg [a,b,c, [...] << cn ]
25377 return typeof(rec.data.cn) == 'undefined' ? [] : rec.data.cn;
25384 * Ext JS Library 1.1.1
25385 * Copyright(c) 2006-2007, Ext JS, LLC.
25387 * Originally Released Under LGPL - original licence link has changed is not relivant.
25390 * <script type="text/javascript">
25395 * @class Roo.data.Tree
25396 * @extends Roo.util.Observable
25397 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
25398 * in the tree have most standard DOM functionality.
25400 * @param {Node} root (optional) The root node
25402 Roo.data.Tree = function(root){
25403 this.nodeHash = {};
25405 * The root node for this tree
25410 this.setRootNode(root);
25415 * Fires when a new child node is appended to a node in this tree.
25416 * @param {Tree} tree The owner tree
25417 * @param {Node} parent The parent node
25418 * @param {Node} node The newly appended node
25419 * @param {Number} index The index of the newly appended node
25424 * Fires when a child node is removed from a node in this tree.
25425 * @param {Tree} tree The owner tree
25426 * @param {Node} parent The parent node
25427 * @param {Node} node The child node removed
25432 * Fires when a node is moved to a new location in the tree
25433 * @param {Tree} tree The owner tree
25434 * @param {Node} node The node moved
25435 * @param {Node} oldParent The old parent of this node
25436 * @param {Node} newParent The new parent of this node
25437 * @param {Number} index The index it was moved to
25442 * Fires when a new child node is inserted in a node in this tree.
25443 * @param {Tree} tree The owner tree
25444 * @param {Node} parent The parent node
25445 * @param {Node} node The child node inserted
25446 * @param {Node} refNode The child node the node was inserted before
25450 * @event beforeappend
25451 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
25452 * @param {Tree} tree The owner tree
25453 * @param {Node} parent The parent node
25454 * @param {Node} node The child node to be appended
25456 "beforeappend" : true,
25458 * @event beforeremove
25459 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
25460 * @param {Tree} tree The owner tree
25461 * @param {Node} parent The parent node
25462 * @param {Node} node The child node to be removed
25464 "beforeremove" : true,
25466 * @event beforemove
25467 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
25468 * @param {Tree} tree The owner tree
25469 * @param {Node} node The node being moved
25470 * @param {Node} oldParent The parent of the node
25471 * @param {Node} newParent The new parent the node is moving to
25472 * @param {Number} index The index it is being moved to
25474 "beforemove" : true,
25476 * @event beforeinsert
25477 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
25478 * @param {Tree} tree The owner tree
25479 * @param {Node} parent The parent node
25480 * @param {Node} node The child node to be inserted
25481 * @param {Node} refNode The child node the node is being inserted before
25483 "beforeinsert" : true
25486 Roo.data.Tree.superclass.constructor.call(this);
25489 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
25490 pathSeparator: "/",
25492 proxyNodeEvent : function(){
25493 return this.fireEvent.apply(this, arguments);
25497 * Returns the root node for this tree.
25500 getRootNode : function(){
25505 * Sets the root node for this tree.
25506 * @param {Node} node
25509 setRootNode : function(node){
25511 node.ownerTree = this;
25512 node.isRoot = true;
25513 this.registerNode(node);
25518 * Gets a node in this tree by its id.
25519 * @param {String} id
25522 getNodeById : function(id){
25523 return this.nodeHash[id];
25526 registerNode : function(node){
25527 this.nodeHash[node.id] = node;
25530 unregisterNode : function(node){
25531 delete this.nodeHash[node.id];
25534 toString : function(){
25535 return "[Tree"+(this.id?" "+this.id:"")+"]";
25540 * @class Roo.data.Node
25541 * @extends Roo.util.Observable
25542 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
25543 * @cfg {String} id The id for this node. If one is not specified, one is generated.
25545 * @param {Object} attributes The attributes/config for the node
25547 Roo.data.Node = function(attributes){
25549 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
25552 this.attributes = attributes || {};
25553 this.leaf = this.attributes.leaf;
25555 * The node id. @type String
25557 this.id = this.attributes.id;
25559 this.id = Roo.id(null, "ynode-");
25560 this.attributes.id = this.id;
25565 * All child nodes of this node. @type Array
25567 this.childNodes = [];
25568 if(!this.childNodes.indexOf){ // indexOf is a must
25569 this.childNodes.indexOf = function(o){
25570 for(var i = 0, len = this.length; i < len; i++){
25579 * The parent node for this node. @type Node
25581 this.parentNode = null;
25583 * The first direct child node of this node, or null if this node has no child nodes. @type Node
25585 this.firstChild = null;
25587 * The last direct child node of this node, or null if this node has no child nodes. @type Node
25589 this.lastChild = null;
25591 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
25593 this.previousSibling = null;
25595 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
25597 this.nextSibling = null;
25602 * Fires when a new child node is appended
25603 * @param {Tree} tree The owner tree
25604 * @param {Node} this This node
25605 * @param {Node} node The newly appended node
25606 * @param {Number} index The index of the newly appended node
25611 * Fires when a child node is removed
25612 * @param {Tree} tree The owner tree
25613 * @param {Node} this This node
25614 * @param {Node} node The removed node
25619 * Fires when this node is moved to a new location in the tree
25620 * @param {Tree} tree The owner tree
25621 * @param {Node} this This node
25622 * @param {Node} oldParent The old parent of this node
25623 * @param {Node} newParent The new parent of this node
25624 * @param {Number} index The index it was moved to
25629 * Fires when a new child node is inserted.
25630 * @param {Tree} tree The owner tree
25631 * @param {Node} this This node
25632 * @param {Node} node The child node inserted
25633 * @param {Node} refNode The child node the node was inserted before
25637 * @event beforeappend
25638 * Fires before a new child is appended, return false to cancel the append.
25639 * @param {Tree} tree The owner tree
25640 * @param {Node} this This node
25641 * @param {Node} node The child node to be appended
25643 "beforeappend" : true,
25645 * @event beforeremove
25646 * Fires before a child is removed, return false to cancel the remove.
25647 * @param {Tree} tree The owner tree
25648 * @param {Node} this This node
25649 * @param {Node} node The child node to be removed
25651 "beforeremove" : true,
25653 * @event beforemove
25654 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
25655 * @param {Tree} tree The owner tree
25656 * @param {Node} this This node
25657 * @param {Node} oldParent The parent of this node
25658 * @param {Node} newParent The new parent this node is moving to
25659 * @param {Number} index The index it is being moved to
25661 "beforemove" : true,
25663 * @event beforeinsert
25664 * Fires before a new child is inserted, return false to cancel the insert.
25665 * @param {Tree} tree The owner tree
25666 * @param {Node} this This node
25667 * @param {Node} node The child node to be inserted
25668 * @param {Node} refNode The child node the node is being inserted before
25670 "beforeinsert" : true
25672 this.listeners = this.attributes.listeners;
25673 Roo.data.Node.superclass.constructor.call(this);
25676 Roo.extend(Roo.data.Node, Roo.util.Observable, {
25677 fireEvent : function(evtName){
25678 // first do standard event for this node
25679 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
25682 // then bubble it up to the tree if the event wasn't cancelled
25683 var ot = this.getOwnerTree();
25685 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
25693 * Returns true if this node is a leaf
25694 * @return {Boolean}
25696 isLeaf : function(){
25697 return this.leaf === true;
25701 setFirstChild : function(node){
25702 this.firstChild = node;
25706 setLastChild : function(node){
25707 this.lastChild = node;
25712 * Returns true if this node is the last child of its parent
25713 * @return {Boolean}
25715 isLast : function(){
25716 return (!this.parentNode ? true : this.parentNode.lastChild == this);
25720 * Returns true if this node is the first child of its parent
25721 * @return {Boolean}
25723 isFirst : function(){
25724 return (!this.parentNode ? true : this.parentNode.firstChild == this);
25727 hasChildNodes : function(){
25728 return !this.isLeaf() && this.childNodes.length > 0;
25732 * Insert node(s) as the last child node of this node.
25733 * @param {Node/Array} node The node or Array of nodes to append
25734 * @return {Node} The appended node if single append, or null if an array was passed
25736 appendChild : function(node){
25738 if(node instanceof Array){
25740 }else if(arguments.length > 1){
25744 // if passed an array or multiple args do them one by one
25746 for(var i = 0, len = multi.length; i < len; i++) {
25747 this.appendChild(multi[i]);
25750 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
25753 var index = this.childNodes.length;
25754 var oldParent = node.parentNode;
25755 // it's a move, make sure we move it cleanly
25757 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
25760 oldParent.removeChild(node);
25763 index = this.childNodes.length;
25765 this.setFirstChild(node);
25767 this.childNodes.push(node);
25768 node.parentNode = this;
25769 var ps = this.childNodes[index-1];
25771 node.previousSibling = ps;
25772 ps.nextSibling = node;
25774 node.previousSibling = null;
25776 node.nextSibling = null;
25777 this.setLastChild(node);
25778 node.setOwnerTree(this.getOwnerTree());
25779 this.fireEvent("append", this.ownerTree, this, node, index);
25780 if(this.ownerTree) {
25781 this.ownerTree.fireEvent("appendnode", this, node, index);
25784 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
25791 * Removes a child node from this node.
25792 * @param {Node} node The node to remove
25793 * @return {Node} The removed node
25795 removeChild : function(node){
25796 var index = this.childNodes.indexOf(node);
25800 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
25804 // remove it from childNodes collection
25805 this.childNodes.splice(index, 1);
25808 if(node.previousSibling){
25809 node.previousSibling.nextSibling = node.nextSibling;
25811 if(node.nextSibling){
25812 node.nextSibling.previousSibling = node.previousSibling;
25815 // update child refs
25816 if(this.firstChild == node){
25817 this.setFirstChild(node.nextSibling);
25819 if(this.lastChild == node){
25820 this.setLastChild(node.previousSibling);
25823 node.setOwnerTree(null);
25824 // clear any references from the node
25825 node.parentNode = null;
25826 node.previousSibling = null;
25827 node.nextSibling = null;
25828 this.fireEvent("remove", this.ownerTree, this, node);
25833 * Inserts the first node before the second node in this nodes childNodes collection.
25834 * @param {Node} node The node to insert
25835 * @param {Node} refNode The node to insert before (if null the node is appended)
25836 * @return {Node} The inserted node
25838 insertBefore : function(node, refNode){
25839 if(!refNode){ // like standard Dom, refNode can be null for append
25840 return this.appendChild(node);
25843 if(node == refNode){
25847 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
25850 var index = this.childNodes.indexOf(refNode);
25851 var oldParent = node.parentNode;
25852 var refIndex = index;
25854 // when moving internally, indexes will change after remove
25855 if(oldParent == this && this.childNodes.indexOf(node) < index){
25859 // it's a move, make sure we move it cleanly
25861 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
25864 oldParent.removeChild(node);
25867 this.setFirstChild(node);
25869 this.childNodes.splice(refIndex, 0, node);
25870 node.parentNode = this;
25871 var ps = this.childNodes[refIndex-1];
25873 node.previousSibling = ps;
25874 ps.nextSibling = node;
25876 node.previousSibling = null;
25878 node.nextSibling = refNode;
25879 refNode.previousSibling = node;
25880 node.setOwnerTree(this.getOwnerTree());
25881 this.fireEvent("insert", this.ownerTree, this, node, refNode);
25883 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
25889 * Returns the child node at the specified index.
25890 * @param {Number} index
25893 item : function(index){
25894 return this.childNodes[index];
25898 * Replaces one child node in this node with another.
25899 * @param {Node} newChild The replacement node
25900 * @param {Node} oldChild The node to replace
25901 * @return {Node} The replaced node
25903 replaceChild : function(newChild, oldChild){
25904 this.insertBefore(newChild, oldChild);
25905 this.removeChild(oldChild);
25910 * Returns the index of a child node
25911 * @param {Node} node
25912 * @return {Number} The index of the node or -1 if it was not found
25914 indexOf : function(child){
25915 return this.childNodes.indexOf(child);
25919 * Returns the tree this node is in.
25922 getOwnerTree : function(){
25923 // if it doesn't have one, look for one
25924 if(!this.ownerTree){
25928 this.ownerTree = p.ownerTree;
25934 return this.ownerTree;
25938 * Returns depth of this node (the root node has a depth of 0)
25941 getDepth : function(){
25944 while(p.parentNode){
25952 setOwnerTree : function(tree){
25953 // if it's move, we need to update everyone
25954 if(tree != this.ownerTree){
25955 if(this.ownerTree){
25956 this.ownerTree.unregisterNode(this);
25958 this.ownerTree = tree;
25959 var cs = this.childNodes;
25960 for(var i = 0, len = cs.length; i < len; i++) {
25961 cs[i].setOwnerTree(tree);
25964 tree.registerNode(this);
25970 * Returns the path for this node. The path can be used to expand or select this node programmatically.
25971 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
25972 * @return {String} The path
25974 getPath : function(attr){
25975 attr = attr || "id";
25976 var p = this.parentNode;
25977 var b = [this.attributes[attr]];
25979 b.unshift(p.attributes[attr]);
25982 var sep = this.getOwnerTree().pathSeparator;
25983 return sep + b.join(sep);
25987 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
25988 * function call will be the scope provided or the current node. The arguments to the function
25989 * will be the args provided or the current node. If the function returns false at any point,
25990 * the bubble is stopped.
25991 * @param {Function} fn The function to call
25992 * @param {Object} scope (optional) The scope of the function (defaults to current node)
25993 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
25995 bubble : function(fn, scope, args){
25998 if(fn.call(scope || p, args || p) === false){
26006 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
26007 * function call will be the scope provided or the current node. The arguments to the function
26008 * will be the args provided or the current node. If the function returns false at any point,
26009 * the cascade is stopped on that branch.
26010 * @param {Function} fn The function to call
26011 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26012 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26014 cascade : function(fn, scope, args){
26015 if(fn.call(scope || this, args || this) !== false){
26016 var cs = this.childNodes;
26017 for(var i = 0, len = cs.length; i < len; i++) {
26018 cs[i].cascade(fn, scope, args);
26024 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
26025 * function call will be the scope provided or the current node. The arguments to the function
26026 * will be the args provided or the current node. If the function returns false at any point,
26027 * the iteration stops.
26028 * @param {Function} fn The function to call
26029 * @param {Object} scope (optional) The scope of the function (defaults to current node)
26030 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
26032 eachChild : function(fn, scope, args){
26033 var cs = this.childNodes;
26034 for(var i = 0, len = cs.length; i < len; i++) {
26035 if(fn.call(scope || this, args || cs[i]) === false){
26042 * Finds the first child that has the attribute with the specified value.
26043 * @param {String} attribute The attribute name
26044 * @param {Mixed} value The value to search for
26045 * @return {Node} The found child or null if none was found
26047 findChild : function(attribute, value){
26048 var cs = this.childNodes;
26049 for(var i = 0, len = cs.length; i < len; i++) {
26050 if(cs[i].attributes[attribute] == value){
26058 * Finds the first child by a custom function. The child matches if the function passed
26060 * @param {Function} fn
26061 * @param {Object} scope (optional)
26062 * @return {Node} The found child or null if none was found
26064 findChildBy : function(fn, scope){
26065 var cs = this.childNodes;
26066 for(var i = 0, len = cs.length; i < len; i++) {
26067 if(fn.call(scope||cs[i], cs[i]) === true){
26075 * Sorts this nodes children using the supplied sort function
26076 * @param {Function} fn
26077 * @param {Object} scope (optional)
26079 sort : function(fn, scope){
26080 var cs = this.childNodes;
26081 var len = cs.length;
26083 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
26085 for(var i = 0; i < len; i++){
26087 n.previousSibling = cs[i-1];
26088 n.nextSibling = cs[i+1];
26090 this.setFirstChild(n);
26093 this.setLastChild(n);
26100 * Returns true if this node is an ancestor (at any point) of the passed node.
26101 * @param {Node} node
26102 * @return {Boolean}
26104 contains : function(node){
26105 return node.isAncestor(this);
26109 * Returns true if the passed node is an ancestor (at any point) of this node.
26110 * @param {Node} node
26111 * @return {Boolean}
26113 isAncestor : function(node){
26114 var p = this.parentNode;
26124 toString : function(){
26125 return "[Node"+(this.id?" "+this.id:"")+"]";
26129 * Ext JS Library 1.1.1
26130 * Copyright(c) 2006-2007, Ext JS, LLC.
26132 * Originally Released Under LGPL - original licence link has changed is not relivant.
26135 * <script type="text/javascript">
26140 * @class Roo.Shadow
26141 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
26142 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
26143 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
26145 * Create a new Shadow
26146 * @param {Object} config The config object
26148 Roo.Shadow = function(config){
26149 Roo.apply(this, config);
26150 if(typeof this.mode != "string"){
26151 this.mode = this.defaultMode;
26153 var o = this.offset, a = {h: 0};
26154 var rad = Math.floor(this.offset/2);
26155 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
26161 a.l -= this.offset + rad;
26162 a.t -= this.offset + rad;
26173 a.l -= (this.offset - rad);
26174 a.t -= this.offset + rad;
26176 a.w -= (this.offset - rad)*2;
26187 a.l -= (this.offset - rad);
26188 a.t -= (this.offset - rad);
26190 a.w -= (this.offset + rad + 1);
26191 a.h -= (this.offset + rad);
26200 Roo.Shadow.prototype = {
26202 * @cfg {String} mode
26203 * The shadow display mode. Supports the following options:<br />
26204 * sides: Shadow displays on both sides and bottom only<br />
26205 * frame: Shadow displays equally on all four sides<br />
26206 * drop: Traditional bottom-right drop shadow (default)
26209 * @cfg {String} offset
26210 * The number of pixels to offset the shadow from the element (defaults to 4)
26215 defaultMode: "drop",
26218 * Displays the shadow under the target element
26219 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
26221 show : function(target){
26222 target = Roo.get(target);
26224 this.el = Roo.Shadow.Pool.pull();
26225 if(this.el.dom.nextSibling != target.dom){
26226 this.el.insertBefore(target);
26229 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
26231 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
26234 target.getLeft(true),
26235 target.getTop(true),
26239 this.el.dom.style.display = "block";
26243 * Returns true if the shadow is visible, else false
26245 isVisible : function(){
26246 return this.el ? true : false;
26250 * Direct alignment when values are already available. Show must be called at least once before
26251 * calling this method to ensure it is initialized.
26252 * @param {Number} left The target element left position
26253 * @param {Number} top The target element top position
26254 * @param {Number} width The target element width
26255 * @param {Number} height The target element height
26257 realign : function(l, t, w, h){
26261 var a = this.adjusts, d = this.el.dom, s = d.style;
26263 s.left = (l+a.l)+"px";
26264 s.top = (t+a.t)+"px";
26265 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
26267 if(s.width != sws || s.height != shs){
26271 var cn = d.childNodes;
26272 var sww = Math.max(0, (sw-12))+"px";
26273 cn[0].childNodes[1].style.width = sww;
26274 cn[1].childNodes[1].style.width = sww;
26275 cn[2].childNodes[1].style.width = sww;
26276 cn[1].style.height = Math.max(0, (sh-12))+"px";
26282 * Hides this shadow
26286 this.el.dom.style.display = "none";
26287 Roo.Shadow.Pool.push(this.el);
26293 * Adjust the z-index of this shadow
26294 * @param {Number} zindex The new z-index
26296 setZIndex : function(z){
26299 this.el.setStyle("z-index", z);
26304 // Private utility class that manages the internal Shadow cache
26305 Roo.Shadow.Pool = function(){
26307 var markup = Roo.isIE ?
26308 '<div class="x-ie-shadow"></div>' :
26309 '<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>';
26312 var sh = p.shift();
26314 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
26315 sh.autoBoxAdjust = false;
26320 push : function(sh){
26326 * Ext JS Library 1.1.1
26327 * Copyright(c) 2006-2007, Ext JS, LLC.
26329 * Originally Released Under LGPL - original licence link has changed is not relivant.
26332 * <script type="text/javascript">
26337 * @class Roo.SplitBar
26338 * @extends Roo.util.Observable
26339 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
26343 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
26344 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
26345 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
26346 split.minSize = 100;
26347 split.maxSize = 600;
26348 split.animate = true;
26349 split.on('moved', splitterMoved);
26352 * Create a new SplitBar
26353 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
26354 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
26355 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26356 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
26357 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
26358 position of the SplitBar).
26360 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
26363 this.el = Roo.get(dragElement, true);
26364 this.el.dom.unselectable = "on";
26366 this.resizingEl = Roo.get(resizingElement, true);
26370 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
26371 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
26374 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
26377 * The minimum size of the resizing element. (Defaults to 0)
26383 * The maximum size of the resizing element. (Defaults to 2000)
26386 this.maxSize = 2000;
26389 * Whether to animate the transition to the new size
26392 this.animate = false;
26395 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
26398 this.useShim = false;
26403 if(!existingProxy){
26405 this.proxy = Roo.SplitBar.createProxy(this.orientation);
26407 this.proxy = Roo.get(existingProxy).dom;
26410 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
26413 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
26416 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
26419 this.dragSpecs = {};
26422 * @private The adapter to use to positon and resize elements
26424 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
26425 this.adapter.init(this);
26427 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26429 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
26430 this.el.addClass("x-splitbar-h");
26433 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
26434 this.el.addClass("x-splitbar-v");
26440 * Fires when the splitter is moved (alias for {@link #event-moved})
26441 * @param {Roo.SplitBar} this
26442 * @param {Number} newSize the new width or height
26447 * Fires when the splitter is moved
26448 * @param {Roo.SplitBar} this
26449 * @param {Number} newSize the new width or height
26453 * @event beforeresize
26454 * Fires before the splitter is dragged
26455 * @param {Roo.SplitBar} this
26457 "beforeresize" : true,
26459 "beforeapply" : true
26462 Roo.util.Observable.call(this);
26465 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
26466 onStartProxyDrag : function(x, y){
26467 this.fireEvent("beforeresize", this);
26469 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
26471 o.enableDisplayMode("block");
26472 // all splitbars share the same overlay
26473 Roo.SplitBar.prototype.overlay = o;
26475 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
26476 this.overlay.show();
26477 Roo.get(this.proxy).setDisplayed("block");
26478 var size = this.adapter.getElementSize(this);
26479 this.activeMinSize = this.getMinimumSize();;
26480 this.activeMaxSize = this.getMaximumSize();;
26481 var c1 = size - this.activeMinSize;
26482 var c2 = Math.max(this.activeMaxSize - size, 0);
26483 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26484 this.dd.resetConstraints();
26485 this.dd.setXConstraint(
26486 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
26487 this.placement == Roo.SplitBar.LEFT ? c2 : c1
26489 this.dd.setYConstraint(0, 0);
26491 this.dd.resetConstraints();
26492 this.dd.setXConstraint(0, 0);
26493 this.dd.setYConstraint(
26494 this.placement == Roo.SplitBar.TOP ? c1 : c2,
26495 this.placement == Roo.SplitBar.TOP ? c2 : c1
26498 this.dragSpecs.startSize = size;
26499 this.dragSpecs.startPoint = [x, y];
26500 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
26504 * @private Called after the drag operation by the DDProxy
26506 onEndProxyDrag : function(e){
26507 Roo.get(this.proxy).setDisplayed(false);
26508 var endPoint = Roo.lib.Event.getXY(e);
26510 this.overlay.hide();
26513 if(this.orientation == Roo.SplitBar.HORIZONTAL){
26514 newSize = this.dragSpecs.startSize +
26515 (this.placement == Roo.SplitBar.LEFT ?
26516 endPoint[0] - this.dragSpecs.startPoint[0] :
26517 this.dragSpecs.startPoint[0] - endPoint[0]
26520 newSize = this.dragSpecs.startSize +
26521 (this.placement == Roo.SplitBar.TOP ?
26522 endPoint[1] - this.dragSpecs.startPoint[1] :
26523 this.dragSpecs.startPoint[1] - endPoint[1]
26526 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
26527 if(newSize != this.dragSpecs.startSize){
26528 if(this.fireEvent('beforeapply', this, newSize) !== false){
26529 this.adapter.setElementSize(this, newSize);
26530 this.fireEvent("moved", this, newSize);
26531 this.fireEvent("resize", this, newSize);
26537 * Get the adapter this SplitBar uses
26538 * @return The adapter object
26540 getAdapter : function(){
26541 return this.adapter;
26545 * Set the adapter this SplitBar uses
26546 * @param {Object} adapter A SplitBar adapter object
26548 setAdapter : function(adapter){
26549 this.adapter = adapter;
26550 this.adapter.init(this);
26554 * Gets the minimum size for the resizing element
26555 * @return {Number} The minimum size
26557 getMinimumSize : function(){
26558 return this.minSize;
26562 * Sets the minimum size for the resizing element
26563 * @param {Number} minSize The minimum size
26565 setMinimumSize : function(minSize){
26566 this.minSize = minSize;
26570 * Gets the maximum size for the resizing element
26571 * @return {Number} The maximum size
26573 getMaximumSize : function(){
26574 return this.maxSize;
26578 * Sets the maximum size for the resizing element
26579 * @param {Number} maxSize The maximum size
26581 setMaximumSize : function(maxSize){
26582 this.maxSize = maxSize;
26586 * Sets the initialize size for the resizing element
26587 * @param {Number} size The initial size
26589 setCurrentSize : function(size){
26590 var oldAnimate = this.animate;
26591 this.animate = false;
26592 this.adapter.setElementSize(this, size);
26593 this.animate = oldAnimate;
26597 * Destroy this splitbar.
26598 * @param {Boolean} removeEl True to remove the element
26600 destroy : function(removeEl){
26602 this.shim.remove();
26605 this.proxy.parentNode.removeChild(this.proxy);
26613 * @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.
26615 Roo.SplitBar.createProxy = function(dir){
26616 var proxy = new Roo.Element(document.createElement("div"));
26617 proxy.unselectable();
26618 var cls = 'x-splitbar-proxy';
26619 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
26620 document.body.appendChild(proxy.dom);
26625 * @class Roo.SplitBar.BasicLayoutAdapter
26626 * Default Adapter. It assumes the splitter and resizing element are not positioned
26627 * elements and only gets/sets the width of the element. Generally used for table based layouts.
26629 Roo.SplitBar.BasicLayoutAdapter = function(){
26632 Roo.SplitBar.BasicLayoutAdapter.prototype = {
26633 // do nothing for now
26634 init : function(s){
26638 * Called before drag operations to get the current size of the resizing element.
26639 * @param {Roo.SplitBar} s The SplitBar using this adapter
26641 getElementSize : function(s){
26642 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26643 return s.resizingEl.getWidth();
26645 return s.resizingEl.getHeight();
26650 * Called after drag operations to set the size of the resizing element.
26651 * @param {Roo.SplitBar} s The SplitBar using this adapter
26652 * @param {Number} newSize The new size to set
26653 * @param {Function} onComplete A function to be invoked when resizing is complete
26655 setElementSize : function(s, newSize, onComplete){
26656 if(s.orientation == Roo.SplitBar.HORIZONTAL){
26658 s.resizingEl.setWidth(newSize);
26660 onComplete(s, newSize);
26663 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
26668 s.resizingEl.setHeight(newSize);
26670 onComplete(s, newSize);
26673 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
26680 *@class Roo.SplitBar.AbsoluteLayoutAdapter
26681 * @extends Roo.SplitBar.BasicLayoutAdapter
26682 * Adapter that moves the splitter element to align with the resized sizing element.
26683 * Used with an absolute positioned SplitBar.
26684 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
26685 * document.body, make sure you assign an id to the body element.
26687 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
26688 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
26689 this.container = Roo.get(container);
26692 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
26693 init : function(s){
26694 this.basic.init(s);
26697 getElementSize : function(s){
26698 return this.basic.getElementSize(s);
26701 setElementSize : function(s, newSize, onComplete){
26702 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
26705 moveSplitter : function(s){
26706 var yes = Roo.SplitBar;
26707 switch(s.placement){
26709 s.el.setX(s.resizingEl.getRight());
26712 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
26715 s.el.setY(s.resizingEl.getBottom());
26718 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
26725 * Orientation constant - Create a vertical SplitBar
26729 Roo.SplitBar.VERTICAL = 1;
26732 * Orientation constant - Create a horizontal SplitBar
26736 Roo.SplitBar.HORIZONTAL = 2;
26739 * Placement constant - The resizing element is to the left of the splitter element
26743 Roo.SplitBar.LEFT = 1;
26746 * Placement constant - The resizing element is to the right of the splitter element
26750 Roo.SplitBar.RIGHT = 2;
26753 * Placement constant - The resizing element is positioned above the splitter element
26757 Roo.SplitBar.TOP = 3;
26760 * Placement constant - The resizing element is positioned under splitter element
26764 Roo.SplitBar.BOTTOM = 4;
26767 * Ext JS Library 1.1.1
26768 * Copyright(c) 2006-2007, Ext JS, LLC.
26770 * Originally Released Under LGPL - original licence link has changed is not relivant.
26773 * <script type="text/javascript">
26778 * @extends Roo.util.Observable
26779 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
26780 * This class also supports single and multi selection modes. <br>
26781 * Create a data model bound view:
26783 var store = new Roo.data.Store(...);
26785 var view = new Roo.View({
26787 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
26789 singleSelect: true,
26790 selectedClass: "ydataview-selected",
26794 // listen for node click?
26795 view.on("click", function(vw, index, node, e){
26796 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
26800 dataModel.load("foobar.xml");
26802 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
26804 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
26805 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
26807 * Note: old style constructor is still suported (container, template, config)
26810 * Create a new View
26811 * @param {Object} config The config object
26814 Roo.View = function(config, depreciated_tpl, depreciated_config){
26816 this.parent = false;
26818 if (typeof(depreciated_tpl) == 'undefined') {
26819 // new way.. - universal constructor.
26820 Roo.apply(this, config);
26821 this.el = Roo.get(this.el);
26824 this.el = Roo.get(config);
26825 this.tpl = depreciated_tpl;
26826 Roo.apply(this, depreciated_config);
26828 this.wrapEl = this.el.wrap().wrap();
26829 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
26832 if(typeof(this.tpl) == "string"){
26833 this.tpl = new Roo.Template(this.tpl);
26835 // support xtype ctors..
26836 this.tpl = new Roo.factory(this.tpl, Roo);
26840 this.tpl.compile();
26845 * @event beforeclick
26846 * Fires before a click is processed. Returns false to cancel the default action.
26847 * @param {Roo.View} this
26848 * @param {Number} index The index of the target node
26849 * @param {HTMLElement} node The target node
26850 * @param {Roo.EventObject} e The raw event object
26852 "beforeclick" : true,
26855 * Fires when a template node is clicked.
26856 * @param {Roo.View} this
26857 * @param {Number} index The index of the target node
26858 * @param {HTMLElement} node The target node
26859 * @param {Roo.EventObject} e The raw event object
26864 * Fires when a template node is double clicked.
26865 * @param {Roo.View} this
26866 * @param {Number} index The index of the target node
26867 * @param {HTMLElement} node The target node
26868 * @param {Roo.EventObject} e The raw event object
26872 * @event contextmenu
26873 * Fires when a template node is right clicked.
26874 * @param {Roo.View} this
26875 * @param {Number} index The index of the target node
26876 * @param {HTMLElement} node The target node
26877 * @param {Roo.EventObject} e The raw event object
26879 "contextmenu" : true,
26881 * @event selectionchange
26882 * Fires when the selected nodes change.
26883 * @param {Roo.View} this
26884 * @param {Array} selections Array of the selected nodes
26886 "selectionchange" : true,
26889 * @event beforeselect
26890 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
26891 * @param {Roo.View} this
26892 * @param {HTMLElement} node The node to be selected
26893 * @param {Array} selections Array of currently selected nodes
26895 "beforeselect" : true,
26897 * @event preparedata
26898 * Fires on every row to render, to allow you to change the data.
26899 * @param {Roo.View} this
26900 * @param {Object} data to be rendered (change this)
26902 "preparedata" : true
26910 "click": this.onClick,
26911 "dblclick": this.onDblClick,
26912 "contextmenu": this.onContextMenu,
26916 this.selections = [];
26918 this.cmp = new Roo.CompositeElementLite([]);
26920 this.store = Roo.factory(this.store, Roo.data);
26921 this.setStore(this.store, true);
26924 if ( this.footer && this.footer.xtype) {
26926 var fctr = this.wrapEl.appendChild(document.createElement("div"));
26928 this.footer.dataSource = this.store;
26929 this.footer.container = fctr;
26930 this.footer = Roo.factory(this.footer, Roo);
26931 fctr.insertFirst(this.el);
26933 // this is a bit insane - as the paging toolbar seems to detach the el..
26934 // dom.parentNode.parentNode.parentNode
26935 // they get detached?
26939 Roo.View.superclass.constructor.call(this);
26944 Roo.extend(Roo.View, Roo.util.Observable, {
26947 * @cfg {Roo.data.Store} store Data store to load data from.
26952 * @cfg {String|Roo.Element} el The container element.
26957 * @cfg {String|Roo.Template} tpl The template used by this View
26961 * @cfg {String} dataName the named area of the template to use as the data area
26962 * Works with domtemplates roo-name="name"
26966 * @cfg {String} selectedClass The css class to add to selected nodes
26968 selectedClass : "x-view-selected",
26970 * @cfg {String} emptyText The empty text to show when nothing is loaded.
26975 * @cfg {String} text to display on mask (default Loading)
26979 * @cfg {Boolean} multiSelect Allow multiple selection
26981 multiSelect : false,
26983 * @cfg {Boolean} singleSelect Allow single selection
26985 singleSelect: false,
26988 * @cfg {Boolean} toggleSelect - selecting
26990 toggleSelect : false,
26993 * @cfg {Boolean} tickable - selecting
26998 * Returns the element this view is bound to.
26999 * @return {Roo.Element}
27001 getEl : function(){
27002 return this.wrapEl;
27008 * Refreshes the view. - called by datachanged on the store. - do not call directly.
27010 refresh : function(){
27011 //Roo.log('refresh');
27014 // if we are using something like 'domtemplate', then
27015 // the what gets used is:
27016 // t.applySubtemplate(NAME, data, wrapping data..)
27017 // the outer template then get' applied with
27018 // the store 'extra data'
27019 // and the body get's added to the
27020 // roo-name="data" node?
27021 // <span class='roo-tpl-{name}'></span> ?????
27025 this.clearSelections();
27026 this.el.update("");
27028 var records = this.store.getRange();
27029 if(records.length < 1) {
27031 // is this valid?? = should it render a template??
27033 this.el.update(this.emptyText);
27037 if (this.dataName) {
27038 this.el.update(t.apply(this.store.meta)); //????
27039 el = this.el.child('.roo-tpl-' + this.dataName);
27042 for(var i = 0, len = records.length; i < len; i++){
27043 var data = this.prepareData(records[i].data, i, records[i]);
27044 this.fireEvent("preparedata", this, data, i, records[i]);
27046 var d = Roo.apply({}, data);
27049 Roo.apply(d, {'roo-id' : Roo.id()});
27053 Roo.each(this.parent.item, function(item){
27054 if(item[_this.parent.valueField] != data[_this.parent.valueField]){
27057 Roo.apply(d, {'roo-data-checked' : 'checked'});
27061 html[html.length] = Roo.util.Format.trim(
27063 t.applySubtemplate(this.dataName, d, this.store.meta) :
27070 el.update(html.join(""));
27071 this.nodes = el.dom.childNodes;
27072 this.updateIndexes(0);
27077 * Function to override to reformat the data that is sent to
27078 * the template for each node.
27079 * DEPRICATED - use the preparedata event handler.
27080 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
27081 * a JSON object for an UpdateManager bound view).
27083 prepareData : function(data, index, record)
27085 this.fireEvent("preparedata", this, data, index, record);
27089 onUpdate : function(ds, record){
27090 // Roo.log('on update');
27091 this.clearSelections();
27092 var index = this.store.indexOf(record);
27093 var n = this.nodes[index];
27094 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
27095 n.parentNode.removeChild(n);
27096 this.updateIndexes(index, index);
27102 onAdd : function(ds, records, index)
27104 //Roo.log(['on Add', ds, records, index] );
27105 this.clearSelections();
27106 if(this.nodes.length == 0){
27110 var n = this.nodes[index];
27111 for(var i = 0, len = records.length; i < len; i++){
27112 var d = this.prepareData(records[i].data, i, records[i]);
27114 this.tpl.insertBefore(n, d);
27117 this.tpl.append(this.el, d);
27120 this.updateIndexes(index);
27123 onRemove : function(ds, record, index){
27124 // Roo.log('onRemove');
27125 this.clearSelections();
27126 var el = this.dataName ?
27127 this.el.child('.roo-tpl-' + this.dataName) :
27130 el.dom.removeChild(this.nodes[index]);
27131 this.updateIndexes(index);
27135 * Refresh an individual node.
27136 * @param {Number} index
27138 refreshNode : function(index){
27139 this.onUpdate(this.store, this.store.getAt(index));
27142 updateIndexes : function(startIndex, endIndex){
27143 var ns = this.nodes;
27144 startIndex = startIndex || 0;
27145 endIndex = endIndex || ns.length - 1;
27146 for(var i = startIndex; i <= endIndex; i++){
27147 ns[i].nodeIndex = i;
27152 * Changes the data store this view uses and refresh the view.
27153 * @param {Store} store
27155 setStore : function(store, initial){
27156 if(!initial && this.store){
27157 this.store.un("datachanged", this.refresh);
27158 this.store.un("add", this.onAdd);
27159 this.store.un("remove", this.onRemove);
27160 this.store.un("update", this.onUpdate);
27161 this.store.un("clear", this.refresh);
27162 this.store.un("beforeload", this.onBeforeLoad);
27163 this.store.un("load", this.onLoad);
27164 this.store.un("loadexception", this.onLoad);
27168 store.on("datachanged", this.refresh, this);
27169 store.on("add", this.onAdd, this);
27170 store.on("remove", this.onRemove, this);
27171 store.on("update", this.onUpdate, this);
27172 store.on("clear", this.refresh, this);
27173 store.on("beforeload", this.onBeforeLoad, this);
27174 store.on("load", this.onLoad, this);
27175 store.on("loadexception", this.onLoad, this);
27183 * onbeforeLoad - masks the loading area.
27186 onBeforeLoad : function(store,opts)
27188 //Roo.log('onBeforeLoad');
27190 this.el.update("");
27192 this.el.mask(this.mask ? this.mask : "Loading" );
27194 onLoad : function ()
27201 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
27202 * @param {HTMLElement} node
27203 * @return {HTMLElement} The template node
27205 findItemFromChild : function(node){
27206 var el = this.dataName ?
27207 this.el.child('.roo-tpl-' + this.dataName,true) :
27210 if(!node || node.parentNode == el){
27213 var p = node.parentNode;
27214 while(p && p != el){
27215 if(p.parentNode == el){
27224 onClick : function(e){
27225 var item = this.findItemFromChild(e.getTarget());
27227 var index = this.indexOf(item);
27228 if(this.onItemClick(item, index, e) !== false){
27229 this.fireEvent("click", this, index, item, e);
27232 this.clearSelections();
27237 onContextMenu : function(e){
27238 var item = this.findItemFromChild(e.getTarget());
27240 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
27245 onDblClick : function(e){
27246 var item = this.findItemFromChild(e.getTarget());
27248 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
27252 onItemClick : function(item, index, e)
27254 if(this.fireEvent("beforeclick", this, index, item, e) === false){
27257 if (this.toggleSelect) {
27258 var m = this.isSelected(item) ? 'unselect' : 'select';
27261 _t[m](item, true, false);
27264 if(this.multiSelect || this.singleSelect){
27265 if(this.multiSelect && e.shiftKey && this.lastSelection){
27266 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
27268 this.select(item, this.multiSelect && e.ctrlKey);
27269 this.lastSelection = item;
27272 if(!this.tickable){
27273 e.preventDefault();
27281 * Get the number of selected nodes.
27284 getSelectionCount : function(){
27285 return this.selections.length;
27289 * Get the currently selected nodes.
27290 * @return {Array} An array of HTMLElements
27292 getSelectedNodes : function(){
27293 return this.selections;
27297 * Get the indexes of the selected nodes.
27300 getSelectedIndexes : function(){
27301 var indexes = [], s = this.selections;
27302 for(var i = 0, len = s.length; i < len; i++){
27303 indexes.push(s[i].nodeIndex);
27309 * Clear all selections
27310 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
27312 clearSelections : function(suppressEvent){
27313 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
27314 this.cmp.elements = this.selections;
27315 this.cmp.removeClass(this.selectedClass);
27316 this.selections = [];
27317 if(!suppressEvent){
27318 this.fireEvent("selectionchange", this, this.selections);
27324 * Returns true if the passed node is selected
27325 * @param {HTMLElement/Number} node The node or node index
27326 * @return {Boolean}
27328 isSelected : function(node){
27329 var s = this.selections;
27333 node = this.getNode(node);
27334 return s.indexOf(node) !== -1;
27339 * @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
27340 * @param {Boolean} keepExisting (optional) true to keep existing selections
27341 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27343 select : function(nodeInfo, keepExisting, suppressEvent){
27344 if(nodeInfo instanceof Array){
27346 this.clearSelections(true);
27348 for(var i = 0, len = nodeInfo.length; i < len; i++){
27349 this.select(nodeInfo[i], true, true);
27353 var node = this.getNode(nodeInfo);
27354 if(!node || this.isSelected(node)){
27355 return; // already selected.
27358 this.clearSelections(true);
27361 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
27362 Roo.fly(node).addClass(this.selectedClass);
27363 this.selections.push(node);
27364 if(!suppressEvent){
27365 this.fireEvent("selectionchange", this, this.selections);
27373 * @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
27374 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
27375 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
27377 unselect : function(nodeInfo, keepExisting, suppressEvent)
27379 if(nodeInfo instanceof Array){
27380 Roo.each(this.selections, function(s) {
27381 this.unselect(s, nodeInfo);
27385 var node = this.getNode(nodeInfo);
27386 if(!node || !this.isSelected(node)){
27387 //Roo.log("not selected");
27388 return; // not selected.
27392 Roo.each(this.selections, function(s) {
27394 Roo.fly(node).removeClass(this.selectedClass);
27401 this.selections= ns;
27402 this.fireEvent("selectionchange", this, this.selections);
27406 * Gets a template node.
27407 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27408 * @return {HTMLElement} The node or null if it wasn't found
27410 getNode : function(nodeInfo){
27411 if(typeof nodeInfo == "string"){
27412 return document.getElementById(nodeInfo);
27413 }else if(typeof nodeInfo == "number"){
27414 return this.nodes[nodeInfo];
27420 * Gets a range template nodes.
27421 * @param {Number} startIndex
27422 * @param {Number} endIndex
27423 * @return {Array} An array of nodes
27425 getNodes : function(start, end){
27426 var ns = this.nodes;
27427 start = start || 0;
27428 end = typeof end == "undefined" ? ns.length - 1 : end;
27431 for(var i = start; i <= end; i++){
27435 for(var i = start; i >= end; i--){
27443 * Finds the index of the passed node
27444 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
27445 * @return {Number} The index of the node or -1
27447 indexOf : function(node){
27448 node = this.getNode(node);
27449 if(typeof node.nodeIndex == "number"){
27450 return node.nodeIndex;
27452 var ns = this.nodes;
27453 for(var i = 0, len = ns.length; i < len; i++){
27463 * Ext JS Library 1.1.1
27464 * Copyright(c) 2006-2007, Ext JS, LLC.
27466 * Originally Released Under LGPL - original licence link has changed is not relivant.
27469 * <script type="text/javascript">
27473 * @class Roo.JsonView
27474 * @extends Roo.View
27475 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
27477 var view = new Roo.JsonView({
27478 container: "my-element",
27479 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
27484 // listen for node click?
27485 view.on("click", function(vw, index, node, e){
27486 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
27489 // direct load of JSON data
27490 view.load("foobar.php");
27492 // Example from my blog list
27493 var tpl = new Roo.Template(
27494 '<div class="entry">' +
27495 '<a class="entry-title" href="{link}">{title}</a>' +
27496 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
27497 "</div><hr />"
27500 var moreView = new Roo.JsonView({
27501 container : "entry-list",
27505 moreView.on("beforerender", this.sortEntries, this);
27507 url: "/blog/get-posts.php",
27508 params: "allposts=true",
27509 text: "Loading Blog Entries..."
27513 * Note: old code is supported with arguments : (container, template, config)
27517 * Create a new JsonView
27519 * @param {Object} config The config object
27522 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
27525 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
27527 var um = this.el.getUpdateManager();
27528 um.setRenderer(this);
27529 um.on("update", this.onLoad, this);
27530 um.on("failure", this.onLoadException, this);
27533 * @event beforerender
27534 * Fires before rendering of the downloaded JSON data.
27535 * @param {Roo.JsonView} this
27536 * @param {Object} data The JSON data loaded
27540 * Fires when data is loaded.
27541 * @param {Roo.JsonView} this
27542 * @param {Object} data The JSON data loaded
27543 * @param {Object} response The raw Connect response object
27546 * @event loadexception
27547 * Fires when loading fails.
27548 * @param {Roo.JsonView} this
27549 * @param {Object} response The raw Connect response object
27552 'beforerender' : true,
27554 'loadexception' : true
27557 Roo.extend(Roo.JsonView, Roo.View, {
27559 * @type {String} The root property in the loaded JSON object that contains the data
27564 * Refreshes the view.
27566 refresh : function(){
27567 this.clearSelections();
27568 this.el.update("");
27570 var o = this.jsonData;
27571 if(o && o.length > 0){
27572 for(var i = 0, len = o.length; i < len; i++){
27573 var data = this.prepareData(o[i], i, o);
27574 html[html.length] = this.tpl.apply(data);
27577 html.push(this.emptyText);
27579 this.el.update(html.join(""));
27580 this.nodes = this.el.dom.childNodes;
27581 this.updateIndexes(0);
27585 * 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.
27586 * @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:
27589 url: "your-url.php",
27590 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
27591 callback: yourFunction,
27592 scope: yourObject, //(optional scope)
27595 text: "Loading...",
27600 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
27601 * 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.
27602 * @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}
27603 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
27604 * @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.
27607 var um = this.el.getUpdateManager();
27608 um.update.apply(um, arguments);
27611 // note - render is a standard framework call...
27612 // using it for the response is really flaky... - it's called by UpdateManager normally, except when called by the XComponent/addXtype.
27613 render : function(el, response){
27615 this.clearSelections();
27616 this.el.update("");
27619 if (response != '') {
27620 o = Roo.util.JSON.decode(response.responseText);
27623 o = o[this.jsonRoot];
27629 * The current JSON data or null
27632 this.beforeRender();
27637 * Get the number of records in the current JSON dataset
27640 getCount : function(){
27641 return this.jsonData ? this.jsonData.length : 0;
27645 * Returns the JSON object for the specified node(s)
27646 * @param {HTMLElement/Array} node The node or an array of nodes
27647 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
27648 * you get the JSON object for the node
27650 getNodeData : function(node){
27651 if(node instanceof Array){
27653 for(var i = 0, len = node.length; i < len; i++){
27654 data.push(this.getNodeData(node[i]));
27658 return this.jsonData[this.indexOf(node)] || null;
27661 beforeRender : function(){
27662 this.snapshot = this.jsonData;
27664 this.sort.apply(this, this.sortInfo);
27666 this.fireEvent("beforerender", this, this.jsonData);
27669 onLoad : function(el, o){
27670 this.fireEvent("load", this, this.jsonData, o);
27673 onLoadException : function(el, o){
27674 this.fireEvent("loadexception", this, o);
27678 * Filter the data by a specific property.
27679 * @param {String} property A property on your JSON objects
27680 * @param {String/RegExp} value Either string that the property values
27681 * should start with, or a RegExp to test against the property
27683 filter : function(property, value){
27686 var ss = this.snapshot;
27687 if(typeof value == "string"){
27688 var vlen = value.length;
27690 this.clearFilter();
27693 value = value.toLowerCase();
27694 for(var i = 0, len = ss.length; i < len; i++){
27696 if(o[property].substr(0, vlen).toLowerCase() == value){
27700 } else if(value.exec){ // regex?
27701 for(var i = 0, len = ss.length; i < len; i++){
27703 if(value.test(o[property])){
27710 this.jsonData = data;
27716 * Filter by a function. The passed function will be called with each
27717 * object in the current dataset. If the function returns true the value is kept,
27718 * otherwise it is filtered.
27719 * @param {Function} fn
27720 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
27722 filterBy : function(fn, scope){
27725 var ss = this.snapshot;
27726 for(var i = 0, len = ss.length; i < len; i++){
27728 if(fn.call(scope || this, o)){
27732 this.jsonData = data;
27738 * Clears the current filter.
27740 clearFilter : function(){
27741 if(this.snapshot && this.jsonData != this.snapshot){
27742 this.jsonData = this.snapshot;
27749 * Sorts the data for this view and refreshes it.
27750 * @param {String} property A property on your JSON objects to sort on
27751 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
27752 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
27754 sort : function(property, dir, sortType){
27755 this.sortInfo = Array.prototype.slice.call(arguments, 0);
27758 var dsc = dir && dir.toLowerCase() == "desc";
27759 var f = function(o1, o2){
27760 var v1 = sortType ? sortType(o1[p]) : o1[p];
27761 var v2 = sortType ? sortType(o2[p]) : o2[p];
27764 return dsc ? +1 : -1;
27765 } else if(v1 > v2){
27766 return dsc ? -1 : +1;
27771 this.jsonData.sort(f);
27773 if(this.jsonData != this.snapshot){
27774 this.snapshot.sort(f);
27780 * Ext JS Library 1.1.1
27781 * Copyright(c) 2006-2007, Ext JS, LLC.
27783 * Originally Released Under LGPL - original licence link has changed is not relivant.
27786 * <script type="text/javascript">
27791 * @class Roo.ColorPalette
27792 * @extends Roo.Component
27793 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
27794 * Here's an example of typical usage:
27796 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
27797 cp.render('my-div');
27799 cp.on('select', function(palette, selColor){
27800 // do something with selColor
27804 * Create a new ColorPalette
27805 * @param {Object} config The config object
27807 Roo.ColorPalette = function(config){
27808 Roo.ColorPalette.superclass.constructor.call(this, config);
27812 * Fires when a color is selected
27813 * @param {ColorPalette} this
27814 * @param {String} color The 6-digit color hex code (without the # symbol)
27820 this.on("select", this.handler, this.scope, true);
27823 Roo.extend(Roo.ColorPalette, Roo.Component, {
27825 * @cfg {String} itemCls
27826 * The CSS class to apply to the containing element (defaults to "x-color-palette")
27828 itemCls : "x-color-palette",
27830 * @cfg {String} value
27831 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
27832 * the hex codes are case-sensitive.
27835 clickEvent:'click',
27837 ctype: "Roo.ColorPalette",
27840 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
27842 allowReselect : false,
27845 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
27846 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
27847 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
27848 * of colors with the width setting until the box is symmetrical.</p>
27849 * <p>You can override individual colors if needed:</p>
27851 var cp = new Roo.ColorPalette();
27852 cp.colors[0] = "FF0000"; // change the first box to red
27855 Or you can provide a custom array of your own for complete control:
27857 var cp = new Roo.ColorPalette();
27858 cp.colors = ["000000", "993300", "333300"];
27863 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
27864 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
27865 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
27866 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
27867 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
27871 onRender : function(container, position){
27872 var t = new Roo.MasterTemplate(
27873 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
27875 var c = this.colors;
27876 for(var i = 0, len = c.length; i < len; i++){
27879 var el = document.createElement("div");
27880 el.className = this.itemCls;
27882 container.dom.insertBefore(el, position);
27883 this.el = Roo.get(el);
27884 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
27885 if(this.clickEvent != 'click'){
27886 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
27891 afterRender : function(){
27892 Roo.ColorPalette.superclass.afterRender.call(this);
27894 var s = this.value;
27901 handleClick : function(e, t){
27902 e.preventDefault();
27903 if(!this.disabled){
27904 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
27905 this.select(c.toUpperCase());
27910 * Selects the specified color in the palette (fires the select event)
27911 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
27913 select : function(color){
27914 color = color.replace("#", "");
27915 if(color != this.value || this.allowReselect){
27918 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
27920 el.child("a.color-"+color).addClass("x-color-palette-sel");
27921 this.value = color;
27922 this.fireEvent("select", this, color);
27927 * Ext JS Library 1.1.1
27928 * Copyright(c) 2006-2007, Ext JS, LLC.
27930 * Originally Released Under LGPL - original licence link has changed is not relivant.
27933 * <script type="text/javascript">
27937 * @class Roo.DatePicker
27938 * @extends Roo.Component
27939 * Simple date picker class.
27941 * Create a new DatePicker
27942 * @param {Object} config The config object
27944 Roo.DatePicker = function(config){
27945 Roo.DatePicker.superclass.constructor.call(this, config);
27947 this.value = config && config.value ?
27948 config.value.clearTime() : new Date().clearTime();
27953 * Fires when a date is selected
27954 * @param {DatePicker} this
27955 * @param {Date} date The selected date
27959 * @event monthchange
27960 * Fires when the displayed month changes
27961 * @param {DatePicker} this
27962 * @param {Date} date The selected month
27964 'monthchange': true
27968 this.on("select", this.handler, this.scope || this);
27970 // build the disabledDatesRE
27971 if(!this.disabledDatesRE && this.disabledDates){
27972 var dd = this.disabledDates;
27974 for(var i = 0; i < dd.length; i++){
27976 if(i != dd.length-1) {
27980 this.disabledDatesRE = new RegExp(re + ")");
27984 Roo.extend(Roo.DatePicker, Roo.Component, {
27986 * @cfg {String} todayText
27987 * The text to display on the button that selects the current date (defaults to "Today")
27989 todayText : "Today",
27991 * @cfg {String} okText
27992 * The text to display on the ok button
27994 okText : " OK ", //   to give the user extra clicking room
27996 * @cfg {String} cancelText
27997 * The text to display on the cancel button
27999 cancelText : "Cancel",
28001 * @cfg {String} todayTip
28002 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
28004 todayTip : "{0} (Spacebar)",
28006 * @cfg {Date} minDate
28007 * Minimum allowable date (JavaScript date object, defaults to null)
28011 * @cfg {Date} maxDate
28012 * Maximum allowable date (JavaScript date object, defaults to null)
28016 * @cfg {String} minText
28017 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
28019 minText : "This date is before the minimum date",
28021 * @cfg {String} maxText
28022 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
28024 maxText : "This date is after the maximum date",
28026 * @cfg {String} format
28027 * The default date format string which can be overriden for localization support. The format must be
28028 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
28032 * @cfg {Array} disabledDays
28033 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
28035 disabledDays : null,
28037 * @cfg {String} disabledDaysText
28038 * The tooltip to display when the date falls on a disabled day (defaults to "")
28040 disabledDaysText : "",
28042 * @cfg {RegExp} disabledDatesRE
28043 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
28045 disabledDatesRE : null,
28047 * @cfg {String} disabledDatesText
28048 * The tooltip text to display when the date falls on a disabled date (defaults to "")
28050 disabledDatesText : "",
28052 * @cfg {Boolean} constrainToViewport
28053 * True to constrain the date picker to the viewport (defaults to true)
28055 constrainToViewport : true,
28057 * @cfg {Array} monthNames
28058 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
28060 monthNames : Date.monthNames,
28062 * @cfg {Array} dayNames
28063 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
28065 dayNames : Date.dayNames,
28067 * @cfg {String} nextText
28068 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
28070 nextText: 'Next Month (Control+Right)',
28072 * @cfg {String} prevText
28073 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
28075 prevText: 'Previous Month (Control+Left)',
28077 * @cfg {String} monthYearText
28078 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
28080 monthYearText: 'Choose a month (Control+Up/Down to move years)',
28082 * @cfg {Number} startDay
28083 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
28087 * @cfg {Bool} showClear
28088 * Show a clear button (usefull for date form elements that can be blank.)
28094 * Sets the value of the date field
28095 * @param {Date} value The date to set
28097 setValue : function(value){
28098 var old = this.value;
28100 if (typeof(value) == 'string') {
28102 value = Date.parseDate(value, this.format);
28105 value = new Date();
28108 this.value = value.clearTime(true);
28110 this.update(this.value);
28115 * Gets the current selected value of the date field
28116 * @return {Date} The selected date
28118 getValue : function(){
28123 focus : function(){
28125 this.update(this.activeDate);
28130 onRender : function(container, position){
28133 '<table cellspacing="0">',
28134 '<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>',
28135 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
28136 var dn = this.dayNames;
28137 for(var i = 0; i < 7; i++){
28138 var d = this.startDay+i;
28142 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
28144 m[m.length] = "</tr></thead><tbody><tr>";
28145 for(var i = 0; i < 42; i++) {
28146 if(i % 7 == 0 && i != 0){
28147 m[m.length] = "</tr><tr>";
28149 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
28151 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
28152 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
28154 var el = document.createElement("div");
28155 el.className = "x-date-picker";
28156 el.innerHTML = m.join("");
28158 container.dom.insertBefore(el, position);
28160 this.el = Roo.get(el);
28161 this.eventEl = Roo.get(el.firstChild);
28163 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
28164 handler: this.showPrevMonth,
28166 preventDefault:true,
28170 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
28171 handler: this.showNextMonth,
28173 preventDefault:true,
28177 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
28179 this.monthPicker = this.el.down('div.x-date-mp');
28180 this.monthPicker.enableDisplayMode('block');
28182 var kn = new Roo.KeyNav(this.eventEl, {
28183 "left" : function(e){
28185 this.showPrevMonth() :
28186 this.update(this.activeDate.add("d", -1));
28189 "right" : function(e){
28191 this.showNextMonth() :
28192 this.update(this.activeDate.add("d", 1));
28195 "up" : function(e){
28197 this.showNextYear() :
28198 this.update(this.activeDate.add("d", -7));
28201 "down" : function(e){
28203 this.showPrevYear() :
28204 this.update(this.activeDate.add("d", 7));
28207 "pageUp" : function(e){
28208 this.showNextMonth();
28211 "pageDown" : function(e){
28212 this.showPrevMonth();
28215 "enter" : function(e){
28216 e.stopPropagation();
28223 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
28225 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
28227 this.el.unselectable();
28229 this.cells = this.el.select("table.x-date-inner tbody td");
28230 this.textNodes = this.el.query("table.x-date-inner tbody span");
28232 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
28234 tooltip: this.monthYearText
28237 this.mbtn.on('click', this.showMonthPicker, this);
28238 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
28241 var today = (new Date()).dateFormat(this.format);
28243 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
28244 if (this.showClear) {
28245 baseTb.add( new Roo.Toolbar.Fill());
28248 text: String.format(this.todayText, today),
28249 tooltip: String.format(this.todayTip, today),
28250 handler: this.selectToday,
28254 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
28257 if (this.showClear) {
28259 baseTb.add( new Roo.Toolbar.Fill());
28262 cls: 'x-btn-icon x-btn-clear',
28263 handler: function() {
28265 this.fireEvent("select", this, '');
28275 this.update(this.value);
28278 createMonthPicker : function(){
28279 if(!this.monthPicker.dom.firstChild){
28280 var buf = ['<table border="0" cellspacing="0">'];
28281 for(var i = 0; i < 6; i++){
28283 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
28284 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
28286 '<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>' :
28287 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
28291 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
28293 '</button><button type="button" class="x-date-mp-cancel">',
28295 '</button></td></tr>',
28298 this.monthPicker.update(buf.join(''));
28299 this.monthPicker.on('click', this.onMonthClick, this);
28300 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
28302 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
28303 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
28305 this.mpMonths.each(function(m, a, i){
28308 m.dom.xmonth = 5 + Math.round(i * .5);
28310 m.dom.xmonth = Math.round((i-1) * .5);
28316 showMonthPicker : function(){
28317 this.createMonthPicker();
28318 var size = this.el.getSize();
28319 this.monthPicker.setSize(size);
28320 this.monthPicker.child('table').setSize(size);
28322 this.mpSelMonth = (this.activeDate || this.value).getMonth();
28323 this.updateMPMonth(this.mpSelMonth);
28324 this.mpSelYear = (this.activeDate || this.value).getFullYear();
28325 this.updateMPYear(this.mpSelYear);
28327 this.monthPicker.slideIn('t', {duration:.2});
28330 updateMPYear : function(y){
28332 var ys = this.mpYears.elements;
28333 for(var i = 1; i <= 10; i++){
28334 var td = ys[i-1], y2;
28336 y2 = y + Math.round(i * .5);
28337 td.firstChild.innerHTML = y2;
28340 y2 = y - (5-Math.round(i * .5));
28341 td.firstChild.innerHTML = y2;
28344 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
28348 updateMPMonth : function(sm){
28349 this.mpMonths.each(function(m, a, i){
28350 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
28354 selectMPMonth: function(m){
28358 onMonthClick : function(e, t){
28360 var el = new Roo.Element(t), pn;
28361 if(el.is('button.x-date-mp-cancel')){
28362 this.hideMonthPicker();
28364 else if(el.is('button.x-date-mp-ok')){
28365 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28366 this.hideMonthPicker();
28368 else if(pn = el.up('td.x-date-mp-month', 2)){
28369 this.mpMonths.removeClass('x-date-mp-sel');
28370 pn.addClass('x-date-mp-sel');
28371 this.mpSelMonth = pn.dom.xmonth;
28373 else if(pn = el.up('td.x-date-mp-year', 2)){
28374 this.mpYears.removeClass('x-date-mp-sel');
28375 pn.addClass('x-date-mp-sel');
28376 this.mpSelYear = pn.dom.xyear;
28378 else if(el.is('a.x-date-mp-prev')){
28379 this.updateMPYear(this.mpyear-10);
28381 else if(el.is('a.x-date-mp-next')){
28382 this.updateMPYear(this.mpyear+10);
28386 onMonthDblClick : function(e, t){
28388 var el = new Roo.Element(t), pn;
28389 if(pn = el.up('td.x-date-mp-month', 2)){
28390 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
28391 this.hideMonthPicker();
28393 else if(pn = el.up('td.x-date-mp-year', 2)){
28394 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
28395 this.hideMonthPicker();
28399 hideMonthPicker : function(disableAnim){
28400 if(this.monthPicker){
28401 if(disableAnim === true){
28402 this.monthPicker.hide();
28404 this.monthPicker.slideOut('t', {duration:.2});
28410 showPrevMonth : function(e){
28411 this.update(this.activeDate.add("mo", -1));
28415 showNextMonth : function(e){
28416 this.update(this.activeDate.add("mo", 1));
28420 showPrevYear : function(){
28421 this.update(this.activeDate.add("y", -1));
28425 showNextYear : function(){
28426 this.update(this.activeDate.add("y", 1));
28430 handleMouseWheel : function(e){
28431 var delta = e.getWheelDelta();
28433 this.showPrevMonth();
28435 } else if(delta < 0){
28436 this.showNextMonth();
28442 handleDateClick : function(e, t){
28444 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
28445 this.setValue(new Date(t.dateValue));
28446 this.fireEvent("select", this, this.value);
28451 selectToday : function(){
28452 this.setValue(new Date().clearTime());
28453 this.fireEvent("select", this, this.value);
28457 update : function(date)
28459 var vd = this.activeDate;
28460 this.activeDate = date;
28462 var t = date.getTime();
28463 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
28464 this.cells.removeClass("x-date-selected");
28465 this.cells.each(function(c){
28466 if(c.dom.firstChild.dateValue == t){
28467 c.addClass("x-date-selected");
28468 setTimeout(function(){
28469 try{c.dom.firstChild.focus();}catch(e){}
28478 var days = date.getDaysInMonth();
28479 var firstOfMonth = date.getFirstDateOfMonth();
28480 var startingPos = firstOfMonth.getDay()-this.startDay;
28482 if(startingPos <= this.startDay){
28486 var pm = date.add("mo", -1);
28487 var prevStart = pm.getDaysInMonth()-startingPos;
28489 var cells = this.cells.elements;
28490 var textEls = this.textNodes;
28491 days += startingPos;
28493 // convert everything to numbers so it's fast
28494 var day = 86400000;
28495 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
28496 var today = new Date().clearTime().getTime();
28497 var sel = date.clearTime().getTime();
28498 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
28499 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
28500 var ddMatch = this.disabledDatesRE;
28501 var ddText = this.disabledDatesText;
28502 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
28503 var ddaysText = this.disabledDaysText;
28504 var format = this.format;
28506 var setCellClass = function(cal, cell){
28508 var t = d.getTime();
28509 cell.firstChild.dateValue = t;
28511 cell.className += " x-date-today";
28512 cell.title = cal.todayText;
28515 cell.className += " x-date-selected";
28516 setTimeout(function(){
28517 try{cell.firstChild.focus();}catch(e){}
28522 cell.className = " x-date-disabled";
28523 cell.title = cal.minText;
28527 cell.className = " x-date-disabled";
28528 cell.title = cal.maxText;
28532 if(ddays.indexOf(d.getDay()) != -1){
28533 cell.title = ddaysText;
28534 cell.className = " x-date-disabled";
28537 if(ddMatch && format){
28538 var fvalue = d.dateFormat(format);
28539 if(ddMatch.test(fvalue)){
28540 cell.title = ddText.replace("%0", fvalue);
28541 cell.className = " x-date-disabled";
28547 for(; i < startingPos; i++) {
28548 textEls[i].innerHTML = (++prevStart);
28549 d.setDate(d.getDate()+1);
28550 cells[i].className = "x-date-prevday";
28551 setCellClass(this, cells[i]);
28553 for(; i < days; i++){
28554 intDay = i - startingPos + 1;
28555 textEls[i].innerHTML = (intDay);
28556 d.setDate(d.getDate()+1);
28557 cells[i].className = "x-date-active";
28558 setCellClass(this, cells[i]);
28561 for(; i < 42; i++) {
28562 textEls[i].innerHTML = (++extraDays);
28563 d.setDate(d.getDate()+1);
28564 cells[i].className = "x-date-nextday";
28565 setCellClass(this, cells[i]);
28568 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
28569 this.fireEvent('monthchange', this, date);
28571 if(!this.internalRender){
28572 var main = this.el.dom.firstChild;
28573 var w = main.offsetWidth;
28574 this.el.setWidth(w + this.el.getBorderWidth("lr"));
28575 Roo.fly(main).setWidth(w);
28576 this.internalRender = true;
28577 // opera does not respect the auto grow header center column
28578 // then, after it gets a width opera refuses to recalculate
28579 // without a second pass
28580 if(Roo.isOpera && !this.secondPass){
28581 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
28582 this.secondPass = true;
28583 this.update.defer(10, this, [date]);
28591 * Ext JS Library 1.1.1
28592 * Copyright(c) 2006-2007, Ext JS, LLC.
28594 * Originally Released Under LGPL - original licence link has changed is not relivant.
28597 * <script type="text/javascript">
28600 * @class Roo.TabPanel
28601 * @extends Roo.util.Observable
28602 * A lightweight tab container.
28606 // basic tabs 1, built from existing content
28607 var tabs = new Roo.TabPanel("tabs1");
28608 tabs.addTab("script", "View Script");
28609 tabs.addTab("markup", "View Markup");
28610 tabs.activate("script");
28612 // more advanced tabs, built from javascript
28613 var jtabs = new Roo.TabPanel("jtabs");
28614 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
28616 // set up the UpdateManager
28617 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
28618 var updater = tab2.getUpdateManager();
28619 updater.setDefaultUrl("ajax1.htm");
28620 tab2.on('activate', updater.refresh, updater, true);
28622 // Use setUrl for Ajax loading
28623 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
28624 tab3.setUrl("ajax2.htm", null, true);
28627 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
28630 jtabs.activate("jtabs-1");
28633 * Create a new TabPanel.
28634 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
28635 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
28637 Roo.TabPanel = function(container, config){
28639 * The container element for this TabPanel.
28640 * @type Roo.Element
28642 this.el = Roo.get(container, true);
28644 if(typeof config == "boolean"){
28645 this.tabPosition = config ? "bottom" : "top";
28647 Roo.apply(this, config);
28650 if(this.tabPosition == "bottom"){
28651 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28652 this.el.addClass("x-tabs-bottom");
28654 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
28655 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
28656 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
28658 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
28660 if(this.tabPosition != "bottom"){
28661 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
28662 * @type Roo.Element
28664 this.bodyEl = Roo.get(this.createBody(this.el.dom));
28665 this.el.addClass("x-tabs-top");
28669 this.bodyEl.setStyle("position", "relative");
28671 this.active = null;
28672 this.activateDelegate = this.activate.createDelegate(this);
28677 * Fires when the active tab changes
28678 * @param {Roo.TabPanel} this
28679 * @param {Roo.TabPanelItem} activePanel The new active tab
28683 * @event beforetabchange
28684 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
28685 * @param {Roo.TabPanel} this
28686 * @param {Object} e Set cancel to true on this object to cancel the tab change
28687 * @param {Roo.TabPanelItem} tab The tab being changed to
28689 "beforetabchange" : true
28692 Roo.EventManager.onWindowResize(this.onResize, this);
28693 this.cpad = this.el.getPadding("lr");
28694 this.hiddenCount = 0;
28697 // toolbar on the tabbar support...
28698 if (this.toolbar) {
28699 var tcfg = this.toolbar;
28700 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
28701 this.toolbar = new Roo.Toolbar(tcfg);
28702 if (Roo.isSafari) {
28703 var tbl = tcfg.container.child('table', true);
28704 tbl.setAttribute('width', '100%');
28711 Roo.TabPanel.superclass.constructor.call(this);
28714 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
28716 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
28718 tabPosition : "top",
28720 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
28722 currentTabWidth : 0,
28724 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
28728 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
28732 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
28734 preferredTabWidth : 175,
28736 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
28738 resizeTabs : false,
28740 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
28742 monitorResize : true,
28744 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
28749 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
28750 * @param {String} id The id of the div to use <b>or create</b>
28751 * @param {String} text The text for the tab
28752 * @param {String} content (optional) Content to put in the TabPanelItem body
28753 * @param {Boolean} closable (optional) True to create a close icon on the tab
28754 * @return {Roo.TabPanelItem} The created TabPanelItem
28756 addTab : function(id, text, content, closable){
28757 var item = new Roo.TabPanelItem(this, id, text, closable);
28758 this.addTabItem(item);
28760 item.setContent(content);
28766 * Returns the {@link Roo.TabPanelItem} with the specified id/index
28767 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
28768 * @return {Roo.TabPanelItem}
28770 getTab : function(id){
28771 return this.items[id];
28775 * Hides the {@link Roo.TabPanelItem} with the specified id/index
28776 * @param {String/Number} id The id or index of the TabPanelItem to hide.
28778 hideTab : function(id){
28779 var t = this.items[id];
28782 this.hiddenCount++;
28783 this.autoSizeTabs();
28788 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
28789 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
28791 unhideTab : function(id){
28792 var t = this.items[id];
28794 t.setHidden(false);
28795 this.hiddenCount--;
28796 this.autoSizeTabs();
28801 * Adds an existing {@link Roo.TabPanelItem}.
28802 * @param {Roo.TabPanelItem} item The TabPanelItem to add
28804 addTabItem : function(item){
28805 this.items[item.id] = item;
28806 this.items.push(item);
28807 if(this.resizeTabs){
28808 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
28809 this.autoSizeTabs();
28816 * Removes a {@link Roo.TabPanelItem}.
28817 * @param {String/Number} id The id or index of the TabPanelItem to remove.
28819 removeTab : function(id){
28820 var items = this.items;
28821 var tab = items[id];
28822 if(!tab) { return; }
28823 var index = items.indexOf(tab);
28824 if(this.active == tab && items.length > 1){
28825 var newTab = this.getNextAvailable(index);
28830 this.stripEl.dom.removeChild(tab.pnode.dom);
28831 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
28832 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
28834 items.splice(index, 1);
28835 delete this.items[tab.id];
28836 tab.fireEvent("close", tab);
28837 tab.purgeListeners();
28838 this.autoSizeTabs();
28841 getNextAvailable : function(start){
28842 var items = this.items;
28844 // look for a next tab that will slide over to
28845 // replace the one being removed
28846 while(index < items.length){
28847 var item = items[++index];
28848 if(item && !item.isHidden()){
28852 // if one isn't found select the previous tab (on the left)
28855 var item = items[--index];
28856 if(item && !item.isHidden()){
28864 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
28865 * @param {String/Number} id The id or index of the TabPanelItem to disable.
28867 disableTab : function(id){
28868 var tab = this.items[id];
28869 if(tab && this.active != tab){
28875 * Enables a {@link Roo.TabPanelItem} that is disabled.
28876 * @param {String/Number} id The id or index of the TabPanelItem to enable.
28878 enableTab : function(id){
28879 var tab = this.items[id];
28884 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
28885 * @param {String/Number} id The id or index of the TabPanelItem to activate.
28886 * @return {Roo.TabPanelItem} The TabPanelItem.
28888 activate : function(id){
28889 var tab = this.items[id];
28893 if(tab == this.active || tab.disabled){
28897 this.fireEvent("beforetabchange", this, e, tab);
28898 if(e.cancel !== true && !tab.disabled){
28900 this.active.hide();
28902 this.active = this.items[id];
28903 this.active.show();
28904 this.fireEvent("tabchange", this, this.active);
28910 * Gets the active {@link Roo.TabPanelItem}.
28911 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
28913 getActiveTab : function(){
28914 return this.active;
28918 * Updates the tab body element to fit the height of the container element
28919 * for overflow scrolling
28920 * @param {Number} targetHeight (optional) Override the starting height from the elements height
28922 syncHeight : function(targetHeight){
28923 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28924 var bm = this.bodyEl.getMargins();
28925 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
28926 this.bodyEl.setHeight(newHeight);
28930 onResize : function(){
28931 if(this.monitorResize){
28932 this.autoSizeTabs();
28937 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
28939 beginUpdate : function(){
28940 this.updating = true;
28944 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
28946 endUpdate : function(){
28947 this.updating = false;
28948 this.autoSizeTabs();
28952 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
28954 autoSizeTabs : function(){
28955 var count = this.items.length;
28956 var vcount = count - this.hiddenCount;
28957 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) {
28960 var w = Math.max(this.el.getWidth() - this.cpad, 10);
28961 var availWidth = Math.floor(w / vcount);
28962 var b = this.stripBody;
28963 if(b.getWidth() > w){
28964 var tabs = this.items;
28965 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
28966 if(availWidth < this.minTabWidth){
28967 /*if(!this.sleft){ // incomplete scrolling code
28968 this.createScrollButtons();
28971 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
28974 if(this.currentTabWidth < this.preferredTabWidth){
28975 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
28981 * Returns the number of tabs in this TabPanel.
28984 getCount : function(){
28985 return this.items.length;
28989 * Resizes all the tabs to the passed width
28990 * @param {Number} The new width
28992 setTabWidth : function(width){
28993 this.currentTabWidth = width;
28994 for(var i = 0, len = this.items.length; i < len; i++) {
28995 if(!this.items[i].isHidden()) {
28996 this.items[i].setWidth(width);
29002 * Destroys this TabPanel
29003 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
29005 destroy : function(removeEl){
29006 Roo.EventManager.removeResizeListener(this.onResize, this);
29007 for(var i = 0, len = this.items.length; i < len; i++){
29008 this.items[i].purgeListeners();
29010 if(removeEl === true){
29011 this.el.update("");
29018 * @class Roo.TabPanelItem
29019 * @extends Roo.util.Observable
29020 * Represents an individual item (tab plus body) in a TabPanel.
29021 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
29022 * @param {String} id The id of this TabPanelItem
29023 * @param {String} text The text for the tab of this TabPanelItem
29024 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
29026 Roo.TabPanelItem = function(tabPanel, id, text, closable){
29028 * The {@link Roo.TabPanel} this TabPanelItem belongs to
29029 * @type Roo.TabPanel
29031 this.tabPanel = tabPanel;
29033 * The id for this TabPanelItem
29038 this.disabled = false;
29042 this.loaded = false;
29043 this.closable = closable;
29046 * The body element for this TabPanelItem.
29047 * @type Roo.Element
29049 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
29050 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
29051 this.bodyEl.setStyle("display", "block");
29052 this.bodyEl.setStyle("zoom", "1");
29055 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
29057 this.el = Roo.get(els.el, true);
29058 this.inner = Roo.get(els.inner, true);
29059 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
29060 this.pnode = Roo.get(els.el.parentNode, true);
29061 this.el.on("mousedown", this.onTabMouseDown, this);
29062 this.el.on("click", this.onTabClick, this);
29065 var c = Roo.get(els.close, true);
29066 c.dom.title = this.closeText;
29067 c.addClassOnOver("close-over");
29068 c.on("click", this.closeClick, this);
29074 * Fires when this tab becomes the active tab.
29075 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29076 * @param {Roo.TabPanelItem} this
29080 * @event beforeclose
29081 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
29082 * @param {Roo.TabPanelItem} this
29083 * @param {Object} e Set cancel to true on this object to cancel the close.
29085 "beforeclose": true,
29088 * Fires when this tab is closed.
29089 * @param {Roo.TabPanelItem} this
29093 * @event deactivate
29094 * Fires when this tab is no longer the active tab.
29095 * @param {Roo.TabPanel} tabPanel The parent TabPanel
29096 * @param {Roo.TabPanelItem} this
29098 "deactivate" : true
29100 this.hidden = false;
29102 Roo.TabPanelItem.superclass.constructor.call(this);
29105 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
29106 purgeListeners : function(){
29107 Roo.util.Observable.prototype.purgeListeners.call(this);
29108 this.el.removeAllListeners();
29111 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
29114 this.pnode.addClass("on");
29117 this.tabPanel.stripWrap.repaint();
29119 this.fireEvent("activate", this.tabPanel, this);
29123 * Returns true if this tab is the active tab.
29124 * @return {Boolean}
29126 isActive : function(){
29127 return this.tabPanel.getActiveTab() == this;
29131 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
29134 this.pnode.removeClass("on");
29136 this.fireEvent("deactivate", this.tabPanel, this);
29139 hideAction : function(){
29140 this.bodyEl.hide();
29141 this.bodyEl.setStyle("position", "absolute");
29142 this.bodyEl.setLeft("-20000px");
29143 this.bodyEl.setTop("-20000px");
29146 showAction : function(){
29147 this.bodyEl.setStyle("position", "relative");
29148 this.bodyEl.setTop("");
29149 this.bodyEl.setLeft("");
29150 this.bodyEl.show();
29154 * Set the tooltip for the tab.
29155 * @param {String} tooltip The tab's tooltip
29157 setTooltip : function(text){
29158 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
29159 this.textEl.dom.qtip = text;
29160 this.textEl.dom.removeAttribute('title');
29162 this.textEl.dom.title = text;
29166 onTabClick : function(e){
29167 e.preventDefault();
29168 this.tabPanel.activate(this.id);
29171 onTabMouseDown : function(e){
29172 e.preventDefault();
29173 this.tabPanel.activate(this.id);
29176 getWidth : function(){
29177 return this.inner.getWidth();
29180 setWidth : function(width){
29181 var iwidth = width - this.pnode.getPadding("lr");
29182 this.inner.setWidth(iwidth);
29183 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
29184 this.pnode.setWidth(width);
29188 * Show or hide the tab
29189 * @param {Boolean} hidden True to hide or false to show.
29191 setHidden : function(hidden){
29192 this.hidden = hidden;
29193 this.pnode.setStyle("display", hidden ? "none" : "");
29197 * Returns true if this tab is "hidden"
29198 * @return {Boolean}
29200 isHidden : function(){
29201 return this.hidden;
29205 * Returns the text for this tab
29208 getText : function(){
29212 autoSize : function(){
29213 //this.el.beginMeasure();
29214 this.textEl.setWidth(1);
29216 * #2804 [new] Tabs in Roojs
29217 * increase the width by 2-4 pixels to prevent the ellipssis showing in chrome
29219 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr") + 2);
29220 //this.el.endMeasure();
29224 * Sets the text for the tab (Note: this also sets the tooltip text)
29225 * @param {String} text The tab's text and tooltip
29227 setText : function(text){
29229 this.textEl.update(text);
29230 this.setTooltip(text);
29231 if(!this.tabPanel.resizeTabs){
29236 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
29238 activate : function(){
29239 this.tabPanel.activate(this.id);
29243 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
29245 disable : function(){
29246 if(this.tabPanel.active != this){
29247 this.disabled = true;
29248 this.pnode.addClass("disabled");
29253 * Enables this TabPanelItem if it was previously disabled.
29255 enable : function(){
29256 this.disabled = false;
29257 this.pnode.removeClass("disabled");
29261 * Sets the content for this TabPanelItem.
29262 * @param {String} content The content
29263 * @param {Boolean} loadScripts true to look for and load scripts
29265 setContent : function(content, loadScripts){
29266 this.bodyEl.update(content, loadScripts);
29270 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
29271 * @return {Roo.UpdateManager} The UpdateManager
29273 getUpdateManager : function(){
29274 return this.bodyEl.getUpdateManager();
29278 * Set a URL to be used to load the content for this TabPanelItem.
29279 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
29280 * @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)
29281 * @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)
29282 * @return {Roo.UpdateManager} The UpdateManager
29284 setUrl : function(url, params, loadOnce){
29285 if(this.refreshDelegate){
29286 this.un('activate', this.refreshDelegate);
29288 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
29289 this.on("activate", this.refreshDelegate);
29290 return this.bodyEl.getUpdateManager();
29294 _handleRefresh : function(url, params, loadOnce){
29295 if(!loadOnce || !this.loaded){
29296 var updater = this.bodyEl.getUpdateManager();
29297 updater.update(url, params, this._setLoaded.createDelegate(this));
29302 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
29303 * Will fail silently if the setUrl method has not been called.
29304 * This does not activate the panel, just updates its content.
29306 refresh : function(){
29307 if(this.refreshDelegate){
29308 this.loaded = false;
29309 this.refreshDelegate();
29314 _setLoaded : function(){
29315 this.loaded = true;
29319 closeClick : function(e){
29322 this.fireEvent("beforeclose", this, o);
29323 if(o.cancel !== true){
29324 this.tabPanel.removeTab(this.id);
29328 * The text displayed in the tooltip for the close icon.
29331 closeText : "Close this tab"
29335 Roo.TabPanel.prototype.createStrip = function(container){
29336 var strip = document.createElement("div");
29337 strip.className = "x-tabs-wrap";
29338 container.appendChild(strip);
29342 Roo.TabPanel.prototype.createStripList = function(strip){
29343 // div wrapper for retard IE
29344 // returns the "tr" element.
29345 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
29346 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
29347 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
29348 return strip.firstChild.firstChild.firstChild.firstChild;
29351 Roo.TabPanel.prototype.createBody = function(container){
29352 var body = document.createElement("div");
29353 Roo.id(body, "tab-body");
29354 Roo.fly(body).addClass("x-tabs-body");
29355 container.appendChild(body);
29359 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
29360 var body = Roo.getDom(id);
29362 body = document.createElement("div");
29365 Roo.fly(body).addClass("x-tabs-item-body");
29366 bodyEl.insertBefore(body, bodyEl.firstChild);
29370 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
29371 var td = document.createElement("td");
29372 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
29373 //stripEl.appendChild(td);
29375 td.className = "x-tabs-closable";
29376 if(!this.closeTpl){
29377 this.closeTpl = new Roo.Template(
29378 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29379 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
29380 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
29383 var el = this.closeTpl.overwrite(td, {"text": text});
29384 var close = el.getElementsByTagName("div")[0];
29385 var inner = el.getElementsByTagName("em")[0];
29386 return {"el": el, "close": close, "inner": inner};
29389 this.tabTpl = new Roo.Template(
29390 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
29391 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
29394 var el = this.tabTpl.overwrite(td, {"text": text});
29395 var inner = el.getElementsByTagName("em")[0];
29396 return {"el": el, "inner": inner};
29400 * Ext JS Library 1.1.1
29401 * Copyright(c) 2006-2007, Ext JS, LLC.
29403 * Originally Released Under LGPL - original licence link has changed is not relivant.
29406 * <script type="text/javascript">
29410 * @class Roo.Button
29411 * @extends Roo.util.Observable
29412 * Simple Button class
29413 * @cfg {String} text The button text
29414 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
29415 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
29416 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
29417 * @cfg {Object} scope The scope of the handler
29418 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
29419 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
29420 * @cfg {Boolean} hidden True to start hidden (defaults to false)
29421 * @cfg {Boolean} disabled True to start disabled (defaults to false)
29422 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
29423 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
29424 applies if enableToggle = true)
29425 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
29426 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
29427 an {@link Roo.util.ClickRepeater} config object (defaults to false).
29429 * Create a new button
29430 * @param {Object} config The config object
29432 Roo.Button = function(renderTo, config)
29436 renderTo = config.renderTo || false;
29439 Roo.apply(this, config);
29443 * Fires when this button is clicked
29444 * @param {Button} this
29445 * @param {EventObject} e The click event
29450 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
29451 * @param {Button} this
29452 * @param {Boolean} pressed
29457 * Fires when the mouse hovers over the button
29458 * @param {Button} this
29459 * @param {Event} e The event object
29461 'mouseover' : true,
29464 * Fires when the mouse exits the button
29465 * @param {Button} this
29466 * @param {Event} e The event object
29471 * Fires when the button is rendered
29472 * @param {Button} this
29477 this.menu = Roo.menu.MenuMgr.get(this.menu);
29479 // register listeners first!! - so render can be captured..
29480 Roo.util.Observable.call(this);
29482 this.render(renderTo);
29488 Roo.extend(Roo.Button, Roo.util.Observable, {
29494 * Read-only. True if this button is hidden
29499 * Read-only. True if this button is disabled
29504 * Read-only. True if this button is pressed (only if enableToggle = true)
29510 * @cfg {Number} tabIndex
29511 * The DOM tabIndex for this button (defaults to undefined)
29513 tabIndex : undefined,
29516 * @cfg {Boolean} enableToggle
29517 * True to enable pressed/not pressed toggling (defaults to false)
29519 enableToggle: false,
29521 * @cfg {Mixed} menu
29522 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
29526 * @cfg {String} menuAlign
29527 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
29529 menuAlign : "tl-bl?",
29532 * @cfg {String} iconCls
29533 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
29535 iconCls : undefined,
29537 * @cfg {String} type
29538 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
29543 menuClassTarget: 'tr',
29546 * @cfg {String} clickEvent
29547 * The type of event to map to the button's event handler (defaults to 'click')
29549 clickEvent : 'click',
29552 * @cfg {Boolean} handleMouseEvents
29553 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
29555 handleMouseEvents : true,
29558 * @cfg {String} tooltipType
29559 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
29561 tooltipType : 'qtip',
29564 * @cfg {String} cls
29565 * A CSS class to apply to the button's main element.
29569 * @cfg {Roo.Template} template (Optional)
29570 * An {@link Roo.Template} with which to create the Button's main element. This Template must
29571 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
29572 * require code modifications if required elements (e.g. a button) aren't present.
29576 render : function(renderTo){
29578 if(this.hideParent){
29579 this.parentEl = Roo.get(renderTo);
29581 if(!this.dhconfig){
29582 if(!this.template){
29583 if(!Roo.Button.buttonTemplate){
29584 // hideous table template
29585 Roo.Button.buttonTemplate = new Roo.Template(
29586 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
29587 '<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>',
29588 "</tr></tbody></table>");
29590 this.template = Roo.Button.buttonTemplate;
29592 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
29593 var btnEl = btn.child("button:first");
29594 btnEl.on('focus', this.onFocus, this);
29595 btnEl.on('blur', this.onBlur, this);
29597 btn.addClass(this.cls);
29600 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29603 btnEl.addClass(this.iconCls);
29605 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29608 if(this.tabIndex !== undefined){
29609 btnEl.dom.tabIndex = this.tabIndex;
29612 if(typeof this.tooltip == 'object'){
29613 Roo.QuickTips.tips(Roo.apply({
29617 btnEl.dom[this.tooltipType] = this.tooltip;
29621 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
29625 this.el.dom.id = this.el.id = this.id;
29628 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
29629 this.menu.on("show", this.onMenuShow, this);
29630 this.menu.on("hide", this.onMenuHide, this);
29632 btn.addClass("x-btn");
29633 if(Roo.isIE && !Roo.isIE7){
29634 this.autoWidth.defer(1, this);
29638 if(this.handleMouseEvents){
29639 btn.on("mouseover", this.onMouseOver, this);
29640 btn.on("mouseout", this.onMouseOut, this);
29641 btn.on("mousedown", this.onMouseDown, this);
29643 btn.on(this.clickEvent, this.onClick, this);
29644 //btn.on("mouseup", this.onMouseUp, this);
29651 Roo.ButtonToggleMgr.register(this);
29653 this.el.addClass("x-btn-pressed");
29656 var repeater = new Roo.util.ClickRepeater(btn,
29657 typeof this.repeat == "object" ? this.repeat : {}
29659 repeater.on("click", this.onClick, this);
29662 this.fireEvent('render', this);
29666 * Returns the button's underlying element
29667 * @return {Roo.Element} The element
29669 getEl : function(){
29674 * Destroys this Button and removes any listeners.
29676 destroy : function(){
29677 Roo.ButtonToggleMgr.unregister(this);
29678 this.el.removeAllListeners();
29679 this.purgeListeners();
29684 autoWidth : function(){
29686 this.el.setWidth("auto");
29687 if(Roo.isIE7 && Roo.isStrict){
29688 var ib = this.el.child('button');
29689 if(ib && ib.getWidth() > 20){
29691 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
29696 this.el.beginMeasure();
29698 if(this.el.getWidth() < this.minWidth){
29699 this.el.setWidth(this.minWidth);
29702 this.el.endMeasure();
29709 * Assigns this button's click handler
29710 * @param {Function} handler The function to call when the button is clicked
29711 * @param {Object} scope (optional) Scope for the function passed in
29713 setHandler : function(handler, scope){
29714 this.handler = handler;
29715 this.scope = scope;
29719 * Sets this button's text
29720 * @param {String} text The button text
29722 setText : function(text){
29725 this.el.child("td.x-btn-center button.x-btn-text").update(text);
29731 * Gets the text for this button
29732 * @return {String} The button text
29734 getText : function(){
29742 this.hidden = false;
29744 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
29752 this.hidden = true;
29754 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
29759 * Convenience function for boolean show/hide
29760 * @param {Boolean} visible True to show, false to hide
29762 setVisible: function(visible){
29771 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
29772 * @param {Boolean} state (optional) Force a particular state
29774 toggle : function(state){
29775 state = state === undefined ? !this.pressed : state;
29776 if(state != this.pressed){
29778 this.el.addClass("x-btn-pressed");
29779 this.pressed = true;
29780 this.fireEvent("toggle", this, true);
29782 this.el.removeClass("x-btn-pressed");
29783 this.pressed = false;
29784 this.fireEvent("toggle", this, false);
29786 if(this.toggleHandler){
29787 this.toggleHandler.call(this.scope || this, this, state);
29795 focus : function(){
29796 this.el.child('button:first').focus();
29800 * Disable this button
29802 disable : function(){
29804 this.el.addClass("x-btn-disabled");
29806 this.disabled = true;
29810 * Enable this button
29812 enable : function(){
29814 this.el.removeClass("x-btn-disabled");
29816 this.disabled = false;
29820 * Convenience function for boolean enable/disable
29821 * @param {Boolean} enabled True to enable, false to disable
29823 setDisabled : function(v){
29824 this[v !== true ? "enable" : "disable"]();
29828 onClick : function(e)
29831 e.preventDefault();
29836 if(!this.disabled){
29837 if(this.enableToggle){
29840 if(this.menu && !this.menu.isVisible()){
29841 this.menu.show(this.el, this.menuAlign);
29843 this.fireEvent("click", this, e);
29845 this.el.removeClass("x-btn-over");
29846 this.handler.call(this.scope || this, this, e);
29851 onMouseOver : function(e){
29852 if(!this.disabled){
29853 this.el.addClass("x-btn-over");
29854 this.fireEvent('mouseover', this, e);
29858 onMouseOut : function(e){
29859 if(!e.within(this.el, true)){
29860 this.el.removeClass("x-btn-over");
29861 this.fireEvent('mouseout', this, e);
29865 onFocus : function(e){
29866 if(!this.disabled){
29867 this.el.addClass("x-btn-focus");
29871 onBlur : function(e){
29872 this.el.removeClass("x-btn-focus");
29875 onMouseDown : function(e){
29876 if(!this.disabled && e.button == 0){
29877 this.el.addClass("x-btn-click");
29878 Roo.get(document).on('mouseup', this.onMouseUp, this);
29882 onMouseUp : function(e){
29884 this.el.removeClass("x-btn-click");
29885 Roo.get(document).un('mouseup', this.onMouseUp, this);
29889 onMenuShow : function(e){
29890 this.el.addClass("x-btn-menu-active");
29893 onMenuHide : function(e){
29894 this.el.removeClass("x-btn-menu-active");
29898 // Private utility class used by Button
29899 Roo.ButtonToggleMgr = function(){
29902 function toggleGroup(btn, state){
29904 var g = groups[btn.toggleGroup];
29905 for(var i = 0, l = g.length; i < l; i++){
29907 g[i].toggle(false);
29914 register : function(btn){
29915 if(!btn.toggleGroup){
29918 var g = groups[btn.toggleGroup];
29920 g = groups[btn.toggleGroup] = [];
29923 btn.on("toggle", toggleGroup);
29926 unregister : function(btn){
29927 if(!btn.toggleGroup){
29930 var g = groups[btn.toggleGroup];
29933 btn.un("toggle", toggleGroup);
29939 * Ext JS Library 1.1.1
29940 * Copyright(c) 2006-2007, Ext JS, LLC.
29942 * Originally Released Under LGPL - original licence link has changed is not relivant.
29945 * <script type="text/javascript">
29949 * @class Roo.SplitButton
29950 * @extends Roo.Button
29951 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
29952 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
29953 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
29954 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
29955 * @cfg {String} arrowTooltip The title attribute of the arrow
29957 * Create a new menu button
29958 * @param {String/HTMLElement/Element} renderTo The element to append the button to
29959 * @param {Object} config The config object
29961 Roo.SplitButton = function(renderTo, config){
29962 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
29964 * @event arrowclick
29965 * Fires when this button's arrow is clicked
29966 * @param {SplitButton} this
29967 * @param {EventObject} e The click event
29969 this.addEvents({"arrowclick":true});
29972 Roo.extend(Roo.SplitButton, Roo.Button, {
29973 render : function(renderTo){
29974 // this is one sweet looking template!
29975 var tpl = new Roo.Template(
29976 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
29977 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
29978 '<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>',
29979 "</tbody></table></td><td>",
29980 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
29981 '<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>',
29982 "</tbody></table></td></tr></table>"
29984 var btn = tpl.append(renderTo, [this.text, this.type], true);
29985 var btnEl = btn.child("button");
29987 btn.addClass(this.cls);
29990 btnEl.setStyle('background-image', 'url(' +this.icon +')');
29993 btnEl.addClass(this.iconCls);
29995 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
29999 if(this.handleMouseEvents){
30000 btn.on("mouseover", this.onMouseOver, this);
30001 btn.on("mouseout", this.onMouseOut, this);
30002 btn.on("mousedown", this.onMouseDown, this);
30003 btn.on("mouseup", this.onMouseUp, this);
30005 btn.on(this.clickEvent, this.onClick, this);
30007 if(typeof this.tooltip == 'object'){
30008 Roo.QuickTips.tips(Roo.apply({
30012 btnEl.dom[this.tooltipType] = this.tooltip;
30015 if(this.arrowTooltip){
30016 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
30025 this.el.addClass("x-btn-pressed");
30027 if(Roo.isIE && !Roo.isIE7){
30028 this.autoWidth.defer(1, this);
30033 this.menu.on("show", this.onMenuShow, this);
30034 this.menu.on("hide", this.onMenuHide, this);
30036 this.fireEvent('render', this);
30040 autoWidth : function(){
30042 var tbl = this.el.child("table:first");
30043 var tbl2 = this.el.child("table:last");
30044 this.el.setWidth("auto");
30045 tbl.setWidth("auto");
30046 if(Roo.isIE7 && Roo.isStrict){
30047 var ib = this.el.child('button:first');
30048 if(ib && ib.getWidth() > 20){
30050 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
30055 this.el.beginMeasure();
30057 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
30058 tbl.setWidth(this.minWidth-tbl2.getWidth());
30061 this.el.endMeasure();
30064 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
30068 * Sets this button's click handler
30069 * @param {Function} handler The function to call when the button is clicked
30070 * @param {Object} scope (optional) Scope for the function passed above
30072 setHandler : function(handler, scope){
30073 this.handler = handler;
30074 this.scope = scope;
30078 * Sets this button's arrow click handler
30079 * @param {Function} handler The function to call when the arrow is clicked
30080 * @param {Object} scope (optional) Scope for the function passed above
30082 setArrowHandler : function(handler, scope){
30083 this.arrowHandler = handler;
30084 this.scope = scope;
30090 focus : function(){
30092 this.el.child("button:first").focus();
30097 onClick : function(e){
30098 e.preventDefault();
30099 if(!this.disabled){
30100 if(e.getTarget(".x-btn-menu-arrow-wrap")){
30101 if(this.menu && !this.menu.isVisible()){
30102 this.menu.show(this.el, this.menuAlign);
30104 this.fireEvent("arrowclick", this, e);
30105 if(this.arrowHandler){
30106 this.arrowHandler.call(this.scope || this, this, e);
30109 this.fireEvent("click", this, e);
30111 this.handler.call(this.scope || this, this, e);
30117 onMouseDown : function(e){
30118 if(!this.disabled){
30119 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
30123 onMouseUp : function(e){
30124 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
30129 // backwards compat
30130 Roo.MenuButton = Roo.SplitButton;/*
30132 * Ext JS Library 1.1.1
30133 * Copyright(c) 2006-2007, Ext JS, LLC.
30135 * Originally Released Under LGPL - original licence link has changed is not relivant.
30138 * <script type="text/javascript">
30142 * @class Roo.Toolbar
30143 * Basic Toolbar class.
30145 * Creates a new Toolbar
30146 * @param {Object} container The config object
30148 Roo.Toolbar = function(container, buttons, config)
30150 /// old consturctor format still supported..
30151 if(container instanceof Array){ // omit the container for later rendering
30152 buttons = container;
30156 if (typeof(container) == 'object' && container.xtype) {
30157 config = container;
30158 container = config.container;
30159 buttons = config.buttons || []; // not really - use items!!
30162 if (config && config.items) {
30163 xitems = config.items;
30164 delete config.items;
30166 Roo.apply(this, config);
30167 this.buttons = buttons;
30170 this.render(container);
30172 this.xitems = xitems;
30173 Roo.each(xitems, function(b) {
30179 Roo.Toolbar.prototype = {
30181 * @cfg {Array} items
30182 * array of button configs or elements to add (will be converted to a MixedCollection)
30186 * @cfg {String/HTMLElement/Element} container
30187 * The id or element that will contain the toolbar
30190 render : function(ct){
30191 this.el = Roo.get(ct);
30193 this.el.addClass(this.cls);
30195 // using a table allows for vertical alignment
30196 // 100% width is needed by Safari...
30197 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
30198 this.tr = this.el.child("tr", true);
30200 this.items = new Roo.util.MixedCollection(false, function(o){
30201 return o.id || ("item" + (++autoId));
30204 this.add.apply(this, this.buttons);
30205 delete this.buttons;
30210 * Adds element(s) to the toolbar -- this function takes a variable number of
30211 * arguments of mixed type and adds them to the toolbar.
30212 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
30214 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
30215 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
30216 * <li>Field: Any form field (equivalent to {@link #addField})</li>
30217 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
30218 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
30219 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
30220 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
30221 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
30222 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
30224 * @param {Mixed} arg2
30225 * @param {Mixed} etc.
30228 var a = arguments, l = a.length;
30229 for(var i = 0; i < l; i++){
30234 _add : function(el) {
30237 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
30240 if (el.applyTo){ // some kind of form field
30241 return this.addField(el);
30243 if (el.render){ // some kind of Toolbar.Item
30244 return this.addItem(el);
30246 if (typeof el == "string"){ // string
30247 if(el == "separator" || el == "-"){
30248 return this.addSeparator();
30251 return this.addSpacer();
30254 return this.addFill();
30256 return this.addText(el);
30259 if(el.tagName){ // element
30260 return this.addElement(el);
30262 if(typeof el == "object"){ // must be button config?
30263 return this.addButton(el);
30265 // and now what?!?!
30271 * Add an Xtype element
30272 * @param {Object} xtype Xtype Object
30273 * @return {Object} created Object
30275 addxtype : function(e){
30276 return this.add(e);
30280 * Returns the Element for this toolbar.
30281 * @return {Roo.Element}
30283 getEl : function(){
30289 * @return {Roo.Toolbar.Item} The separator item
30291 addSeparator : function(){
30292 return this.addItem(new Roo.Toolbar.Separator());
30296 * Adds a spacer element
30297 * @return {Roo.Toolbar.Spacer} The spacer item
30299 addSpacer : function(){
30300 return this.addItem(new Roo.Toolbar.Spacer());
30304 * Adds a fill element that forces subsequent additions to the right side of the toolbar
30305 * @return {Roo.Toolbar.Fill} The fill item
30307 addFill : function(){
30308 return this.addItem(new Roo.Toolbar.Fill());
30312 * Adds any standard HTML element to the toolbar
30313 * @param {String/HTMLElement/Element} el The element or id of the element to add
30314 * @return {Roo.Toolbar.Item} The element's item
30316 addElement : function(el){
30317 return this.addItem(new Roo.Toolbar.Item(el));
30320 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
30321 * @type Roo.util.MixedCollection
30326 * Adds any Toolbar.Item or subclass
30327 * @param {Roo.Toolbar.Item} item
30328 * @return {Roo.Toolbar.Item} The item
30330 addItem : function(item){
30331 var td = this.nextBlock();
30333 this.items.add(item);
30338 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
30339 * @param {Object/Array} config A button config or array of configs
30340 * @return {Roo.Toolbar.Button/Array}
30342 addButton : function(config){
30343 if(config instanceof Array){
30345 for(var i = 0, len = config.length; i < len; i++) {
30346 buttons.push(this.addButton(config[i]));
30351 if(!(config instanceof Roo.Toolbar.Button)){
30353 new Roo.Toolbar.SplitButton(config) :
30354 new Roo.Toolbar.Button(config);
30356 var td = this.nextBlock();
30363 * Adds text to the toolbar
30364 * @param {String} text The text to add
30365 * @return {Roo.Toolbar.Item} The element's item
30367 addText : function(text){
30368 return this.addItem(new Roo.Toolbar.TextItem(text));
30372 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
30373 * @param {Number} index The index where the item is to be inserted
30374 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
30375 * @return {Roo.Toolbar.Button/Item}
30377 insertButton : function(index, item){
30378 if(item instanceof Array){
30380 for(var i = 0, len = item.length; i < len; i++) {
30381 buttons.push(this.insertButton(index + i, item[i]));
30385 if (!(item instanceof Roo.Toolbar.Button)){
30386 item = new Roo.Toolbar.Button(item);
30388 var td = document.createElement("td");
30389 this.tr.insertBefore(td, this.tr.childNodes[index]);
30391 this.items.insert(index, item);
30396 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
30397 * @param {Object} config
30398 * @return {Roo.Toolbar.Item} The element's item
30400 addDom : function(config, returnEl){
30401 var td = this.nextBlock();
30402 Roo.DomHelper.overwrite(td, config);
30403 var ti = new Roo.Toolbar.Item(td.firstChild);
30405 this.items.add(ti);
30410 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
30411 * @type Roo.util.MixedCollection
30416 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
30417 * Note: the field should not have been rendered yet. For a field that has already been
30418 * rendered, use {@link #addElement}.
30419 * @param {Roo.form.Field} field
30420 * @return {Roo.ToolbarItem}
30424 addField : function(field) {
30425 if (!this.fields) {
30427 this.fields = new Roo.util.MixedCollection(false, function(o){
30428 return o.id || ("item" + (++autoId));
30433 var td = this.nextBlock();
30435 var ti = new Roo.Toolbar.Item(td.firstChild);
30437 this.items.add(ti);
30438 this.fields.add(field);
30449 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
30450 this.el.child('div').hide();
30458 this.el.child('div').show();
30462 nextBlock : function(){
30463 var td = document.createElement("td");
30464 this.tr.appendChild(td);
30469 destroy : function(){
30470 if(this.items){ // rendered?
30471 Roo.destroy.apply(Roo, this.items.items);
30473 if(this.fields){ // rendered?
30474 Roo.destroy.apply(Roo, this.fields.items);
30476 Roo.Element.uncache(this.el, this.tr);
30481 * @class Roo.Toolbar.Item
30482 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
30484 * Creates a new Item
30485 * @param {HTMLElement} el
30487 Roo.Toolbar.Item = function(el){
30489 if (typeof (el.xtype) != 'undefined') {
30494 this.el = Roo.getDom(el);
30495 this.id = Roo.id(this.el);
30496 this.hidden = false;
30501 * Fires when the button is rendered
30502 * @param {Button} this
30506 Roo.Toolbar.Item.superclass.constructor.call(this,cfg);
30508 Roo.extend(Roo.Toolbar.Item, Roo.util.Observable, {
30509 //Roo.Toolbar.Item.prototype = {
30512 * Get this item's HTML Element
30513 * @return {HTMLElement}
30515 getEl : function(){
30520 render : function(td){
30523 td.appendChild(this.el);
30525 this.fireEvent('render', this);
30529 * Removes and destroys this item.
30531 destroy : function(){
30532 this.td.parentNode.removeChild(this.td);
30539 this.hidden = false;
30540 this.td.style.display = "";
30547 this.hidden = true;
30548 this.td.style.display = "none";
30552 * Convenience function for boolean show/hide.
30553 * @param {Boolean} visible true to show/false to hide
30555 setVisible: function(visible){
30564 * Try to focus this item.
30566 focus : function(){
30567 Roo.fly(this.el).focus();
30571 * Disables this item.
30573 disable : function(){
30574 Roo.fly(this.td).addClass("x-item-disabled");
30575 this.disabled = true;
30576 this.el.disabled = true;
30580 * Enables this item.
30582 enable : function(){
30583 Roo.fly(this.td).removeClass("x-item-disabled");
30584 this.disabled = false;
30585 this.el.disabled = false;
30591 * @class Roo.Toolbar.Separator
30592 * @extends Roo.Toolbar.Item
30593 * A simple toolbar separator class
30595 * Creates a new Separator
30597 Roo.Toolbar.Separator = function(cfg){
30599 var s = document.createElement("span");
30600 s.className = "ytb-sep";
30605 Roo.Toolbar.Separator.superclass.constructor.call(this, cfg || s);
30607 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
30608 enable:Roo.emptyFn,
30609 disable:Roo.emptyFn,
30614 * @class Roo.Toolbar.Spacer
30615 * @extends Roo.Toolbar.Item
30616 * A simple element that adds extra horizontal space to a toolbar.
30618 * Creates a new Spacer
30620 Roo.Toolbar.Spacer = function(cfg){
30621 var s = document.createElement("div");
30622 s.className = "ytb-spacer";
30626 Roo.Toolbar.Spacer.superclass.constructor.call(this, cfg || s);
30628 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
30629 enable:Roo.emptyFn,
30630 disable:Roo.emptyFn,
30635 * @class Roo.Toolbar.Fill
30636 * @extends Roo.Toolbar.Spacer
30637 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
30639 * Creates a new Spacer
30641 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
30643 render : function(td){
30644 td.style.width = '100%';
30645 Roo.Toolbar.Fill.superclass.render.call(this, td);
30650 * @class Roo.Toolbar.TextItem
30651 * @extends Roo.Toolbar.Item
30652 * A simple class that renders text directly into a toolbar.
30654 * Creates a new TextItem
30655 * @cfg {string} text
30657 Roo.Toolbar.TextItem = function(cfg){
30658 var text = cfg || "";
30659 if (typeof(cfg) == 'object') {
30660 text = cfg.text || "";
30664 var s = document.createElement("span");
30665 s.className = "ytb-text";
30666 s.innerHTML = text;
30671 Roo.Toolbar.TextItem.superclass.constructor.call(this, cfg || s);
30673 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
30676 enable:Roo.emptyFn,
30677 disable:Roo.emptyFn,
30682 * @class Roo.Toolbar.Button
30683 * @extends Roo.Button
30684 * A button that renders into a toolbar.
30686 * Creates a new Button
30687 * @param {Object} config A standard {@link Roo.Button} config object
30689 Roo.Toolbar.Button = function(config){
30690 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
30692 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
30693 render : function(td){
30695 Roo.Toolbar.Button.superclass.render.call(this, td);
30699 * Removes and destroys this button
30701 destroy : function(){
30702 Roo.Toolbar.Button.superclass.destroy.call(this);
30703 this.td.parentNode.removeChild(this.td);
30707 * Shows this button
30710 this.hidden = false;
30711 this.td.style.display = "";
30715 * Hides this button
30718 this.hidden = true;
30719 this.td.style.display = "none";
30723 * Disables this item
30725 disable : function(){
30726 Roo.fly(this.td).addClass("x-item-disabled");
30727 this.disabled = true;
30731 * Enables this item
30733 enable : function(){
30734 Roo.fly(this.td).removeClass("x-item-disabled");
30735 this.disabled = false;
30738 // backwards compat
30739 Roo.ToolbarButton = Roo.Toolbar.Button;
30742 * @class Roo.Toolbar.SplitButton
30743 * @extends Roo.SplitButton
30744 * A menu button that renders into a toolbar.
30746 * Creates a new SplitButton
30747 * @param {Object} config A standard {@link Roo.SplitButton} config object
30749 Roo.Toolbar.SplitButton = function(config){
30750 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
30752 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
30753 render : function(td){
30755 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
30759 * Removes and destroys this button
30761 destroy : function(){
30762 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
30763 this.td.parentNode.removeChild(this.td);
30767 * Shows this button
30770 this.hidden = false;
30771 this.td.style.display = "";
30775 * Hides this button
30778 this.hidden = true;
30779 this.td.style.display = "none";
30783 // backwards compat
30784 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
30786 * Ext JS Library 1.1.1
30787 * Copyright(c) 2006-2007, Ext JS, LLC.
30789 * Originally Released Under LGPL - original licence link has changed is not relivant.
30792 * <script type="text/javascript">
30796 * @class Roo.PagingToolbar
30797 * @extends Roo.Toolbar
30798 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
30800 * Create a new PagingToolbar
30801 * @param {Object} config The config object
30803 Roo.PagingToolbar = function(el, ds, config)
30805 // old args format still supported... - xtype is prefered..
30806 if (typeof(el) == 'object' && el.xtype) {
30807 // created from xtype...
30809 ds = el.dataSource;
30810 el = config.container;
30813 if (config.items) {
30814 items = config.items;
30818 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
30821 this.renderButtons(this.el);
30824 // supprot items array.
30826 Roo.each(items, function(e) {
30827 this.add(Roo.factory(e));
30832 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
30834 * @cfg {Roo.data.Store} dataSource
30835 * The underlying data store providing the paged data
30838 * @cfg {String/HTMLElement/Element} container
30839 * container The id or element that will contain the toolbar
30842 * @cfg {Boolean} displayInfo
30843 * True to display the displayMsg (defaults to false)
30846 * @cfg {Number} pageSize
30847 * The number of records to display per page (defaults to 20)
30851 * @cfg {String} displayMsg
30852 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
30854 displayMsg : 'Displaying {0} - {1} of {2}',
30856 * @cfg {String} emptyMsg
30857 * The message to display when no records are found (defaults to "No data to display")
30859 emptyMsg : 'No data to display',
30861 * Customizable piece of the default paging text (defaults to "Page")
30864 beforePageText : "Page",
30866 * Customizable piece of the default paging text (defaults to "of %0")
30869 afterPageText : "of {0}",
30871 * Customizable piece of the default paging text (defaults to "First Page")
30874 firstText : "First Page",
30876 * Customizable piece of the default paging text (defaults to "Previous Page")
30879 prevText : "Previous Page",
30881 * Customizable piece of the default paging text (defaults to "Next Page")
30884 nextText : "Next Page",
30886 * Customizable piece of the default paging text (defaults to "Last Page")
30889 lastText : "Last Page",
30891 * Customizable piece of the default paging text (defaults to "Refresh")
30894 refreshText : "Refresh",
30897 renderButtons : function(el){
30898 Roo.PagingToolbar.superclass.render.call(this, el);
30899 this.first = this.addButton({
30900 tooltip: this.firstText,
30901 cls: "x-btn-icon x-grid-page-first",
30903 handler: this.onClick.createDelegate(this, ["first"])
30905 this.prev = this.addButton({
30906 tooltip: this.prevText,
30907 cls: "x-btn-icon x-grid-page-prev",
30909 handler: this.onClick.createDelegate(this, ["prev"])
30911 //this.addSeparator();
30912 this.add(this.beforePageText);
30913 this.field = Roo.get(this.addDom({
30918 cls: "x-grid-page-number"
30920 this.field.on("keydown", this.onPagingKeydown, this);
30921 this.field.on("focus", function(){this.dom.select();});
30922 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
30923 this.field.setHeight(18);
30924 //this.addSeparator();
30925 this.next = this.addButton({
30926 tooltip: this.nextText,
30927 cls: "x-btn-icon x-grid-page-next",
30929 handler: this.onClick.createDelegate(this, ["next"])
30931 this.last = this.addButton({
30932 tooltip: this.lastText,
30933 cls: "x-btn-icon x-grid-page-last",
30935 handler: this.onClick.createDelegate(this, ["last"])
30937 //this.addSeparator();
30938 this.loading = this.addButton({
30939 tooltip: this.refreshText,
30940 cls: "x-btn-icon x-grid-loading",
30941 handler: this.onClick.createDelegate(this, ["refresh"])
30944 if(this.displayInfo){
30945 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
30950 updateInfo : function(){
30951 if(this.displayEl){
30952 var count = this.ds.getCount();
30953 var msg = count == 0 ?
30957 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
30959 this.displayEl.update(msg);
30964 onLoad : function(ds, r, o){
30965 this.cursor = o.params ? o.params.start : 0;
30966 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
30968 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
30969 this.field.dom.value = ap;
30970 this.first.setDisabled(ap == 1);
30971 this.prev.setDisabled(ap == 1);
30972 this.next.setDisabled(ap == ps);
30973 this.last.setDisabled(ap == ps);
30974 this.loading.enable();
30979 getPageData : function(){
30980 var total = this.ds.getTotalCount();
30983 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
30984 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
30989 onLoadError : function(){
30990 this.loading.enable();
30994 onPagingKeydown : function(e){
30995 var k = e.getKey();
30996 var d = this.getPageData();
30998 var v = this.field.dom.value, pageNum;
30999 if(!v || isNaN(pageNum = parseInt(v, 10))){
31000 this.field.dom.value = d.activePage;
31003 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
31004 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31007 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))
31009 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
31010 this.field.dom.value = pageNum;
31011 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
31014 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
31016 var v = this.field.dom.value, pageNum;
31017 var increment = (e.shiftKey) ? 10 : 1;
31018 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN) {
31021 if(!v || isNaN(pageNum = parseInt(v, 10))) {
31022 this.field.dom.value = d.activePage;
31025 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
31027 this.field.dom.value = parseInt(v, 10) + increment;
31028 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
31029 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
31036 beforeLoad : function(){
31038 this.loading.disable();
31043 onClick : function(which){
31047 ds.load({params:{start: 0, limit: this.pageSize}});
31050 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
31053 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
31056 var total = ds.getTotalCount();
31057 var extra = total % this.pageSize;
31058 var lastStart = extra ? (total - extra) : total-this.pageSize;
31059 ds.load({params:{start: lastStart, limit: this.pageSize}});
31062 ds.load({params:{start: this.cursor, limit: this.pageSize}});
31068 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
31069 * @param {Roo.data.Store} store The data store to unbind
31071 unbind : function(ds){
31072 ds.un("beforeload", this.beforeLoad, this);
31073 ds.un("load", this.onLoad, this);
31074 ds.un("loadexception", this.onLoadError, this);
31075 ds.un("remove", this.updateInfo, this);
31076 ds.un("add", this.updateInfo, this);
31077 this.ds = undefined;
31081 * Binds the paging toolbar to the specified {@link Roo.data.Store}
31082 * @param {Roo.data.Store} store The data store to bind
31084 bind : function(ds){
31085 ds.on("beforeload", this.beforeLoad, this);
31086 ds.on("load", this.onLoad, this);
31087 ds.on("loadexception", this.onLoadError, this);
31088 ds.on("remove", this.updateInfo, this);
31089 ds.on("add", this.updateInfo, this);
31094 * Ext JS Library 1.1.1
31095 * Copyright(c) 2006-2007, Ext JS, LLC.
31097 * Originally Released Under LGPL - original licence link has changed is not relivant.
31100 * <script type="text/javascript">
31104 * @class Roo.Resizable
31105 * @extends Roo.util.Observable
31106 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
31107 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
31108 * 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
31109 * the element will be wrapped for you automatically.</p>
31110 * <p>Here is the list of valid resize handles:</p>
31113 ------ -------------------
31122 'hd' horizontal drag
31125 * <p>Here's an example showing the creation of a typical Resizable:</p>
31127 var resizer = new Roo.Resizable("element-id", {
31135 resizer.on("resize", myHandler);
31137 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
31138 * resizer.east.setDisplayed(false);</p>
31139 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
31140 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
31141 * resize operation's new size (defaults to [0, 0])
31142 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
31143 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
31144 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
31145 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
31146 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
31147 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
31148 * @cfg {Number} width The width of the element in pixels (defaults to null)
31149 * @cfg {Number} height The height of the element in pixels (defaults to null)
31150 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
31151 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
31152 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
31153 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
31154 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
31155 * in favor of the handles config option (defaults to false)
31156 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
31157 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
31158 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
31159 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
31160 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
31161 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
31162 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
31163 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
31164 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
31165 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
31166 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
31168 * Create a new resizable component
31169 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
31170 * @param {Object} config configuration options
31172 Roo.Resizable = function(el, config)
31174 this.el = Roo.get(el);
31176 if(config && config.wrap){
31177 config.resizeChild = this.el;
31178 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
31179 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
31180 this.el.setStyle("overflow", "hidden");
31181 this.el.setPositioning(config.resizeChild.getPositioning());
31182 config.resizeChild.clearPositioning();
31183 if(!config.width || !config.height){
31184 var csize = config.resizeChild.getSize();
31185 this.el.setSize(csize.width, csize.height);
31187 if(config.pinned && !config.adjustments){
31188 config.adjustments = "auto";
31192 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
31193 this.proxy.unselectable();
31194 this.proxy.enableDisplayMode('block');
31196 Roo.apply(this, config);
31199 this.disableTrackOver = true;
31200 this.el.addClass("x-resizable-pinned");
31202 // if the element isn't positioned, make it relative
31203 var position = this.el.getStyle("position");
31204 if(position != "absolute" && position != "fixed"){
31205 this.el.setStyle("position", "relative");
31207 if(!this.handles){ // no handles passed, must be legacy style
31208 this.handles = 's,e,se';
31209 if(this.multiDirectional){
31210 this.handles += ',n,w';
31213 if(this.handles == "all"){
31214 this.handles = "n s e w ne nw se sw";
31216 var hs = this.handles.split(/\s*?[,;]\s*?| /);
31217 var ps = Roo.Resizable.positions;
31218 for(var i = 0, len = hs.length; i < len; i++){
31219 if(hs[i] && ps[hs[i]]){
31220 var pos = ps[hs[i]];
31221 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
31225 this.corner = this.southeast;
31227 // updateBox = the box can move..
31228 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
31229 this.updateBox = true;
31232 this.activeHandle = null;
31234 if(this.resizeChild){
31235 if(typeof this.resizeChild == "boolean"){
31236 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
31238 this.resizeChild = Roo.get(this.resizeChild, true);
31242 if(this.adjustments == "auto"){
31243 var rc = this.resizeChild;
31244 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
31245 if(rc && (hw || hn)){
31246 rc.position("relative");
31247 rc.setLeft(hw ? hw.el.getWidth() : 0);
31248 rc.setTop(hn ? hn.el.getHeight() : 0);
31250 this.adjustments = [
31251 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
31252 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
31256 if(this.draggable){
31257 this.dd = this.dynamic ?
31258 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
31259 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
31265 * @event beforeresize
31266 * Fired before resize is allowed. Set enabled to false to cancel resize.
31267 * @param {Roo.Resizable} this
31268 * @param {Roo.EventObject} e The mousedown event
31270 "beforeresize" : true,
31273 * Fired a resizing.
31274 * @param {Roo.Resizable} this
31275 * @param {Number} x The new x position
31276 * @param {Number} y The new y position
31277 * @param {Number} w The new w width
31278 * @param {Number} h The new h hight
31279 * @param {Roo.EventObject} e The mouseup event
31284 * Fired after a resize.
31285 * @param {Roo.Resizable} this
31286 * @param {Number} width The new width
31287 * @param {Number} height The new height
31288 * @param {Roo.EventObject} e The mouseup event
31293 if(this.width !== null && this.height !== null){
31294 this.resizeTo(this.width, this.height);
31296 this.updateChildSize();
31299 this.el.dom.style.zoom = 1;
31301 Roo.Resizable.superclass.constructor.call(this);
31304 Roo.extend(Roo.Resizable, Roo.util.Observable, {
31305 resizeChild : false,
31306 adjustments : [0, 0],
31316 multiDirectional : false,
31317 disableTrackOver : false,
31318 easing : 'easeOutStrong',
31319 widthIncrement : 0,
31320 heightIncrement : 0,
31324 preserveRatio : false,
31325 transparent: false,
31331 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
31333 constrainTo: undefined,
31335 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
31337 resizeRegion: undefined,
31341 * Perform a manual resize
31342 * @param {Number} width
31343 * @param {Number} height
31345 resizeTo : function(width, height){
31346 this.el.setSize(width, height);
31347 this.updateChildSize();
31348 this.fireEvent("resize", this, width, height, null);
31352 startSizing : function(e, handle){
31353 this.fireEvent("beforeresize", this, e);
31354 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
31357 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
31358 this.overlay.unselectable();
31359 this.overlay.enableDisplayMode("block");
31360 this.overlay.on("mousemove", this.onMouseMove, this);
31361 this.overlay.on("mouseup", this.onMouseUp, this);
31363 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
31365 this.resizing = true;
31366 this.startBox = this.el.getBox();
31367 this.startPoint = e.getXY();
31368 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
31369 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
31371 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
31372 this.overlay.show();
31374 if(this.constrainTo) {
31375 var ct = Roo.get(this.constrainTo);
31376 this.resizeRegion = ct.getRegion().adjust(
31377 ct.getFrameWidth('t'),
31378 ct.getFrameWidth('l'),
31379 -ct.getFrameWidth('b'),
31380 -ct.getFrameWidth('r')
31384 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
31386 this.proxy.setBox(this.startBox);
31388 this.proxy.setStyle('visibility', 'visible');
31394 onMouseDown : function(handle, e){
31397 this.activeHandle = handle;
31398 this.startSizing(e, handle);
31403 onMouseUp : function(e){
31404 var size = this.resizeElement();
31405 this.resizing = false;
31407 this.overlay.hide();
31409 this.fireEvent("resize", this, size.width, size.height, e);
31413 updateChildSize : function(){
31415 if(this.resizeChild){
31417 var child = this.resizeChild;
31418 var adj = this.adjustments;
31419 if(el.dom.offsetWidth){
31420 var b = el.getSize(true);
31421 child.setSize(b.width+adj[0], b.height+adj[1]);
31423 // Second call here for IE
31424 // The first call enables instant resizing and
31425 // the second call corrects scroll bars if they
31428 setTimeout(function(){
31429 if(el.dom.offsetWidth){
31430 var b = el.getSize(true);
31431 child.setSize(b.width+adj[0], b.height+adj[1]);
31439 snap : function(value, inc, min){
31440 if(!inc || !value) {
31443 var newValue = value;
31444 var m = value % inc;
31447 newValue = value + (inc-m);
31449 newValue = value - m;
31452 return Math.max(min, newValue);
31456 resizeElement : function(){
31457 var box = this.proxy.getBox();
31458 if(this.updateBox){
31459 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
31461 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
31463 this.updateChildSize();
31471 constrain : function(v, diff, m, mx){
31474 }else if(v - diff > mx){
31481 onMouseMove : function(e){
31484 try{// try catch so if something goes wrong the user doesn't get hung
31486 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
31490 //var curXY = this.startPoint;
31491 var curSize = this.curSize || this.startBox;
31492 var x = this.startBox.x, y = this.startBox.y;
31493 var ox = x, oy = y;
31494 var w = curSize.width, h = curSize.height;
31495 var ow = w, oh = h;
31496 var mw = this.minWidth, mh = this.minHeight;
31497 var mxw = this.maxWidth, mxh = this.maxHeight;
31498 var wi = this.widthIncrement;
31499 var hi = this.heightIncrement;
31501 var eventXY = e.getXY();
31502 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
31503 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
31505 var pos = this.activeHandle.position;
31510 w = Math.min(Math.max(mw, w), mxw);
31515 h = Math.min(Math.max(mh, h), mxh);
31520 w = Math.min(Math.max(mw, w), mxw);
31521 h = Math.min(Math.max(mh, h), mxh);
31524 diffY = this.constrain(h, diffY, mh, mxh);
31531 var adiffX = Math.abs(diffX);
31532 var sub = (adiffX % wi); // how much
31533 if (sub > (wi/2)) { // far enough to snap
31534 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
31536 // remove difference..
31537 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
31541 x = Math.max(this.minX, x);
31544 diffX = this.constrain(w, diffX, mw, mxw);
31550 w = Math.min(Math.max(mw, w), mxw);
31551 diffY = this.constrain(h, diffY, mh, mxh);
31556 diffX = this.constrain(w, diffX, mw, mxw);
31557 diffY = this.constrain(h, diffY, mh, mxh);
31564 diffX = this.constrain(w, diffX, mw, mxw);
31566 h = Math.min(Math.max(mh, h), mxh);
31572 var sw = this.snap(w, wi, mw);
31573 var sh = this.snap(h, hi, mh);
31574 if(sw != w || sh != h){
31597 if(this.preserveRatio){
31602 h = Math.min(Math.max(mh, h), mxh);
31607 w = Math.min(Math.max(mw, w), mxw);
31612 w = Math.min(Math.max(mw, w), mxw);
31618 w = Math.min(Math.max(mw, w), mxw);
31624 h = Math.min(Math.max(mh, h), mxh);
31632 h = Math.min(Math.max(mh, h), mxh);
31642 h = Math.min(Math.max(mh, h), mxh);
31650 if (pos == 'hdrag') {
31653 this.proxy.setBounds(x, y, w, h);
31655 this.resizeElement();
31659 this.fireEvent("resizing", this, x, y, w, h, e);
31663 handleOver : function(){
31665 this.el.addClass("x-resizable-over");
31670 handleOut : function(){
31671 if(!this.resizing){
31672 this.el.removeClass("x-resizable-over");
31677 * Returns the element this component is bound to.
31678 * @return {Roo.Element}
31680 getEl : function(){
31685 * Returns the resizeChild element (or null).
31686 * @return {Roo.Element}
31688 getResizeChild : function(){
31689 return this.resizeChild;
31691 groupHandler : function()
31696 * Destroys this resizable. If the element was wrapped and
31697 * removeEl is not true then the element remains.
31698 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
31700 destroy : function(removeEl){
31701 this.proxy.remove();
31703 this.overlay.removeAllListeners();
31704 this.overlay.remove();
31706 var ps = Roo.Resizable.positions;
31708 if(typeof ps[k] != "function" && this[ps[k]]){
31709 var h = this[ps[k]];
31710 h.el.removeAllListeners();
31715 this.el.update("");
31722 // hash to map config positions to true positions
31723 Roo.Resizable.positions = {
31724 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
31729 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
31731 // only initialize the template if resizable is used
31732 var tpl = Roo.DomHelper.createTemplate(
31733 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
31736 Roo.Resizable.Handle.prototype.tpl = tpl;
31738 this.position = pos;
31740 // show north drag fro topdra
31741 var handlepos = pos == 'hdrag' ? 'north' : pos;
31743 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
31744 if (pos == 'hdrag') {
31745 this.el.setStyle('cursor', 'pointer');
31747 this.el.unselectable();
31749 this.el.setOpacity(0);
31751 this.el.on("mousedown", this.onMouseDown, this);
31752 if(!disableTrackOver){
31753 this.el.on("mouseover", this.onMouseOver, this);
31754 this.el.on("mouseout", this.onMouseOut, this);
31759 Roo.Resizable.Handle.prototype = {
31760 afterResize : function(rz){
31765 onMouseDown : function(e){
31766 this.rz.onMouseDown(this, e);
31769 onMouseOver : function(e){
31770 this.rz.handleOver(this, e);
31773 onMouseOut : function(e){
31774 this.rz.handleOut(this, e);
31778 * Ext JS Library 1.1.1
31779 * Copyright(c) 2006-2007, Ext JS, LLC.
31781 * Originally Released Under LGPL - original licence link has changed is not relivant.
31784 * <script type="text/javascript">
31788 * @class Roo.Editor
31789 * @extends Roo.Component
31790 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
31792 * Create a new Editor
31793 * @param {Roo.form.Field} field The Field object (or descendant)
31794 * @param {Object} config The config object
31796 Roo.Editor = function(field, config){
31797 Roo.Editor.superclass.constructor.call(this, config);
31798 this.field = field;
31801 * @event beforestartedit
31802 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
31803 * false from the handler of this event.
31804 * @param {Editor} this
31805 * @param {Roo.Element} boundEl The underlying element bound to this editor
31806 * @param {Mixed} value The field value being set
31808 "beforestartedit" : true,
31811 * Fires when this editor is displayed
31812 * @param {Roo.Element} boundEl The underlying element bound to this editor
31813 * @param {Mixed} value The starting field value
31815 "startedit" : true,
31817 * @event beforecomplete
31818 * Fires after a change has been made to the field, but before the change is reflected in the underlying
31819 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
31820 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
31821 * event will not fire since no edit actually occurred.
31822 * @param {Editor} this
31823 * @param {Mixed} value The current field value
31824 * @param {Mixed} startValue The original field value
31826 "beforecomplete" : true,
31829 * Fires after editing is complete and any changed value has been written to the underlying field.
31830 * @param {Editor} this
31831 * @param {Mixed} value The current field value
31832 * @param {Mixed} startValue The original field value
31836 * @event specialkey
31837 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
31838 * {@link Roo.EventObject#getKey} to determine which key was pressed.
31839 * @param {Roo.form.Field} this
31840 * @param {Roo.EventObject} e The event object
31842 "specialkey" : true
31846 Roo.extend(Roo.Editor, Roo.Component, {
31848 * @cfg {Boolean/String} autosize
31849 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
31850 * or "height" to adopt the height only (defaults to false)
31853 * @cfg {Boolean} revertInvalid
31854 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
31855 * validation fails (defaults to true)
31858 * @cfg {Boolean} ignoreNoChange
31859 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
31860 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
31861 * will never be ignored.
31864 * @cfg {Boolean} hideEl
31865 * False to keep the bound element visible while the editor is displayed (defaults to true)
31868 * @cfg {Mixed} value
31869 * The data value of the underlying field (defaults to "")
31873 * @cfg {String} alignment
31874 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
31878 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
31879 * for bottom-right shadow (defaults to "frame")
31883 * @cfg {Boolean} constrain True to constrain the editor to the viewport
31887 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
31889 completeOnEnter : false,
31891 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
31893 cancelOnEsc : false,
31895 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
31900 onRender : function(ct, position){
31901 this.el = new Roo.Layer({
31902 shadow: this.shadow,
31908 constrain: this.constrain
31910 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
31911 if(this.field.msgTarget != 'title'){
31912 this.field.msgTarget = 'qtip';
31914 this.field.render(this.el);
31916 this.field.el.dom.setAttribute('autocomplete', 'off');
31918 this.field.on("specialkey", this.onSpecialKey, this);
31919 if(this.swallowKeys){
31920 this.field.el.swallowEvent(['keydown','keypress']);
31923 this.field.on("blur", this.onBlur, this);
31924 if(this.field.grow){
31925 this.field.on("autosize", this.el.sync, this.el, {delay:1});
31929 onSpecialKey : function(field, e)
31931 //Roo.log('editor onSpecialKey');
31932 if(this.completeOnEnter && e.getKey() == e.ENTER){
31934 this.completeEdit();
31937 // do not fire special key otherwise it might hide close the editor...
31938 if(e.getKey() == e.ENTER){
31941 if(this.cancelOnEsc && e.getKey() == e.ESC){
31945 this.fireEvent('specialkey', field, e);
31950 * Starts the editing process and shows the editor.
31951 * @param {String/HTMLElement/Element} el The element to edit
31952 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
31953 * to the innerHTML of el.
31955 startEdit : function(el, value){
31957 this.completeEdit();
31959 this.boundEl = Roo.get(el);
31960 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
31961 if(!this.rendered){
31962 this.render(this.parentEl || document.body);
31964 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
31967 this.startValue = v;
31968 this.field.setValue(v);
31970 var sz = this.boundEl.getSize();
31971 switch(this.autoSize){
31973 this.setSize(sz.width, "");
31976 this.setSize("", sz.height);
31979 this.setSize(sz.width, sz.height);
31982 this.el.alignTo(this.boundEl, this.alignment);
31983 this.editing = true;
31985 Roo.QuickTips.disable();
31991 * Sets the height and width of this editor.
31992 * @param {Number} width The new width
31993 * @param {Number} height The new height
31995 setSize : function(w, h){
31996 this.field.setSize(w, h);
32003 * Realigns the editor to the bound field based on the current alignment config value.
32005 realign : function(){
32006 this.el.alignTo(this.boundEl, this.alignment);
32010 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
32011 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
32013 completeEdit : function(remainVisible){
32017 var v = this.getValue();
32018 if(this.revertInvalid !== false && !this.field.isValid()){
32019 v = this.startValue;
32020 this.cancelEdit(true);
32022 if(String(v) === String(this.startValue) && this.ignoreNoChange){
32023 this.editing = false;
32027 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
32028 this.editing = false;
32029 if(this.updateEl && this.boundEl){
32030 this.boundEl.update(v);
32032 if(remainVisible !== true){
32035 this.fireEvent("complete", this, v, this.startValue);
32040 onShow : function(){
32042 if(this.hideEl !== false){
32043 this.boundEl.hide();
32046 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
32047 this.fixIEFocus = true;
32048 this.deferredFocus.defer(50, this);
32050 this.field.focus();
32052 this.fireEvent("startedit", this.boundEl, this.startValue);
32055 deferredFocus : function(){
32057 this.field.focus();
32062 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
32063 * reverted to the original starting value.
32064 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
32065 * cancel (defaults to false)
32067 cancelEdit : function(remainVisible){
32069 this.setValue(this.startValue);
32070 if(remainVisible !== true){
32077 onBlur : function(){
32078 if(this.allowBlur !== true && this.editing){
32079 this.completeEdit();
32084 onHide : function(){
32086 this.completeEdit();
32090 if(this.field.collapse){
32091 this.field.collapse();
32094 if(this.hideEl !== false){
32095 this.boundEl.show();
32098 Roo.QuickTips.enable();
32103 * Sets the data value of the editor
32104 * @param {Mixed} value Any valid value supported by the underlying field
32106 setValue : function(v){
32107 this.field.setValue(v);
32111 * Gets the data value of the editor
32112 * @return {Mixed} The data value
32114 getValue : function(){
32115 return this.field.getValue();
32119 * Ext JS Library 1.1.1
32120 * Copyright(c) 2006-2007, Ext JS, LLC.
32122 * Originally Released Under LGPL - original licence link has changed is not relivant.
32125 * <script type="text/javascript">
32129 * @class Roo.BasicDialog
32130 * @extends Roo.util.Observable
32131 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
32133 var dlg = new Roo.BasicDialog("my-dlg", {
32142 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
32143 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
32144 dlg.addButton('Cancel', dlg.hide, dlg);
32147 <b>A Dialog should always be a direct child of the body element.</b>
32148 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
32149 * @cfg {String} title Default text to display in the title bar (defaults to null)
32150 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32151 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
32152 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
32153 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
32154 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
32155 * (defaults to null with no animation)
32156 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
32157 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
32158 * property for valid values (defaults to 'all')
32159 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
32160 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
32161 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
32162 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
32163 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
32164 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
32165 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
32166 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
32167 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
32168 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
32169 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
32170 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
32171 * draggable = true (defaults to false)
32172 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
32173 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
32174 * shadow (defaults to false)
32175 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
32176 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
32177 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
32178 * @cfg {Array} buttons Array of buttons
32179 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
32181 * Create a new BasicDialog.
32182 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
32183 * @param {Object} config Configuration options
32185 Roo.BasicDialog = function(el, config){
32186 this.el = Roo.get(el);
32187 var dh = Roo.DomHelper;
32188 if(!this.el && config && config.autoCreate){
32189 if(typeof config.autoCreate == "object"){
32190 if(!config.autoCreate.id){
32191 config.autoCreate.id = el;
32193 this.el = dh.append(document.body,
32194 config.autoCreate, true);
32196 this.el = dh.append(document.body,
32197 {tag: "div", id: el, style:'visibility:hidden;'}, true);
32201 el.setDisplayed(true);
32202 el.hide = this.hideAction;
32204 el.addClass("x-dlg");
32206 Roo.apply(this, config);
32208 this.proxy = el.createProxy("x-dlg-proxy");
32209 this.proxy.hide = this.hideAction;
32210 this.proxy.setOpacity(.5);
32214 el.setWidth(config.width);
32217 el.setHeight(config.height);
32219 this.size = el.getSize();
32220 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
32221 this.xy = [config.x,config.y];
32223 this.xy = el.getCenterXY(true);
32225 /** The header element @type Roo.Element */
32226 this.header = el.child("> .x-dlg-hd");
32227 /** The body element @type Roo.Element */
32228 this.body = el.child("> .x-dlg-bd");
32229 /** The footer element @type Roo.Element */
32230 this.footer = el.child("> .x-dlg-ft");
32233 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
32236 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
32239 this.header.unselectable();
32241 this.header.update(this.title);
32243 // this element allows the dialog to be focused for keyboard event
32244 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
32245 this.focusEl.swallowEvent("click", true);
32247 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
32249 // wrap the body and footer for special rendering
32250 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
32252 this.bwrap.dom.appendChild(this.footer.dom);
32255 this.bg = this.el.createChild({
32256 tag: "div", cls:"x-dlg-bg",
32257 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
32259 this.centerBg = this.bg.child("div.x-dlg-bg-center");
32262 if(this.autoScroll !== false && !this.autoTabs){
32263 this.body.setStyle("overflow", "auto");
32266 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
32268 if(this.closable !== false){
32269 this.el.addClass("x-dlg-closable");
32270 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
32271 this.close.on("click", this.closeClick, this);
32272 this.close.addClassOnOver("x-dlg-close-over");
32274 if(this.collapsible !== false){
32275 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
32276 this.collapseBtn.on("click", this.collapseClick, this);
32277 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
32278 this.header.on("dblclick", this.collapseClick, this);
32280 if(this.resizable !== false){
32281 this.el.addClass("x-dlg-resizable");
32282 this.resizer = new Roo.Resizable(el, {
32283 minWidth: this.minWidth || 80,
32284 minHeight:this.minHeight || 80,
32285 handles: this.resizeHandles || "all",
32288 this.resizer.on("beforeresize", this.beforeResize, this);
32289 this.resizer.on("resize", this.onResize, this);
32291 if(this.draggable !== false){
32292 el.addClass("x-dlg-draggable");
32293 if (!this.proxyDrag) {
32294 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
32297 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
32299 dd.setHandleElId(this.header.id);
32300 dd.endDrag = this.endMove.createDelegate(this);
32301 dd.startDrag = this.startMove.createDelegate(this);
32302 dd.onDrag = this.onDrag.createDelegate(this);
32307 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
32308 this.mask.enableDisplayMode("block");
32310 this.el.addClass("x-dlg-modal");
32313 this.shadow = new Roo.Shadow({
32314 mode : typeof this.shadow == "string" ? this.shadow : "sides",
32315 offset : this.shadowOffset
32318 this.shadowOffset = 0;
32320 if(Roo.useShims && this.shim !== false){
32321 this.shim = this.el.createShim();
32322 this.shim.hide = this.hideAction;
32330 if (this.buttons) {
32331 var bts= this.buttons;
32333 Roo.each(bts, function(b) {
32342 * Fires when a key is pressed
32343 * @param {Roo.BasicDialog} this
32344 * @param {Roo.EventObject} e
32349 * Fires when this dialog is moved by the user.
32350 * @param {Roo.BasicDialog} this
32351 * @param {Number} x The new page X
32352 * @param {Number} y The new page Y
32357 * Fires when this dialog is resized by the user.
32358 * @param {Roo.BasicDialog} this
32359 * @param {Number} width The new width
32360 * @param {Number} height The new height
32364 * @event beforehide
32365 * Fires before this dialog is hidden.
32366 * @param {Roo.BasicDialog} this
32368 "beforehide" : true,
32371 * Fires when this dialog is hidden.
32372 * @param {Roo.BasicDialog} this
32376 * @event beforeshow
32377 * Fires before this dialog is shown.
32378 * @param {Roo.BasicDialog} this
32380 "beforeshow" : true,
32383 * Fires when this dialog is shown.
32384 * @param {Roo.BasicDialog} this
32388 el.on("keydown", this.onKeyDown, this);
32389 el.on("mousedown", this.toFront, this);
32390 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
32392 Roo.DialogManager.register(this);
32393 Roo.BasicDialog.superclass.constructor.call(this);
32396 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
32397 shadowOffset: Roo.isIE ? 6 : 5,
32400 minButtonWidth: 75,
32401 defaultButton: null,
32402 buttonAlign: "right",
32407 * Sets the dialog title text
32408 * @param {String} text The title text to display
32409 * @return {Roo.BasicDialog} this
32411 setTitle : function(text){
32412 this.header.update(text);
32417 closeClick : function(){
32422 collapseClick : function(){
32423 this[this.collapsed ? "expand" : "collapse"]();
32427 * Collapses the dialog to its minimized state (only the title bar is visible).
32428 * Equivalent to the user clicking the collapse dialog button.
32430 collapse : function(){
32431 if(!this.collapsed){
32432 this.collapsed = true;
32433 this.el.addClass("x-dlg-collapsed");
32434 this.restoreHeight = this.el.getHeight();
32435 this.resizeTo(this.el.getWidth(), this.header.getHeight());
32440 * Expands a collapsed dialog back to its normal state. Equivalent to the user
32441 * clicking the expand dialog button.
32443 expand : function(){
32444 if(this.collapsed){
32445 this.collapsed = false;
32446 this.el.removeClass("x-dlg-collapsed");
32447 this.resizeTo(this.el.getWidth(), this.restoreHeight);
32452 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
32453 * @return {Roo.TabPanel} The tabs component
32455 initTabs : function(){
32456 var tabs = this.getTabs();
32457 while(tabs.getTab(0)){
32460 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
32462 tabs.addTab(Roo.id(dom), dom.title);
32470 beforeResize : function(){
32471 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
32475 onResize : function(){
32476 this.refreshSize();
32477 this.syncBodyHeight();
32478 this.adjustAssets();
32480 this.fireEvent("resize", this, this.size.width, this.size.height);
32484 onKeyDown : function(e){
32485 if(this.isVisible()){
32486 this.fireEvent("keydown", this, e);
32491 * Resizes the dialog.
32492 * @param {Number} width
32493 * @param {Number} height
32494 * @return {Roo.BasicDialog} this
32496 resizeTo : function(width, height){
32497 this.el.setSize(width, height);
32498 this.size = {width: width, height: height};
32499 this.syncBodyHeight();
32500 if(this.fixedcenter){
32503 if(this.isVisible()){
32504 this.constrainXY();
32505 this.adjustAssets();
32507 this.fireEvent("resize", this, width, height);
32513 * Resizes the dialog to fit the specified content size.
32514 * @param {Number} width
32515 * @param {Number} height
32516 * @return {Roo.BasicDialog} this
32518 setContentSize : function(w, h){
32519 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
32520 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
32521 //if(!this.el.isBorderBox()){
32522 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
32523 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
32526 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
32527 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
32529 this.resizeTo(w, h);
32534 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
32535 * executed in response to a particular key being pressed while the dialog is active.
32536 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
32537 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
32538 * @param {Function} fn The function to call
32539 * @param {Object} scope (optional) The scope of the function
32540 * @return {Roo.BasicDialog} this
32542 addKeyListener : function(key, fn, scope){
32543 var keyCode, shift, ctrl, alt;
32544 if(typeof key == "object" && !(key instanceof Array)){
32545 keyCode = key["key"];
32546 shift = key["shift"];
32547 ctrl = key["ctrl"];
32552 var handler = function(dlg, e){
32553 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
32554 var k = e.getKey();
32555 if(keyCode instanceof Array){
32556 for(var i = 0, len = keyCode.length; i < len; i++){
32557 if(keyCode[i] == k){
32558 fn.call(scope || window, dlg, k, e);
32564 fn.call(scope || window, dlg, k, e);
32569 this.on("keydown", handler);
32574 * Returns the TabPanel component (creates it if it doesn't exist).
32575 * Note: If you wish to simply check for the existence of tabs without creating them,
32576 * check for a null 'tabs' property.
32577 * @return {Roo.TabPanel} The tabs component
32579 getTabs : function(){
32581 this.el.addClass("x-dlg-auto-tabs");
32582 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
32583 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
32589 * Adds a button to the footer section of the dialog.
32590 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
32591 * object or a valid Roo.DomHelper element config
32592 * @param {Function} handler The function called when the button is clicked
32593 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
32594 * @return {Roo.Button} The new button
32596 addButton : function(config, handler, scope){
32597 var dh = Roo.DomHelper;
32599 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
32601 if(!this.btnContainer){
32602 var tb = this.footer.createChild({
32604 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
32605 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
32607 this.btnContainer = tb.firstChild.firstChild.firstChild;
32612 minWidth: this.minButtonWidth,
32615 if(typeof config == "string"){
32616 bconfig.text = config;
32619 bconfig.dhconfig = config;
32621 Roo.apply(bconfig, config);
32625 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
32626 bconfig.position = Math.max(0, bconfig.position);
32627 fc = this.btnContainer.childNodes[bconfig.position];
32630 var btn = new Roo.Button(
32632 this.btnContainer.insertBefore(document.createElement("td"),fc)
32633 : this.btnContainer.appendChild(document.createElement("td")),
32634 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
32637 this.syncBodyHeight();
32640 * Array of all the buttons that have been added to this dialog via addButton
32645 this.buttons.push(btn);
32650 * Sets the default button to be focused when the dialog is displayed.
32651 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
32652 * @return {Roo.BasicDialog} this
32654 setDefaultButton : function(btn){
32655 this.defaultButton = btn;
32660 getHeaderFooterHeight : function(safe){
32663 height += this.header.getHeight();
32666 var fm = this.footer.getMargins();
32667 height += (this.footer.getHeight()+fm.top+fm.bottom);
32669 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
32670 height += this.centerBg.getPadding("tb");
32675 syncBodyHeight : function()
32677 var bd = this.body, // the text
32678 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
32680 var height = this.size.height - this.getHeaderFooterHeight(false);
32681 bd.setHeight(height-bd.getMargins("tb"));
32682 var hh = this.header.getHeight();
32683 var h = this.size.height-hh;
32686 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
32687 bw.setHeight(h-cb.getPadding("tb"));
32689 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
32690 bd.setWidth(bw.getWidth(true));
32692 this.tabs.syncHeight();
32694 this.tabs.el.repaint();
32700 * Restores the previous state of the dialog if Roo.state is configured.
32701 * @return {Roo.BasicDialog} this
32703 restoreState : function(){
32704 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
32705 if(box && box.width){
32706 this.xy = [box.x, box.y];
32707 this.resizeTo(box.width, box.height);
32713 beforeShow : function(){
32715 if(this.fixedcenter){
32716 this.xy = this.el.getCenterXY(true);
32719 Roo.get(document.body).addClass("x-body-masked");
32720 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32723 this.constrainXY();
32727 animShow : function(){
32728 var b = Roo.get(this.animateTarget).getBox();
32729 this.proxy.setSize(b.width, b.height);
32730 this.proxy.setLocation(b.x, b.y);
32732 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
32733 true, .35, this.showEl.createDelegate(this));
32737 * Shows the dialog.
32738 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
32739 * @return {Roo.BasicDialog} this
32741 show : function(animateTarget){
32742 if (this.fireEvent("beforeshow", this) === false){
32745 if(this.syncHeightBeforeShow){
32746 this.syncBodyHeight();
32747 }else if(this.firstShow){
32748 this.firstShow = false;
32749 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
32751 this.animateTarget = animateTarget || this.animateTarget;
32752 if(!this.el.isVisible()){
32754 if(this.animateTarget && Roo.get(this.animateTarget)){
32764 showEl : function(){
32766 this.el.setXY(this.xy);
32768 this.adjustAssets(true);
32771 // IE peekaboo bug - fix found by Dave Fenwick
32775 this.fireEvent("show", this);
32779 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
32780 * dialog itself will receive focus.
32782 focus : function(){
32783 if(this.defaultButton){
32784 this.defaultButton.focus();
32786 this.focusEl.focus();
32791 constrainXY : function(){
32792 if(this.constraintoviewport !== false){
32793 if(!this.viewSize){
32794 if(this.container){
32795 var s = this.container.getSize();
32796 this.viewSize = [s.width, s.height];
32798 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
32801 var s = Roo.get(this.container||document).getScroll();
32803 var x = this.xy[0], y = this.xy[1];
32804 var w = this.size.width, h = this.size.height;
32805 var vw = this.viewSize[0], vh = this.viewSize[1];
32806 // only move it if it needs it
32808 // first validate right/bottom
32809 if(x + w > vw+s.left){
32813 if(y + h > vh+s.top){
32817 // then make sure top/left isn't negative
32829 if(this.isVisible()){
32830 this.el.setLocation(x, y);
32831 this.adjustAssets();
32838 onDrag : function(){
32839 if(!this.proxyDrag){
32840 this.xy = this.el.getXY();
32841 this.adjustAssets();
32846 adjustAssets : function(doShow){
32847 var x = this.xy[0], y = this.xy[1];
32848 var w = this.size.width, h = this.size.height;
32849 if(doShow === true){
32851 this.shadow.show(this.el);
32857 if(this.shadow && this.shadow.isVisible()){
32858 this.shadow.show(this.el);
32860 if(this.shim && this.shim.isVisible()){
32861 this.shim.setBounds(x, y, w, h);
32866 adjustViewport : function(w, h){
32868 w = Roo.lib.Dom.getViewWidth();
32869 h = Roo.lib.Dom.getViewHeight();
32872 this.viewSize = [w, h];
32873 if(this.modal && this.mask.isVisible()){
32874 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
32875 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
32877 if(this.isVisible()){
32878 this.constrainXY();
32883 * Destroys this dialog and all its supporting elements (including any tabs, shim,
32884 * shadow, proxy, mask, etc.) Also removes all event listeners.
32885 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
32887 destroy : function(removeEl){
32888 if(this.isVisible()){
32889 this.animateTarget = null;
32892 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
32894 this.tabs.destroy(removeEl);
32907 for(var i = 0, len = this.buttons.length; i < len; i++){
32908 this.buttons[i].destroy();
32911 this.el.removeAllListeners();
32912 if(removeEl === true){
32913 this.el.update("");
32916 Roo.DialogManager.unregister(this);
32920 startMove : function(){
32921 if(this.proxyDrag){
32924 if(this.constraintoviewport !== false){
32925 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
32930 endMove : function(){
32931 if(!this.proxyDrag){
32932 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
32934 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
32937 this.refreshSize();
32938 this.adjustAssets();
32940 this.fireEvent("move", this, this.xy[0], this.xy[1]);
32944 * Brings this dialog to the front of any other visible dialogs
32945 * @return {Roo.BasicDialog} this
32947 toFront : function(){
32948 Roo.DialogManager.bringToFront(this);
32953 * Sends this dialog to the back (under) of any other visible dialogs
32954 * @return {Roo.BasicDialog} this
32956 toBack : function(){
32957 Roo.DialogManager.sendToBack(this);
32962 * Centers this dialog in the viewport
32963 * @return {Roo.BasicDialog} this
32965 center : function(){
32966 var xy = this.el.getCenterXY(true);
32967 this.moveTo(xy[0], xy[1]);
32972 * Moves the dialog's top-left corner to the specified point
32973 * @param {Number} x
32974 * @param {Number} y
32975 * @return {Roo.BasicDialog} this
32977 moveTo : function(x, y){
32979 if(this.isVisible()){
32980 this.el.setXY(this.xy);
32981 this.adjustAssets();
32987 * Aligns the dialog to the specified element
32988 * @param {String/HTMLElement/Roo.Element} element The element to align to.
32989 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
32990 * @param {Array} offsets (optional) Offset the positioning by [x, y]
32991 * @return {Roo.BasicDialog} this
32993 alignTo : function(element, position, offsets){
32994 this.xy = this.el.getAlignToXY(element, position, offsets);
32995 if(this.isVisible()){
32996 this.el.setXY(this.xy);
32997 this.adjustAssets();
33003 * Anchors an element to another element and realigns it when the window is resized.
33004 * @param {String/HTMLElement/Roo.Element} element The element to align to.
33005 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
33006 * @param {Array} offsets (optional) Offset the positioning by [x, y]
33007 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
33008 * is a number, it is used as the buffer delay (defaults to 50ms).
33009 * @return {Roo.BasicDialog} this
33011 anchorTo : function(el, alignment, offsets, monitorScroll){
33012 var action = function(){
33013 this.alignTo(el, alignment, offsets);
33015 Roo.EventManager.onWindowResize(action, this);
33016 var tm = typeof monitorScroll;
33017 if(tm != 'undefined'){
33018 Roo.EventManager.on(window, 'scroll', action, this,
33019 {buffer: tm == 'number' ? monitorScroll : 50});
33026 * Returns true if the dialog is visible
33027 * @return {Boolean}
33029 isVisible : function(){
33030 return this.el.isVisible();
33034 animHide : function(callback){
33035 var b = Roo.get(this.animateTarget).getBox();
33037 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
33039 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
33040 this.hideEl.createDelegate(this, [callback]));
33044 * Hides the dialog.
33045 * @param {Function} callback (optional) Function to call when the dialog is hidden
33046 * @return {Roo.BasicDialog} this
33048 hide : function(callback){
33049 if (this.fireEvent("beforehide", this) === false){
33053 this.shadow.hide();
33058 // sometimes animateTarget seems to get set.. causing problems...
33059 // this just double checks..
33060 if(this.animateTarget && Roo.get(this.animateTarget)) {
33061 this.animHide(callback);
33064 this.hideEl(callback);
33070 hideEl : function(callback){
33074 Roo.get(document.body).removeClass("x-body-masked");
33076 this.fireEvent("hide", this);
33077 if(typeof callback == "function"){
33083 hideAction : function(){
33084 this.setLeft("-10000px");
33085 this.setTop("-10000px");
33086 this.setStyle("visibility", "hidden");
33090 refreshSize : function(){
33091 this.size = this.el.getSize();
33092 this.xy = this.el.getXY();
33093 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
33097 // z-index is managed by the DialogManager and may be overwritten at any time
33098 setZIndex : function(index){
33100 this.mask.setStyle("z-index", index);
33103 this.shim.setStyle("z-index", ++index);
33106 this.shadow.setZIndex(++index);
33108 this.el.setStyle("z-index", ++index);
33110 this.proxy.setStyle("z-index", ++index);
33113 this.resizer.proxy.setStyle("z-index", ++index);
33116 this.lastZIndex = index;
33120 * Returns the element for this dialog
33121 * @return {Roo.Element} The underlying dialog Element
33123 getEl : function(){
33129 * @class Roo.DialogManager
33130 * Provides global access to BasicDialogs that have been created and
33131 * support for z-indexing (layering) multiple open dialogs.
33133 Roo.DialogManager = function(){
33135 var accessList = [];
33139 var sortDialogs = function(d1, d2){
33140 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
33144 var orderDialogs = function(){
33145 accessList.sort(sortDialogs);
33146 var seed = Roo.DialogManager.zseed;
33147 for(var i = 0, len = accessList.length; i < len; i++){
33148 var dlg = accessList[i];
33150 dlg.setZIndex(seed + (i*10));
33157 * The starting z-index for BasicDialogs (defaults to 9000)
33158 * @type Number The z-index value
33163 register : function(dlg){
33164 list[dlg.id] = dlg;
33165 accessList.push(dlg);
33169 unregister : function(dlg){
33170 delete list[dlg.id];
33173 if(!accessList.indexOf){
33174 for( i = 0, len = accessList.length; i < len; i++){
33175 if(accessList[i] == dlg){
33176 accessList.splice(i, 1);
33181 i = accessList.indexOf(dlg);
33183 accessList.splice(i, 1);
33189 * Gets a registered dialog by id
33190 * @param {String/Object} id The id of the dialog or a dialog
33191 * @return {Roo.BasicDialog} this
33193 get : function(id){
33194 return typeof id == "object" ? id : list[id];
33198 * Brings the specified dialog to the front
33199 * @param {String/Object} dlg The id of the dialog or a dialog
33200 * @return {Roo.BasicDialog} this
33202 bringToFront : function(dlg){
33203 dlg = this.get(dlg);
33206 dlg._lastAccess = new Date().getTime();
33213 * Sends the specified dialog to the back
33214 * @param {String/Object} dlg The id of the dialog or a dialog
33215 * @return {Roo.BasicDialog} this
33217 sendToBack : function(dlg){
33218 dlg = this.get(dlg);
33219 dlg._lastAccess = -(new Date().getTime());
33225 * Hides all dialogs
33227 hideAll : function(){
33228 for(var id in list){
33229 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
33238 * @class Roo.LayoutDialog
33239 * @extends Roo.BasicDialog
33240 * Dialog which provides adjustments for working with a layout in a Dialog.
33241 * Add your necessary layout config options to the dialog's config.<br>
33242 * Example usage (including a nested layout):
33245 dialog = new Roo.LayoutDialog("download-dlg", {
33254 // layout config merges with the dialog config
33256 tabPosition: "top",
33257 alwaysShowTabs: true
33260 dialog.addKeyListener(27, dialog.hide, dialog);
33261 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
33262 dialog.addButton("Build It!", this.getDownload, this);
33264 // we can even add nested layouts
33265 var innerLayout = new Roo.BorderLayout("dl-inner", {
33275 innerLayout.beginUpdate();
33276 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
33277 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
33278 innerLayout.endUpdate(true);
33280 var layout = dialog.getLayout();
33281 layout.beginUpdate();
33282 layout.add("center", new Roo.ContentPanel("standard-panel",
33283 {title: "Download the Source", fitToFrame:true}));
33284 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
33285 {title: "Build your own roo.js"}));
33286 layout.getRegion("center").showPanel(sp);
33287 layout.endUpdate();
33291 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
33292 * @param {Object} config configuration options
33294 Roo.LayoutDialog = function(el, cfg){
33297 if (typeof(cfg) == 'undefined') {
33298 config = Roo.apply({}, el);
33299 // not sure why we use documentElement here.. - it should always be body.
33300 // IE7 borks horribly if we use documentElement.
33301 // webkit also does not like documentElement - it creates a body element...
33302 el = Roo.get( document.body || document.documentElement ).createChild();
33303 //config.autoCreate = true;
33307 config.autoTabs = false;
33308 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
33309 this.body.setStyle({overflow:"hidden", position:"relative"});
33310 this.layout = new Roo.BorderLayout(this.body.dom, config);
33311 this.layout.monitorWindowResize = false;
33312 this.el.addClass("x-dlg-auto-layout");
33313 // fix case when center region overwrites center function
33314 this.center = Roo.BasicDialog.prototype.center;
33315 this.on("show", this.layout.layout, this.layout, true);
33316 if (config.items) {
33317 var xitems = config.items;
33318 delete config.items;
33319 Roo.each(xitems, this.addxtype, this);
33324 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
33326 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
33329 endUpdate : function(){
33330 this.layout.endUpdate();
33334 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
33337 beginUpdate : function(){
33338 this.layout.beginUpdate();
33342 * Get the BorderLayout for this dialog
33343 * @return {Roo.BorderLayout}
33345 getLayout : function(){
33346 return this.layout;
33349 showEl : function(){
33350 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
33352 this.layout.layout();
33357 // Use the syncHeightBeforeShow config option to control this automatically
33358 syncBodyHeight : function(){
33359 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
33360 if(this.layout){this.layout.layout();}
33364 * Add an xtype element (actually adds to the layout.)
33365 * @return {Object} xdata xtype object data.
33368 addxtype : function(c) {
33369 return this.layout.addxtype(c);
33373 * Ext JS Library 1.1.1
33374 * Copyright(c) 2006-2007, Ext JS, LLC.
33376 * Originally Released Under LGPL - original licence link has changed is not relivant.
33379 * <script type="text/javascript">
33383 * @class Roo.MessageBox
33384 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
33388 Roo.Msg.alert('Status', 'Changes saved successfully.');
33390 // Prompt for user data:
33391 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
33393 // process text value...
33397 // Show a dialog using config options:
33399 title:'Save Changes?',
33400 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
33401 buttons: Roo.Msg.YESNOCANCEL,
33408 Roo.MessageBox = function(){
33409 var dlg, opt, mask, waitTimer;
33410 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
33411 var buttons, activeTextEl, bwidth;
33414 var handleButton = function(button){
33416 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
33420 var handleHide = function(){
33421 if(opt && opt.cls){
33422 dlg.el.removeClass(opt.cls);
33425 Roo.TaskMgr.stop(waitTimer);
33431 var updateButtons = function(b){
33434 buttons["ok"].hide();
33435 buttons["cancel"].hide();
33436 buttons["yes"].hide();
33437 buttons["no"].hide();
33438 dlg.footer.dom.style.display = 'none';
33441 dlg.footer.dom.style.display = '';
33442 for(var k in buttons){
33443 if(typeof buttons[k] != "function"){
33446 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
33447 width += buttons[k].el.getWidth()+15;
33457 var handleEsc = function(d, k, e){
33458 if(opt && opt.closable !== false){
33468 * Returns a reference to the underlying {@link Roo.BasicDialog} element
33469 * @return {Roo.BasicDialog} The BasicDialog element
33471 getDialog : function(){
33473 dlg = new Roo.BasicDialog("x-msg-box", {
33478 constraintoviewport:false,
33480 collapsible : false,
33483 width:400, height:100,
33484 buttonAlign:"center",
33485 closeClick : function(){
33486 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
33487 handleButton("no");
33489 handleButton("cancel");
33493 dlg.on("hide", handleHide);
33495 dlg.addKeyListener(27, handleEsc);
33497 var bt = this.buttonText;
33498 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
33499 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
33500 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
33501 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
33502 bodyEl = dlg.body.createChild({
33504 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>'
33506 msgEl = bodyEl.dom.firstChild;
33507 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
33508 textboxEl.enableDisplayMode();
33509 textboxEl.addKeyListener([10,13], function(){
33510 if(dlg.isVisible() && opt && opt.buttons){
33511 if(opt.buttons.ok){
33512 handleButton("ok");
33513 }else if(opt.buttons.yes){
33514 handleButton("yes");
33518 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
33519 textareaEl.enableDisplayMode();
33520 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
33521 progressEl.enableDisplayMode();
33522 var pf = progressEl.dom.firstChild;
33524 pp = Roo.get(pf.firstChild);
33525 pp.setHeight(pf.offsetHeight);
33533 * Updates the message box body text
33534 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
33535 * the XHTML-compliant non-breaking space character '&#160;')
33536 * @return {Roo.MessageBox} This message box
33538 updateText : function(text){
33539 if(!dlg.isVisible() && !opt.width){
33540 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
33542 msgEl.innerHTML = text || ' ';
33544 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
33545 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
33547 Math.min(opt.width || cw , this.maxWidth),
33548 Math.max(opt.minWidth || this.minWidth, bwidth)
33551 activeTextEl.setWidth(w);
33553 if(dlg.isVisible()){
33554 dlg.fixedcenter = false;
33556 // to big, make it scroll. = But as usual stupid IE does not support
33559 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
33560 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
33561 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
33563 bodyEl.dom.style.height = '';
33564 bodyEl.dom.style.overflowY = '';
33567 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
33569 bodyEl.dom.style.overflowX = '';
33572 dlg.setContentSize(w, bodyEl.getHeight());
33573 if(dlg.isVisible()){
33574 dlg.fixedcenter = true;
33580 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
33581 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
33582 * @param {Number} value Any number between 0 and 1 (e.g., .5)
33583 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
33584 * @return {Roo.MessageBox} This message box
33586 updateProgress : function(value, text){
33588 this.updateText(text);
33590 if (pp) { // weird bug on my firefox - for some reason this is not defined
33591 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
33597 * Returns true if the message box is currently displayed
33598 * @return {Boolean} True if the message box is visible, else false
33600 isVisible : function(){
33601 return dlg && dlg.isVisible();
33605 * Hides the message box if it is displayed
33608 if(this.isVisible()){
33614 * Displays a new message box, or reinitializes an existing message box, based on the config options
33615 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
33616 * The following config object properties are supported:
33618 Property Type Description
33619 ---------- --------------- ------------------------------------------------------------------------------------
33620 animEl String/Element An id or Element from which the message box should animate as it opens and
33621 closes (defaults to undefined)
33622 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
33623 cancel:'Bar'}), or false to not show any buttons (defaults to false)
33624 closable Boolean False to hide the top-right close button (defaults to true). Note that
33625 progress and wait dialogs will ignore this property and always hide the
33626 close button as they can only be closed programmatically.
33627 cls String A custom CSS class to apply to the message box element
33628 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
33629 displayed (defaults to 75)
33630 fn Function A callback function to execute after closing the dialog. The arguments to the
33631 function will be btn (the name of the button that was clicked, if applicable,
33632 e.g. "ok"), and text (the value of the active text field, if applicable).
33633 Progress and wait dialogs will ignore this option since they do not respond to
33634 user actions and can only be closed programmatically, so any required function
33635 should be called by the same code after it closes the dialog.
33636 icon String A CSS class that provides a background image to be used as an icon for
33637 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
33638 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
33639 minWidth Number The minimum width in pixels of the message box (defaults to 100)
33640 modal Boolean False to allow user interaction with the page while the message box is
33641 displayed (defaults to true)
33642 msg String A string that will replace the existing message box body text (defaults
33643 to the XHTML-compliant non-breaking space character ' ')
33644 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
33645 progress Boolean True to display a progress bar (defaults to false)
33646 progressText String The text to display inside the progress bar if progress = true (defaults to '')
33647 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
33648 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
33649 title String The title text
33650 value String The string value to set into the active textbox element if displayed
33651 wait Boolean True to display a progress bar (defaults to false)
33652 width Number The width of the dialog in pixels
33659 msg: 'Please enter your address:',
33661 buttons: Roo.MessageBox.OKCANCEL,
33664 animEl: 'addAddressBtn'
33667 * @param {Object} config Configuration options
33668 * @return {Roo.MessageBox} This message box
33670 show : function(options)
33673 // this causes nightmares if you show one dialog after another
33674 // especially on callbacks..
33676 if(this.isVisible()){
33679 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
33680 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
33681 Roo.log("New Dialog Message:" + options.msg )
33682 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
33683 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
33686 var d = this.getDialog();
33688 d.setTitle(opt.title || " ");
33689 d.close.setDisplayed(opt.closable !== false);
33690 activeTextEl = textboxEl;
33691 opt.prompt = opt.prompt || (opt.multiline ? true : false);
33696 textareaEl.setHeight(typeof opt.multiline == "number" ?
33697 opt.multiline : this.defaultTextHeight);
33698 activeTextEl = textareaEl;
33707 progressEl.setDisplayed(opt.progress === true);
33708 this.updateProgress(0);
33709 activeTextEl.dom.value = opt.value || "";
33711 dlg.setDefaultButton(activeTextEl);
33713 var bs = opt.buttons;
33716 db = buttons["ok"];
33717 }else if(bs && bs.yes){
33718 db = buttons["yes"];
33720 dlg.setDefaultButton(db);
33722 bwidth = updateButtons(opt.buttons);
33723 this.updateText(opt.msg);
33725 d.el.addClass(opt.cls);
33727 d.proxyDrag = opt.proxyDrag === true;
33728 d.modal = opt.modal !== false;
33729 d.mask = opt.modal !== false ? mask : false;
33730 if(!d.isVisible()){
33731 // force it to the end of the z-index stack so it gets a cursor in FF
33732 document.body.appendChild(dlg.el.dom);
33733 d.animateTarget = null;
33734 d.show(options.animEl);
33740 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
33741 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
33742 * and closing the message box when the process is complete.
33743 * @param {String} title The title bar text
33744 * @param {String} msg The message box body text
33745 * @return {Roo.MessageBox} This message box
33747 progress : function(title, msg){
33754 minWidth: this.minProgressWidth,
33761 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
33762 * If a callback function is passed it will be called after the user clicks the button, and the
33763 * id of the button that was clicked will be passed as the only parameter to the callback
33764 * (could also be the top-right close button).
33765 * @param {String} title The title bar text
33766 * @param {String} msg The message box body text
33767 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33768 * @param {Object} scope (optional) The scope of the callback function
33769 * @return {Roo.MessageBox} This message box
33771 alert : function(title, msg, fn, scope){
33784 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
33785 * interaction while waiting for a long-running process to complete that does not have defined intervals.
33786 * You are responsible for closing the message box when the process is complete.
33787 * @param {String} msg The message box body text
33788 * @param {String} title (optional) The title bar text
33789 * @return {Roo.MessageBox} This message box
33791 wait : function(msg, title){
33802 waitTimer = Roo.TaskMgr.start({
33804 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
33812 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
33813 * If a callback function is passed it will be called after the user clicks either button, and the id of the
33814 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
33815 * @param {String} title The title bar text
33816 * @param {String} msg The message box body text
33817 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33818 * @param {Object} scope (optional) The scope of the callback function
33819 * @return {Roo.MessageBox} This message box
33821 confirm : function(title, msg, fn, scope){
33825 buttons: this.YESNO,
33834 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
33835 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
33836 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
33837 * (could also be the top-right close button) and the text that was entered will be passed as the two
33838 * parameters to the callback.
33839 * @param {String} title The title bar text
33840 * @param {String} msg The message box body text
33841 * @param {Function} fn (optional) The callback function invoked after the message box is closed
33842 * @param {Object} scope (optional) The scope of the callback function
33843 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
33844 * property, or the height in pixels to create the textbox (defaults to false / single-line)
33845 * @return {Roo.MessageBox} This message box
33847 prompt : function(title, msg, fn, scope, multiline){
33851 buttons: this.OKCANCEL,
33856 multiline: multiline,
33863 * Button config that displays a single OK button
33868 * Button config that displays Yes and No buttons
33871 YESNO : {yes:true, no:true},
33873 * Button config that displays OK and Cancel buttons
33876 OKCANCEL : {ok:true, cancel:true},
33878 * Button config that displays Yes, No and Cancel buttons
33881 YESNOCANCEL : {yes:true, no:true, cancel:true},
33884 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
33887 defaultTextHeight : 75,
33889 * The maximum width in pixels of the message box (defaults to 600)
33894 * The minimum width in pixels of the message box (defaults to 100)
33899 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
33900 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
33903 minProgressWidth : 250,
33905 * An object containing the default button text strings that can be overriden for localized language support.
33906 * Supported properties are: ok, cancel, yes and no.
33907 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
33920 * Shorthand for {@link Roo.MessageBox}
33922 Roo.Msg = Roo.MessageBox;/*
33924 * Ext JS Library 1.1.1
33925 * Copyright(c) 2006-2007, Ext JS, LLC.
33927 * Originally Released Under LGPL - original licence link has changed is not relivant.
33930 * <script type="text/javascript">
33933 * @class Roo.QuickTips
33934 * Provides attractive and customizable tooltips for any element.
33937 Roo.QuickTips = function(){
33938 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
33939 var ce, bd, xy, dd;
33940 var visible = false, disabled = true, inited = false;
33941 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
33943 var onOver = function(e){
33947 var t = e.getTarget();
33948 if(!t || t.nodeType !== 1 || t == document || t == document.body){
33951 if(ce && t == ce.el){
33952 clearTimeout(hideProc);
33955 if(t && tagEls[t.id]){
33956 tagEls[t.id].el = t;
33957 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
33960 var ttp, et = Roo.fly(t);
33961 var ns = cfg.namespace;
33962 if(tm.interceptTitles && t.title){
33965 t.removeAttribute("title");
33966 e.preventDefault();
33968 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute) || et.getAttributeNS(cfg.alt_namespace, cfg.attribute) ;
33971 showProc = show.defer(tm.showDelay, tm, [{
33973 text: ttp.replace(/\\n/g,'<br/>'),
33974 width: et.getAttributeNS(ns, cfg.width),
33975 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
33976 title: et.getAttributeNS(ns, cfg.title),
33977 cls: et.getAttributeNS(ns, cfg.cls)
33982 var onOut = function(e){
33983 clearTimeout(showProc);
33984 var t = e.getTarget();
33985 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
33986 hideProc = setTimeout(hide, tm.hideDelay);
33990 var onMove = function(e){
33996 if(tm.trackMouse && ce){
34001 var onDown = function(e){
34002 clearTimeout(showProc);
34003 clearTimeout(hideProc);
34005 if(tm.hideOnClick){
34008 tm.enable.defer(100, tm);
34013 var getPad = function(){
34014 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
34017 var show = function(o){
34021 clearTimeout(dismissProc);
34023 if(removeCls){ // in case manually hidden
34024 el.removeClass(removeCls);
34028 el.addClass(ce.cls);
34029 removeCls = ce.cls;
34032 tipTitle.update(ce.title);
34035 tipTitle.update('');
34038 el.dom.style.width = tm.maxWidth+'px';
34039 //tipBody.dom.style.width = '';
34040 tipBodyText.update(o.text);
34041 var p = getPad(), w = ce.width;
34043 var td = tipBodyText.dom;
34044 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
34045 if(aw > tm.maxWidth){
34047 }else if(aw < tm.minWidth){
34053 //tipBody.setWidth(w);
34054 el.setWidth(parseInt(w, 10) + p);
34055 if(ce.autoHide === false){
34056 close.setDisplayed(true);
34061 close.setDisplayed(false);
34067 el.avoidY = xy[1]-18;
34072 el.setStyle("visibility", "visible");
34073 el.fadeIn({callback: afterShow});
34079 var afterShow = function(){
34083 if(tm.autoDismiss && ce.autoHide !== false){
34084 dismissProc = setTimeout(hide, tm.autoDismissDelay);
34089 var hide = function(noanim){
34090 clearTimeout(dismissProc);
34091 clearTimeout(hideProc);
34093 if(el.isVisible()){
34095 if(noanim !== true && tm.animate){
34096 el.fadeOut({callback: afterHide});
34103 var afterHide = function(){
34106 el.removeClass(removeCls);
34113 * @cfg {Number} minWidth
34114 * The minimum width of the quick tip (defaults to 40)
34118 * @cfg {Number} maxWidth
34119 * The maximum width of the quick tip (defaults to 300)
34123 * @cfg {Boolean} interceptTitles
34124 * True to automatically use the element's DOM title value if available (defaults to false)
34126 interceptTitles : false,
34128 * @cfg {Boolean} trackMouse
34129 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
34131 trackMouse : false,
34133 * @cfg {Boolean} hideOnClick
34134 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
34136 hideOnClick : true,
34138 * @cfg {Number} showDelay
34139 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
34143 * @cfg {Number} hideDelay
34144 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
34148 * @cfg {Boolean} autoHide
34149 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
34150 * Used in conjunction with hideDelay.
34155 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
34156 * (defaults to true). Used in conjunction with autoDismissDelay.
34158 autoDismiss : true,
34161 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
34163 autoDismissDelay : 5000,
34165 * @cfg {Boolean} animate
34166 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
34171 * @cfg {String} title
34172 * Title text to display (defaults to ''). This can be any valid HTML markup.
34176 * @cfg {String} text
34177 * Body text to display (defaults to ''). This can be any valid HTML markup.
34181 * @cfg {String} cls
34182 * A CSS class to apply to the base quick tip element (defaults to '').
34186 * @cfg {Number} width
34187 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
34188 * minWidth or maxWidth.
34193 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
34194 * or display QuickTips in a page.
34197 tm = Roo.QuickTips;
34198 cfg = tm.tagConfig;
34200 if(!Roo.isReady){ // allow calling of init() before onReady
34201 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
34204 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
34205 el.fxDefaults = {stopFx: true};
34206 // maximum custom styling
34207 //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>');
34208 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>');
34209 tipTitle = el.child('h3');
34210 tipTitle.enableDisplayMode("block");
34211 tipBody = el.child('div.x-tip-bd');
34212 tipBodyText = el.child('div.x-tip-bd-inner');
34213 //bdLeft = el.child('div.x-tip-bd-left');
34214 //bdRight = el.child('div.x-tip-bd-right');
34215 close = el.child('div.x-tip-close');
34216 close.enableDisplayMode("block");
34217 close.on("click", hide);
34218 var d = Roo.get(document);
34219 d.on("mousedown", onDown);
34220 d.on("mouseover", onOver);
34221 d.on("mouseout", onOut);
34222 d.on("mousemove", onMove);
34223 esc = d.addKeyListener(27, hide);
34226 dd = el.initDD("default", null, {
34227 onDrag : function(){
34231 dd.setHandleElId(tipTitle.id);
34240 * Configures a new quick tip instance and assigns it to a target element. The following config options
34243 Property Type Description
34244 ---------- --------------------- ------------------------------------------------------------------------
34245 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
34247 * @param {Object} config The config object
34249 register : function(config){
34250 var cs = config instanceof Array ? config : arguments;
34251 for(var i = 0, len = cs.length; i < len; i++) {
34253 var target = c.target;
34255 if(target instanceof Array){
34256 for(var j = 0, jlen = target.length; j < jlen; j++){
34257 tagEls[target[j]] = c;
34260 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
34267 * Removes this quick tip from its element and destroys it.
34268 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
34270 unregister : function(el){
34271 delete tagEls[Roo.id(el)];
34275 * Enable this quick tip.
34277 enable : function(){
34278 if(inited && disabled){
34280 if(locks.length < 1){
34287 * Disable this quick tip.
34289 disable : function(){
34291 clearTimeout(showProc);
34292 clearTimeout(hideProc);
34293 clearTimeout(dismissProc);
34301 * Returns true if the quick tip is enabled, else false.
34303 isEnabled : function(){
34309 namespace : "roo", // was ext?? this may break..
34310 alt_namespace : "ext",
34311 attribute : "qtip",
34321 // backwards compat
34322 Roo.QuickTips.tips = Roo.QuickTips.register;/*
34324 * Ext JS Library 1.1.1
34325 * Copyright(c) 2006-2007, Ext JS, LLC.
34327 * Originally Released Under LGPL - original licence link has changed is not relivant.
34330 * <script type="text/javascript">
34335 * @class Roo.tree.TreePanel
34336 * @extends Roo.data.Tree
34338 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
34339 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
34340 * @cfg {Boolean} enableDD true to enable drag and drop
34341 * @cfg {Boolean} enableDrag true to enable just drag
34342 * @cfg {Boolean} enableDrop true to enable just drop
34343 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
34344 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
34345 * @cfg {String} ddGroup The DD group this TreePanel belongs to
34346 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
34347 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
34348 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
34349 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
34350 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
34351 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
34352 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
34353 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
34354 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
34355 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
34356 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
34357 * @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>
34358 * @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>
34361 * @param {String/HTMLElement/Element} el The container element
34362 * @param {Object} config
34364 Roo.tree.TreePanel = function(el, config){
34366 var loader = false;
34368 root = config.root;
34369 delete config.root;
34371 if (config.loader) {
34372 loader = config.loader;
34373 delete config.loader;
34376 Roo.apply(this, config);
34377 Roo.tree.TreePanel.superclass.constructor.call(this);
34378 this.el = Roo.get(el);
34379 this.el.addClass('x-tree');
34380 //console.log(root);
34382 this.setRootNode( Roo.factory(root, Roo.tree));
34385 this.loader = Roo.factory(loader, Roo.tree);
34388 * Read-only. The id of the container element becomes this TreePanel's id.
34390 this.id = this.el.id;
34393 * @event beforeload
34394 * Fires before a node is loaded, return false to cancel
34395 * @param {Node} node The node being loaded
34397 "beforeload" : true,
34400 * Fires when a node is loaded
34401 * @param {Node} node The node that was loaded
34405 * @event textchange
34406 * Fires when the text for a node is changed
34407 * @param {Node} node The node
34408 * @param {String} text The new text
34409 * @param {String} oldText The old text
34411 "textchange" : true,
34413 * @event beforeexpand
34414 * Fires before a node is expanded, return false to cancel.
34415 * @param {Node} node The node
34416 * @param {Boolean} deep
34417 * @param {Boolean} anim
34419 "beforeexpand" : true,
34421 * @event beforecollapse
34422 * Fires before a node is collapsed, return false to cancel.
34423 * @param {Node} node The node
34424 * @param {Boolean} deep
34425 * @param {Boolean} anim
34427 "beforecollapse" : true,
34430 * Fires when a node is expanded
34431 * @param {Node} node The node
34435 * @event disabledchange
34436 * Fires when the disabled status of a node changes
34437 * @param {Node} node The node
34438 * @param {Boolean} disabled
34440 "disabledchange" : true,
34443 * Fires when a node is collapsed
34444 * @param {Node} node The node
34448 * @event beforeclick
34449 * Fires before click processing on a node. Return false to cancel the default action.
34450 * @param {Node} node The node
34451 * @param {Roo.EventObject} e The event object
34453 "beforeclick":true,
34455 * @event checkchange
34456 * Fires when a node with a checkbox's checked property changes
34457 * @param {Node} this This node
34458 * @param {Boolean} checked
34460 "checkchange":true,
34463 * Fires when a node is clicked
34464 * @param {Node} node The node
34465 * @param {Roo.EventObject} e The event object
34470 * Fires when a node is double clicked
34471 * @param {Node} node The node
34472 * @param {Roo.EventObject} e The event object
34476 * @event contextmenu
34477 * Fires when a node is right clicked
34478 * @param {Node} node The node
34479 * @param {Roo.EventObject} e The event object
34481 "contextmenu":true,
34483 * @event beforechildrenrendered
34484 * Fires right before the child nodes for a node are rendered
34485 * @param {Node} node The node
34487 "beforechildrenrendered":true,
34490 * Fires when a node starts being dragged
34491 * @param {Roo.tree.TreePanel} this
34492 * @param {Roo.tree.TreeNode} node
34493 * @param {event} e The raw browser event
34495 "startdrag" : true,
34498 * Fires when a drag operation is complete
34499 * @param {Roo.tree.TreePanel} this
34500 * @param {Roo.tree.TreeNode} node
34501 * @param {event} e The raw browser event
34506 * Fires when a dragged node is dropped on a valid DD target
34507 * @param {Roo.tree.TreePanel} this
34508 * @param {Roo.tree.TreeNode} node
34509 * @param {DD} dd The dd it was dropped on
34510 * @param {event} e The raw browser event
34514 * @event beforenodedrop
34515 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
34516 * passed to handlers has the following properties:<br />
34517 * <ul style="padding:5px;padding-left:16px;">
34518 * <li>tree - The TreePanel</li>
34519 * <li>target - The node being targeted for the drop</li>
34520 * <li>data - The drag data from the drag source</li>
34521 * <li>point - The point of the drop - append, above or below</li>
34522 * <li>source - The drag source</li>
34523 * <li>rawEvent - Raw mouse event</li>
34524 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
34525 * to be inserted by setting them on this object.</li>
34526 * <li>cancel - Set this to true to cancel the drop.</li>
34528 * @param {Object} dropEvent
34530 "beforenodedrop" : true,
34533 * Fires after a DD object is dropped on a node in this tree. The dropEvent
34534 * passed to handlers has the following properties:<br />
34535 * <ul style="padding:5px;padding-left:16px;">
34536 * <li>tree - The TreePanel</li>
34537 * <li>target - The node being targeted for the drop</li>
34538 * <li>data - The drag data from the drag source</li>
34539 * <li>point - The point of the drop - append, above or below</li>
34540 * <li>source - The drag source</li>
34541 * <li>rawEvent - Raw mouse event</li>
34542 * <li>dropNode - Dropped node(s).</li>
34544 * @param {Object} dropEvent
34548 * @event nodedragover
34549 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
34550 * passed to handlers has the following properties:<br />
34551 * <ul style="padding:5px;padding-left:16px;">
34552 * <li>tree - The TreePanel</li>
34553 * <li>target - The node being targeted for the drop</li>
34554 * <li>data - The drag data from the drag source</li>
34555 * <li>point - The point of the drop - append, above or below</li>
34556 * <li>source - The drag source</li>
34557 * <li>rawEvent - Raw mouse event</li>
34558 * <li>dropNode - Drop node(s) provided by the source.</li>
34559 * <li>cancel - Set this to true to signal drop not allowed.</li>
34561 * @param {Object} dragOverEvent
34563 "nodedragover" : true,
34565 * @event appendnode
34566 * Fires when append node to the tree
34567 * @param {Roo.tree.TreePanel} this
34568 * @param {Roo.tree.TreeNode} node
34569 * @param {Number} index The index of the newly appended node
34571 "appendnode" : true
34574 if(this.singleExpand){
34575 this.on("beforeexpand", this.restrictExpand, this);
34578 this.editor.tree = this;
34579 this.editor = Roo.factory(this.editor, Roo.tree);
34582 if (this.selModel) {
34583 this.selModel = Roo.factory(this.selModel, Roo.tree);
34587 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
34588 rootVisible : true,
34589 animate: Roo.enableFx,
34592 hlDrop : Roo.enableFx,
34596 rendererTip: false,
34598 restrictExpand : function(node){
34599 var p = node.parentNode;
34601 if(p.expandedChild && p.expandedChild.parentNode == p){
34602 p.expandedChild.collapse();
34604 p.expandedChild = node;
34608 // private override
34609 setRootNode : function(node){
34610 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
34611 if(!this.rootVisible){
34612 node.ui = new Roo.tree.RootTreeNodeUI(node);
34618 * Returns the container element for this TreePanel
34620 getEl : function(){
34625 * Returns the default TreeLoader for this TreePanel
34627 getLoader : function(){
34628 return this.loader;
34634 expandAll : function(){
34635 this.root.expand(true);
34639 * Collapse all nodes
34641 collapseAll : function(){
34642 this.root.collapse(true);
34646 * Returns the selection model used by this TreePanel
34648 getSelectionModel : function(){
34649 if(!this.selModel){
34650 this.selModel = new Roo.tree.DefaultSelectionModel();
34652 return this.selModel;
34656 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
34657 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
34658 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
34661 getChecked : function(a, startNode){
34662 startNode = startNode || this.root;
34664 var f = function(){
34665 if(this.attributes.checked){
34666 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
34669 startNode.cascade(f);
34674 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34675 * @param {String} path
34676 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34677 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
34678 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
34680 expandPath : function(path, attr, callback){
34681 attr = attr || "id";
34682 var keys = path.split(this.pathSeparator);
34683 var curNode = this.root;
34684 if(curNode.attributes[attr] != keys[1]){ // invalid root
34686 callback(false, null);
34691 var f = function(){
34692 if(++index == keys.length){
34694 callback(true, curNode);
34698 var c = curNode.findChild(attr, keys[index]);
34701 callback(false, curNode);
34706 c.expand(false, false, f);
34708 curNode.expand(false, false, f);
34712 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
34713 * @param {String} path
34714 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
34715 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
34716 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
34718 selectPath : function(path, attr, callback){
34719 attr = attr || "id";
34720 var keys = path.split(this.pathSeparator);
34721 var v = keys.pop();
34722 if(keys.length > 0){
34723 var f = function(success, node){
34724 if(success && node){
34725 var n = node.findChild(attr, v);
34731 }else if(callback){
34732 callback(false, n);
34736 callback(false, n);
34740 this.expandPath(keys.join(this.pathSeparator), attr, f);
34742 this.root.select();
34744 callback(true, this.root);
34749 getTreeEl : function(){
34754 * Trigger rendering of this TreePanel
34756 render : function(){
34757 if (this.innerCt) {
34758 return this; // stop it rendering more than once!!
34761 this.innerCt = this.el.createChild({tag:"ul",
34762 cls:"x-tree-root-ct " +
34763 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
34765 if(this.containerScroll){
34766 Roo.dd.ScrollManager.register(this.el);
34768 if((this.enableDD || this.enableDrop) && !this.dropZone){
34770 * The dropZone used by this tree if drop is enabled
34771 * @type Roo.tree.TreeDropZone
34773 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
34774 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
34777 if((this.enableDD || this.enableDrag) && !this.dragZone){
34779 * The dragZone used by this tree if drag is enabled
34780 * @type Roo.tree.TreeDragZone
34782 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
34783 ddGroup: this.ddGroup || "TreeDD",
34784 scroll: this.ddScroll
34787 this.getSelectionModel().init(this);
34789 Roo.log("ROOT not set in tree");
34792 this.root.render();
34793 if(!this.rootVisible){
34794 this.root.renderChildren();
34800 * Ext JS Library 1.1.1
34801 * Copyright(c) 2006-2007, Ext JS, LLC.
34803 * Originally Released Under LGPL - original licence link has changed is not relivant.
34806 * <script type="text/javascript">
34811 * @class Roo.tree.DefaultSelectionModel
34812 * @extends Roo.util.Observable
34813 * The default single selection for a TreePanel.
34814 * @param {Object} cfg Configuration
34816 Roo.tree.DefaultSelectionModel = function(cfg){
34817 this.selNode = null;
34823 * @event selectionchange
34824 * Fires when the selected node changes
34825 * @param {DefaultSelectionModel} this
34826 * @param {TreeNode} node the new selection
34828 "selectionchange" : true,
34831 * @event beforeselect
34832 * Fires before the selected node changes, return false to cancel the change
34833 * @param {DefaultSelectionModel} this
34834 * @param {TreeNode} node the new selection
34835 * @param {TreeNode} node the old selection
34837 "beforeselect" : true
34840 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
34843 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
34844 init : function(tree){
34846 tree.getTreeEl().on("keydown", this.onKeyDown, this);
34847 tree.on("click", this.onNodeClick, this);
34850 onNodeClick : function(node, e){
34851 if (e.ctrlKey && this.selNode == node) {
34852 this.unselect(node);
34860 * @param {TreeNode} node The node to select
34861 * @return {TreeNode} The selected node
34863 select : function(node){
34864 var last = this.selNode;
34865 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
34867 last.ui.onSelectedChange(false);
34869 this.selNode = node;
34870 node.ui.onSelectedChange(true);
34871 this.fireEvent("selectionchange", this, node, last);
34878 * @param {TreeNode} node The node to unselect
34880 unselect : function(node){
34881 if(this.selNode == node){
34882 this.clearSelections();
34887 * Clear all selections
34889 clearSelections : function(){
34890 var n = this.selNode;
34892 n.ui.onSelectedChange(false);
34893 this.selNode = null;
34894 this.fireEvent("selectionchange", this, null);
34900 * Get the selected node
34901 * @return {TreeNode} The selected node
34903 getSelectedNode : function(){
34904 return this.selNode;
34908 * Returns true if the node is selected
34909 * @param {TreeNode} node The node to check
34910 * @return {Boolean}
34912 isSelected : function(node){
34913 return this.selNode == node;
34917 * Selects the node above the selected node in the tree, intelligently walking the nodes
34918 * @return TreeNode The new selection
34920 selectPrevious : function(){
34921 var s = this.selNode || this.lastSelNode;
34925 var ps = s.previousSibling;
34927 if(!ps.isExpanded() || ps.childNodes.length < 1){
34928 return this.select(ps);
34930 var lc = ps.lastChild;
34931 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
34934 return this.select(lc);
34936 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
34937 return this.select(s.parentNode);
34943 * Selects the node above the selected node in the tree, intelligently walking the nodes
34944 * @return TreeNode The new selection
34946 selectNext : function(){
34947 var s = this.selNode || this.lastSelNode;
34951 if(s.firstChild && s.isExpanded()){
34952 return this.select(s.firstChild);
34953 }else if(s.nextSibling){
34954 return this.select(s.nextSibling);
34955 }else if(s.parentNode){
34957 s.parentNode.bubble(function(){
34958 if(this.nextSibling){
34959 newS = this.getOwnerTree().selModel.select(this.nextSibling);
34968 onKeyDown : function(e){
34969 var s = this.selNode || this.lastSelNode;
34970 // undesirable, but required
34975 var k = e.getKey();
34983 this.selectPrevious();
34986 e.preventDefault();
34987 if(s.hasChildNodes()){
34988 if(!s.isExpanded()){
34990 }else if(s.firstChild){
34991 this.select(s.firstChild, e);
34996 e.preventDefault();
34997 if(s.hasChildNodes() && s.isExpanded()){
34999 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
35000 this.select(s.parentNode, e);
35008 * @class Roo.tree.MultiSelectionModel
35009 * @extends Roo.util.Observable
35010 * Multi selection for a TreePanel.
35011 * @param {Object} cfg Configuration
35013 Roo.tree.MultiSelectionModel = function(){
35014 this.selNodes = [];
35018 * @event selectionchange
35019 * Fires when the selected nodes change
35020 * @param {MultiSelectionModel} this
35021 * @param {Array} nodes Array of the selected nodes
35023 "selectionchange" : true
35025 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
35029 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
35030 init : function(tree){
35032 tree.getTreeEl().on("keydown", this.onKeyDown, this);
35033 tree.on("click", this.onNodeClick, this);
35036 onNodeClick : function(node, e){
35037 this.select(node, e, e.ctrlKey);
35042 * @param {TreeNode} node The node to select
35043 * @param {EventObject} e (optional) An event associated with the selection
35044 * @param {Boolean} keepExisting True to retain existing selections
35045 * @return {TreeNode} The selected node
35047 select : function(node, e, keepExisting){
35048 if(keepExisting !== true){
35049 this.clearSelections(true);
35051 if(this.isSelected(node)){
35052 this.lastSelNode = node;
35055 this.selNodes.push(node);
35056 this.selMap[node.id] = node;
35057 this.lastSelNode = node;
35058 node.ui.onSelectedChange(true);
35059 this.fireEvent("selectionchange", this, this.selNodes);
35065 * @param {TreeNode} node The node to unselect
35067 unselect : function(node){
35068 if(this.selMap[node.id]){
35069 node.ui.onSelectedChange(false);
35070 var sn = this.selNodes;
35073 index = sn.indexOf(node);
35075 for(var i = 0, len = sn.length; i < len; i++){
35083 this.selNodes.splice(index, 1);
35085 delete this.selMap[node.id];
35086 this.fireEvent("selectionchange", this, this.selNodes);
35091 * Clear all selections
35093 clearSelections : function(suppressEvent){
35094 var sn = this.selNodes;
35096 for(var i = 0, len = sn.length; i < len; i++){
35097 sn[i].ui.onSelectedChange(false);
35099 this.selNodes = [];
35101 if(suppressEvent !== true){
35102 this.fireEvent("selectionchange", this, this.selNodes);
35108 * Returns true if the node is selected
35109 * @param {TreeNode} node The node to check
35110 * @return {Boolean}
35112 isSelected : function(node){
35113 return this.selMap[node.id] ? true : false;
35117 * Returns an array of the selected nodes
35120 getSelectedNodes : function(){
35121 return this.selNodes;
35124 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
35126 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
35128 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
35131 * Ext JS Library 1.1.1
35132 * Copyright(c) 2006-2007, Ext JS, LLC.
35134 * Originally Released Under LGPL - original licence link has changed is not relivant.
35137 * <script type="text/javascript">
35141 * @class Roo.tree.TreeNode
35142 * @extends Roo.data.Node
35143 * @cfg {String} text The text for this node
35144 * @cfg {Boolean} expanded true to start the node expanded
35145 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
35146 * @cfg {Boolean} allowDrop false if this node cannot be drop on
35147 * @cfg {Boolean} disabled true to start the node disabled
35148 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
35149 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
35150 * @cfg {String} cls A css class to be added to the node
35151 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
35152 * @cfg {String} href URL of the link used for the node (defaults to #)
35153 * @cfg {String} hrefTarget target frame for the link
35154 * @cfg {String} qtip An Ext QuickTip for the node
35155 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
35156 * @cfg {Boolean} singleClickExpand True for single click expand on this node
35157 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
35158 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
35159 * (defaults to undefined with no checkbox rendered)
35161 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35163 Roo.tree.TreeNode = function(attributes){
35164 attributes = attributes || {};
35165 if(typeof attributes == "string"){
35166 attributes = {text: attributes};
35168 this.childrenRendered = false;
35169 this.rendered = false;
35170 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
35171 this.expanded = attributes.expanded === true;
35172 this.isTarget = attributes.isTarget !== false;
35173 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
35174 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
35177 * Read-only. The text for this node. To change it use setText().
35180 this.text = attributes.text;
35182 * True if this node is disabled.
35185 this.disabled = attributes.disabled === true;
35189 * @event textchange
35190 * Fires when the text for this node is changed
35191 * @param {Node} this This node
35192 * @param {String} text The new text
35193 * @param {String} oldText The old text
35195 "textchange" : true,
35197 * @event beforeexpand
35198 * Fires before this node is expanded, return false to cancel.
35199 * @param {Node} this This node
35200 * @param {Boolean} deep
35201 * @param {Boolean} anim
35203 "beforeexpand" : true,
35205 * @event beforecollapse
35206 * Fires before this node is collapsed, return false to cancel.
35207 * @param {Node} this This node
35208 * @param {Boolean} deep
35209 * @param {Boolean} anim
35211 "beforecollapse" : true,
35214 * Fires when this node is expanded
35215 * @param {Node} this This node
35219 * @event disabledchange
35220 * Fires when the disabled status of this node changes
35221 * @param {Node} this This node
35222 * @param {Boolean} disabled
35224 "disabledchange" : true,
35227 * Fires when this node is collapsed
35228 * @param {Node} this This node
35232 * @event beforeclick
35233 * Fires before click processing. Return false to cancel the default action.
35234 * @param {Node} this This node
35235 * @param {Roo.EventObject} e The event object
35237 "beforeclick":true,
35239 * @event checkchange
35240 * Fires when a node with a checkbox's checked property changes
35241 * @param {Node} this This node
35242 * @param {Boolean} checked
35244 "checkchange":true,
35247 * Fires when this node is clicked
35248 * @param {Node} this This node
35249 * @param {Roo.EventObject} e The event object
35254 * Fires when this node is double clicked
35255 * @param {Node} this This node
35256 * @param {Roo.EventObject} e The event object
35260 * @event contextmenu
35261 * Fires when this node is right clicked
35262 * @param {Node} this This node
35263 * @param {Roo.EventObject} e The event object
35265 "contextmenu":true,
35267 * @event beforechildrenrendered
35268 * Fires right before the child nodes for this node are rendered
35269 * @param {Node} this This node
35271 "beforechildrenrendered":true
35274 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
35277 * Read-only. The UI for this node
35280 this.ui = new uiClass(this);
35282 // finally support items[]
35283 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
35288 Roo.each(this.attributes.items, function(c) {
35289 this.appendChild(Roo.factory(c,Roo.Tree));
35291 delete this.attributes.items;
35296 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
35297 preventHScroll: true,
35299 * Returns true if this node is expanded
35300 * @return {Boolean}
35302 isExpanded : function(){
35303 return this.expanded;
35307 * Returns the UI object for this node
35308 * @return {TreeNodeUI}
35310 getUI : function(){
35314 // private override
35315 setFirstChild : function(node){
35316 var of = this.firstChild;
35317 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
35318 if(this.childrenRendered && of && node != of){
35319 of.renderIndent(true, true);
35322 this.renderIndent(true, true);
35326 // private override
35327 setLastChild : function(node){
35328 var ol = this.lastChild;
35329 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
35330 if(this.childrenRendered && ol && node != ol){
35331 ol.renderIndent(true, true);
35334 this.renderIndent(true, true);
35338 // these methods are overridden to provide lazy rendering support
35339 // private override
35340 appendChild : function()
35342 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
35343 if(node && this.childrenRendered){
35346 this.ui.updateExpandIcon();
35350 // private override
35351 removeChild : function(node){
35352 this.ownerTree.getSelectionModel().unselect(node);
35353 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
35354 // if it's been rendered remove dom node
35355 if(this.childrenRendered){
35358 if(this.childNodes.length < 1){
35359 this.collapse(false, false);
35361 this.ui.updateExpandIcon();
35363 if(!this.firstChild) {
35364 this.childrenRendered = false;
35369 // private override
35370 insertBefore : function(node, refNode){
35371 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
35372 if(newNode && refNode && this.childrenRendered){
35375 this.ui.updateExpandIcon();
35380 * Sets the text for this node
35381 * @param {String} text
35383 setText : function(text){
35384 var oldText = this.text;
35386 this.attributes.text = text;
35387 if(this.rendered){ // event without subscribing
35388 this.ui.onTextChange(this, text, oldText);
35390 this.fireEvent("textchange", this, text, oldText);
35394 * Triggers selection of this node
35396 select : function(){
35397 this.getOwnerTree().getSelectionModel().select(this);
35401 * Triggers deselection of this node
35403 unselect : function(){
35404 this.getOwnerTree().getSelectionModel().unselect(this);
35408 * Returns true if this node is selected
35409 * @return {Boolean}
35411 isSelected : function(){
35412 return this.getOwnerTree().getSelectionModel().isSelected(this);
35416 * Expand this node.
35417 * @param {Boolean} deep (optional) True to expand all children as well
35418 * @param {Boolean} anim (optional) false to cancel the default animation
35419 * @param {Function} callback (optional) A callback to be called when
35420 * expanding this node completes (does not wait for deep expand to complete).
35421 * Called with 1 parameter, this node.
35423 expand : function(deep, anim, callback){
35424 if(!this.expanded){
35425 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
35428 if(!this.childrenRendered){
35429 this.renderChildren();
35431 this.expanded = true;
35433 if(!this.isHiddenRoot() && (this.getOwnerTree() && this.getOwnerTree().animate && anim !== false) || anim){
35434 this.ui.animExpand(function(){
35435 this.fireEvent("expand", this);
35436 if(typeof callback == "function"){
35440 this.expandChildNodes(true);
35442 }.createDelegate(this));
35446 this.fireEvent("expand", this);
35447 if(typeof callback == "function"){
35452 if(typeof callback == "function"){
35457 this.expandChildNodes(true);
35461 isHiddenRoot : function(){
35462 return this.isRoot && !this.getOwnerTree().rootVisible;
35466 * Collapse this node.
35467 * @param {Boolean} deep (optional) True to collapse all children as well
35468 * @param {Boolean} anim (optional) false to cancel the default animation
35470 collapse : function(deep, anim){
35471 if(this.expanded && !this.isHiddenRoot()){
35472 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
35475 this.expanded = false;
35476 if((this.getOwnerTree().animate && anim !== false) || anim){
35477 this.ui.animCollapse(function(){
35478 this.fireEvent("collapse", this);
35480 this.collapseChildNodes(true);
35482 }.createDelegate(this));
35485 this.ui.collapse();
35486 this.fireEvent("collapse", this);
35490 var cs = this.childNodes;
35491 for(var i = 0, len = cs.length; i < len; i++) {
35492 cs[i].collapse(true, false);
35498 delayedExpand : function(delay){
35499 if(!this.expandProcId){
35500 this.expandProcId = this.expand.defer(delay, this);
35505 cancelExpand : function(){
35506 if(this.expandProcId){
35507 clearTimeout(this.expandProcId);
35509 this.expandProcId = false;
35513 * Toggles expanded/collapsed state of the node
35515 toggle : function(){
35524 * Ensures all parent nodes are expanded
35526 ensureVisible : function(callback){
35527 var tree = this.getOwnerTree();
35528 tree.expandPath(this.parentNode.getPath(), false, function(){
35529 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
35530 Roo.callback(callback);
35531 }.createDelegate(this));
35535 * Expand all child nodes
35536 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
35538 expandChildNodes : function(deep){
35539 var cs = this.childNodes;
35540 for(var i = 0, len = cs.length; i < len; i++) {
35541 cs[i].expand(deep);
35546 * Collapse all child nodes
35547 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
35549 collapseChildNodes : function(deep){
35550 var cs = this.childNodes;
35551 for(var i = 0, len = cs.length; i < len; i++) {
35552 cs[i].collapse(deep);
35557 * Disables this node
35559 disable : function(){
35560 this.disabled = true;
35562 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35563 this.ui.onDisableChange(this, true);
35565 this.fireEvent("disabledchange", this, true);
35569 * Enables this node
35571 enable : function(){
35572 this.disabled = false;
35573 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
35574 this.ui.onDisableChange(this, false);
35576 this.fireEvent("disabledchange", this, false);
35580 renderChildren : function(suppressEvent){
35581 if(suppressEvent !== false){
35582 this.fireEvent("beforechildrenrendered", this);
35584 var cs = this.childNodes;
35585 for(var i = 0, len = cs.length; i < len; i++){
35586 cs[i].render(true);
35588 this.childrenRendered = true;
35592 sort : function(fn, scope){
35593 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
35594 if(this.childrenRendered){
35595 var cs = this.childNodes;
35596 for(var i = 0, len = cs.length; i < len; i++){
35597 cs[i].render(true);
35603 render : function(bulkRender){
35604 this.ui.render(bulkRender);
35605 if(!this.rendered){
35606 this.rendered = true;
35608 this.expanded = false;
35609 this.expand(false, false);
35615 renderIndent : function(deep, refresh){
35617 this.ui.childIndent = null;
35619 this.ui.renderIndent();
35620 if(deep === true && this.childrenRendered){
35621 var cs = this.childNodes;
35622 for(var i = 0, len = cs.length; i < len; i++){
35623 cs[i].renderIndent(true, refresh);
35629 * Ext JS Library 1.1.1
35630 * Copyright(c) 2006-2007, Ext JS, LLC.
35632 * Originally Released Under LGPL - original licence link has changed is not relivant.
35635 * <script type="text/javascript">
35639 * @class Roo.tree.AsyncTreeNode
35640 * @extends Roo.tree.TreeNode
35641 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
35643 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
35645 Roo.tree.AsyncTreeNode = function(config){
35646 this.loaded = false;
35647 this.loading = false;
35648 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
35650 * @event beforeload
35651 * Fires before this node is loaded, return false to cancel
35652 * @param {Node} this This node
35654 this.addEvents({'beforeload':true, 'load': true});
35657 * Fires when this node is loaded
35658 * @param {Node} this This node
35661 * The loader used by this node (defaults to using the tree's defined loader)
35666 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
35667 expand : function(deep, anim, callback){
35668 if(this.loading){ // if an async load is already running, waiting til it's done
35670 var f = function(){
35671 if(!this.loading){ // done loading
35672 clearInterval(timer);
35673 this.expand(deep, anim, callback);
35675 }.createDelegate(this);
35676 timer = setInterval(f, 200);
35680 if(this.fireEvent("beforeload", this) === false){
35683 this.loading = true;
35684 this.ui.beforeLoad(this);
35685 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
35687 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
35691 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
35695 * Returns true if this node is currently loading
35696 * @return {Boolean}
35698 isLoading : function(){
35699 return this.loading;
35702 loadComplete : function(deep, anim, callback){
35703 this.loading = false;
35704 this.loaded = true;
35705 this.ui.afterLoad(this);
35706 this.fireEvent("load", this);
35707 this.expand(deep, anim, callback);
35711 * Returns true if this node has been loaded
35712 * @return {Boolean}
35714 isLoaded : function(){
35715 return this.loaded;
35718 hasChildNodes : function(){
35719 if(!this.isLeaf() && !this.loaded){
35722 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
35727 * Trigger a reload for this node
35728 * @param {Function} callback
35730 reload : function(callback){
35731 this.collapse(false, false);
35732 while(this.firstChild){
35733 this.removeChild(this.firstChild);
35735 this.childrenRendered = false;
35736 this.loaded = false;
35737 if(this.isHiddenRoot()){
35738 this.expanded = false;
35740 this.expand(false, false, callback);
35744 * Ext JS Library 1.1.1
35745 * Copyright(c) 2006-2007, Ext JS, LLC.
35747 * Originally Released Under LGPL - original licence link has changed is not relivant.
35750 * <script type="text/javascript">
35754 * @class Roo.tree.TreeNodeUI
35756 * @param {Object} node The node to render
35757 * The TreeNode UI implementation is separate from the
35758 * tree implementation. Unless you are customizing the tree UI,
35759 * you should never have to use this directly.
35761 Roo.tree.TreeNodeUI = function(node){
35763 this.rendered = false;
35764 this.animating = false;
35765 this.emptyIcon = Roo.BLANK_IMAGE_URL;
35768 Roo.tree.TreeNodeUI.prototype = {
35769 removeChild : function(node){
35771 this.ctNode.removeChild(node.ui.getEl());
35775 beforeLoad : function(){
35776 this.addClass("x-tree-node-loading");
35779 afterLoad : function(){
35780 this.removeClass("x-tree-node-loading");
35783 onTextChange : function(node, text, oldText){
35785 this.textNode.innerHTML = text;
35789 onDisableChange : function(node, state){
35790 this.disabled = state;
35792 this.addClass("x-tree-node-disabled");
35794 this.removeClass("x-tree-node-disabled");
35798 onSelectedChange : function(state){
35801 this.addClass("x-tree-selected");
35804 this.removeClass("x-tree-selected");
35808 onMove : function(tree, node, oldParent, newParent, index, refNode){
35809 this.childIndent = null;
35811 var targetNode = newParent.ui.getContainer();
35812 if(!targetNode){//target not rendered
35813 this.holder = document.createElement("div");
35814 this.holder.appendChild(this.wrap);
35817 var insertBefore = refNode ? refNode.ui.getEl() : null;
35819 targetNode.insertBefore(this.wrap, insertBefore);
35821 targetNode.appendChild(this.wrap);
35823 this.node.renderIndent(true);
35827 addClass : function(cls){
35829 Roo.fly(this.elNode).addClass(cls);
35833 removeClass : function(cls){
35835 Roo.fly(this.elNode).removeClass(cls);
35839 remove : function(){
35841 this.holder = document.createElement("div");
35842 this.holder.appendChild(this.wrap);
35846 fireEvent : function(){
35847 return this.node.fireEvent.apply(this.node, arguments);
35850 initEvents : function(){
35851 this.node.on("move", this.onMove, this);
35852 var E = Roo.EventManager;
35853 var a = this.anchor;
35855 var el = Roo.fly(a, '_treeui');
35857 if(Roo.isOpera){ // opera render bug ignores the CSS
35858 el.setStyle("text-decoration", "none");
35861 el.on("click", this.onClick, this);
35862 el.on("dblclick", this.onDblClick, this);
35865 Roo.EventManager.on(this.checkbox,
35866 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
35869 el.on("contextmenu", this.onContextMenu, this);
35871 var icon = Roo.fly(this.iconNode);
35872 icon.on("click", this.onClick, this);
35873 icon.on("dblclick", this.onDblClick, this);
35874 icon.on("contextmenu", this.onContextMenu, this);
35875 E.on(this.ecNode, "click", this.ecClick, this, true);
35877 if(this.node.disabled){
35878 this.addClass("x-tree-node-disabled");
35880 if(this.node.hidden){
35881 this.addClass("x-tree-node-disabled");
35883 var ot = this.node.getOwnerTree();
35884 var dd = ot ? (ot.enableDD || ot.enableDrag || ot.enableDrop) : false;
35885 if(dd && (!this.node.isRoot || ot.rootVisible)){
35886 Roo.dd.Registry.register(this.elNode, {
35888 handles: this.getDDHandles(),
35894 getDDHandles : function(){
35895 return [this.iconNode, this.textNode];
35900 this.wrap.style.display = "none";
35906 this.wrap.style.display = "";
35910 onContextMenu : function(e){
35911 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
35912 e.preventDefault();
35914 this.fireEvent("contextmenu", this.node, e);
35918 onClick : function(e){
35923 if(this.fireEvent("beforeclick", this.node, e) !== false){
35924 if(!this.disabled && this.node.attributes.href){
35925 this.fireEvent("click", this.node, e);
35928 e.preventDefault();
35933 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
35934 this.node.toggle();
35937 this.fireEvent("click", this.node, e);
35943 onDblClick : function(e){
35944 e.preventDefault();
35949 this.toggleCheck();
35951 if(!this.animating && this.node.hasChildNodes()){
35952 this.node.toggle();
35954 this.fireEvent("dblclick", this.node, e);
35957 onCheckChange : function(){
35958 var checked = this.checkbox.checked;
35959 this.node.attributes.checked = checked;
35960 this.fireEvent('checkchange', this.node, checked);
35963 ecClick : function(e){
35964 if(!this.animating && this.node.hasChildNodes()){
35965 this.node.toggle();
35969 startDrop : function(){
35970 this.dropping = true;
35973 // delayed drop so the click event doesn't get fired on a drop
35974 endDrop : function(){
35975 setTimeout(function(){
35976 this.dropping = false;
35977 }.createDelegate(this), 50);
35980 expand : function(){
35981 this.updateExpandIcon();
35982 this.ctNode.style.display = "";
35985 focus : function(){
35986 if(!this.node.preventHScroll){
35987 try{this.anchor.focus();
35989 }else if(!Roo.isIE){
35991 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
35992 var l = noscroll.scrollLeft;
35993 this.anchor.focus();
35994 noscroll.scrollLeft = l;
35999 toggleCheck : function(value){
36000 var cb = this.checkbox;
36002 cb.checked = (value === undefined ? !cb.checked : value);
36008 this.anchor.blur();
36012 animExpand : function(callback){
36013 var ct = Roo.get(this.ctNode);
36015 if(!this.node.hasChildNodes()){
36016 this.updateExpandIcon();
36017 this.ctNode.style.display = "";
36018 Roo.callback(callback);
36021 this.animating = true;
36022 this.updateExpandIcon();
36025 callback : function(){
36026 this.animating = false;
36027 Roo.callback(callback);
36030 duration: this.node.ownerTree.duration || .25
36034 highlight : function(){
36035 var tree = this.node.getOwnerTree();
36036 Roo.fly(this.wrap).highlight(
36037 tree.hlColor || "C3DAF9",
36038 {endColor: tree.hlBaseColor}
36042 collapse : function(){
36043 this.updateExpandIcon();
36044 this.ctNode.style.display = "none";
36047 animCollapse : function(callback){
36048 var ct = Roo.get(this.ctNode);
36049 ct.enableDisplayMode('block');
36052 this.animating = true;
36053 this.updateExpandIcon();
36056 callback : function(){
36057 this.animating = false;
36058 Roo.callback(callback);
36061 duration: this.node.ownerTree.duration || .25
36065 getContainer : function(){
36066 return this.ctNode;
36069 getEl : function(){
36073 appendDDGhost : function(ghostNode){
36074 ghostNode.appendChild(this.elNode.cloneNode(true));
36077 getDDRepairXY : function(){
36078 return Roo.lib.Dom.getXY(this.iconNode);
36081 onRender : function(){
36085 render : function(bulkRender){
36086 var n = this.node, a = n.attributes;
36087 var targetNode = n.parentNode ?
36088 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
36090 if(!this.rendered){
36091 this.rendered = true;
36093 this.renderElements(n, a, targetNode, bulkRender);
36096 if(this.textNode.setAttributeNS){
36097 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
36099 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
36102 this.textNode.setAttribute("ext:qtip", a.qtip);
36104 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
36107 }else if(a.qtipCfg){
36108 a.qtipCfg.target = Roo.id(this.textNode);
36109 Roo.QuickTips.register(a.qtipCfg);
36112 if(!this.node.expanded){
36113 this.updateExpandIcon();
36116 if(bulkRender === true) {
36117 targetNode.appendChild(this.wrap);
36122 renderElements : function(n, a, targetNode, bulkRender)
36124 // add some indent caching, this helps performance when rendering a large tree
36125 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
36126 var t = n.getOwnerTree();
36127 var txt = t && t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
36128 if (typeof(n.attributes.html) != 'undefined') {
36129 txt = n.attributes.html;
36131 var tip = t && t.rendererTip ? t.rendererTip(n.attributes) : txt;
36132 var cb = typeof a.checked == 'boolean';
36133 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
36134 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
36135 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
36136 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
36137 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
36138 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
36139 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
36140 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
36141 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
36142 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
36145 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
36146 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
36147 n.nextSibling.ui.getEl(), buf.join(""));
36149 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
36152 this.elNode = this.wrap.childNodes[0];
36153 this.ctNode = this.wrap.childNodes[1];
36154 var cs = this.elNode.childNodes;
36155 this.indentNode = cs[0];
36156 this.ecNode = cs[1];
36157 this.iconNode = cs[2];
36160 this.checkbox = cs[3];
36163 this.anchor = cs[index];
36164 this.textNode = cs[index].firstChild;
36167 getAnchor : function(){
36168 return this.anchor;
36171 getTextEl : function(){
36172 return this.textNode;
36175 getIconEl : function(){
36176 return this.iconNode;
36179 isChecked : function(){
36180 return this.checkbox ? this.checkbox.checked : false;
36183 updateExpandIcon : function(){
36185 var n = this.node, c1, c2;
36186 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
36187 var hasChild = n.hasChildNodes();
36191 c1 = "x-tree-node-collapsed";
36192 c2 = "x-tree-node-expanded";
36195 c1 = "x-tree-node-expanded";
36196 c2 = "x-tree-node-collapsed";
36199 this.removeClass("x-tree-node-leaf");
36200 this.wasLeaf = false;
36202 if(this.c1 != c1 || this.c2 != c2){
36203 Roo.fly(this.elNode).replaceClass(c1, c2);
36204 this.c1 = c1; this.c2 = c2;
36207 // this changes non-leafs into leafs if they have no children.
36208 // it's not very rational behaviour..
36210 if(!this.wasLeaf && this.node.leaf){
36211 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
36214 this.wasLeaf = true;
36217 var ecc = "x-tree-ec-icon "+cls;
36218 if(this.ecc != ecc){
36219 this.ecNode.className = ecc;
36225 getChildIndent : function(){
36226 if(!this.childIndent){
36230 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
36232 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
36234 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
36239 this.childIndent = buf.join("");
36241 return this.childIndent;
36244 renderIndent : function(){
36247 var p = this.node.parentNode;
36249 indent = p.ui.getChildIndent();
36251 if(this.indentMarkup != indent){ // don't rerender if not required
36252 this.indentNode.innerHTML = indent;
36253 this.indentMarkup = indent;
36255 this.updateExpandIcon();
36260 Roo.tree.RootTreeNodeUI = function(){
36261 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
36263 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
36264 render : function(){
36265 if(!this.rendered){
36266 var targetNode = this.node.ownerTree.innerCt.dom;
36267 this.node.expanded = true;
36268 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
36269 this.wrap = this.ctNode = targetNode.firstChild;
36272 collapse : function(){
36274 expand : function(){
36278 * Ext JS Library 1.1.1
36279 * Copyright(c) 2006-2007, Ext JS, LLC.
36281 * Originally Released Under LGPL - original licence link has changed is not relivant.
36284 * <script type="text/javascript">
36287 * @class Roo.tree.TreeLoader
36288 * @extends Roo.util.Observable
36289 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
36290 * nodes from a specified URL. The response must be a javascript Array definition
36291 * who's elements are node definition objects. eg:
36296 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
36297 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
36304 * The old style respose with just an array is still supported, but not recommended.
36307 * A server request is sent, and child nodes are loaded only when a node is expanded.
36308 * The loading node's id is passed to the server under the parameter name "node" to
36309 * enable the server to produce the correct child nodes.
36311 * To pass extra parameters, an event handler may be attached to the "beforeload"
36312 * event, and the parameters specified in the TreeLoader's baseParams property:
36314 myTreeLoader.on("beforeload", function(treeLoader, node) {
36315 this.baseParams.category = node.attributes.category;
36320 * This would pass an HTTP parameter called "category" to the server containing
36321 * the value of the Node's "category" attribute.
36323 * Creates a new Treeloader.
36324 * @param {Object} config A config object containing config properties.
36326 Roo.tree.TreeLoader = function(config){
36327 this.baseParams = {};
36328 this.requestMethod = "POST";
36329 Roo.apply(this, config);
36334 * @event beforeload
36335 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
36336 * @param {Object} This TreeLoader object.
36337 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36338 * @param {Object} callback The callback function specified in the {@link #load} call.
36343 * Fires when the node has been successfuly loaded.
36344 * @param {Object} This TreeLoader object.
36345 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36346 * @param {Object} response The response object containing the data from the server.
36350 * @event loadexception
36351 * Fires if the network request failed.
36352 * @param {Object} This TreeLoader object.
36353 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
36354 * @param {Object} response The response object containing the data from the server.
36356 loadexception : true,
36359 * Fires before a node is created, enabling you to return custom Node types
36360 * @param {Object} This TreeLoader object.
36361 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
36366 Roo.tree.TreeLoader.superclass.constructor.call(this);
36369 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
36371 * @cfg {String} dataUrl The URL from which to request a Json string which
36372 * specifies an array of node definition object representing the child nodes
36376 * @cfg {String} requestMethod either GET or POST
36377 * defaults to POST (due to BC)
36381 * @cfg {Object} baseParams (optional) An object containing properties which
36382 * specify HTTP parameters to be passed to each request for child nodes.
36385 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
36386 * created by this loader. If the attributes sent by the server have an attribute in this object,
36387 * they take priority.
36390 * @cfg {Object} uiProviders (optional) An object containing properties which
36392 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
36393 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
36394 * <i>uiProvider</i> attribute of a returned child node is a string rather
36395 * than a reference to a TreeNodeUI implementation, this that string value
36396 * is used as a property name in the uiProviders object. You can define the provider named
36397 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
36402 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
36403 * child nodes before loading.
36405 clearOnLoad : true,
36408 * @cfg {String} root (optional) Default to false. Use this to read data from an object
36409 * property on loading, rather than expecting an array. (eg. more compatible to a standard
36410 * Grid query { data : [ .....] }
36415 * @cfg {String} queryParam (optional)
36416 * Name of the query as it will be passed on the querystring (defaults to 'node')
36417 * eg. the request will be ?node=[id]
36424 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
36425 * This is called automatically when a node is expanded, but may be used to reload
36426 * a node (or append new children if the {@link #clearOnLoad} option is false.)
36427 * @param {Roo.tree.TreeNode} node
36428 * @param {Function} callback
36430 load : function(node, callback){
36431 if(this.clearOnLoad){
36432 while(node.firstChild){
36433 node.removeChild(node.firstChild);
36436 if(node.attributes.children){ // preloaded json children
36437 var cs = node.attributes.children;
36438 for(var i = 0, len = cs.length; i < len; i++){
36439 node.appendChild(this.createNode(cs[i]));
36441 if(typeof callback == "function"){
36444 }else if(this.dataUrl){
36445 this.requestData(node, callback);
36449 getParams: function(node){
36450 var buf = [], bp = this.baseParams;
36451 for(var key in bp){
36452 if(typeof bp[key] != "function"){
36453 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
36456 var n = this.queryParam === false ? 'node' : this.queryParam;
36457 buf.push(n + "=", encodeURIComponent(node.id));
36458 return buf.join("");
36461 requestData : function(node, callback){
36462 if(this.fireEvent("beforeload", this, node, callback) !== false){
36463 this.transId = Roo.Ajax.request({
36464 method:this.requestMethod,
36465 url: this.dataUrl||this.url,
36466 success: this.handleResponse,
36467 failure: this.handleFailure,
36469 argument: {callback: callback, node: node},
36470 params: this.getParams(node)
36473 // if the load is cancelled, make sure we notify
36474 // the node that we are done
36475 if(typeof callback == "function"){
36481 isLoading : function(){
36482 return this.transId ? true : false;
36485 abort : function(){
36486 if(this.isLoading()){
36487 Roo.Ajax.abort(this.transId);
36492 createNode : function(attr)
36494 // apply baseAttrs, nice idea Corey!
36495 if(this.baseAttrs){
36496 Roo.applyIf(attr, this.baseAttrs);
36498 if(this.applyLoader !== false){
36499 attr.loader = this;
36501 // uiProvider = depreciated..
36503 if(typeof(attr.uiProvider) == 'string'){
36504 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
36505 /** eval:var:attr */ eval(attr.uiProvider);
36507 if(typeof(this.uiProviders['default']) != 'undefined') {
36508 attr.uiProvider = this.uiProviders['default'];
36511 this.fireEvent('create', this, attr);
36513 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
36515 new Roo.tree.TreeNode(attr) :
36516 new Roo.tree.AsyncTreeNode(attr));
36519 processResponse : function(response, node, callback)
36521 var json = response.responseText;
36524 var o = Roo.decode(json);
36526 if (this.root === false && typeof(o.success) != undefined) {
36527 this.root = 'data'; // the default behaviour for list like data..
36530 if (this.root !== false && !o.success) {
36531 // it's a failure condition.
36532 var a = response.argument;
36533 this.fireEvent("loadexception", this, a.node, response);
36534 Roo.log("Load failed - should have a handler really");
36540 if (this.root !== false) {
36544 for(var i = 0, len = o.length; i < len; i++){
36545 var n = this.createNode(o[i]);
36547 node.appendChild(n);
36550 if(typeof callback == "function"){
36551 callback(this, node);
36554 this.handleFailure(response);
36558 handleResponse : function(response){
36559 this.transId = false;
36560 var a = response.argument;
36561 this.processResponse(response, a.node, a.callback);
36562 this.fireEvent("load", this, a.node, response);
36565 handleFailure : function(response)
36567 // should handle failure better..
36568 this.transId = false;
36569 var a = response.argument;
36570 this.fireEvent("loadexception", this, a.node, response);
36571 if(typeof a.callback == "function"){
36572 a.callback(this, a.node);
36577 * Ext JS Library 1.1.1
36578 * Copyright(c) 2006-2007, Ext JS, LLC.
36580 * Originally Released Under LGPL - original licence link has changed is not relivant.
36583 * <script type="text/javascript">
36587 * @class Roo.tree.TreeFilter
36588 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
36589 * @param {TreePanel} tree
36590 * @param {Object} config (optional)
36592 Roo.tree.TreeFilter = function(tree, config){
36594 this.filtered = {};
36595 Roo.apply(this, config);
36598 Roo.tree.TreeFilter.prototype = {
36605 * Filter the data by a specific attribute.
36606 * @param {String/RegExp} value Either string that the attribute value
36607 * should start with or a RegExp to test against the attribute
36608 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
36609 * @param {TreeNode} startNode (optional) The node to start the filter at.
36611 filter : function(value, attr, startNode){
36612 attr = attr || "text";
36614 if(typeof value == "string"){
36615 var vlen = value.length;
36616 // auto clear empty filter
36617 if(vlen == 0 && this.clearBlank){
36621 value = value.toLowerCase();
36623 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
36625 }else if(value.exec){ // regex?
36627 return value.test(n.attributes[attr]);
36630 throw 'Illegal filter type, must be string or regex';
36632 this.filterBy(f, null, startNode);
36636 * Filter by a function. The passed function will be called with each
36637 * node in the tree (or from the startNode). If the function returns true, the node is kept
36638 * otherwise it is filtered. If a node is filtered, its children are also filtered.
36639 * @param {Function} fn The filter function
36640 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
36642 filterBy : function(fn, scope, startNode){
36643 startNode = startNode || this.tree.root;
36644 if(this.autoClear){
36647 var af = this.filtered, rv = this.reverse;
36648 var f = function(n){
36649 if(n == startNode){
36655 var m = fn.call(scope || n, n);
36663 startNode.cascade(f);
36666 if(typeof id != "function"){
36668 if(n && n.parentNode){
36669 n.parentNode.removeChild(n);
36677 * Clears the current filter. Note: with the "remove" option
36678 * set a filter cannot be cleared.
36680 clear : function(){
36682 var af = this.filtered;
36684 if(typeof id != "function"){
36691 this.filtered = {};
36696 * Ext JS Library 1.1.1
36697 * Copyright(c) 2006-2007, Ext JS, LLC.
36699 * Originally Released Under LGPL - original licence link has changed is not relivant.
36702 * <script type="text/javascript">
36707 * @class Roo.tree.TreeSorter
36708 * Provides sorting of nodes in a TreePanel
36710 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
36711 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
36712 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
36713 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
36714 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
36715 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
36717 * @param {TreePanel} tree
36718 * @param {Object} config
36720 Roo.tree.TreeSorter = function(tree, config){
36721 Roo.apply(this, config);
36722 tree.on("beforechildrenrendered", this.doSort, this);
36723 tree.on("append", this.updateSort, this);
36724 tree.on("insert", this.updateSort, this);
36726 var dsc = this.dir && this.dir.toLowerCase() == "desc";
36727 var p = this.property || "text";
36728 var sortType = this.sortType;
36729 var fs = this.folderSort;
36730 var cs = this.caseSensitive === true;
36731 var leafAttr = this.leafAttr || 'leaf';
36733 this.sortFn = function(n1, n2){
36735 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
36738 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
36742 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
36743 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
36745 return dsc ? +1 : -1;
36747 return dsc ? -1 : +1;
36754 Roo.tree.TreeSorter.prototype = {
36755 doSort : function(node){
36756 node.sort(this.sortFn);
36759 compareNodes : function(n1, n2){
36760 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
36763 updateSort : function(tree, node){
36764 if(node.childrenRendered){
36765 this.doSort.defer(1, this, [node]);
36770 * Ext JS Library 1.1.1
36771 * Copyright(c) 2006-2007, Ext JS, LLC.
36773 * Originally Released Under LGPL - original licence link has changed is not relivant.
36776 * <script type="text/javascript">
36779 if(Roo.dd.DropZone){
36781 Roo.tree.TreeDropZone = function(tree, config){
36782 this.allowParentInsert = false;
36783 this.allowContainerDrop = false;
36784 this.appendOnly = false;
36785 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
36787 this.lastInsertClass = "x-tree-no-status";
36788 this.dragOverData = {};
36791 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
36792 ddGroup : "TreeDD",
36795 expandDelay : 1000,
36797 expandNode : function(node){
36798 if(node.hasChildNodes() && !node.isExpanded()){
36799 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
36803 queueExpand : function(node){
36804 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
36807 cancelExpand : function(){
36808 if(this.expandProcId){
36809 clearTimeout(this.expandProcId);
36810 this.expandProcId = false;
36814 isValidDropPoint : function(n, pt, dd, e, data){
36815 if(!n || !data){ return false; }
36816 var targetNode = n.node;
36817 var dropNode = data.node;
36818 // default drop rules
36819 if(!(targetNode && targetNode.isTarget && pt)){
36822 if(pt == "append" && targetNode.allowChildren === false){
36825 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
36828 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
36831 // reuse the object
36832 var overEvent = this.dragOverData;
36833 overEvent.tree = this.tree;
36834 overEvent.target = targetNode;
36835 overEvent.data = data;
36836 overEvent.point = pt;
36837 overEvent.source = dd;
36838 overEvent.rawEvent = e;
36839 overEvent.dropNode = dropNode;
36840 overEvent.cancel = false;
36841 var result = this.tree.fireEvent("nodedragover", overEvent);
36842 return overEvent.cancel === false && result !== false;
36845 getDropPoint : function(e, n, dd)
36849 return tn.allowChildren !== false ? "append" : false; // always append for root
36851 var dragEl = n.ddel;
36852 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
36853 var y = Roo.lib.Event.getPageY(e);
36854 //var noAppend = tn.allowChildren === false || tn.isLeaf();
36856 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
36857 var noAppend = tn.allowChildren === false;
36858 if(this.appendOnly || tn.parentNode.allowChildren === false){
36859 return noAppend ? false : "append";
36861 var noBelow = false;
36862 if(!this.allowParentInsert){
36863 noBelow = tn.hasChildNodes() && tn.isExpanded();
36865 var q = (b - t) / (noAppend ? 2 : 3);
36866 if(y >= t && y < (t + q)){
36868 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
36875 onNodeEnter : function(n, dd, e, data)
36877 this.cancelExpand();
36880 onNodeOver : function(n, dd, e, data)
36883 var pt = this.getDropPoint(e, n, dd);
36886 // auto node expand check
36887 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
36888 this.queueExpand(node);
36889 }else if(pt != "append"){
36890 this.cancelExpand();
36893 // set the insert point style on the target node
36894 var returnCls = this.dropNotAllowed;
36895 if(this.isValidDropPoint(n, pt, dd, e, data)){
36900 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
36901 cls = "x-tree-drag-insert-above";
36902 }else if(pt == "below"){
36903 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
36904 cls = "x-tree-drag-insert-below";
36906 returnCls = "x-tree-drop-ok-append";
36907 cls = "x-tree-drag-append";
36909 if(this.lastInsertClass != cls){
36910 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
36911 this.lastInsertClass = cls;
36918 onNodeOut : function(n, dd, e, data){
36920 this.cancelExpand();
36921 this.removeDropIndicators(n);
36924 onNodeDrop : function(n, dd, e, data){
36925 var point = this.getDropPoint(e, n, dd);
36926 var targetNode = n.node;
36927 targetNode.ui.startDrop();
36928 if(!this.isValidDropPoint(n, point, dd, e, data)){
36929 targetNode.ui.endDrop();
36932 // first try to find the drop node
36933 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
36936 target: targetNode,
36941 dropNode: dropNode,
36944 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
36945 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
36946 targetNode.ui.endDrop();
36949 // allow target changing
36950 targetNode = dropEvent.target;
36951 if(point == "append" && !targetNode.isExpanded()){
36952 targetNode.expand(false, null, function(){
36953 this.completeDrop(dropEvent);
36954 }.createDelegate(this));
36956 this.completeDrop(dropEvent);
36961 completeDrop : function(de){
36962 var ns = de.dropNode, p = de.point, t = de.target;
36963 if(!(ns instanceof Array)){
36967 for(var i = 0, len = ns.length; i < len; i++){
36970 t.parentNode.insertBefore(n, t);
36971 }else if(p == "below"){
36972 t.parentNode.insertBefore(n, t.nextSibling);
36978 if(this.tree.hlDrop){
36982 this.tree.fireEvent("nodedrop", de);
36985 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
36986 if(this.tree.hlDrop){
36987 dropNode.ui.focus();
36988 dropNode.ui.highlight();
36990 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
36993 getTree : function(){
36997 removeDropIndicators : function(n){
37000 Roo.fly(el).removeClass([
37001 "x-tree-drag-insert-above",
37002 "x-tree-drag-insert-below",
37003 "x-tree-drag-append"]);
37004 this.lastInsertClass = "_noclass";
37008 beforeDragDrop : function(target, e, id){
37009 this.cancelExpand();
37013 afterRepair : function(data){
37014 if(data && Roo.enableFx){
37015 data.node.ui.highlight();
37025 * Ext JS Library 1.1.1
37026 * Copyright(c) 2006-2007, Ext JS, LLC.
37028 * Originally Released Under LGPL - original licence link has changed is not relivant.
37031 * <script type="text/javascript">
37035 if(Roo.dd.DragZone){
37036 Roo.tree.TreeDragZone = function(tree, config){
37037 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
37041 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
37042 ddGroup : "TreeDD",
37044 onBeforeDrag : function(data, e){
37046 return n && n.draggable && !n.disabled;
37050 onInitDrag : function(e){
37051 var data = this.dragData;
37052 this.tree.getSelectionModel().select(data.node);
37053 this.proxy.update("");
37054 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
37055 this.tree.fireEvent("startdrag", this.tree, data.node, e);
37058 getRepairXY : function(e, data){
37059 return data.node.ui.getDDRepairXY();
37062 onEndDrag : function(data, e){
37063 this.tree.fireEvent("enddrag", this.tree, data.node, e);
37068 onValidDrop : function(dd, e, id){
37069 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
37073 beforeInvalidDrop : function(e, id){
37074 // this scrolls the original position back into view
37075 var sm = this.tree.getSelectionModel();
37076 sm.clearSelections();
37077 sm.select(this.dragData.node);
37082 * Ext JS Library 1.1.1
37083 * Copyright(c) 2006-2007, Ext JS, LLC.
37085 * Originally Released Under LGPL - original licence link has changed is not relivant.
37088 * <script type="text/javascript">
37091 * @class Roo.tree.TreeEditor
37092 * @extends Roo.Editor
37093 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
37094 * as the editor field.
37096 * @param {Object} config (used to be the tree panel.)
37097 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
37099 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
37100 * @cfg {Roo.form.TextField|Object} field The field configuration
37104 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
37107 if (oldconfig) { // old style..
37108 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
37111 tree = config.tree;
37112 config.field = config.field || {};
37113 config.field.xtype = 'TextField';
37114 field = Roo.factory(config.field, Roo.form);
37116 config = config || {};
37121 * @event beforenodeedit
37122 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
37123 * false from the handler of this event.
37124 * @param {Editor} this
37125 * @param {Roo.tree.Node} node
37127 "beforenodeedit" : true
37131 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
37135 tree.on('beforeclick', this.beforeNodeClick, this);
37136 tree.getTreeEl().on('mousedown', this.hide, this);
37137 this.on('complete', this.updateNode, this);
37138 this.on('beforestartedit', this.fitToTree, this);
37139 this.on('startedit', this.bindScroll, this, {delay:10});
37140 this.on('specialkey', this.onSpecialKey, this);
37143 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
37145 * @cfg {String} alignment
37146 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
37152 * @cfg {Boolean} hideEl
37153 * True to hide the bound element while the editor is displayed (defaults to false)
37157 * @cfg {String} cls
37158 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
37160 cls: "x-small-editor x-tree-editor",
37162 * @cfg {Boolean} shim
37163 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
37169 * @cfg {Number} maxWidth
37170 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
37171 * the containing tree element's size, it will be automatically limited for you to the container width, taking
37172 * scroll and client offsets into account prior to each edit.
37179 fitToTree : function(ed, el){
37180 var td = this.tree.getTreeEl().dom, nd = el.dom;
37181 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
37182 td.scrollLeft = nd.offsetLeft;
37186 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
37187 this.setSize(w, '');
37189 return this.fireEvent('beforenodeedit', this, this.editNode);
37194 triggerEdit : function(node){
37195 this.completeEdit();
37196 this.editNode = node;
37197 this.startEdit(node.ui.textNode, node.text);
37201 bindScroll : function(){
37202 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
37206 beforeNodeClick : function(node, e){
37207 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
37208 this.lastClick = new Date();
37209 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
37211 this.triggerEdit(node);
37218 updateNode : function(ed, value){
37219 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
37220 this.editNode.setText(value);
37224 onHide : function(){
37225 Roo.tree.TreeEditor.superclass.onHide.call(this);
37227 this.editNode.ui.focus();
37232 onSpecialKey : function(field, e){
37233 var k = e.getKey();
37237 }else if(k == e.ENTER && !e.hasModifier()){
37239 this.completeEdit();
37242 });//<Script type="text/javascript">
37245 * Ext JS Library 1.1.1
37246 * Copyright(c) 2006-2007, Ext JS, LLC.
37248 * Originally Released Under LGPL - original licence link has changed is not relivant.
37251 * <script type="text/javascript">
37255 * Not documented??? - probably should be...
37258 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
37259 //focus: Roo.emptyFn, // prevent odd scrolling behavior
37261 renderElements : function(n, a, targetNode, bulkRender){
37262 //consel.log("renderElements?");
37263 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
37265 var t = n.getOwnerTree();
37266 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
37268 var cols = t.columns;
37269 var bw = t.borderWidth;
37271 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
37272 var cb = typeof a.checked == "boolean";
37273 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37274 var colcls = 'x-t-' + tid + '-c0';
37276 '<li class="x-tree-node">',
37279 '<div class="x-tree-node-el ', a.cls,'">',
37281 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
37284 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
37285 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
37286 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
37287 (a.icon ? ' x-tree-node-inline-icon' : ''),
37288 (a.iconCls ? ' '+a.iconCls : ''),
37289 '" unselectable="on" />',
37290 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
37291 (a.checked ? 'checked="checked" />' : ' />')) : ''),
37293 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37294 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
37295 '<span unselectable="on" qtip="' + tx + '">',
37299 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
37300 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
37302 for(var i = 1, len = cols.length; i < len; i++){
37304 colcls = 'x-t-' + tid + '-c' +i;
37305 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
37306 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
37307 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
37313 '<div class="x-clear"></div></div>',
37314 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
37317 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
37318 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
37319 n.nextSibling.ui.getEl(), buf.join(""));
37321 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
37323 var el = this.wrap.firstChild;
37325 this.elNode = el.firstChild;
37326 this.ranchor = el.childNodes[1];
37327 this.ctNode = this.wrap.childNodes[1];
37328 var cs = el.firstChild.childNodes;
37329 this.indentNode = cs[0];
37330 this.ecNode = cs[1];
37331 this.iconNode = cs[2];
37334 this.checkbox = cs[3];
37337 this.anchor = cs[index];
37339 this.textNode = cs[index].firstChild;
37341 //el.on("click", this.onClick, this);
37342 //el.on("dblclick", this.onDblClick, this);
37345 // console.log(this);
37347 initEvents : function(){
37348 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
37351 var a = this.ranchor;
37353 var el = Roo.get(a);
37355 if(Roo.isOpera){ // opera render bug ignores the CSS
37356 el.setStyle("text-decoration", "none");
37359 el.on("click", this.onClick, this);
37360 el.on("dblclick", this.onDblClick, this);
37361 el.on("contextmenu", this.onContextMenu, this);
37365 /*onSelectedChange : function(state){
37368 this.addClass("x-tree-selected");
37371 this.removeClass("x-tree-selected");
37374 addClass : function(cls){
37376 Roo.fly(this.elRow).addClass(cls);
37382 removeClass : function(cls){
37384 Roo.fly(this.elRow).removeClass(cls);
37390 });//<Script type="text/javascript">
37394 * Ext JS Library 1.1.1
37395 * Copyright(c) 2006-2007, Ext JS, LLC.
37397 * Originally Released Under LGPL - original licence link has changed is not relivant.
37400 * <script type="text/javascript">
37405 * @class Roo.tree.ColumnTree
37406 * @extends Roo.data.TreePanel
37407 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
37408 * @cfg {int} borderWidth compined right/left border allowance
37410 * @param {String/HTMLElement/Element} el The container element
37411 * @param {Object} config
37413 Roo.tree.ColumnTree = function(el, config)
37415 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
37419 * Fire this event on a container when it resizes
37420 * @param {int} w Width
37421 * @param {int} h Height
37425 this.on('resize', this.onResize, this);
37428 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
37432 borderWidth: Roo.isBorderBox ? 0 : 2,
37435 render : function(){
37436 // add the header.....
37438 Roo.tree.ColumnTree.superclass.render.apply(this);
37440 this.el.addClass('x-column-tree');
37442 this.headers = this.el.createChild(
37443 {cls:'x-tree-headers'},this.innerCt.dom);
37445 var cols = this.columns, c;
37446 var totalWidth = 0;
37448 var len = cols.length;
37449 for(var i = 0; i < len; i++){
37451 totalWidth += c.width;
37452 this.headEls.push(this.headers.createChild({
37453 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
37455 cls:'x-tree-hd-text',
37458 style:'width:'+(c.width-this.borderWidth)+'px;'
37461 this.headers.createChild({cls:'x-clear'});
37462 // prevent floats from wrapping when clipped
37463 this.headers.setWidth(totalWidth);
37464 //this.innerCt.setWidth(totalWidth);
37465 this.innerCt.setStyle({ overflow: 'auto' });
37466 this.onResize(this.width, this.height);
37470 onResize : function(w,h)
37475 this.innerCt.setWidth(this.width);
37476 this.innerCt.setHeight(this.height-20);
37479 var cols = this.columns, c;
37480 var totalWidth = 0;
37482 var len = cols.length;
37483 for(var i = 0; i < len; i++){
37485 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
37486 // it's the expander..
37487 expEl = this.headEls[i];
37490 totalWidth += c.width;
37494 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
37496 this.headers.setWidth(w-20);
37505 * Ext JS Library 1.1.1
37506 * Copyright(c) 2006-2007, Ext JS, LLC.
37508 * Originally Released Under LGPL - original licence link has changed is not relivant.
37511 * <script type="text/javascript">
37515 * @class Roo.menu.Menu
37516 * @extends Roo.util.Observable
37517 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
37518 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
37520 * Creates a new Menu
37521 * @param {Object} config Configuration options
37523 Roo.menu.Menu = function(config){
37525 Roo.menu.Menu.superclass.constructor.call(this, config);
37527 this.id = this.id || Roo.id();
37530 * @event beforeshow
37531 * Fires before this menu is displayed
37532 * @param {Roo.menu.Menu} this
37536 * @event beforehide
37537 * Fires before this menu is hidden
37538 * @param {Roo.menu.Menu} this
37543 * Fires after this menu is displayed
37544 * @param {Roo.menu.Menu} this
37549 * Fires after this menu is hidden
37550 * @param {Roo.menu.Menu} this
37555 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
37556 * @param {Roo.menu.Menu} this
37557 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37558 * @param {Roo.EventObject} e
37563 * Fires when the mouse is hovering over this menu
37564 * @param {Roo.menu.Menu} this
37565 * @param {Roo.EventObject} e
37566 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37571 * Fires when the mouse exits this menu
37572 * @param {Roo.menu.Menu} this
37573 * @param {Roo.EventObject} e
37574 * @param {Roo.menu.Item} menuItem The menu item that was clicked
37579 * Fires when a menu item contained in this menu is clicked
37580 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
37581 * @param {Roo.EventObject} e
37585 if (this.registerMenu) {
37586 Roo.menu.MenuMgr.register(this);
37589 var mis = this.items;
37590 this.items = new Roo.util.MixedCollection();
37592 this.add.apply(this, mis);
37596 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
37598 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
37602 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
37603 * for bottom-right shadow (defaults to "sides")
37607 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
37608 * this menu (defaults to "tl-tr?")
37610 subMenuAlign : "tl-tr?",
37612 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
37613 * relative to its element of origin (defaults to "tl-bl?")
37615 defaultAlign : "tl-bl?",
37617 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
37619 allowOtherMenus : false,
37621 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
37623 registerMenu : true,
37628 render : function(){
37632 var el = this.el = new Roo.Layer({
37634 shadow:this.shadow,
37636 parentEl: this.parentEl || document.body,
37640 this.keyNav = new Roo.menu.MenuNav(this);
37643 el.addClass("x-menu-plain");
37646 el.addClass(this.cls);
37648 // generic focus element
37649 this.focusEl = el.createChild({
37650 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
37652 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
37653 //disabling touch- as it's causing issues ..
37654 //ul.on(Roo.isTouch ? 'touchstart' : 'click' , this.onClick, this);
37655 ul.on('click' , this.onClick, this);
37658 ul.on("mouseover", this.onMouseOver, this);
37659 ul.on("mouseout", this.onMouseOut, this);
37660 this.items.each(function(item){
37665 var li = document.createElement("li");
37666 li.className = "x-menu-list-item";
37667 ul.dom.appendChild(li);
37668 item.render(li, this);
37675 autoWidth : function(){
37676 var el = this.el, ul = this.ul;
37680 var w = this.width;
37683 }else if(Roo.isIE){
37684 el.setWidth(this.minWidth);
37685 var t = el.dom.offsetWidth; // force recalc
37686 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
37691 delayAutoWidth : function(){
37694 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
37696 this.awTask.delay(20);
37701 findTargetItem : function(e){
37702 var t = e.getTarget(".x-menu-list-item", this.ul, true);
37703 if(t && t.menuItemId){
37704 return this.items.get(t.menuItemId);
37709 onClick : function(e){
37710 Roo.log("menu.onClick");
37711 var t = this.findTargetItem(e);
37716 if (Roo.isTouch && e.type == 'touchstart' && t.menu && !t.disabled) {
37717 if(t == this.activeItem && t.shouldDeactivate(e)){
37718 this.activeItem.deactivate();
37719 delete this.activeItem;
37723 this.setActiveItem(t, true);
37731 this.fireEvent("click", this, t, e);
37735 setActiveItem : function(item, autoExpand){
37736 if(item != this.activeItem){
37737 if(this.activeItem){
37738 this.activeItem.deactivate();
37740 this.activeItem = item;
37741 item.activate(autoExpand);
37742 }else if(autoExpand){
37748 tryActivate : function(start, step){
37749 var items = this.items;
37750 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
37751 var item = items.get(i);
37752 if(!item.disabled && item.canActivate){
37753 this.setActiveItem(item, false);
37761 onMouseOver : function(e){
37763 if(t = this.findTargetItem(e)){
37764 if(t.canActivate && !t.disabled){
37765 this.setActiveItem(t, true);
37768 this.fireEvent("mouseover", this, e, t);
37772 onMouseOut : function(e){
37774 if(t = this.findTargetItem(e)){
37775 if(t == this.activeItem && t.shouldDeactivate(e)){
37776 this.activeItem.deactivate();
37777 delete this.activeItem;
37780 this.fireEvent("mouseout", this, e, t);
37784 * Read-only. Returns true if the menu is currently displayed, else false.
37787 isVisible : function(){
37788 return this.el && !this.hidden;
37792 * Displays this menu relative to another element
37793 * @param {String/HTMLElement/Roo.Element} element The element to align to
37794 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
37795 * the element (defaults to this.defaultAlign)
37796 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37798 show : function(el, pos, parentMenu){
37799 this.parentMenu = parentMenu;
37803 this.fireEvent("beforeshow", this);
37804 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
37808 * Displays this menu at a specific xy position
37809 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
37810 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
37812 showAt : function(xy, parentMenu, /* private: */_e){
37813 this.parentMenu = parentMenu;
37818 this.fireEvent("beforeshow", this);
37819 xy = this.el.adjustForConstraints(xy);
37823 this.hidden = false;
37825 this.fireEvent("show", this);
37828 focus : function(){
37830 this.doFocus.defer(50, this);
37834 doFocus : function(){
37836 this.focusEl.focus();
37841 * Hides this menu and optionally all parent menus
37842 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
37844 hide : function(deep){
37845 if(this.el && this.isVisible()){
37846 this.fireEvent("beforehide", this);
37847 if(this.activeItem){
37848 this.activeItem.deactivate();
37849 this.activeItem = null;
37852 this.hidden = true;
37853 this.fireEvent("hide", this);
37855 if(deep === true && this.parentMenu){
37856 this.parentMenu.hide(true);
37861 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
37862 * Any of the following are valid:
37864 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
37865 * <li>An HTMLElement object which will be converted to a menu item</li>
37866 * <li>A menu item config object that will be created as a new menu item</li>
37867 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
37868 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
37873 var menu = new Roo.menu.Menu();
37875 // Create a menu item to add by reference
37876 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
37878 // Add a bunch of items at once using different methods.
37879 // Only the last item added will be returned.
37880 var item = menu.add(
37881 menuItem, // add existing item by ref
37882 'Dynamic Item', // new TextItem
37883 '-', // new separator
37884 { text: 'Config Item' } // new item by config
37887 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
37888 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
37891 var a = arguments, l = a.length, item;
37892 for(var i = 0; i < l; i++){
37894 if ((typeof(el) == "object") && el.xtype && el.xns) {
37895 el = Roo.factory(el, Roo.menu);
37898 if(el.render){ // some kind of Item
37899 item = this.addItem(el);
37900 }else if(typeof el == "string"){ // string
37901 if(el == "separator" || el == "-"){
37902 item = this.addSeparator();
37904 item = this.addText(el);
37906 }else if(el.tagName || el.el){ // element
37907 item = this.addElement(el);
37908 }else if(typeof el == "object"){ // must be menu item config?
37909 item = this.addMenuItem(el);
37916 * Returns this menu's underlying {@link Roo.Element} object
37917 * @return {Roo.Element} The element
37919 getEl : function(){
37927 * Adds a separator bar to the menu
37928 * @return {Roo.menu.Item} The menu item that was added
37930 addSeparator : function(){
37931 return this.addItem(new Roo.menu.Separator());
37935 * Adds an {@link Roo.Element} object to the menu
37936 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
37937 * @return {Roo.menu.Item} The menu item that was added
37939 addElement : function(el){
37940 return this.addItem(new Roo.menu.BaseItem(el));
37944 * Adds an existing object based on {@link Roo.menu.Item} to the menu
37945 * @param {Roo.menu.Item} item The menu item to add
37946 * @return {Roo.menu.Item} The menu item that was added
37948 addItem : function(item){
37949 this.items.add(item);
37951 var li = document.createElement("li");
37952 li.className = "x-menu-list-item";
37953 this.ul.dom.appendChild(li);
37954 item.render(li, this);
37955 this.delayAutoWidth();
37961 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
37962 * @param {Object} config A MenuItem config object
37963 * @return {Roo.menu.Item} The menu item that was added
37965 addMenuItem : function(config){
37966 if(!(config instanceof Roo.menu.Item)){
37967 if(typeof config.checked == "boolean"){ // must be check menu item config?
37968 config = new Roo.menu.CheckItem(config);
37970 config = new Roo.menu.Item(config);
37973 return this.addItem(config);
37977 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
37978 * @param {String} text The text to display in the menu item
37979 * @return {Roo.menu.Item} The menu item that was added
37981 addText : function(text){
37982 return this.addItem(new Roo.menu.TextItem({ text : text }));
37986 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
37987 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
37988 * @param {Roo.menu.Item} item The menu item to add
37989 * @return {Roo.menu.Item} The menu item that was added
37991 insert : function(index, item){
37992 this.items.insert(index, item);
37994 var li = document.createElement("li");
37995 li.className = "x-menu-list-item";
37996 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
37997 item.render(li, this);
37998 this.delayAutoWidth();
38004 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
38005 * @param {Roo.menu.Item} item The menu item to remove
38007 remove : function(item){
38008 this.items.removeKey(item.id);
38013 * Removes and destroys all items in the menu
38015 removeAll : function(){
38017 while(f = this.items.first()){
38023 // MenuNav is a private utility class used internally by the Menu
38024 Roo.menu.MenuNav = function(menu){
38025 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
38026 this.scope = this.menu = menu;
38029 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
38030 doRelay : function(e, h){
38031 var k = e.getKey();
38032 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
38033 this.menu.tryActivate(0, 1);
38036 return h.call(this.scope || this, e, this.menu);
38039 up : function(e, m){
38040 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
38041 m.tryActivate(m.items.length-1, -1);
38045 down : function(e, m){
38046 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
38047 m.tryActivate(0, 1);
38051 right : function(e, m){
38053 m.activeItem.expandMenu(true);
38057 left : function(e, m){
38059 if(m.parentMenu && m.parentMenu.activeItem){
38060 m.parentMenu.activeItem.activate();
38064 enter : function(e, m){
38066 e.stopPropagation();
38067 m.activeItem.onClick(e);
38068 m.fireEvent("click", this, m.activeItem);
38074 * Ext JS Library 1.1.1
38075 * Copyright(c) 2006-2007, Ext JS, LLC.
38077 * Originally Released Under LGPL - original licence link has changed is not relivant.
38080 * <script type="text/javascript">
38084 * @class Roo.menu.MenuMgr
38085 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
38088 Roo.menu.MenuMgr = function(){
38089 var menus, active, groups = {}, attached = false, lastShow = new Date();
38091 // private - called when first menu is created
38094 active = new Roo.util.MixedCollection();
38095 Roo.get(document).addKeyListener(27, function(){
38096 if(active.length > 0){
38103 function hideAll(){
38104 if(active && active.length > 0){
38105 var c = active.clone();
38106 c.each(function(m){
38113 function onHide(m){
38115 if(active.length < 1){
38116 Roo.get(document).un("mousedown", onMouseDown);
38122 function onShow(m){
38123 var last = active.last();
38124 lastShow = new Date();
38127 Roo.get(document).on("mousedown", onMouseDown);
38131 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
38132 m.parentMenu.activeChild = m;
38133 }else if(last && last.isVisible()){
38134 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
38139 function onBeforeHide(m){
38141 m.activeChild.hide();
38143 if(m.autoHideTimer){
38144 clearTimeout(m.autoHideTimer);
38145 delete m.autoHideTimer;
38150 function onBeforeShow(m){
38151 var pm = m.parentMenu;
38152 if(!pm && !m.allowOtherMenus){
38154 }else if(pm && pm.activeChild && active != m){
38155 pm.activeChild.hide();
38160 function onMouseDown(e){
38161 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
38167 function onBeforeCheck(mi, state){
38169 var g = groups[mi.group];
38170 for(var i = 0, l = g.length; i < l; i++){
38172 g[i].setChecked(false);
38181 * Hides all menus that are currently visible
38183 hideAll : function(){
38188 register : function(menu){
38192 menus[menu.id] = menu;
38193 menu.on("beforehide", onBeforeHide);
38194 menu.on("hide", onHide);
38195 menu.on("beforeshow", onBeforeShow);
38196 menu.on("show", onShow);
38197 var g = menu.group;
38198 if(g && menu.events["checkchange"]){
38202 groups[g].push(menu);
38203 menu.on("checkchange", onCheck);
38208 * Returns a {@link Roo.menu.Menu} object
38209 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
38210 * be used to generate and return a new Menu instance.
38212 get : function(menu){
38213 if(typeof menu == "string"){ // menu id
38214 return menus[menu];
38215 }else if(menu.events){ // menu instance
38217 }else if(typeof menu.length == 'number'){ // array of menu items?
38218 return new Roo.menu.Menu({items:menu});
38219 }else{ // otherwise, must be a config
38220 return new Roo.menu.Menu(menu);
38225 unregister : function(menu){
38226 delete menus[menu.id];
38227 menu.un("beforehide", onBeforeHide);
38228 menu.un("hide", onHide);
38229 menu.un("beforeshow", onBeforeShow);
38230 menu.un("show", onShow);
38231 var g = menu.group;
38232 if(g && menu.events["checkchange"]){
38233 groups[g].remove(menu);
38234 menu.un("checkchange", onCheck);
38239 registerCheckable : function(menuItem){
38240 var g = menuItem.group;
38245 groups[g].push(menuItem);
38246 menuItem.on("beforecheckchange", onBeforeCheck);
38251 unregisterCheckable : function(menuItem){
38252 var g = menuItem.group;
38254 groups[g].remove(menuItem);
38255 menuItem.un("beforecheckchange", onBeforeCheck);
38261 * Ext JS Library 1.1.1
38262 * Copyright(c) 2006-2007, Ext JS, LLC.
38264 * Originally Released Under LGPL - original licence link has changed is not relivant.
38267 * <script type="text/javascript">
38272 * @class Roo.menu.BaseItem
38273 * @extends Roo.Component
38274 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
38275 * management and base configuration options shared by all menu components.
38277 * Creates a new BaseItem
38278 * @param {Object} config Configuration options
38280 Roo.menu.BaseItem = function(config){
38281 Roo.menu.BaseItem.superclass.constructor.call(this, config);
38286 * Fires when this item is clicked
38287 * @param {Roo.menu.BaseItem} this
38288 * @param {Roo.EventObject} e
38293 * Fires when this item is activated
38294 * @param {Roo.menu.BaseItem} this
38298 * @event deactivate
38299 * Fires when this item is deactivated
38300 * @param {Roo.menu.BaseItem} this
38306 this.on("click", this.handler, this.scope, true);
38310 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
38312 * @cfg {Function} handler
38313 * A function that will handle the click event of this menu item (defaults to undefined)
38316 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
38318 canActivate : false,
38321 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
38326 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
38328 activeClass : "x-menu-item-active",
38330 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
38332 hideOnClick : true,
38334 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
38339 ctype: "Roo.menu.BaseItem",
38342 actionMode : "container",
38345 render : function(container, parentMenu){
38346 this.parentMenu = parentMenu;
38347 Roo.menu.BaseItem.superclass.render.call(this, container);
38348 this.container.menuItemId = this.id;
38352 onRender : function(container, position){
38353 this.el = Roo.get(this.el);
38354 container.dom.appendChild(this.el.dom);
38358 onClick : function(e){
38359 if(!this.disabled && this.fireEvent("click", this, e) !== false
38360 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
38361 this.handleClick(e);
38368 activate : function(){
38372 var li = this.container;
38373 li.addClass(this.activeClass);
38374 this.region = li.getRegion().adjust(2, 2, -2, -2);
38375 this.fireEvent("activate", this);
38380 deactivate : function(){
38381 this.container.removeClass(this.activeClass);
38382 this.fireEvent("deactivate", this);
38386 shouldDeactivate : function(e){
38387 return !this.region || !this.region.contains(e.getPoint());
38391 handleClick : function(e){
38392 if(this.hideOnClick){
38393 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
38398 expandMenu : function(autoActivate){
38403 hideMenu : function(){
38408 * Ext JS Library 1.1.1
38409 * Copyright(c) 2006-2007, Ext JS, LLC.
38411 * Originally Released Under LGPL - original licence link has changed is not relivant.
38414 * <script type="text/javascript">
38418 * @class Roo.menu.Adapter
38419 * @extends Roo.menu.BaseItem
38420 * 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.
38421 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
38423 * Creates a new Adapter
38424 * @param {Object} config Configuration options
38426 Roo.menu.Adapter = function(component, config){
38427 Roo.menu.Adapter.superclass.constructor.call(this, config);
38428 this.component = component;
38430 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
38432 canActivate : true,
38435 onRender : function(container, position){
38436 this.component.render(container);
38437 this.el = this.component.getEl();
38441 activate : function(){
38445 this.component.focus();
38446 this.fireEvent("activate", this);
38451 deactivate : function(){
38452 this.fireEvent("deactivate", this);
38456 disable : function(){
38457 this.component.disable();
38458 Roo.menu.Adapter.superclass.disable.call(this);
38462 enable : function(){
38463 this.component.enable();
38464 Roo.menu.Adapter.superclass.enable.call(this);
38468 * Ext JS Library 1.1.1
38469 * Copyright(c) 2006-2007, Ext JS, LLC.
38471 * Originally Released Under LGPL - original licence link has changed is not relivant.
38474 * <script type="text/javascript">
38478 * @class Roo.menu.TextItem
38479 * @extends Roo.menu.BaseItem
38480 * Adds a static text string to a menu, usually used as either a heading or group separator.
38481 * Note: old style constructor with text is still supported.
38484 * Creates a new TextItem
38485 * @param {Object} cfg Configuration
38487 Roo.menu.TextItem = function(cfg){
38488 if (typeof(cfg) == 'string') {
38491 Roo.apply(this,cfg);
38494 Roo.menu.TextItem.superclass.constructor.call(this);
38497 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
38499 * @cfg {String} text Text to show on item.
38504 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38506 hideOnClick : false,
38508 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
38510 itemCls : "x-menu-text",
38513 onRender : function(){
38514 var s = document.createElement("span");
38515 s.className = this.itemCls;
38516 s.innerHTML = this.text;
38518 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
38522 * Ext JS Library 1.1.1
38523 * Copyright(c) 2006-2007, Ext JS, LLC.
38525 * Originally Released Under LGPL - original licence link has changed is not relivant.
38528 * <script type="text/javascript">
38532 * @class Roo.menu.Separator
38533 * @extends Roo.menu.BaseItem
38534 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
38535 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
38537 * @param {Object} config Configuration options
38539 Roo.menu.Separator = function(config){
38540 Roo.menu.Separator.superclass.constructor.call(this, config);
38543 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
38545 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
38547 itemCls : "x-menu-sep",
38549 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
38551 hideOnClick : false,
38554 onRender : function(li){
38555 var s = document.createElement("span");
38556 s.className = this.itemCls;
38557 s.innerHTML = " ";
38559 li.addClass("x-menu-sep-li");
38560 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
38564 * Ext JS Library 1.1.1
38565 * Copyright(c) 2006-2007, Ext JS, LLC.
38567 * Originally Released Under LGPL - original licence link has changed is not relivant.
38570 * <script type="text/javascript">
38573 * @class Roo.menu.Item
38574 * @extends Roo.menu.BaseItem
38575 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
38576 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
38577 * activation and click handling.
38579 * Creates a new Item
38580 * @param {Object} config Configuration options
38582 Roo.menu.Item = function(config){
38583 Roo.menu.Item.superclass.constructor.call(this, config);
38585 this.menu = Roo.menu.MenuMgr.get(this.menu);
38588 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
38591 * @cfg {String} text
38592 * The text to show on the menu item.
38596 * @cfg {String} HTML to render in menu
38597 * The text to show on the menu item (HTML version).
38601 * @cfg {String} icon
38602 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
38606 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
38608 itemCls : "x-menu-item",
38610 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
38612 canActivate : true,
38614 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
38617 // doc'd in BaseItem
38621 ctype: "Roo.menu.Item",
38624 onRender : function(container, position){
38625 var el = document.createElement("a");
38626 el.hideFocus = true;
38627 el.unselectable = "on";
38628 el.href = this.href || "#";
38629 if(this.hrefTarget){
38630 el.target = this.hrefTarget;
38632 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
38634 var html = this.html.length ? this.html : String.format('{0}',this.text);
38636 el.innerHTML = String.format(
38637 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
38638 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
38640 Roo.menu.Item.superclass.onRender.call(this, container, position);
38644 * Sets the text to display in this menu item
38645 * @param {String} text The text to display
38646 * @param {Boolean} isHTML true to indicate text is pure html.
38648 setText : function(text, isHTML){
38656 var html = this.html.length ? this.html : String.format('{0}',this.text);
38658 this.el.update(String.format(
38659 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
38660 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
38661 this.parentMenu.autoWidth();
38666 handleClick : function(e){
38667 if(!this.href){ // if no link defined, stop the event automatically
38670 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
38674 activate : function(autoExpand){
38675 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
38685 shouldDeactivate : function(e){
38686 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
38687 if(this.menu && this.menu.isVisible()){
38688 return !this.menu.getEl().getRegion().contains(e.getPoint());
38696 deactivate : function(){
38697 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
38702 expandMenu : function(autoActivate){
38703 if(!this.disabled && this.menu){
38704 clearTimeout(this.hideTimer);
38705 delete this.hideTimer;
38706 if(!this.menu.isVisible() && !this.showTimer){
38707 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
38708 }else if (this.menu.isVisible() && autoActivate){
38709 this.menu.tryActivate(0, 1);
38715 deferExpand : function(autoActivate){
38716 delete this.showTimer;
38717 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
38719 this.menu.tryActivate(0, 1);
38724 hideMenu : function(){
38725 clearTimeout(this.showTimer);
38726 delete this.showTimer;
38727 if(!this.hideTimer && this.menu && this.menu.isVisible()){
38728 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
38733 deferHide : function(){
38734 delete this.hideTimer;
38739 * Ext JS Library 1.1.1
38740 * Copyright(c) 2006-2007, Ext JS, LLC.
38742 * Originally Released Under LGPL - original licence link has changed is not relivant.
38745 * <script type="text/javascript">
38749 * @class Roo.menu.CheckItem
38750 * @extends Roo.menu.Item
38751 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
38753 * Creates a new CheckItem
38754 * @param {Object} config Configuration options
38756 Roo.menu.CheckItem = function(config){
38757 Roo.menu.CheckItem.superclass.constructor.call(this, config);
38760 * @event beforecheckchange
38761 * Fires before the checked value is set, providing an opportunity to cancel if needed
38762 * @param {Roo.menu.CheckItem} this
38763 * @param {Boolean} checked The new checked value that will be set
38765 "beforecheckchange" : true,
38767 * @event checkchange
38768 * Fires after the checked value has been set
38769 * @param {Roo.menu.CheckItem} this
38770 * @param {Boolean} checked The checked value that was set
38772 "checkchange" : true
38774 if(this.checkHandler){
38775 this.on('checkchange', this.checkHandler, this.scope);
38778 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
38780 * @cfg {String} group
38781 * All check items with the same group name will automatically be grouped into a single-select
38782 * radio button group (defaults to '')
38785 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
38787 itemCls : "x-menu-item x-menu-check-item",
38789 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
38791 groupClass : "x-menu-group-item",
38794 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
38795 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
38796 * initialized with checked = true will be rendered as checked.
38801 ctype: "Roo.menu.CheckItem",
38804 onRender : function(c){
38805 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
38807 this.el.addClass(this.groupClass);
38809 Roo.menu.MenuMgr.registerCheckable(this);
38811 this.checked = false;
38812 this.setChecked(true, true);
38817 destroy : function(){
38819 Roo.menu.MenuMgr.unregisterCheckable(this);
38821 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
38825 * Set the checked state of this item
38826 * @param {Boolean} checked The new checked value
38827 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
38829 setChecked : function(state, suppressEvent){
38830 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
38831 if(this.container){
38832 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
38834 this.checked = state;
38835 if(suppressEvent !== true){
38836 this.fireEvent("checkchange", this, state);
38842 handleClick : function(e){
38843 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
38844 this.setChecked(!this.checked);
38846 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
38850 * Ext JS Library 1.1.1
38851 * Copyright(c) 2006-2007, Ext JS, LLC.
38853 * Originally Released Under LGPL - original licence link has changed is not relivant.
38856 * <script type="text/javascript">
38860 * @class Roo.menu.DateItem
38861 * @extends Roo.menu.Adapter
38862 * A menu item that wraps the {@link Roo.DatPicker} component.
38864 * Creates a new DateItem
38865 * @param {Object} config Configuration options
38867 Roo.menu.DateItem = function(config){
38868 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
38869 /** The Roo.DatePicker object @type Roo.DatePicker */
38870 this.picker = this.component;
38871 this.addEvents({select: true});
38873 this.picker.on("render", function(picker){
38874 picker.getEl().swallowEvent("click");
38875 picker.container.addClass("x-menu-date-item");
38878 this.picker.on("select", this.onSelect, this);
38881 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
38883 onSelect : function(picker, date){
38884 this.fireEvent("select", this, date, picker);
38885 Roo.menu.DateItem.superclass.handleClick.call(this);
38889 * Ext JS Library 1.1.1
38890 * Copyright(c) 2006-2007, Ext JS, LLC.
38892 * Originally Released Under LGPL - original licence link has changed is not relivant.
38895 * <script type="text/javascript">
38899 * @class Roo.menu.ColorItem
38900 * @extends Roo.menu.Adapter
38901 * A menu item that wraps the {@link Roo.ColorPalette} component.
38903 * Creates a new ColorItem
38904 * @param {Object} config Configuration options
38906 Roo.menu.ColorItem = function(config){
38907 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
38908 /** The Roo.ColorPalette object @type Roo.ColorPalette */
38909 this.palette = this.component;
38910 this.relayEvents(this.palette, ["select"]);
38911 if(this.selectHandler){
38912 this.on('select', this.selectHandler, this.scope);
38915 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
38917 * Ext JS Library 1.1.1
38918 * Copyright(c) 2006-2007, Ext JS, LLC.
38920 * Originally Released Under LGPL - original licence link has changed is not relivant.
38923 * <script type="text/javascript">
38928 * @class Roo.menu.DateMenu
38929 * @extends Roo.menu.Menu
38930 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
38932 * Creates a new DateMenu
38933 * @param {Object} config Configuration options
38935 Roo.menu.DateMenu = function(config){
38936 Roo.menu.DateMenu.superclass.constructor.call(this, config);
38938 var di = new Roo.menu.DateItem(config);
38941 * The {@link Roo.DatePicker} instance for this DateMenu
38944 this.picker = di.picker;
38947 * @param {DatePicker} picker
38948 * @param {Date} date
38950 this.relayEvents(di, ["select"]);
38951 this.on('beforeshow', function(){
38953 this.picker.hideMonthPicker(false);
38957 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
38961 * Ext JS Library 1.1.1
38962 * Copyright(c) 2006-2007, Ext JS, LLC.
38964 * Originally Released Under LGPL - original licence link has changed is not relivant.
38967 * <script type="text/javascript">
38972 * @class Roo.menu.ColorMenu
38973 * @extends Roo.menu.Menu
38974 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
38976 * Creates a new ColorMenu
38977 * @param {Object} config Configuration options
38979 Roo.menu.ColorMenu = function(config){
38980 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
38982 var ci = new Roo.menu.ColorItem(config);
38985 * The {@link Roo.ColorPalette} instance for this ColorMenu
38986 * @type ColorPalette
38988 this.palette = ci.palette;
38991 * @param {ColorPalette} palette
38992 * @param {String} color
38994 this.relayEvents(ci, ["select"]);
38996 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
38998 * Ext JS Library 1.1.1
38999 * Copyright(c) 2006-2007, Ext JS, LLC.
39001 * Originally Released Under LGPL - original licence link has changed is not relivant.
39004 * <script type="text/javascript">
39008 * @class Roo.form.TextItem
39009 * @extends Roo.BoxComponent
39010 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39012 * Creates a new TextItem
39013 * @param {Object} config Configuration options
39015 Roo.form.TextItem = function(config){
39016 Roo.form.TextItem.superclass.constructor.call(this, config);
39019 Roo.extend(Roo.form.TextItem, Roo.BoxComponent, {
39022 * @cfg {String} tag the tag for this item (default div)
39026 * @cfg {String} html the content for this item
39030 getAutoCreate : function()
39043 onRender : function(ct, position)
39045 Roo.form.TextItem.superclass.onRender.call(this, ct, position);
39048 var cfg = this.getAutoCreate();
39050 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39052 if (!cfg.name.length) {
39055 this.el = ct.createChild(cfg, position);
39060 * @param {String} html update the Contents of the element.
39062 setHTML : function(html)
39064 this.fieldEl.dom.innerHTML = html;
39069 * Ext JS Library 1.1.1
39070 * Copyright(c) 2006-2007, Ext JS, LLC.
39072 * Originally Released Under LGPL - original licence link has changed is not relivant.
39075 * <script type="text/javascript">
39079 * @class Roo.form.Field
39080 * @extends Roo.BoxComponent
39081 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
39083 * Creates a new Field
39084 * @param {Object} config Configuration options
39086 Roo.form.Field = function(config){
39087 Roo.form.Field.superclass.constructor.call(this, config);
39090 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
39092 * @cfg {String} fieldLabel Label to use when rendering a form.
39095 * @cfg {String} qtip Mouse over tip
39099 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
39101 invalidClass : "x-form-invalid",
39103 * @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")
39105 invalidText : "The value in this field is invalid",
39107 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
39109 focusClass : "x-form-focus",
39111 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
39112 automatic validation (defaults to "keyup").
39114 validationEvent : "keyup",
39116 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
39118 validateOnBlur : true,
39120 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
39122 validationDelay : 250,
39124 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
39125 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
39127 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "new-password"},
39129 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
39131 fieldClass : "x-form-field",
39133 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
39136 ----------- ----------------------------------------------------------------------
39137 qtip Display a quick tip when the user hovers over the field
39138 title Display a default browser title attribute popup
39139 under Add a block div beneath the field containing the error text
39140 side Add an error icon to the right of the field with a popup on hover
39141 [element id] Add the error text directly to the innerHTML of the specified element
39144 msgTarget : 'qtip',
39146 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
39151 * @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.
39156 * @cfg {Boolean} disabled True to disable the field (defaults to false).
39161 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
39163 inputType : undefined,
39166 * @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).
39168 tabIndex : undefined,
39171 isFormField : true,
39176 * @property {Roo.Element} fieldEl
39177 * Element Containing the rendered Field (with label etc.)
39180 * @cfg {Mixed} value A value to initialize this field with.
39185 * @cfg {String} name The field's HTML name attribute.
39188 * @cfg {String} cls A CSS class to apply to the field's underlying element.
39191 loadedValue : false,
39195 initComponent : function(){
39196 Roo.form.Field.superclass.initComponent.call(this);
39200 * Fires when this field receives input focus.
39201 * @param {Roo.form.Field} this
39206 * Fires when this field loses input focus.
39207 * @param {Roo.form.Field} this
39211 * @event specialkey
39212 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
39213 * {@link Roo.EventObject#getKey} to determine which key was pressed.
39214 * @param {Roo.form.Field} this
39215 * @param {Roo.EventObject} e The event object
39220 * Fires just before the field blurs if the field value has changed.
39221 * @param {Roo.form.Field} this
39222 * @param {Mixed} newValue The new value
39223 * @param {Mixed} oldValue The original value
39228 * Fires after the field has been marked as invalid.
39229 * @param {Roo.form.Field} this
39230 * @param {String} msg The validation message
39235 * Fires after the field has been validated with no errors.
39236 * @param {Roo.form.Field} this
39241 * Fires after the key up
39242 * @param {Roo.form.Field} this
39243 * @param {Roo.EventObject} e The event Object
39250 * Returns the name attribute of the field if available
39251 * @return {String} name The field name
39253 getName: function(){
39254 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
39258 onRender : function(ct, position){
39259 Roo.form.Field.superclass.onRender.call(this, ct, position);
39261 var cfg = this.getAutoCreate();
39263 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
39265 if (!cfg.name.length) {
39268 if(this.inputType){
39269 cfg.type = this.inputType;
39271 this.el = ct.createChild(cfg, position);
39273 var type = this.el.dom.type;
39275 if(type == 'password'){
39278 this.el.addClass('x-form-'+type);
39281 this.el.dom.readOnly = true;
39283 if(this.tabIndex !== undefined){
39284 this.el.dom.setAttribute('tabIndex', this.tabIndex);
39287 this.el.addClass([this.fieldClass, this.cls]);
39292 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
39293 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
39294 * @return {Roo.form.Field} this
39296 applyTo : function(target){
39297 this.allowDomMove = false;
39298 this.el = Roo.get(target);
39299 this.render(this.el.dom.parentNode);
39304 initValue : function(){
39305 if(this.value !== undefined){
39306 this.setValue(this.value);
39307 }else if(this.el.dom.value.length > 0){
39308 this.setValue(this.el.dom.value);
39313 * Returns true if this field has been changed since it was originally loaded and is not disabled.
39314 * DEPRICATED - it never worked well - use hasChanged/resetHasChanged.
39316 isDirty : function() {
39317 if(this.disabled) {
39320 return String(this.getValue()) !== String(this.originalValue);
39324 * stores the current value in loadedValue
39326 resetHasChanged : function()
39328 this.loadedValue = String(this.getValue());
39331 * checks the current value against the 'loaded' value.
39332 * Note - will return false if 'resetHasChanged' has not been called first.
39334 hasChanged : function()
39336 if(this.disabled || this.readOnly) {
39339 return this.loadedValue !== false && String(this.getValue()) !== this.loadedValue;
39345 afterRender : function(){
39346 Roo.form.Field.superclass.afterRender.call(this);
39351 fireKey : function(e){
39352 //Roo.log('field ' + e.getKey());
39353 if(e.isNavKeyPress()){
39354 this.fireEvent("specialkey", this, e);
39359 * Resets the current field value to the originally loaded value and clears any validation messages
39361 reset : function(){
39362 this.setValue(this.resetValue);
39363 this.originalValue = this.getValue();
39364 this.clearInvalid();
39368 initEvents : function(){
39369 // safari killled keypress - so keydown is now used..
39370 this.el.on("keydown" , this.fireKey, this);
39371 this.el.on("focus", this.onFocus, this);
39372 this.el.on("blur", this.onBlur, this);
39373 this.el.relayEvent('keyup', this);
39375 // reference to original value for reset
39376 this.originalValue = this.getValue();
39377 this.resetValue = this.getValue();
39381 onFocus : function(){
39382 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39383 this.el.addClass(this.focusClass);
39385 if(!this.hasFocus){
39386 this.hasFocus = true;
39387 this.startValue = this.getValue();
39388 this.fireEvent("focus", this);
39392 beforeBlur : Roo.emptyFn,
39395 onBlur : function(){
39397 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
39398 this.el.removeClass(this.focusClass);
39400 this.hasFocus = false;
39401 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
39404 var v = this.getValue();
39405 if(String(v) !== String(this.startValue)){
39406 this.fireEvent('change', this, v, this.startValue);
39408 this.fireEvent("blur", this);
39412 * Returns whether or not the field value is currently valid
39413 * @param {Boolean} preventMark True to disable marking the field invalid
39414 * @return {Boolean} True if the value is valid, else false
39416 isValid : function(preventMark){
39420 var restore = this.preventMark;
39421 this.preventMark = preventMark === true;
39422 var v = this.validateValue(this.processValue(this.getRawValue()));
39423 this.preventMark = restore;
39428 * Validates the field value
39429 * @return {Boolean} True if the value is valid, else false
39431 validate : function(){
39432 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
39433 this.clearInvalid();
39439 processValue : function(value){
39444 // Subclasses should provide the validation implementation by overriding this
39445 validateValue : function(value){
39450 * Mark this field as invalid
39451 * @param {String} msg The validation message
39453 markInvalid : function(msg){
39454 if(!this.rendered || this.preventMark){ // not rendered
39458 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39460 obj.el.addClass(this.invalidClass);
39461 msg = msg || this.invalidText;
39462 switch(this.msgTarget){
39464 obj.el.dom.qtip = msg;
39465 obj.el.dom.qclass = 'x-form-invalid-tip';
39466 if(Roo.QuickTips){ // fix for floating editors interacting with DND
39467 Roo.QuickTips.enable();
39471 this.el.dom.title = msg;
39475 var elp = this.el.findParent('.x-form-element', 5, true);
39476 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
39477 this.errorEl.setWidth(elp.getWidth(true)-20);
39479 this.errorEl.update(msg);
39480 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
39483 if(!this.errorIcon){
39484 var elp = this.el.findParent('.x-form-element', 5, true);
39485 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
39487 this.alignErrorIcon();
39488 this.errorIcon.dom.qtip = msg;
39489 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
39490 this.errorIcon.show();
39491 this.on('resize', this.alignErrorIcon, this);
39494 var t = Roo.getDom(this.msgTarget);
39496 t.style.display = this.msgDisplay;
39499 this.fireEvent('invalid', this, msg);
39503 alignErrorIcon : function(){
39504 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
39508 * Clear any invalid styles/messages for this field
39510 clearInvalid : function(){
39511 if(!this.rendered || this.preventMark){ // not rendered
39514 var obj = (typeof(this.combo) != 'undefined') ? this.combo : this; // fix the combox array!!
39516 obj.el.removeClass(this.invalidClass);
39517 switch(this.msgTarget){
39519 obj.el.dom.qtip = '';
39522 this.el.dom.title = '';
39526 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
39530 if(this.errorIcon){
39531 this.errorIcon.dom.qtip = '';
39532 this.errorIcon.hide();
39533 this.un('resize', this.alignErrorIcon, this);
39537 var t = Roo.getDom(this.msgTarget);
39539 t.style.display = 'none';
39542 this.fireEvent('valid', this);
39546 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
39547 * @return {Mixed} value The field value
39549 getRawValue : function(){
39550 var v = this.el.getValue();
39556 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
39557 * @return {Mixed} value The field value
39559 getValue : function(){
39560 var v = this.el.getValue();
39566 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
39567 * @param {Mixed} value The value to set
39569 setRawValue : function(v){
39570 return this.el.dom.value = (v === null || v === undefined ? '' : v);
39574 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
39575 * @param {Mixed} value The value to set
39577 setValue : function(v){
39580 this.el.dom.value = (v === null || v === undefined ? '' : v);
39585 adjustSize : function(w, h){
39586 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
39587 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
39591 adjustWidth : function(tag, w){
39592 tag = tag.toLowerCase();
39593 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
39594 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
39595 if(tag == 'input'){
39598 if(tag == 'textarea'){
39601 }else if(Roo.isOpera){
39602 if(tag == 'input'){
39605 if(tag == 'textarea'){
39615 // anything other than normal should be considered experimental
39616 Roo.form.Field.msgFx = {
39618 show: function(msgEl, f){
39619 msgEl.setDisplayed('block');
39622 hide : function(msgEl, f){
39623 msgEl.setDisplayed(false).update('');
39628 show: function(msgEl, f){
39629 msgEl.slideIn('t', {stopFx:true});
39632 hide : function(msgEl, f){
39633 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
39638 show: function(msgEl, f){
39639 msgEl.fixDisplay();
39640 msgEl.alignTo(f.el, 'tl-tr');
39641 msgEl.slideIn('l', {stopFx:true});
39644 hide : function(msgEl, f){
39645 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
39650 * Ext JS Library 1.1.1
39651 * Copyright(c) 2006-2007, Ext JS, LLC.
39653 * Originally Released Under LGPL - original licence link has changed is not relivant.
39656 * <script type="text/javascript">
39661 * @class Roo.form.TextField
39662 * @extends Roo.form.Field
39663 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
39664 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
39666 * Creates a new TextField
39667 * @param {Object} config Configuration options
39669 Roo.form.TextField = function(config){
39670 Roo.form.TextField.superclass.constructor.call(this, config);
39674 * Fires when the autosize function is triggered. The field may or may not have actually changed size
39675 * according to the default logic, but this event provides a hook for the developer to apply additional
39676 * logic at runtime to resize the field if needed.
39677 * @param {Roo.form.Field} this This text field
39678 * @param {Number} width The new field width
39684 Roo.extend(Roo.form.TextField, Roo.form.Field, {
39686 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
39690 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
39694 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
39698 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
39702 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
39706 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
39708 disableKeyFilter : false,
39710 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
39714 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
39718 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
39720 maxLength : Number.MAX_VALUE,
39722 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
39724 minLengthText : "The minimum length for this field is {0}",
39726 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
39728 maxLengthText : "The maximum length for this field is {0}",
39730 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
39732 selectOnFocus : false,
39734 * @cfg {Boolean} allowLeadingSpace True to prevent the stripping of leading white space
39736 allowLeadingSpace : false,
39738 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
39740 blankText : "This field is required",
39742 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
39743 * If available, this function will be called only after the basic validators all return true, and will be passed the
39744 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
39748 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
39749 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
39750 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
39754 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
39758 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
39764 initEvents : function()
39766 if (this.emptyText) {
39767 this.el.attr('placeholder', this.emptyText);
39770 Roo.form.TextField.superclass.initEvents.call(this);
39771 if(this.validationEvent == 'keyup'){
39772 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
39773 this.el.on('keyup', this.filterValidation, this);
39775 else if(this.validationEvent !== false){
39776 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
39779 if(this.selectOnFocus){
39780 this.on("focus", this.preFocus, this);
39782 if (!this.allowLeadingSpace) {
39783 this.on('blur', this.cleanLeadingSpace, this);
39786 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
39787 this.el.on("keypress", this.filterKeys, this);
39790 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
39791 this.el.on("click", this.autoSize, this);
39793 if(this.el.is('input[type=password]') && Roo.isSafari){
39794 this.el.on('keydown', this.SafariOnKeyDown, this);
39798 processValue : function(value){
39799 if(this.stripCharsRe){
39800 var newValue = value.replace(this.stripCharsRe, '');
39801 if(newValue !== value){
39802 this.setRawValue(newValue);
39809 filterValidation : function(e){
39810 if(!e.isNavKeyPress()){
39811 this.validationTask.delay(this.validationDelay);
39816 onKeyUp : function(e){
39817 if(!e.isNavKeyPress()){
39821 // private - clean the leading white space
39822 cleanLeadingSpace : function(e)
39824 if ( this.inputType == 'file') {
39828 this.setValue((this.getValue() + '').replace(/^\s+/,''));
39831 * Resets the current field value to the originally-loaded value and clears any validation messages.
39834 reset : function(){
39835 Roo.form.TextField.superclass.reset.call(this);
39839 preFocus : function(){
39841 if(this.selectOnFocus){
39842 this.el.dom.select();
39848 filterKeys : function(e){
39849 var k = e.getKey();
39850 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
39853 var c = e.getCharCode(), cc = String.fromCharCode(c);
39854 if(Roo.isIE && (e.isSpecialKey() || !cc)){
39857 if(!this.maskRe.test(cc)){
39862 setValue : function(v){
39864 Roo.form.TextField.superclass.setValue.apply(this, arguments);
39870 * Validates a value according to the field's validation rules and marks the field as invalid
39871 * if the validation fails
39872 * @param {Mixed} value The value to validate
39873 * @return {Boolean} True if the value is valid, else false
39875 validateValue : function(value){
39876 if(value.length < 1) { // if it's blank
39877 if(this.allowBlank){
39878 this.clearInvalid();
39881 this.markInvalid(this.blankText);
39885 if(value.length < this.minLength){
39886 this.markInvalid(String.format(this.minLengthText, this.minLength));
39889 if(value.length > this.maxLength){
39890 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
39894 var vt = Roo.form.VTypes;
39895 if(!vt[this.vtype](value, this)){
39896 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
39900 if(typeof this.validator == "function"){
39901 var msg = this.validator(value);
39903 this.markInvalid(msg);
39907 if(this.regex && !this.regex.test(value)){
39908 this.markInvalid(this.regexText);
39915 * Selects text in this field
39916 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
39917 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
39919 selectText : function(start, end){
39920 var v = this.getRawValue();
39922 start = start === undefined ? 0 : start;
39923 end = end === undefined ? v.length : end;
39924 var d = this.el.dom;
39925 if(d.setSelectionRange){
39926 d.setSelectionRange(start, end);
39927 }else if(d.createTextRange){
39928 var range = d.createTextRange();
39929 range.moveStart("character", start);
39930 range.moveEnd("character", v.length-end);
39937 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
39938 * This only takes effect if grow = true, and fires the autosize event.
39940 autoSize : function(){
39941 if(!this.grow || !this.rendered){
39945 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
39948 var v = el.dom.value;
39949 var d = document.createElement('div');
39950 d.appendChild(document.createTextNode(v));
39954 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
39955 this.el.setWidth(w);
39956 this.fireEvent("autosize", this, w);
39960 SafariOnKeyDown : function(event)
39962 // this is a workaround for a password hang bug on chrome/ webkit.
39964 var isSelectAll = false;
39966 if(this.el.dom.selectionEnd > 0){
39967 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
39969 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
39970 event.preventDefault();
39975 if(isSelectAll && event.getCharCode() > 31){ // backspace and delete key
39977 event.preventDefault();
39978 // this is very hacky as keydown always get's upper case.
39980 var cc = String.fromCharCode(event.getCharCode());
39983 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
39991 * Ext JS Library 1.1.1
39992 * Copyright(c) 2006-2007, Ext JS, LLC.
39994 * Originally Released Under LGPL - original licence link has changed is not relivant.
39997 * <script type="text/javascript">
40001 * @class Roo.form.Hidden
40002 * @extends Roo.form.TextField
40003 * Simple Hidden element used on forms
40005 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
40008 * Creates a new Hidden form element.
40009 * @param {Object} config Configuration options
40014 // easy hidden field...
40015 Roo.form.Hidden = function(config){
40016 Roo.form.Hidden.superclass.constructor.call(this, config);
40019 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
40021 inputType: 'hidden',
40024 labelSeparator: '',
40026 itemCls : 'x-form-item-display-none'
40034 * Ext JS Library 1.1.1
40035 * Copyright(c) 2006-2007, Ext JS, LLC.
40037 * Originally Released Under LGPL - original licence link has changed is not relivant.
40040 * <script type="text/javascript">
40044 * @class Roo.form.TriggerField
40045 * @extends Roo.form.TextField
40046 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
40047 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
40048 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
40049 * for which you can provide a custom implementation. For example:
40051 var trigger = new Roo.form.TriggerField();
40052 trigger.onTriggerClick = myTriggerFn;
40053 trigger.applyTo('my-field');
40056 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
40057 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
40058 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
40059 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
40061 * Create a new TriggerField.
40062 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
40063 * to the base TextField)
40065 Roo.form.TriggerField = function(config){
40066 this.mimicing = false;
40067 Roo.form.TriggerField.superclass.constructor.call(this, config);
40070 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
40072 * @cfg {String} triggerClass A CSS class to apply to the trigger
40075 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40076 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
40078 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "new-password"},
40080 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
40084 /** @cfg {Boolean} grow @hide */
40085 /** @cfg {Number} growMin @hide */
40086 /** @cfg {Number} growMax @hide */
40092 autoSize: Roo.emptyFn,
40096 deferHeight : true,
40099 actionMode : 'wrap',
40101 onResize : function(w, h){
40102 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
40103 if(typeof w == 'number'){
40104 var x = w - this.trigger.getWidth();
40105 this.el.setWidth(this.adjustWidth('input', x));
40106 this.trigger.setStyle('left', x+'px');
40111 adjustSize : Roo.BoxComponent.prototype.adjustSize,
40114 getResizeEl : function(){
40119 getPositionEl : function(){
40124 alignErrorIcon : function(){
40125 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
40129 onRender : function(ct, position){
40130 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
40131 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
40132 this.trigger = this.wrap.createChild(this.triggerConfig ||
40133 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
40134 if(this.hideTrigger){
40135 this.trigger.setDisplayed(false);
40137 this.initTrigger();
40139 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
40144 initTrigger : function(){
40145 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
40146 this.trigger.addClassOnOver('x-form-trigger-over');
40147 this.trigger.addClassOnClick('x-form-trigger-click');
40151 onDestroy : function(){
40153 this.trigger.removeAllListeners();
40154 this.trigger.remove();
40157 this.wrap.remove();
40159 Roo.form.TriggerField.superclass.onDestroy.call(this);
40163 onFocus : function(){
40164 Roo.form.TriggerField.superclass.onFocus.call(this);
40165 if(!this.mimicing){
40166 this.wrap.addClass('x-trigger-wrap-focus');
40167 this.mimicing = true;
40168 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
40169 if(this.monitorTab){
40170 this.el.on("keydown", this.checkTab, this);
40176 checkTab : function(e){
40177 if(e.getKey() == e.TAB){
40178 this.triggerBlur();
40183 onBlur : function(){
40188 mimicBlur : function(e, t){
40189 if(!this.wrap.contains(t) && this.validateBlur()){
40190 this.triggerBlur();
40195 triggerBlur : function(){
40196 this.mimicing = false;
40197 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
40198 if(this.monitorTab){
40199 this.el.un("keydown", this.checkTab, this);
40201 this.wrap.removeClass('x-trigger-wrap-focus');
40202 Roo.form.TriggerField.superclass.onBlur.call(this);
40206 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
40207 validateBlur : function(e, t){
40212 onDisable : function(){
40213 Roo.form.TriggerField.superclass.onDisable.call(this);
40215 this.wrap.addClass('x-item-disabled');
40220 onEnable : function(){
40221 Roo.form.TriggerField.superclass.onEnable.call(this);
40223 this.wrap.removeClass('x-item-disabled');
40228 onShow : function(){
40229 var ae = this.getActionEl();
40232 ae.dom.style.display = '';
40233 ae.dom.style.visibility = 'visible';
40239 onHide : function(){
40240 var ae = this.getActionEl();
40241 ae.dom.style.display = 'none';
40245 * The function that should handle the trigger's click event. This method does nothing by default until overridden
40246 * by an implementing function.
40248 * @param {EventObject} e
40250 onTriggerClick : Roo.emptyFn
40253 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
40254 // to be extended by an implementing class. For an example of implementing this class, see the custom
40255 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
40256 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
40257 initComponent : function(){
40258 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
40260 this.triggerConfig = {
40261 tag:'span', cls:'x-form-twin-triggers', cn:[
40262 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
40263 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
40267 getTrigger : function(index){
40268 return this.triggers[index];
40271 initTrigger : function(){
40272 var ts = this.trigger.select('.x-form-trigger', true);
40273 this.wrap.setStyle('overflow', 'hidden');
40274 var triggerField = this;
40275 ts.each(function(t, all, index){
40276 t.hide = function(){
40277 var w = triggerField.wrap.getWidth();
40278 this.dom.style.display = 'none';
40279 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40281 t.show = function(){
40282 var w = triggerField.wrap.getWidth();
40283 this.dom.style.display = '';
40284 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
40286 var triggerIndex = 'Trigger'+(index+1);
40288 if(this['hide'+triggerIndex]){
40289 t.dom.style.display = 'none';
40291 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
40292 t.addClassOnOver('x-form-trigger-over');
40293 t.addClassOnClick('x-form-trigger-click');
40295 this.triggers = ts.elements;
40298 onTrigger1Click : Roo.emptyFn,
40299 onTrigger2Click : Roo.emptyFn
40302 * Ext JS Library 1.1.1
40303 * Copyright(c) 2006-2007, Ext JS, LLC.
40305 * Originally Released Under LGPL - original licence link has changed is not relivant.
40308 * <script type="text/javascript">
40312 * @class Roo.form.TextArea
40313 * @extends Roo.form.TextField
40314 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
40315 * support for auto-sizing.
40317 * Creates a new TextArea
40318 * @param {Object} config Configuration options
40320 Roo.form.TextArea = function(config){
40321 Roo.form.TextArea.superclass.constructor.call(this, config);
40322 // these are provided exchanges for backwards compat
40323 // minHeight/maxHeight were replaced by growMin/growMax to be
40324 // compatible with TextField growing config values
40325 if(this.minHeight !== undefined){
40326 this.growMin = this.minHeight;
40328 if(this.maxHeight !== undefined){
40329 this.growMax = this.maxHeight;
40333 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
40335 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
40339 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
40343 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
40344 * in the field (equivalent to setting overflow: hidden, defaults to false)
40346 preventScrollbars: false,
40348 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
40349 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
40353 onRender : function(ct, position){
40355 this.defaultAutoCreate = {
40357 style:"width:300px;height:60px;",
40358 autocomplete: "new-password"
40361 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
40363 this.textSizeEl = Roo.DomHelper.append(document.body, {
40364 tag: "pre", cls: "x-form-grow-sizer"
40366 if(this.preventScrollbars){
40367 this.el.setStyle("overflow", "hidden");
40369 this.el.setHeight(this.growMin);
40373 onDestroy : function(){
40374 if(this.textSizeEl){
40375 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
40377 Roo.form.TextArea.superclass.onDestroy.call(this);
40381 onKeyUp : function(e){
40382 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
40388 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
40389 * This only takes effect if grow = true, and fires the autosize event if the height changes.
40391 autoSize : function(){
40392 if(!this.grow || !this.textSizeEl){
40396 var v = el.dom.value;
40397 var ts = this.textSizeEl;
40400 ts.appendChild(document.createTextNode(v));
40403 Roo.fly(ts).setWidth(this.el.getWidth());
40405 v = "  ";
40408 v = v.replace(/\n/g, '<p> </p>');
40410 v += " \n ";
40413 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
40414 if(h != this.lastHeight){
40415 this.lastHeight = h;
40416 this.el.setHeight(h);
40417 this.fireEvent("autosize", this, h);
40422 * Ext JS Library 1.1.1
40423 * Copyright(c) 2006-2007, Ext JS, LLC.
40425 * Originally Released Under LGPL - original licence link has changed is not relivant.
40428 * <script type="text/javascript">
40433 * @class Roo.form.NumberField
40434 * @extends Roo.form.TextField
40435 * Numeric text field that provides automatic keystroke filtering and numeric validation.
40437 * Creates a new NumberField
40438 * @param {Object} config Configuration options
40440 Roo.form.NumberField = function(config){
40441 Roo.form.NumberField.superclass.constructor.call(this, config);
40444 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
40446 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
40448 fieldClass: "x-form-field x-form-num-field",
40450 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
40452 allowDecimals : true,
40454 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
40456 decimalSeparator : ".",
40458 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
40460 decimalPrecision : 2,
40462 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
40464 allowNegative : true,
40466 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
40468 minValue : Number.NEGATIVE_INFINITY,
40470 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
40472 maxValue : Number.MAX_VALUE,
40474 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
40476 minText : "The minimum value for this field is {0}",
40478 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
40480 maxText : "The maximum value for this field is {0}",
40482 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
40483 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
40485 nanText : "{0} is not a valid number",
40488 initEvents : function(){
40489 Roo.form.NumberField.superclass.initEvents.call(this);
40490 var allowed = "0123456789";
40491 if(this.allowDecimals){
40492 allowed += this.decimalSeparator;
40494 if(this.allowNegative){
40497 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
40498 var keyPress = function(e){
40499 var k = e.getKey();
40500 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
40503 var c = e.getCharCode();
40504 if(allowed.indexOf(String.fromCharCode(c)) === -1){
40508 this.el.on("keypress", keyPress, this);
40512 validateValue : function(value){
40513 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
40516 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40519 var num = this.parseValue(value);
40521 this.markInvalid(String.format(this.nanText, value));
40524 if(num < this.minValue){
40525 this.markInvalid(String.format(this.minText, this.minValue));
40528 if(num > this.maxValue){
40529 this.markInvalid(String.format(this.maxText, this.maxValue));
40535 getValue : function(){
40536 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
40540 parseValue : function(value){
40541 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
40542 return isNaN(value) ? '' : value;
40546 fixPrecision : function(value){
40547 var nan = isNaN(value);
40548 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
40549 return nan ? '' : value;
40551 return parseFloat(value).toFixed(this.decimalPrecision);
40554 setValue : function(v){
40555 v = this.fixPrecision(v);
40556 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
40560 decimalPrecisionFcn : function(v){
40561 return Math.floor(v);
40564 beforeBlur : function(){
40565 var v = this.parseValue(this.getRawValue());
40572 * Ext JS Library 1.1.1
40573 * Copyright(c) 2006-2007, Ext JS, LLC.
40575 * Originally Released Under LGPL - original licence link has changed is not relivant.
40578 * <script type="text/javascript">
40582 * @class Roo.form.DateField
40583 * @extends Roo.form.TriggerField
40584 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40586 * Create a new DateField
40587 * @param {Object} config
40589 Roo.form.DateField = function(config)
40591 Roo.form.DateField.superclass.constructor.call(this, config);
40597 * Fires when a date is selected
40598 * @param {Roo.form.DateField} combo This combo box
40599 * @param {Date} date The date selected
40606 if(typeof this.minValue == "string") {
40607 this.minValue = this.parseDate(this.minValue);
40609 if(typeof this.maxValue == "string") {
40610 this.maxValue = this.parseDate(this.maxValue);
40612 this.ddMatch = null;
40613 if(this.disabledDates){
40614 var dd = this.disabledDates;
40616 for(var i = 0; i < dd.length; i++){
40618 if(i != dd.length-1) {
40622 this.ddMatch = new RegExp(re + ")");
40626 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
40628 * @cfg {String} format
40629 * The default date format string which can be overriden for localization support. The format must be
40630 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
40634 * @cfg {String} altFormats
40635 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
40636 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
40638 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
40640 * @cfg {Array} disabledDays
40641 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
40643 disabledDays : null,
40645 * @cfg {String} disabledDaysText
40646 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
40648 disabledDaysText : "Disabled",
40650 * @cfg {Array} disabledDates
40651 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
40652 * expression so they are very powerful. Some examples:
40654 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
40655 * <li>["03/08", "09/16"] would disable those days for every year</li>
40656 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
40657 * <li>["03/../2006"] would disable every day in March 2006</li>
40658 * <li>["^03"] would disable every day in every March</li>
40660 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
40661 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
40663 disabledDates : null,
40665 * @cfg {String} disabledDatesText
40666 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
40668 disabledDatesText : "Disabled",
40670 * @cfg {Date/String} minValue
40671 * The minimum allowed date. Can be either a Javascript date object or a string date in a
40672 * valid format (defaults to null).
40676 * @cfg {Date/String} maxValue
40677 * The maximum allowed date. Can be either a Javascript date object or a string date in a
40678 * valid format (defaults to null).
40682 * @cfg {String} minText
40683 * The error text to display when the date in the cell is before minValue (defaults to
40684 * 'The date in this field must be after {minValue}').
40686 minText : "The date in this field must be equal to or after {0}",
40688 * @cfg {String} maxText
40689 * The error text to display when the date in the cell is after maxValue (defaults to
40690 * 'The date in this field must be before {maxValue}').
40692 maxText : "The date in this field must be equal to or before {0}",
40694 * @cfg {String} invalidText
40695 * The error text to display when the date in the field is invalid (defaults to
40696 * '{value} is not a valid date - it must be in the format {format}').
40698 invalidText : "{0} is not a valid date - it must be in the format {1}",
40700 * @cfg {String} triggerClass
40701 * An additional CSS class used to style the trigger button. The trigger will always get the
40702 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
40703 * which displays a calendar icon).
40705 triggerClass : 'x-form-date-trigger',
40709 * @cfg {Boolean} useIso
40710 * if enabled, then the date field will use a hidden field to store the
40711 * real value as iso formated date. default (false)
40715 * @cfg {String/Object} autoCreate
40716 * A DomHelper element spec, or true for a default element spec (defaults to
40717 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
40720 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
40723 hiddenField: false,
40725 onRender : function(ct, position)
40727 Roo.form.DateField.superclass.onRender.call(this, ct, position);
40729 //this.el.dom.removeAttribute('name');
40730 Roo.log("Changing name?");
40731 this.el.dom.setAttribute('name', this.name + '____hidden___' );
40732 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
40734 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
40735 // prevent input submission
40736 this.hiddenName = this.name;
40743 validateValue : function(value)
40745 value = this.formatDate(value);
40746 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
40747 Roo.log('super failed');
40750 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
40753 var svalue = value;
40754 value = this.parseDate(value);
40756 Roo.log('parse date failed' + svalue);
40757 this.markInvalid(String.format(this.invalidText, svalue, this.format));
40760 var time = value.getTime();
40761 if(this.minValue && time < this.minValue.getTime()){
40762 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
40765 if(this.maxValue && time > this.maxValue.getTime()){
40766 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
40769 if(this.disabledDays){
40770 var day = value.getDay();
40771 for(var i = 0; i < this.disabledDays.length; i++) {
40772 if(day === this.disabledDays[i]){
40773 this.markInvalid(this.disabledDaysText);
40778 var fvalue = this.formatDate(value);
40779 if(this.ddMatch && this.ddMatch.test(fvalue)){
40780 this.markInvalid(String.format(this.disabledDatesText, fvalue));
40787 // Provides logic to override the default TriggerField.validateBlur which just returns true
40788 validateBlur : function(){
40789 return !this.menu || !this.menu.isVisible();
40792 getName: function()
40794 // returns hidden if it's set..
40795 if (!this.rendered) {return ''};
40796 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
40801 * Returns the current date value of the date field.
40802 * @return {Date} The date value
40804 getValue : function(){
40806 return this.hiddenField ?
40807 this.hiddenField.value :
40808 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
40812 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
40813 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
40814 * (the default format used is "m/d/y").
40817 //All of these calls set the same date value (May 4, 2006)
40819 //Pass a date object:
40820 var dt = new Date('5/4/06');
40821 dateField.setValue(dt);
40823 //Pass a date string (default format):
40824 dateField.setValue('5/4/06');
40826 //Pass a date string (custom format):
40827 dateField.format = 'Y-m-d';
40828 dateField.setValue('2006-5-4');
40830 * @param {String/Date} date The date or valid date string
40832 setValue : function(date){
40833 if (this.hiddenField) {
40834 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
40836 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
40837 // make sure the value field is always stored as a date..
40838 this.value = this.parseDate(date);
40844 parseDate : function(value){
40845 if(!value || value instanceof Date){
40848 var v = Date.parseDate(value, this.format);
40849 if (!v && this.useIso) {
40850 v = Date.parseDate(value, 'Y-m-d');
40852 if(!v && this.altFormats){
40853 if(!this.altFormatsArray){
40854 this.altFormatsArray = this.altFormats.split("|");
40856 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
40857 v = Date.parseDate(value, this.altFormatsArray[i]);
40864 formatDate : function(date, fmt){
40865 return (!date || !(date instanceof Date)) ?
40866 date : date.dateFormat(fmt || this.format);
40871 select: function(m, d){
40874 this.fireEvent('select', this, d);
40876 show : function(){ // retain focus styling
40880 this.focus.defer(10, this);
40881 var ml = this.menuListeners;
40882 this.menu.un("select", ml.select, this);
40883 this.menu.un("show", ml.show, this);
40884 this.menu.un("hide", ml.hide, this);
40889 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
40890 onTriggerClick : function(){
40894 if(this.menu == null){
40895 this.menu = new Roo.menu.DateMenu();
40897 Roo.apply(this.menu.picker, {
40898 showClear: this.allowBlank,
40899 minDate : this.minValue,
40900 maxDate : this.maxValue,
40901 disabledDatesRE : this.ddMatch,
40902 disabledDatesText : this.disabledDatesText,
40903 disabledDays : this.disabledDays,
40904 disabledDaysText : this.disabledDaysText,
40905 format : this.useIso ? 'Y-m-d' : this.format,
40906 minText : String.format(this.minText, this.formatDate(this.minValue)),
40907 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
40909 this.menu.on(Roo.apply({}, this.menuListeners, {
40912 this.menu.picker.setValue(this.getValue() || new Date());
40913 this.menu.show(this.el, "tl-bl?");
40916 beforeBlur : function(){
40917 var v = this.parseDate(this.getRawValue());
40927 isDirty : function() {
40928 if(this.disabled) {
40932 if(typeof(this.startValue) === 'undefined'){
40936 return String(this.getValue()) !== String(this.startValue);
40940 cleanLeadingSpace : function(e)
40947 * Ext JS Library 1.1.1
40948 * Copyright(c) 2006-2007, Ext JS, LLC.
40950 * Originally Released Under LGPL - original licence link has changed is not relivant.
40953 * <script type="text/javascript">
40957 * @class Roo.form.MonthField
40958 * @extends Roo.form.TriggerField
40959 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
40961 * Create a new MonthField
40962 * @param {Object} config
40964 Roo.form.MonthField = function(config){
40966 Roo.form.MonthField.superclass.constructor.call(this, config);
40972 * Fires when a date is selected
40973 * @param {Roo.form.MonthFieeld} combo This combo box
40974 * @param {Date} date The date selected
40981 if(typeof this.minValue == "string") {
40982 this.minValue = this.parseDate(this.minValue);
40984 if(typeof this.maxValue == "string") {
40985 this.maxValue = this.parseDate(this.maxValue);
40987 this.ddMatch = null;
40988 if(this.disabledDates){
40989 var dd = this.disabledDates;
40991 for(var i = 0; i < dd.length; i++){
40993 if(i != dd.length-1) {
40997 this.ddMatch = new RegExp(re + ")");
41001 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
41003 * @cfg {String} format
41004 * The default date format string which can be overriden for localization support. The format must be
41005 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
41009 * @cfg {String} altFormats
41010 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
41011 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
41013 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
41015 * @cfg {Array} disabledDays
41016 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
41018 disabledDays : [0,1,2,3,4,5,6],
41020 * @cfg {String} disabledDaysText
41021 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
41023 disabledDaysText : "Disabled",
41025 * @cfg {Array} disabledDates
41026 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
41027 * expression so they are very powerful. Some examples:
41029 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
41030 * <li>["03/08", "09/16"] would disable those days for every year</li>
41031 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
41032 * <li>["03/../2006"] would disable every day in March 2006</li>
41033 * <li>["^03"] would disable every day in every March</li>
41035 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
41036 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
41038 disabledDates : null,
41040 * @cfg {String} disabledDatesText
41041 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
41043 disabledDatesText : "Disabled",
41045 * @cfg {Date/String} minValue
41046 * The minimum allowed date. Can be either a Javascript date object or a string date in a
41047 * valid format (defaults to null).
41051 * @cfg {Date/String} maxValue
41052 * The maximum allowed date. Can be either a Javascript date object or a string date in a
41053 * valid format (defaults to null).
41057 * @cfg {String} minText
41058 * The error text to display when the date in the cell is before minValue (defaults to
41059 * 'The date in this field must be after {minValue}').
41061 minText : "The date in this field must be equal to or after {0}",
41063 * @cfg {String} maxTextf
41064 * The error text to display when the date in the cell is after maxValue (defaults to
41065 * 'The date in this field must be before {maxValue}').
41067 maxText : "The date in this field must be equal to or before {0}",
41069 * @cfg {String} invalidText
41070 * The error text to display when the date in the field is invalid (defaults to
41071 * '{value} is not a valid date - it must be in the format {format}').
41073 invalidText : "{0} is not a valid date - it must be in the format {1}",
41075 * @cfg {String} triggerClass
41076 * An additional CSS class used to style the trigger button. The trigger will always get the
41077 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
41078 * which displays a calendar icon).
41080 triggerClass : 'x-form-date-trigger',
41084 * @cfg {Boolean} useIso
41085 * if enabled, then the date field will use a hidden field to store the
41086 * real value as iso formated date. default (true)
41090 * @cfg {String/Object} autoCreate
41091 * A DomHelper element spec, or true for a default element spec (defaults to
41092 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
41095 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "new-password"},
41098 hiddenField: false,
41100 hideMonthPicker : false,
41102 onRender : function(ct, position)
41104 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
41106 this.el.dom.removeAttribute('name');
41107 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
41109 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
41110 // prevent input submission
41111 this.hiddenName = this.name;
41118 validateValue : function(value)
41120 value = this.formatDate(value);
41121 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
41124 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
41127 var svalue = value;
41128 value = this.parseDate(value);
41130 this.markInvalid(String.format(this.invalidText, svalue, this.format));
41133 var time = value.getTime();
41134 if(this.minValue && time < this.minValue.getTime()){
41135 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
41138 if(this.maxValue && time > this.maxValue.getTime()){
41139 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
41142 /*if(this.disabledDays){
41143 var day = value.getDay();
41144 for(var i = 0; i < this.disabledDays.length; i++) {
41145 if(day === this.disabledDays[i]){
41146 this.markInvalid(this.disabledDaysText);
41152 var fvalue = this.formatDate(value);
41153 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
41154 this.markInvalid(String.format(this.disabledDatesText, fvalue));
41162 // Provides logic to override the default TriggerField.validateBlur which just returns true
41163 validateBlur : function(){
41164 return !this.menu || !this.menu.isVisible();
41168 * Returns the current date value of the date field.
41169 * @return {Date} The date value
41171 getValue : function(){
41175 return this.hiddenField ?
41176 this.hiddenField.value :
41177 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
41181 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
41182 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
41183 * (the default format used is "m/d/y").
41186 //All of these calls set the same date value (May 4, 2006)
41188 //Pass a date object:
41189 var dt = new Date('5/4/06');
41190 monthField.setValue(dt);
41192 //Pass a date string (default format):
41193 monthField.setValue('5/4/06');
41195 //Pass a date string (custom format):
41196 monthField.format = 'Y-m-d';
41197 monthField.setValue('2006-5-4');
41199 * @param {String/Date} date The date or valid date string
41201 setValue : function(date){
41202 Roo.log('month setValue' + date);
41203 // can only be first of month..
41205 var val = this.parseDate(date);
41207 if (this.hiddenField) {
41208 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
41210 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
41211 this.value = this.parseDate(date);
41215 parseDate : function(value){
41216 if(!value || value instanceof Date){
41217 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
41220 var v = Date.parseDate(value, this.format);
41221 if (!v && this.useIso) {
41222 v = Date.parseDate(value, 'Y-m-d');
41226 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
41230 if(!v && this.altFormats){
41231 if(!this.altFormatsArray){
41232 this.altFormatsArray = this.altFormats.split("|");
41234 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
41235 v = Date.parseDate(value, this.altFormatsArray[i]);
41242 formatDate : function(date, fmt){
41243 return (!date || !(date instanceof Date)) ?
41244 date : date.dateFormat(fmt || this.format);
41249 select: function(m, d){
41251 this.fireEvent('select', this, d);
41253 show : function(){ // retain focus styling
41257 this.focus.defer(10, this);
41258 var ml = this.menuListeners;
41259 this.menu.un("select", ml.select, this);
41260 this.menu.un("show", ml.show, this);
41261 this.menu.un("hide", ml.hide, this);
41265 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
41266 onTriggerClick : function(){
41270 if(this.menu == null){
41271 this.menu = new Roo.menu.DateMenu();
41275 Roo.apply(this.menu.picker, {
41277 showClear: this.allowBlank,
41278 minDate : this.minValue,
41279 maxDate : this.maxValue,
41280 disabledDatesRE : this.ddMatch,
41281 disabledDatesText : this.disabledDatesText,
41283 format : this.useIso ? 'Y-m-d' : this.format,
41284 minText : String.format(this.minText, this.formatDate(this.minValue)),
41285 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
41288 this.menu.on(Roo.apply({}, this.menuListeners, {
41296 // hide month picker get's called when we called by 'before hide';
41298 var ignorehide = true;
41299 p.hideMonthPicker = function(disableAnim){
41303 if(this.monthPicker){
41304 Roo.log("hideMonthPicker called");
41305 if(disableAnim === true){
41306 this.monthPicker.hide();
41308 this.monthPicker.slideOut('t', {duration:.2});
41309 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
41310 p.fireEvent("select", this, this.value);
41316 Roo.log('picker set value');
41317 Roo.log(this.getValue());
41318 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
41319 m.show(this.el, 'tl-bl?');
41320 ignorehide = false;
41321 // this will trigger hideMonthPicker..
41324 // hidden the day picker
41325 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
41331 p.showMonthPicker.defer(100, p);
41337 beforeBlur : function(){
41338 var v = this.parseDate(this.getRawValue());
41344 /** @cfg {Boolean} grow @hide */
41345 /** @cfg {Number} growMin @hide */
41346 /** @cfg {Number} growMax @hide */
41353 * Ext JS Library 1.1.1
41354 * Copyright(c) 2006-2007, Ext JS, LLC.
41356 * Originally Released Under LGPL - original licence link has changed is not relivant.
41359 * <script type="text/javascript">
41364 * @class Roo.form.ComboBox
41365 * @extends Roo.form.TriggerField
41366 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
41368 * Create a new ComboBox.
41369 * @param {Object} config Configuration options
41371 Roo.form.ComboBox = function(config){
41372 Roo.form.ComboBox.superclass.constructor.call(this, config);
41376 * Fires when the dropdown list is expanded
41377 * @param {Roo.form.ComboBox} combo This combo box
41382 * Fires when the dropdown list is collapsed
41383 * @param {Roo.form.ComboBox} combo This combo box
41387 * @event beforeselect
41388 * Fires before a list item is selected. Return false to cancel the selection.
41389 * @param {Roo.form.ComboBox} combo This combo box
41390 * @param {Roo.data.Record} record The data record returned from the underlying store
41391 * @param {Number} index The index of the selected item in the dropdown list
41393 'beforeselect' : true,
41396 * Fires when a list item is selected
41397 * @param {Roo.form.ComboBox} combo This combo box
41398 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
41399 * @param {Number} index The index of the selected item in the dropdown list
41403 * @event beforequery
41404 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
41405 * The event object passed has these properties:
41406 * @param {Roo.form.ComboBox} combo This combo box
41407 * @param {String} query The query
41408 * @param {Boolean} forceAll true to force "all" query
41409 * @param {Boolean} cancel true to cancel the query
41410 * @param {Object} e The query event object
41412 'beforequery': true,
41415 * Fires when the 'add' icon is pressed (add a listener to enable add button)
41416 * @param {Roo.form.ComboBox} combo This combo box
41421 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
41422 * @param {Roo.form.ComboBox} combo This combo box
41423 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
41429 if(this.transform){
41430 this.allowDomMove = false;
41431 var s = Roo.getDom(this.transform);
41432 if(!this.hiddenName){
41433 this.hiddenName = s.name;
41436 this.mode = 'local';
41437 var d = [], opts = s.options;
41438 for(var i = 0, len = opts.length;i < len; i++){
41440 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
41442 this.value = value;
41444 d.push([value, o.text]);
41446 this.store = new Roo.data.SimpleStore({
41448 fields: ['value', 'text'],
41451 this.valueField = 'value';
41452 this.displayField = 'text';
41454 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
41455 if(!this.lazyRender){
41456 this.target = true;
41457 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
41458 s.parentNode.removeChild(s); // remove it
41459 this.render(this.el.parentNode);
41461 s.parentNode.removeChild(s); // remove it
41466 this.store = Roo.factory(this.store, Roo.data);
41469 this.selectedIndex = -1;
41470 if(this.mode == 'local'){
41471 if(config.queryDelay === undefined){
41472 this.queryDelay = 10;
41474 if(config.minChars === undefined){
41480 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
41482 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
41485 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
41486 * rendering into an Roo.Editor, defaults to false)
41489 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
41490 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
41493 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
41496 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
41497 * the dropdown list (defaults to undefined, with no header element)
41501 * @cfg {String/Roo.Template} tpl The template to use to render the output
41505 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
41507 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
41509 listWidth: undefined,
41511 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
41512 * mode = 'remote' or 'text' if mode = 'local')
41514 displayField: undefined,
41516 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
41517 * mode = 'remote' or 'value' if mode = 'local').
41518 * Note: use of a valueField requires the user make a selection
41519 * in order for a value to be mapped.
41521 valueField: undefined,
41525 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
41526 * field's data value (defaults to the underlying DOM element's name)
41528 hiddenName: undefined,
41530 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
41534 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
41536 selectedClass: 'x-combo-selected',
41538 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
41539 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
41540 * which displays a downward arrow icon).
41542 triggerClass : 'x-form-arrow-trigger',
41544 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
41548 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
41549 * anchor positions (defaults to 'tl-bl')
41551 listAlign: 'tl-bl?',
41553 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
41557 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
41558 * query specified by the allQuery config option (defaults to 'query')
41560 triggerAction: 'query',
41562 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
41563 * (defaults to 4, does not apply if editable = false)
41567 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
41568 * delay (typeAheadDelay) if it matches a known value (defaults to false)
41572 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
41573 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
41577 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
41578 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
41582 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
41583 * when editable = true (defaults to false)
41585 selectOnFocus:false,
41587 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
41589 queryParam: 'query',
41591 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
41592 * when mode = 'remote' (defaults to 'Loading...')
41594 loadingText: 'Loading...',
41596 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
41600 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
41604 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
41605 * traditional select (defaults to true)
41609 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
41613 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
41617 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
41618 * listWidth has a higher value)
41622 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
41623 * allow the user to set arbitrary text into the field (defaults to false)
41625 forceSelection:false,
41627 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
41628 * if typeAhead = true (defaults to 250)
41630 typeAheadDelay : 250,
41632 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
41633 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
41635 valueNotFoundText : undefined,
41637 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
41639 blockFocus : false,
41642 * @cfg {Boolean} disableClear Disable showing of clear button.
41644 disableClear : false,
41646 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
41648 alwaysQuery : false,
41654 // element that contains real text value.. (when hidden is used..)
41657 onRender : function(ct, position)
41659 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
41661 if(this.hiddenName){
41662 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
41664 this.hiddenField.value =
41665 this.hiddenValue !== undefined ? this.hiddenValue :
41666 this.value !== undefined ? this.value : '';
41668 // prevent input submission
41669 this.el.dom.removeAttribute('name');
41675 this.el.dom.setAttribute('autocomplete', 'off');
41678 var cls = 'x-combo-list';
41680 this.list = new Roo.Layer({
41681 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
41684 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
41685 this.list.setWidth(lw);
41686 this.list.swallowEvent('mousewheel');
41687 this.assetHeight = 0;
41690 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
41691 this.assetHeight += this.header.getHeight();
41694 this.innerList = this.list.createChild({cls:cls+'-inner'});
41695 this.innerList.on('mouseover', this.onViewOver, this);
41696 this.innerList.on('mousemove', this.onViewMove, this);
41697 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41699 if(this.allowBlank && !this.pageSize && !this.disableClear){
41700 this.footer = this.list.createChild({cls:cls+'-ft'});
41701 this.pageTb = new Roo.Toolbar(this.footer);
41705 this.footer = this.list.createChild({cls:cls+'-ft'});
41706 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
41707 {pageSize: this.pageSize});
41711 if (this.pageTb && this.allowBlank && !this.disableClear) {
41713 this.pageTb.add(new Roo.Toolbar.Fill(), {
41714 cls: 'x-btn-icon x-btn-clear',
41716 handler: function()
41719 _this.clearValue();
41720 _this.onSelect(false, -1);
41725 this.assetHeight += this.footer.getHeight();
41730 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
41733 this.view = new Roo.View(this.innerList, this.tpl, {
41736 selectedClass: this.selectedClass
41739 this.view.on('click', this.onViewClick, this);
41741 this.store.on('beforeload', this.onBeforeLoad, this);
41742 this.store.on('load', this.onLoad, this);
41743 this.store.on('loadexception', this.onLoadException, this);
41745 if(this.resizable){
41746 this.resizer = new Roo.Resizable(this.list, {
41747 pinned:true, handles:'se'
41749 this.resizer.on('resize', function(r, w, h){
41750 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
41751 this.listWidth = w;
41752 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
41753 this.restrictHeight();
41755 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
41757 if(!this.editable){
41758 this.editable = true;
41759 this.setEditable(false);
41763 if (typeof(this.events.add.listeners) != 'undefined') {
41765 this.addicon = this.wrap.createChild(
41766 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
41768 this.addicon.on('click', function(e) {
41769 this.fireEvent('add', this);
41772 if (typeof(this.events.edit.listeners) != 'undefined') {
41774 this.editicon = this.wrap.createChild(
41775 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
41776 if (this.addicon) {
41777 this.editicon.setStyle('margin-left', '40px');
41779 this.editicon.on('click', function(e) {
41781 // we fire even if inothing is selected..
41782 this.fireEvent('edit', this, this.lastData );
41792 initEvents : function(){
41793 Roo.form.ComboBox.superclass.initEvents.call(this);
41795 this.keyNav = new Roo.KeyNav(this.el, {
41796 "up" : function(e){
41797 this.inKeyMode = true;
41801 "down" : function(e){
41802 if(!this.isExpanded()){
41803 this.onTriggerClick();
41805 this.inKeyMode = true;
41810 "enter" : function(e){
41811 this.onViewClick();
41815 "esc" : function(e){
41819 "tab" : function(e){
41820 this.onViewClick(false);
41821 this.fireEvent("specialkey", this, e);
41827 doRelay : function(foo, bar, hname){
41828 if(hname == 'down' || this.scope.isExpanded()){
41829 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
41836 this.queryDelay = Math.max(this.queryDelay || 10,
41837 this.mode == 'local' ? 10 : 250);
41838 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
41839 if(this.typeAhead){
41840 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
41842 if(this.editable !== false){
41843 this.el.on("keyup", this.onKeyUp, this);
41845 if(this.forceSelection){
41846 this.on('blur', this.doForce, this);
41850 onDestroy : function(){
41852 this.view.setStore(null);
41853 this.view.el.removeAllListeners();
41854 this.view.el.remove();
41855 this.view.purgeListeners();
41858 this.list.destroy();
41861 this.store.un('beforeload', this.onBeforeLoad, this);
41862 this.store.un('load', this.onLoad, this);
41863 this.store.un('loadexception', this.onLoadException, this);
41865 Roo.form.ComboBox.superclass.onDestroy.call(this);
41869 fireKey : function(e){
41870 if(e.isNavKeyPress() && !this.list.isVisible()){
41871 this.fireEvent("specialkey", this, e);
41876 onResize: function(w, h){
41877 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
41879 if(typeof w != 'number'){
41880 // we do not handle it!?!?
41883 var tw = this.trigger.getWidth();
41884 tw += this.addicon ? this.addicon.getWidth() : 0;
41885 tw += this.editicon ? this.editicon.getWidth() : 0;
41887 this.el.setWidth( this.adjustWidth('input', x));
41889 this.trigger.setStyle('left', x+'px');
41891 if(this.list && this.listWidth === undefined){
41892 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
41893 this.list.setWidth(lw);
41894 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
41902 * Allow or prevent the user from directly editing the field text. If false is passed,
41903 * the user will only be able to select from the items defined in the dropdown list. This method
41904 * is the runtime equivalent of setting the 'editable' config option at config time.
41905 * @param {Boolean} value True to allow the user to directly edit the field text
41907 setEditable : function(value){
41908 if(value == this.editable){
41911 this.editable = value;
41913 this.el.dom.setAttribute('readOnly', true);
41914 this.el.on('mousedown', this.onTriggerClick, this);
41915 this.el.addClass('x-combo-noedit');
41917 this.el.dom.setAttribute('readOnly', false);
41918 this.el.un('mousedown', this.onTriggerClick, this);
41919 this.el.removeClass('x-combo-noedit');
41924 onBeforeLoad : function(){
41925 if(!this.hasFocus){
41928 this.innerList.update(this.loadingText ?
41929 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
41930 this.restrictHeight();
41931 this.selectedIndex = -1;
41935 onLoad : function(){
41936 if(!this.hasFocus){
41939 if(this.store.getCount() > 0){
41941 this.restrictHeight();
41942 if(this.lastQuery == this.allQuery){
41944 this.el.dom.select();
41946 if(!this.selectByValue(this.value, true)){
41947 this.select(0, true);
41951 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
41952 this.taTask.delay(this.typeAheadDelay);
41956 this.onEmptyResults();
41961 onLoadException : function()
41964 Roo.log(this.store.reader.jsonData);
41965 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
41966 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
41972 onTypeAhead : function(){
41973 if(this.store.getCount() > 0){
41974 var r = this.store.getAt(0);
41975 var newValue = r.data[this.displayField];
41976 var len = newValue.length;
41977 var selStart = this.getRawValue().length;
41978 if(selStart != len){
41979 this.setRawValue(newValue);
41980 this.selectText(selStart, newValue.length);
41986 onSelect : function(record, index){
41987 if(this.fireEvent('beforeselect', this, record, index) !== false){
41988 this.setFromData(index > -1 ? record.data : false);
41990 this.fireEvent('select', this, record, index);
41995 * Returns the currently selected field value or empty string if no value is set.
41996 * @return {String} value The selected value
41998 getValue : function(){
41999 if(this.valueField){
42000 return typeof this.value != 'undefined' ? this.value : '';
42002 return Roo.form.ComboBox.superclass.getValue.call(this);
42006 * Clears any text/value currently set in the field
42008 clearValue : function(){
42009 if(this.hiddenField){
42010 this.hiddenField.value = '';
42013 this.setRawValue('');
42014 this.lastSelectionText = '';
42019 * Sets the specified value into the field. If the value finds a match, the corresponding record text
42020 * will be displayed in the field. If the value does not match the data value of an existing item,
42021 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
42022 * Otherwise the field will be blank (although the value will still be set).
42023 * @param {String} value The value to match
42025 setValue : function(v){
42027 if(this.valueField){
42028 var r = this.findRecord(this.valueField, v);
42030 text = r.data[this.displayField];
42031 }else if(this.valueNotFoundText !== undefined){
42032 text = this.valueNotFoundText;
42035 this.lastSelectionText = text;
42036 if(this.hiddenField){
42037 this.hiddenField.value = v;
42039 Roo.form.ComboBox.superclass.setValue.call(this, text);
42043 * @property {Object} the last set data for the element
42048 * Sets the value of the field based on a object which is related to the record format for the store.
42049 * @param {Object} value the value to set as. or false on reset?
42051 setFromData : function(o){
42052 var dv = ''; // display value
42053 var vv = ''; // value value..
42055 if (this.displayField) {
42056 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
42058 // this is an error condition!!!
42059 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
42062 if(this.valueField){
42063 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
42065 if(this.hiddenField){
42066 this.hiddenField.value = vv;
42068 this.lastSelectionText = dv;
42069 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42073 // no hidden field.. - we store the value in 'value', but still display
42074 // display field!!!!
42075 this.lastSelectionText = dv;
42076 Roo.form.ComboBox.superclass.setValue.call(this, dv);
42082 reset : function(){
42083 // overridden so that last data is reset..
42084 this.setValue(this.resetValue);
42085 this.originalValue = this.getValue();
42086 this.clearInvalid();
42087 this.lastData = false;
42089 this.view.clearSelections();
42093 findRecord : function(prop, value){
42095 if(this.store.getCount() > 0){
42096 this.store.each(function(r){
42097 if(r.data[prop] == value){
42107 getName: function()
42109 // returns hidden if it's set..
42110 if (!this.rendered) {return ''};
42111 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
42115 onViewMove : function(e, t){
42116 this.inKeyMode = false;
42120 onViewOver : function(e, t){
42121 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
42124 var item = this.view.findItemFromChild(t);
42126 var index = this.view.indexOf(item);
42127 this.select(index, false);
42132 onViewClick : function(doFocus)
42134 var index = this.view.getSelectedIndexes()[0];
42135 var r = this.store.getAt(index);
42137 this.onSelect(r, index);
42139 if(doFocus !== false && !this.blockFocus){
42145 restrictHeight : function(){
42146 this.innerList.dom.style.height = '';
42147 var inner = this.innerList.dom;
42148 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
42149 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
42150 this.list.beginUpdate();
42151 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
42152 this.list.alignTo(this.el, this.listAlign);
42153 this.list.endUpdate();
42157 onEmptyResults : function(){
42162 * Returns true if the dropdown list is expanded, else false.
42164 isExpanded : function(){
42165 return this.list.isVisible();
42169 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
42170 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42171 * @param {String} value The data value of the item to select
42172 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42173 * selected item if it is not currently in view (defaults to true)
42174 * @return {Boolean} True if the value matched an item in the list, else false
42176 selectByValue : function(v, scrollIntoView){
42177 if(v !== undefined && v !== null){
42178 var r = this.findRecord(this.valueField || this.displayField, v);
42180 this.select(this.store.indexOf(r), scrollIntoView);
42188 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
42189 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
42190 * @param {Number} index The zero-based index of the list item to select
42191 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
42192 * selected item if it is not currently in view (defaults to true)
42194 select : function(index, scrollIntoView){
42195 this.selectedIndex = index;
42196 this.view.select(index);
42197 if(scrollIntoView !== false){
42198 var el = this.view.getNode(index);
42200 this.innerList.scrollChildIntoView(el, false);
42206 selectNext : function(){
42207 var ct = this.store.getCount();
42209 if(this.selectedIndex == -1){
42211 }else if(this.selectedIndex < ct-1){
42212 this.select(this.selectedIndex+1);
42218 selectPrev : function(){
42219 var ct = this.store.getCount();
42221 if(this.selectedIndex == -1){
42223 }else if(this.selectedIndex != 0){
42224 this.select(this.selectedIndex-1);
42230 onKeyUp : function(e){
42231 if(this.editable !== false && !e.isSpecialKey()){
42232 this.lastKey = e.getKey();
42233 this.dqTask.delay(this.queryDelay);
42238 validateBlur : function(){
42239 return !this.list || !this.list.isVisible();
42243 initQuery : function(){
42244 this.doQuery(this.getRawValue());
42248 doForce : function(){
42249 if(this.el.dom.value.length > 0){
42250 this.el.dom.value =
42251 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
42257 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
42258 * query allowing the query action to be canceled if needed.
42259 * @param {String} query The SQL query to execute
42260 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
42261 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
42262 * saved in the current store (defaults to false)
42264 doQuery : function(q, forceAll){
42265 if(q === undefined || q === null){
42270 forceAll: forceAll,
42274 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
42278 forceAll = qe.forceAll;
42279 if(forceAll === true || (q.length >= this.minChars)){
42280 if(this.lastQuery != q || this.alwaysQuery){
42281 this.lastQuery = q;
42282 if(this.mode == 'local'){
42283 this.selectedIndex = -1;
42285 this.store.clearFilter();
42287 this.store.filter(this.displayField, q);
42291 this.store.baseParams[this.queryParam] = q;
42293 params: this.getParams(q)
42298 this.selectedIndex = -1;
42305 getParams : function(q){
42307 //p[this.queryParam] = q;
42310 p.limit = this.pageSize;
42316 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
42318 collapse : function(){
42319 if(!this.isExpanded()){
42323 Roo.get(document).un('mousedown', this.collapseIf, this);
42324 Roo.get(document).un('mousewheel', this.collapseIf, this);
42325 if (!this.editable) {
42326 Roo.get(document).un('keydown', this.listKeyPress, this);
42328 this.fireEvent('collapse', this);
42332 collapseIf : function(e){
42333 if(!e.within(this.wrap) && !e.within(this.list)){
42339 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
42341 expand : function(){
42342 if(this.isExpanded() || !this.hasFocus){
42345 this.list.alignTo(this.el, this.listAlign);
42347 Roo.get(document).on('mousedown', this.collapseIf, this);
42348 Roo.get(document).on('mousewheel', this.collapseIf, this);
42349 if (!this.editable) {
42350 Roo.get(document).on('keydown', this.listKeyPress, this);
42353 this.fireEvent('expand', this);
42357 // Implements the default empty TriggerField.onTriggerClick function
42358 onTriggerClick : function(){
42362 if(this.isExpanded()){
42364 if (!this.blockFocus) {
42369 this.hasFocus = true;
42370 if(this.triggerAction == 'all') {
42371 this.doQuery(this.allQuery, true);
42373 this.doQuery(this.getRawValue());
42375 if (!this.blockFocus) {
42380 listKeyPress : function(e)
42382 //Roo.log('listkeypress');
42383 // scroll to first matching element based on key pres..
42384 if (e.isSpecialKey()) {
42387 var k = String.fromCharCode(e.getKey()).toUpperCase();
42390 var csel = this.view.getSelectedNodes();
42391 var cselitem = false;
42393 var ix = this.view.indexOf(csel[0]);
42394 cselitem = this.store.getAt(ix);
42395 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
42401 this.store.each(function(v) {
42403 // start at existing selection.
42404 if (cselitem.id == v.id) {
42410 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
42411 match = this.store.indexOf(v);
42416 if (match === false) {
42417 return true; // no more action?
42420 this.view.select(match);
42421 var sn = Roo.get(this.view.getSelectedNodes()[0]);
42422 sn.scrollIntoView(sn.dom.parentNode, false);
42426 * @cfg {Boolean} grow
42430 * @cfg {Number} growMin
42434 * @cfg {Number} growMax
42442 * Copyright(c) 2010-2012, Roo J Solutions Limited
42449 * @class Roo.form.ComboBoxArray
42450 * @extends Roo.form.TextField
42451 * A facebook style adder... for lists of email / people / countries etc...
42452 * pick multiple items from a combo box, and shows each one.
42454 * Fred [x] Brian [x] [Pick another |v]
42457 * For this to work: it needs various extra information
42458 * - normal combo problay has
42460 * + displayField, valueField
42462 * For our purpose...
42465 * If we change from 'extends' to wrapping...
42472 * Create a new ComboBoxArray.
42473 * @param {Object} config Configuration options
42477 Roo.form.ComboBoxArray = function(config)
42481 * @event beforeremove
42482 * Fires before remove the value from the list
42483 * @param {Roo.form.ComboBoxArray} _self This combo box array
42484 * @param {Roo.form.ComboBoxArray.Item} item removed item
42486 'beforeremove' : true,
42489 * Fires when remove the value from the list
42490 * @param {Roo.form.ComboBoxArray} _self This combo box array
42491 * @param {Roo.form.ComboBoxArray.Item} item removed item
42498 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
42500 this.items = new Roo.util.MixedCollection(false);
42502 // construct the child combo...
42512 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
42515 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
42520 // behavies liek a hiddne field
42521 inputType: 'hidden',
42523 * @cfg {Number} width The width of the box that displays the selected element
42530 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
42534 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
42536 hiddenName : false,
42538 * @cfg {String} seperator The value seperator normally ','
42542 // private the array of items that are displayed..
42544 // private - the hidden field el.
42546 // private - the filed el..
42549 //validateValue : function() { return true; }, // all values are ok!
42550 //onAddClick: function() { },
42552 onRender : function(ct, position)
42555 // create the standard hidden element
42556 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
42559 // give fake names to child combo;
42560 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
42561 this.combo.name = this.name ? (this.name+'-subcombo') : this.name;
42563 this.combo = Roo.factory(this.combo, Roo.form);
42564 this.combo.onRender(ct, position);
42565 if (typeof(this.combo.width) != 'undefined') {
42566 this.combo.onResize(this.combo.width,0);
42569 this.combo.initEvents();
42571 // assigned so form know we need to do this..
42572 this.store = this.combo.store;
42573 this.valueField = this.combo.valueField;
42574 this.displayField = this.combo.displayField ;
42577 this.combo.wrap.addClass('x-cbarray-grp');
42579 var cbwrap = this.combo.wrap.createChild(
42580 {tag: 'div', cls: 'x-cbarray-cb'},
42585 this.hiddenEl = this.combo.wrap.createChild({
42586 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
42588 this.el = this.combo.wrap.createChild({
42589 tag: 'input', type:'hidden' , name: this.name, value : ''
42591 // this.el.dom.removeAttribute("name");
42594 this.outerWrap = this.combo.wrap;
42595 this.wrap = cbwrap;
42597 this.outerWrap.setWidth(this.width);
42598 this.outerWrap.dom.removeChild(this.el.dom);
42600 this.wrap.dom.appendChild(this.el.dom);
42601 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
42602 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
42604 this.combo.trigger.setStyle('position','relative');
42605 this.combo.trigger.setStyle('left', '0px');
42606 this.combo.trigger.setStyle('top', '2px');
42608 this.combo.el.setStyle('vertical-align', 'text-bottom');
42610 //this.trigger.setStyle('vertical-align', 'top');
42612 // this should use the code from combo really... on('add' ....)
42616 this.adder = this.outerWrap.createChild(
42617 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
42619 this.adder.on('click', function(e) {
42620 _t.fireEvent('adderclick', this, e);
42624 //this.adder.on('click', this.onAddClick, _t);
42627 this.combo.on('select', function(cb, rec, ix) {
42628 this.addItem(rec.data);
42631 cb.el.dom.value = '';
42632 //cb.lastData = rec.data;
42641 getName: function()
42643 // returns hidden if it's set..
42644 if (!this.rendered) {return ''};
42645 return this.hiddenName ? this.hiddenName : this.name;
42650 onResize: function(w, h){
42653 // not sure if this is needed..
42654 //this.combo.onResize(w,h);
42656 if(typeof w != 'number'){
42657 // we do not handle it!?!?
42660 var tw = this.combo.trigger.getWidth();
42661 tw += this.addicon ? this.addicon.getWidth() : 0;
42662 tw += this.editicon ? this.editicon.getWidth() : 0;
42664 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
42666 this.combo.trigger.setStyle('left', '0px');
42668 if(this.list && this.listWidth === undefined){
42669 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
42670 this.list.setWidth(lw);
42671 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
42678 addItem: function(rec)
42680 var valueField = this.combo.valueField;
42681 var displayField = this.combo.displayField;
42683 if (this.items.indexOfKey(rec[valueField]) > -1) {
42684 //console.log("GOT " + rec.data.id);
42688 var x = new Roo.form.ComboBoxArray.Item({
42689 //id : rec[this.idField],
42691 displayField : displayField ,
42692 tipField : displayField ,
42696 this.items.add(rec[valueField],x);
42697 // add it before the element..
42698 this.updateHiddenEl();
42699 x.render(this.outerWrap, this.wrap.dom);
42700 // add the image handler..
42703 updateHiddenEl : function()
42706 if (!this.hiddenEl) {
42710 var idField = this.combo.valueField;
42712 this.items.each(function(f) {
42713 ar.push(f.data[idField]);
42715 this.hiddenEl.dom.value = ar.join(this.seperator);
42721 this.items.clear();
42723 Roo.each(this.outerWrap.select('.x-cbarray-item', true).elements, function(el){
42727 this.el.dom.value = '';
42728 if (this.hiddenEl) {
42729 this.hiddenEl.dom.value = '';
42733 getValue: function()
42735 return this.hiddenEl ? this.hiddenEl.dom.value : '';
42737 setValue: function(v) // not a valid action - must use addItems..
42742 if (this.store.isLocal && (typeof(v) == 'string')) {
42743 // then we can use the store to find the values..
42744 // comma seperated at present.. this needs to allow JSON based encoding..
42745 this.hiddenEl.value = v;
42747 Roo.each(v.split(this.seperator), function(k) {
42748 Roo.log("CHECK " + this.valueField + ',' + k);
42749 var li = this.store.query(this.valueField, k);
42754 add[this.valueField] = k;
42755 add[this.displayField] = li.item(0).data[this.displayField];
42761 if (typeof(v) == 'object' ) {
42762 // then let's assume it's an array of objects..
42763 Roo.each(v, function(l) {
42765 if (typeof(l) == 'string') {
42767 add[this.valueField] = l;
42768 add[this.displayField] = l
42777 setFromData: function(v)
42779 // this recieves an object, if setValues is called.
42781 this.el.dom.value = v[this.displayField];
42782 this.hiddenEl.dom.value = v[this.valueField];
42783 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
42786 var kv = v[this.valueField];
42787 var dv = v[this.displayField];
42788 kv = typeof(kv) != 'string' ? '' : kv;
42789 dv = typeof(dv) != 'string' ? '' : dv;
42792 var keys = kv.split(this.seperator);
42793 var display = dv.split(this.seperator);
42794 for (var i = 0 ; i < keys.length; i++) {
42796 add[this.valueField] = keys[i];
42797 add[this.displayField] = display[i];
42805 * Validates the combox array value
42806 * @return {Boolean} True if the value is valid, else false
42808 validate : function(){
42809 if(this.disabled || this.validateValue(this.processValue(this.getValue()))){
42810 this.clearInvalid();
42816 validateValue : function(value){
42817 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
42825 isDirty : function() {
42826 if(this.disabled) {
42831 var d = Roo.decode(String(this.originalValue));
42833 return String(this.getValue()) !== String(this.originalValue);
42836 var originalValue = [];
42838 for (var i = 0; i < d.length; i++){
42839 originalValue.push(d[i][this.valueField]);
42842 return String(this.getValue()) !== String(originalValue.join(this.seperator));
42851 * @class Roo.form.ComboBoxArray.Item
42852 * @extends Roo.BoxComponent
42853 * A selected item in the list
42854 * Fred [x] Brian [x] [Pick another |v]
42857 * Create a new item.
42858 * @param {Object} config Configuration options
42861 Roo.form.ComboBoxArray.Item = function(config) {
42862 config.id = Roo.id();
42863 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
42866 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
42869 displayField : false,
42873 defaultAutoCreate : {
42875 cls: 'x-cbarray-item',
42882 src : Roo.BLANK_IMAGE_URL ,
42890 onRender : function(ct, position)
42892 Roo.form.Field.superclass.onRender.call(this, ct, position);
42895 var cfg = this.getAutoCreate();
42896 this.el = ct.createChild(cfg, position);
42899 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
42901 this.el.child('div').dom.innerHTML = this.cb.renderer ?
42902 this.cb.renderer(this.data) :
42903 String.format('{0}',this.data[this.displayField]);
42906 this.el.child('div').dom.setAttribute('qtip',
42907 String.format('{0}',this.data[this.tipField])
42910 this.el.child('img').on('click', this.remove, this);
42914 remove : function()
42916 if(this.cb.disabled){
42920 if(false !== this.cb.fireEvent('beforeremove', this.cb, this)){
42921 this.cb.items.remove(this);
42922 this.el.child('img').un('click', this.remove, this);
42924 this.cb.updateHiddenEl();
42926 this.cb.fireEvent('remove', this.cb, this);
42931 * RooJS Library 1.1.1
42932 * Copyright(c) 2008-2011 Alan Knowles
42939 * @class Roo.form.ComboNested
42940 * @extends Roo.form.ComboBox
42941 * A combobox for that allows selection of nested items in a list,
42956 * Create a new ComboNested
42957 * @param {Object} config Configuration options
42959 Roo.form.ComboNested = function(config){
42960 Roo.form.ComboCheck.superclass.constructor.call(this, config);
42961 // should verify some data...
42963 // hiddenName = required..
42964 // displayField = required
42965 // valudField == required
42966 var req= [ 'hiddenName', 'displayField', 'valueField' ];
42968 Roo.each(req, function(e) {
42969 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
42970 throw "Roo.form.ComboNested : missing value for: " + e;
42977 Roo.extend(Roo.form.ComboNested, Roo.form.ComboBox, {
42980 * @config {Number} max Number of columns to show
42985 list : null, // the outermost div..
42986 innerLists : null, // the
42990 loadingChildren : false,
42992 onRender : function(ct, position)
42994 Roo.form.ComboBox.superclass.onRender.call(this, ct, position); // skip parent call - got to above..
42996 if(this.hiddenName){
42997 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
42999 this.hiddenField.value =
43000 this.hiddenValue !== undefined ? this.hiddenValue :
43001 this.value !== undefined ? this.value : '';
43003 // prevent input submission
43004 this.el.dom.removeAttribute('name');
43010 this.el.dom.setAttribute('autocomplete', 'off');
43013 var cls = 'x-combo-list';
43015 this.list = new Roo.Layer({
43016 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
43019 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
43020 this.list.setWidth(lw);
43021 this.list.swallowEvent('mousewheel');
43022 this.assetHeight = 0;
43025 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
43026 this.assetHeight += this.header.getHeight();
43028 this.innerLists = [];
43031 for (var i =0 ; i < this.maxColumns; i++) {
43032 this.onRenderList( cls, i);
43035 // always needs footer, as we are going to have an 'OK' button.
43036 this.footer = this.list.createChild({cls:cls+'-ft'});
43037 this.pageTb = new Roo.Toolbar(this.footer);
43042 handler: function()
43048 if ( this.allowBlank && !this.disableClear) {
43050 this.pageTb.add(new Roo.Toolbar.Fill(), {
43051 cls: 'x-btn-icon x-btn-clear',
43053 handler: function()
43056 _this.clearValue();
43057 _this.onSelect(false, -1);
43062 this.assetHeight += this.footer.getHeight();
43066 onRenderList : function ( cls, i)
43069 var lw = Math.floor(
43070 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43073 this.list.setWidth(lw); // default to '1'
43075 var il = this.innerLists[i] = this.list.createChild({cls:cls+'-inner'});
43076 //il.on('mouseover', this.onViewOver, this, { list: i });
43077 //il.on('mousemove', this.onViewMove, this, { list: i });
43079 il.setStyle({ 'overflow-x' : 'hidden'});
43082 this.tpl = new Roo.Template({
43083 html : '<div class="'+cls+'-item '+cls+'-item-{cn:this.isEmpty}">{' + this.displayField + '}</div>',
43084 isEmpty: function (value, allValues) {
43086 var dl = typeof(value.data) != 'undefined' ? value.data.length : value.length; ///json is a nested response..
43087 return dl ? 'has-children' : 'no-children'
43092 var store = this.store;
43094 store = new Roo.data.SimpleStore({
43095 //fields : this.store.reader.meta.fields,
43096 reader : this.store.reader,
43100 this.stores[i] = store;
43102 var view = this.views[i] = new Roo.View(
43108 selectedClass: this.selectedClass
43111 view.getEl().setWidth(lw);
43112 view.getEl().setStyle({
43113 position: i < 1 ? 'relative' : 'absolute',
43115 left: (i * lw ) + 'px',
43116 display : i > 0 ? 'none' : 'block'
43118 view.on('selectionchange', this.onSelectChange.createDelegate(this, {list : i }, true));
43119 view.on('dblclick', this.onDoubleClick.createDelegate(this, {list : i }, true));
43120 //view.on('click', this.onViewClick, this, { list : i });
43122 store.on('beforeload', this.onBeforeLoad, this);
43123 store.on('load', this.onLoad, this, { list : i});
43124 store.on('loadexception', this.onLoadException, this);
43126 // hide the other vies..
43132 restrictHeight : function()
43135 Roo.each(this.innerLists, function(il,i) {
43136 var el = this.views[i].getEl();
43137 el.dom.style.height = '';
43138 var inner = el.dom;
43139 var h = Math.max(il.clientHeight, il.offsetHeight, il.scrollHeight);
43140 // only adjust heights on other ones..
43141 mh = Math.max(h, mh);
43144 el.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43145 il.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
43152 this.list.beginUpdate();
43153 this.list.setHeight(mh+this.list.getFrameWidth('tb')+this.assetHeight);
43154 this.list.alignTo(this.el, this.listAlign);
43155 this.list.endUpdate();
43160 // -- store handlers..
43162 onBeforeLoad : function()
43164 if(!this.hasFocus){
43167 this.innerLists[0].update(this.loadingText ?
43168 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
43169 this.restrictHeight();
43170 this.selectedIndex = -1;
43173 onLoad : function(a,b,c,d)
43175 if (!this.loadingChildren) {
43176 // then we are loading the top level. - hide the children
43177 for (var i = 1;i < this.views.length; i++) {
43178 this.views[i].getEl().setStyle({ display : 'none' });
43180 var lw = Math.floor(
43181 ((this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')) / this.maxColumns
43184 this.list.setWidth(lw); // default to '1'
43188 if(!this.hasFocus){
43192 if(this.store.getCount() > 0) {
43194 this.restrictHeight();
43196 this.onEmptyResults();
43199 if (!this.loadingChildren) {
43200 this.selectActive();
43203 this.stores[1].loadData([]);
43204 this.stores[2].loadData([]);
43213 onLoadException : function()
43216 Roo.log(this.store.reader.jsonData);
43217 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
43218 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
43223 // no cleaning of leading spaces on blur here.
43224 cleanLeadingSpace : function(e) { },
43227 onSelectChange : function (view, sels, opts )
43229 var ix = view.getSelectedIndexes();
43231 if (opts.list > this.maxColumns - 2) {
43232 if (view.store.getCount()< 1) {
43233 this.views[opts.list ].getEl().setStyle({ display : 'none' });
43237 // used to clear ?? but if we are loading unselected
43238 this.setFromData(view.store.getAt(ix[0]).data);
43247 // this get's fired when trigger opens..
43248 // this.setFromData({});
43249 var str = this.stores[opts.list+1];
43250 str.data.clear(); // removeall wihtout the fire events..
43254 var rec = view.store.getAt(ix[0]);
43256 this.setFromData(rec.data);
43257 this.fireEvent('select', this, rec, ix[0]);
43259 var lw = Math.floor(
43261 (this.listWidth * this.maxColumns || Math.max(this.wrap.getWidth(), this.minListWidth)) - this.list.getFrameWidth('lr')
43262 ) / this.maxColumns
43264 this.loadingChildren = true;
43265 this.stores[opts.list+1].loadDataFromChildren( rec );
43266 this.loadingChildren = false;
43267 var dl = this.stores[opts.list+1]. getTotalCount();
43269 this.views[opts.list+1].getEl().setHeight( this.innerLists[0].getHeight());
43271 this.views[opts.list+1].getEl().setStyle({ display : dl ? 'block' : 'none' });
43272 for (var i = opts.list+2; i < this.views.length;i++) {
43273 this.views[i].getEl().setStyle({ display : 'none' });
43276 this.innerLists[opts.list+1].setHeight( this.innerLists[0].getHeight());
43277 this.list.setWidth(lw * (opts.list + (dl ? 2 : 1)));
43279 if (this.isLoading) {
43280 // this.selectActive(opts.list);
43288 onDoubleClick : function()
43290 this.collapse(); //??
43298 recordToStack : function(store, prop, value, stack)
43300 var cstore = new Roo.data.SimpleStore({
43301 //fields : this.store.reader.meta.fields, // we need array reader.. for
43302 reader : this.store.reader,
43306 var record = false;
43308 if(store.getCount() < 1){
43311 store.each(function(r){
43312 if(r.data[prop] == value){
43317 if (r.data.cn && r.data.cn.length) {
43318 cstore.loadDataFromChildren( r);
43319 var cret = _this.recordToStack(cstore, prop, value, stack);
43320 if (cret !== false) {
43329 if (record == false) {
43332 stack.unshift(srec);
43337 * find the stack of stores that match our value.
43342 selectActive : function ()
43344 // if store is not loaded, then we will need to wait for that to happen first.
43346 this.recordToStack(this.store, this.valueField, this.getValue(), stack);
43347 for (var i = 0; i < stack.length; i++ ) {
43348 this.views[i].select(stack[i].store.indexOf(stack[i]), false, false );
43360 * Ext JS Library 1.1.1
43361 * Copyright(c) 2006-2007, Ext JS, LLC.
43363 * Originally Released Under LGPL - original licence link has changed is not relivant.
43366 * <script type="text/javascript">
43369 * @class Roo.form.Checkbox
43370 * @extends Roo.form.Field
43371 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
43373 * Creates a new Checkbox
43374 * @param {Object} config Configuration options
43376 Roo.form.Checkbox = function(config){
43377 Roo.form.Checkbox.superclass.constructor.call(this, config);
43381 * Fires when the checkbox is checked or unchecked.
43382 * @param {Roo.form.Checkbox} this This checkbox
43383 * @param {Boolean} checked The new checked value
43389 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
43391 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
43393 focusClass : undefined,
43395 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
43397 fieldClass: "x-form-field",
43399 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
43403 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
43404 * {tag: "input", type: "checkbox", autocomplete: "off"})
43406 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
43408 * @cfg {String} boxLabel The text that appears beside the checkbox
43412 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
43416 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
43418 valueOff: '0', // value when not checked..
43420 actionMode : 'viewEl',
43423 itemCls : 'x-menu-check-item x-form-item',
43424 groupClass : 'x-menu-group-item',
43425 inputType : 'hidden',
43428 inSetChecked: false, // check that we are not calling self...
43430 inputElement: false, // real input element?
43431 basedOn: false, // ????
43433 isFormField: true, // not sure where this is needed!!!!
43435 onResize : function(){
43436 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
43437 if(!this.boxLabel){
43438 this.el.alignTo(this.wrap, 'c-c');
43442 initEvents : function(){
43443 Roo.form.Checkbox.superclass.initEvents.call(this);
43444 this.el.on("click", this.onClick, this);
43445 this.el.on("change", this.onClick, this);
43449 getResizeEl : function(){
43453 getPositionEl : function(){
43458 onRender : function(ct, position){
43459 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43461 if(this.inputValue !== undefined){
43462 this.el.dom.value = this.inputValue;
43465 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43466 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43467 var viewEl = this.wrap.createChild({
43468 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43469 this.viewEl = viewEl;
43470 this.wrap.on('click', this.onClick, this);
43472 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43473 this.el.on('propertychange', this.setFromHidden, this); //ie
43478 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43479 // viewEl.on('click', this.onClick, this);
43481 //if(this.checked){
43482 this.setChecked(this.checked);
43484 //this.checked = this.el.dom;
43490 initValue : Roo.emptyFn,
43493 * Returns the checked state of the checkbox.
43494 * @return {Boolean} True if checked, else false
43496 getValue : function(){
43498 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
43500 return this.valueOff;
43505 onClick : function(){
43506 if (this.disabled) {
43509 this.setChecked(!this.checked);
43511 //if(this.el.dom.checked != this.checked){
43512 // this.setValue(this.el.dom.checked);
43517 * Sets the checked state of the checkbox.
43518 * On is always based on a string comparison between inputValue and the param.
43519 * @param {Boolean/String} value - the value to set
43520 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
43522 setValue : function(v,suppressEvent){
43525 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
43526 //if(this.el && this.el.dom){
43527 // this.el.dom.checked = this.checked;
43528 // this.el.dom.defaultChecked = this.checked;
43530 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
43531 //this.fireEvent("check", this, this.checked);
43534 setChecked : function(state,suppressEvent)
43536 if (this.inSetChecked) {
43537 this.checked = state;
43543 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
43545 this.checked = state;
43546 if(suppressEvent !== true){
43547 this.fireEvent('check', this, state);
43549 this.inSetChecked = true;
43550 this.el.dom.value = state ? this.inputValue : this.valueOff;
43551 this.inSetChecked = false;
43554 // handle setting of hidden value by some other method!!?!?
43555 setFromHidden: function()
43560 //console.log("SET FROM HIDDEN");
43561 //alert('setFrom hidden');
43562 this.setValue(this.el.dom.value);
43565 onDestroy : function()
43568 Roo.get(this.viewEl).remove();
43571 Roo.form.Checkbox.superclass.onDestroy.call(this);
43574 setBoxLabel : function(str)
43576 this.wrap.select('.x-form-cb-label', true).first().dom.innerHTML = str;
43581 * Ext JS Library 1.1.1
43582 * Copyright(c) 2006-2007, Ext JS, LLC.
43584 * Originally Released Under LGPL - original licence link has changed is not relivant.
43587 * <script type="text/javascript">
43591 * @class Roo.form.Radio
43592 * @extends Roo.form.Checkbox
43593 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
43594 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
43596 * Creates a new Radio
43597 * @param {Object} config Configuration options
43599 Roo.form.Radio = function(){
43600 Roo.form.Radio.superclass.constructor.apply(this, arguments);
43602 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
43603 inputType: 'radio',
43606 * If this radio is part of a group, it will return the selected value
43609 getGroupValue : function(){
43610 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
43614 onRender : function(ct, position){
43615 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
43617 if(this.inputValue !== undefined){
43618 this.el.dom.value = this.inputValue;
43621 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
43622 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
43623 //var viewEl = this.wrap.createChild({
43624 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
43625 //this.viewEl = viewEl;
43626 //this.wrap.on('click', this.onClick, this);
43628 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
43629 //this.el.on('propertychange', this.setFromHidden, this); //ie
43634 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
43635 // viewEl.on('click', this.onClick, this);
43638 this.el.dom.checked = 'checked' ;
43644 });//<script type="text/javascript">
43647 * Based Ext JS Library 1.1.1
43648 * Copyright(c) 2006-2007, Ext JS, LLC.
43654 * @class Roo.HtmlEditorCore
43655 * @extends Roo.Component
43656 * Provides a the editing component for the HTML editors in Roo. (bootstrap and Roo.form)
43658 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
43661 Roo.HtmlEditorCore = function(config){
43664 Roo.HtmlEditorCore.superclass.constructor.call(this, config);
43669 * @event initialize
43670 * Fires when the editor is fully initialized (including the iframe)
43671 * @param {Roo.HtmlEditorCore} this
43676 * Fires when the editor is first receives the focus. Any insertion must wait
43677 * until after this event.
43678 * @param {Roo.HtmlEditorCore} this
43682 * @event beforesync
43683 * Fires before the textarea is updated with content from the editor iframe. Return false
43684 * to cancel the sync.
43685 * @param {Roo.HtmlEditorCore} this
43686 * @param {String} html
43690 * @event beforepush
43691 * Fires before the iframe editor is updated with content from the textarea. Return false
43692 * to cancel the push.
43693 * @param {Roo.HtmlEditorCore} this
43694 * @param {String} html
43699 * Fires when the textarea is updated with content from the editor iframe.
43700 * @param {Roo.HtmlEditorCore} this
43701 * @param {String} html
43706 * Fires when the iframe editor is updated with content from the textarea.
43707 * @param {Roo.HtmlEditorCore} this
43708 * @param {String} html
43713 * @event editorevent
43714 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
43715 * @param {Roo.HtmlEditorCore} this
43721 // at this point this.owner is set, so we can start working out the whitelisted / blacklisted elements
43723 // defaults : white / black...
43724 this.applyBlacklists();
43731 Roo.extend(Roo.HtmlEditorCore, Roo.Component, {
43735 * @cfg {Roo.form.HtmlEditor|Roo.bootstrap.HtmlEditor} the owner field
43741 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
43746 * @cfg {Number} height (in pixels)
43750 * @cfg {Number} width (in pixels)
43755 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
43758 stylesheets: false,
43763 // private properties
43764 validationEvent : false,
43766 initialized : false,
43768 sourceEditMode : false,
43769 onFocus : Roo.emptyFn,
43771 hideMode:'offsets',
43775 // blacklist + whitelisted elements..
43782 * Protected method that will not generally be called directly. It
43783 * is called when the editor initializes the iframe with HTML contents. Override this method if you
43784 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
43786 getDocMarkup : function(){
43790 // inherit styels from page...??
43791 if (this.stylesheets === false) {
43793 Roo.get(document.head).select('style').each(function(node) {
43794 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43797 Roo.get(document.head).select('link').each(function(node) {
43798 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
43801 } else if (!this.stylesheets.length) {
43803 st = '<style type="text/css">' +
43804 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43807 for (var i in this.stylesheets) {
43808 st += '<link rel="stylesheet" href="' + this.stylesheets[i] +'" type="text/css">';
43813 st += '<style type="text/css">' +
43814 'IMG { cursor: pointer } ' +
43817 var cls = 'roo-htmleditor-body';
43819 if(this.bodyCls.length){
43820 cls += ' ' + this.bodyCls;
43823 return '<html><head>' + st +
43824 //<style type="text/css">' +
43825 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
43827 ' </head><body contenteditable="true" data-enable-grammerly="true" class="' + cls + '"></body></html>';
43831 onRender : function(ct, position)
43834 //Roo.HtmlEditorCore.superclass.onRender.call(this, ct, position);
43835 this.el = this.owner.inputEl ? this.owner.inputEl() : this.owner.el;
43838 this.el.dom.style.border = '0 none';
43839 this.el.dom.setAttribute('tabIndex', -1);
43840 this.el.addClass('x-hidden hide');
43844 if(Roo.isIE){ // fix IE 1px bogus margin
43845 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
43849 this.frameId = Roo.id();
43853 var iframe = this.owner.wrap.createChild({
43855 cls: 'form-control', // bootstrap..
43857 name: this.frameId,
43858 frameBorder : 'no',
43859 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
43864 this.iframe = iframe.dom;
43866 this.assignDocWin();
43868 this.doc.designMode = 'on';
43871 this.doc.write(this.getDocMarkup());
43875 var task = { // must defer to wait for browser to be ready
43877 //console.log("run task?" + this.doc.readyState);
43878 this.assignDocWin();
43879 if(this.doc.body || this.doc.readyState == 'complete'){
43881 this.doc.designMode="on";
43885 Roo.TaskMgr.stop(task);
43886 this.initEditor.defer(10, this);
43893 Roo.TaskMgr.start(task);
43898 onResize : function(w, h)
43900 Roo.log('resize: ' +w + ',' + h );
43901 //Roo.HtmlEditorCore.superclass.onResize.apply(this, arguments);
43905 if(typeof w == 'number'){
43907 this.iframe.style.width = w + 'px';
43909 if(typeof h == 'number'){
43911 this.iframe.style.height = h + 'px';
43913 (this.doc.body || this.doc.documentElement).style.height = (h - (this.iframePad*2)) + 'px';
43920 * Toggles the editor between standard and source edit mode.
43921 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
43923 toggleSourceEdit : function(sourceEditMode){
43925 this.sourceEditMode = sourceEditMode === true;
43927 if(this.sourceEditMode){
43929 Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these
43932 Roo.get(this.iframe).removeClass(['x-hidden','hide']);
43933 //this.iframe.className = '';
43936 //this.setSize(this.owner.wrap.getSize());
43937 //this.fireEvent('editmodechange', this, this.sourceEditMode);
43944 * Protected method that will not generally be called directly. If you need/want
43945 * custom HTML cleanup, this is the method you should override.
43946 * @param {String} html The HTML to be cleaned
43947 * return {String} The cleaned HTML
43949 cleanHtml : function(html){
43950 html = String(html);
43951 if(html.length > 5){
43952 if(Roo.isSafari){ // strip safari nonsense
43953 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
43956 if(html == ' '){
43963 * HTML Editor -> Textarea
43964 * Protected method that will not generally be called directly. Syncs the contents
43965 * of the editor iframe with the textarea.
43967 syncValue : function(){
43968 if(this.initialized){
43969 var bd = (this.doc.body || this.doc.documentElement);
43970 //this.cleanUpPaste(); -- this is done else where and causes havoc..
43971 var html = bd.innerHTML;
43973 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
43974 var m = bs ? bs.match(/text-align:(.*?);/i) : false;
43976 html = '<div style="'+m[0]+'">' + html + '</div>';
43979 html = this.cleanHtml(html);
43980 // fix up the special chars.. normaly like back quotes in word...
43981 // however we do not want to do this with chinese..
43982 html = html.replace(/[\uD800-\uDBFF][\uDC00-\uDFFF]|[\u0080-\uFFFF]/g, function(match) {
43984 var cc = match.charCodeAt();
43986 // Get the character value, handling surrogate pairs
43987 if (match.length == 2) {
43988 // It's a surrogate pair, calculate the Unicode code point
43989 var high = match.charCodeAt(0) - 0xD800;
43990 var low = match.charCodeAt(1) - 0xDC00;
43991 cc = (high * 0x400) + low + 0x10000;
43993 (cc >= 0x4E00 && cc < 0xA000 ) ||
43994 (cc >= 0x3400 && cc < 0x4E00 ) ||
43995 (cc >= 0xf900 && cc < 0xfb00 )
44000 // No, use a numeric entity. Here we brazenly (and possibly mistakenly)
44001 return "&#" + cc + ";";
44008 if(this.owner.fireEvent('beforesync', this, html) !== false){
44009 this.el.dom.value = html;
44010 this.owner.fireEvent('sync', this, html);
44016 * Protected method that will not generally be called directly. Pushes the value of the textarea
44017 * into the iframe editor.
44019 pushValue : function(){
44020 if(this.initialized){
44021 var v = this.el.dom.value.trim();
44023 // if(v.length < 1){
44027 if(this.owner.fireEvent('beforepush', this, v) !== false){
44028 var d = (this.doc.body || this.doc.documentElement);
44030 this.cleanUpPaste();
44031 this.el.dom.value = d.innerHTML;
44032 this.owner.fireEvent('push', this, v);
44038 deferFocus : function(){
44039 this.focus.defer(10, this);
44043 focus : function(){
44044 if(this.win && !this.sourceEditMode){
44051 assignDocWin: function()
44053 var iframe = this.iframe;
44056 this.doc = iframe.contentWindow.document;
44057 this.win = iframe.contentWindow;
44059 // if (!Roo.get(this.frameId)) {
44062 // this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44063 // this.win = Roo.get(this.frameId).dom.contentWindow;
44065 if (!Roo.get(this.frameId) && !iframe.contentDocument) {
44069 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
44070 this.win = (iframe.contentWindow || Roo.get(this.frameId).dom.contentWindow);
44075 initEditor : function(){
44076 //console.log("INIT EDITOR");
44077 this.assignDocWin();
44081 this.doc.designMode="on";
44083 this.doc.write(this.getDocMarkup());
44086 var dbody = (this.doc.body || this.doc.documentElement);
44087 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
44088 // this copies styles from the containing element into thsi one..
44089 // not sure why we need all of this..
44090 //var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
44092 //var ss = this.el.getStyles( 'background-image', 'background-repeat');
44093 //ss['background-attachment'] = 'fixed'; // w3c
44094 dbody.bgProperties = 'fixed'; // ie
44095 //Roo.DomHelper.applyStyles(dbody, ss);
44096 Roo.EventManager.on(this.doc, {
44097 //'mousedown': this.onEditorEvent,
44098 'mouseup': this.onEditorEvent,
44099 'dblclick': this.onEditorEvent,
44100 'click': this.onEditorEvent,
44101 'keyup': this.onEditorEvent,
44106 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
44108 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
44109 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
44111 this.initialized = true;
44113 this.owner.fireEvent('initialize', this);
44118 onDestroy : function(){
44124 //for (var i =0; i < this.toolbars.length;i++) {
44125 // // fixme - ask toolbars for heights?
44126 // this.toolbars[i].onDestroy();
44129 //this.wrap.dom.innerHTML = '';
44130 //this.wrap.remove();
44135 onFirstFocus : function(){
44137 this.assignDocWin();
44140 this.activated = true;
44143 if(Roo.isGecko){ // prevent silly gecko errors
44145 var s = this.win.getSelection();
44146 if(!s.focusNode || s.focusNode.nodeType != 3){
44147 var r = s.getRangeAt(0);
44148 r.selectNodeContents((this.doc.body || this.doc.documentElement));
44153 this.execCmd('useCSS', true);
44154 this.execCmd('styleWithCSS', false);
44157 this.owner.fireEvent('activate', this);
44161 adjustFont: function(btn){
44162 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
44163 //if(Roo.isSafari){ // safari
44166 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
44167 if(Roo.isSafari){ // safari
44168 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
44169 v = (v < 10) ? 10 : v;
44170 v = (v > 48) ? 48 : v;
44171 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
44176 v = Math.max(1, v+adjust);
44178 this.execCmd('FontSize', v );
44181 onEditorEvent : function(e)
44183 this.owner.fireEvent('editorevent', this, e);
44184 // this.updateToolbar();
44185 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
44188 insertTag : function(tg)
44190 // could be a bit smarter... -> wrap the current selected tRoo..
44191 if (tg.toLowerCase() == 'span' ||
44192 tg.toLowerCase() == 'code' ||
44193 tg.toLowerCase() == 'sup' ||
44194 tg.toLowerCase() == 'sub'
44197 range = this.createRange(this.getSelection());
44198 var wrappingNode = this.doc.createElement(tg.toLowerCase());
44199 wrappingNode.appendChild(range.extractContents());
44200 range.insertNode(wrappingNode);
44207 this.execCmd("formatblock", tg);
44211 insertText : function(txt)
44215 var range = this.createRange();
44216 range.deleteContents();
44217 //alert(Sender.getAttribute('label'));
44219 range.insertNode(this.doc.createTextNode(txt));
44225 * Executes a Midas editor command on the editor document and performs necessary focus and
44226 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
44227 * @param {String} cmd The Midas command
44228 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44230 relayCmd : function(cmd, value){
44232 this.execCmd(cmd, value);
44233 this.owner.fireEvent('editorevent', this);
44234 //this.updateToolbar();
44235 this.owner.deferFocus();
44239 * Executes a Midas editor command directly on the editor document.
44240 * For visual commands, you should use {@link #relayCmd} instead.
44241 * <b>This should only be called after the editor is initialized.</b>
44242 * @param {String} cmd The Midas command
44243 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
44245 execCmd : function(cmd, value){
44246 this.doc.execCommand(cmd, false, value === undefined ? null : value);
44253 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
44255 * @param {String} text | dom node..
44257 insertAtCursor : function(text)
44260 if(!this.activated){
44266 var r = this.doc.selection.createRange();
44277 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
44281 // from jquery ui (MIT licenced)
44283 var win = this.win;
44285 if (win.getSelection && win.getSelection().getRangeAt) {
44286 range = win.getSelection().getRangeAt(0);
44287 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
44288 range.insertNode(node);
44289 } else if (win.document.selection && win.document.selection.createRange) {
44290 // no firefox support
44291 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44292 win.document.selection.createRange().pasteHTML(txt);
44294 // no firefox support
44295 var txt = typeof(text) == 'string' ? text : text.outerHTML;
44296 this.execCmd('InsertHTML', txt);
44305 mozKeyPress : function(e){
44307 var c = e.getCharCode(), cmd;
44310 c = String.fromCharCode(c).toLowerCase();
44324 this.cleanUpPaste.defer(100, this);
44332 e.preventDefault();
44340 fixKeys : function(){ // load time branching for fastest keydown performance
44342 return function(e){
44343 var k = e.getKey(), r;
44346 r = this.doc.selection.createRange();
44349 r.pasteHTML('    ');
44356 r = this.doc.selection.createRange();
44358 var target = r.parentElement();
44359 if(!target || target.tagName.toLowerCase() != 'li'){
44361 r.pasteHTML('<br />');
44367 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44368 this.cleanUpPaste.defer(100, this);
44374 }else if(Roo.isOpera){
44375 return function(e){
44376 var k = e.getKey();
44380 this.execCmd('InsertHTML','    ');
44383 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44384 this.cleanUpPaste.defer(100, this);
44389 }else if(Roo.isSafari){
44390 return function(e){
44391 var k = e.getKey();
44395 this.execCmd('InsertText','\t');
44399 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
44400 this.cleanUpPaste.defer(100, this);
44408 getAllAncestors: function()
44410 var p = this.getSelectedNode();
44413 a.push(p); // push blank onto stack..
44414 p = this.getParentElement();
44418 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
44422 a.push(this.doc.body);
44426 lastSelNode : false,
44429 getSelection : function()
44431 this.assignDocWin();
44432 return Roo.isIE ? this.doc.selection : this.win.getSelection();
44435 getSelectedNode: function()
44437 // this may only work on Gecko!!!
44439 // should we cache this!!!!
44444 var range = this.createRange(this.getSelection()).cloneRange();
44447 var parent = range.parentElement();
44449 var testRange = range.duplicate();
44450 testRange.moveToElementText(parent);
44451 if (testRange.inRange(range)) {
44454 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
44457 parent = parent.parentElement;
44462 // is ancestor a text element.
44463 var ac = range.commonAncestorContainer;
44464 if (ac.nodeType == 3) {
44465 ac = ac.parentNode;
44468 var ar = ac.childNodes;
44471 var other_nodes = [];
44472 var has_other_nodes = false;
44473 for (var i=0;i<ar.length;i++) {
44474 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
44477 // fullly contained node.
44479 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
44484 // probably selected..
44485 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
44486 other_nodes.push(ar[i]);
44490 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
44495 has_other_nodes = true;
44497 if (!nodes.length && other_nodes.length) {
44498 nodes= other_nodes;
44500 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
44506 createRange: function(sel)
44508 // this has strange effects when using with
44509 // top toolbar - not sure if it's a great idea.
44510 //this.editor.contentWindow.focus();
44511 if (typeof sel != "undefined") {
44513 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
44515 return this.doc.createRange();
44518 return this.doc.createRange();
44521 getParentElement: function()
44524 this.assignDocWin();
44525 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
44527 var range = this.createRange(sel);
44530 var p = range.commonAncestorContainer;
44531 while (p.nodeType == 3) { // text node
44542 * Range intersection.. the hard stuff...
44546 * [ -- selected range --- ]
44550 * if end is before start or hits it. fail.
44551 * if start is after end or hits it fail.
44553 * if either hits (but other is outside. - then it's not
44559 // @see http://www.thismuchiknow.co.uk/?p=64.
44560 rangeIntersectsNode : function(range, node)
44562 var nodeRange = node.ownerDocument.createRange();
44564 nodeRange.selectNode(node);
44566 nodeRange.selectNodeContents(node);
44569 var rangeStartRange = range.cloneRange();
44570 rangeStartRange.collapse(true);
44572 var rangeEndRange = range.cloneRange();
44573 rangeEndRange.collapse(false);
44575 var nodeStartRange = nodeRange.cloneRange();
44576 nodeStartRange.collapse(true);
44578 var nodeEndRange = nodeRange.cloneRange();
44579 nodeEndRange.collapse(false);
44581 return rangeStartRange.compareBoundaryPoints(
44582 Range.START_TO_START, nodeEndRange) == -1 &&
44583 rangeEndRange.compareBoundaryPoints(
44584 Range.START_TO_START, nodeStartRange) == 1;
44588 rangeCompareNode : function(range, node)
44590 var nodeRange = node.ownerDocument.createRange();
44592 nodeRange.selectNode(node);
44594 nodeRange.selectNodeContents(node);
44598 range.collapse(true);
44600 nodeRange.collapse(true);
44602 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
44603 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
44605 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
44607 var nodeIsBefore = ss == 1;
44608 var nodeIsAfter = ee == -1;
44610 if (nodeIsBefore && nodeIsAfter) {
44613 if (!nodeIsBefore && nodeIsAfter) {
44614 return 1; //right trailed.
44617 if (nodeIsBefore && !nodeIsAfter) {
44618 return 2; // left trailed.
44624 // private? - in a new class?
44625 cleanUpPaste : function()
44627 // cleans up the whole document..
44628 Roo.log('cleanuppaste');
44630 this.cleanUpChildren(this.doc.body);
44631 var clean = this.cleanWordChars(this.doc.body.innerHTML);
44632 if (clean != this.doc.body.innerHTML) {
44633 this.doc.body.innerHTML = clean;
44638 cleanWordChars : function(input) {// change the chars to hex code
44639 var he = Roo.HtmlEditorCore;
44641 var output = input;
44642 Roo.each(he.swapCodes, function(sw) {
44643 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
44645 output = output.replace(swapper, sw[1]);
44652 cleanUpChildren : function (n)
44654 if (!n.childNodes.length) {
44657 for (var i = n.childNodes.length-1; i > -1 ; i--) {
44658 this.cleanUpChild(n.childNodes[i]);
44665 cleanUpChild : function (node)
44668 //console.log(node);
44669 if (node.nodeName == "#text") {
44670 // clean up silly Windows -- stuff?
44673 if (node.nodeName == "#comment") {
44674 node.parentNode.removeChild(node);
44675 // clean up silly Windows -- stuff?
44678 var lcname = node.tagName.toLowerCase();
44679 // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full
44680 // whitelist of tags..
44682 if (this.black.indexOf(lcname) > -1 && this.clearUp ) {
44684 node.parentNode.removeChild(node);
44689 var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1;
44691 // spans with no attributes - just remove them..
44692 if ((!node.attributes || !node.attributes.length) && lcname == 'span') {
44693 remove_keep_children = true;
44696 // remove <a name=....> as rendering on yahoo mailer is borked with this.
44697 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
44699 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
44700 // remove_keep_children = true;
44703 if (remove_keep_children) {
44704 this.cleanUpChildren(node);
44705 // inserts everything just before this node...
44706 while (node.childNodes.length) {
44707 var cn = node.childNodes[0];
44708 node.removeChild(cn);
44709 node.parentNode.insertBefore(cn, node);
44711 node.parentNode.removeChild(node);
44715 if (!node.attributes || !node.attributes.length) {
44720 this.cleanUpChildren(node);
44724 function cleanAttr(n,v)
44727 if (v.match(/^\./) || v.match(/^\//)) {
44730 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) {
44733 if (v.match(/^#/)) {
44736 if (v.match(/^\{/)) { // allow template editing.
44739 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
44740 node.removeAttribute(n);
44744 var cwhite = this.cwhite;
44745 var cblack = this.cblack;
44747 function cleanStyle(n,v)
44749 if (v.match(/expression/)) { //XSS?? should we even bother..
44750 node.removeAttribute(n);
44754 var parts = v.split(/;/);
44757 Roo.each(parts, function(p) {
44758 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
44762 var l = p.split(':').shift().replace(/\s+/g,'');
44763 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
44765 if ( cwhite.length && cblack.indexOf(l) > -1) {
44766 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44767 //node.removeAttribute(n);
44771 // only allow 'c whitelisted system attributes'
44772 if ( cwhite.length && cwhite.indexOf(l) < 0) {
44773 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
44774 //node.removeAttribute(n);
44784 if (clean.length) {
44785 node.setAttribute(n, clean.join(';'));
44787 node.removeAttribute(n);
44793 for (var i = node.attributes.length-1; i > -1 ; i--) {
44794 var a = node.attributes[i];
44797 if (a.name.toLowerCase().substr(0,2)=='on') {
44798 node.removeAttribute(a.name);
44801 if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) {
44802 node.removeAttribute(a.name);
44805 if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) {
44806 cleanAttr(a.name,a.value); // fixme..
44809 if (a.name == 'style') {
44810 cleanStyle(a.name,a.value);
44813 /// clean up MS crap..
44814 // tecnically this should be a list of valid class'es..
44817 if (a.name == 'class') {
44818 if (a.value.match(/^Mso/)) {
44819 node.removeAttribute('class');
44822 if (a.value.match(/^body$/)) {
44823 node.removeAttribute('class');
44834 this.cleanUpChildren(node);
44840 * Clean up MS wordisms...
44842 cleanWord : function(node)
44845 this.cleanWord(this.doc.body);
44850 node.nodeName == 'SPAN' &&
44851 !node.hasAttributes() &&
44852 node.childNodes.length == 1 &&
44853 node.firstChild.nodeName == "#text"
44855 var textNode = node.firstChild;
44856 node.removeChild(textNode);
44857 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44858 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node);
44860 node.parentNode.insertBefore(textNode, node);
44861 if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters..
44862 node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node);
44864 node.parentNode.removeChild(node);
44867 if (node.nodeName == "#text") {
44868 // clean up silly Windows -- stuff?
44871 if (node.nodeName == "#comment") {
44872 node.parentNode.removeChild(node);
44873 // clean up silly Windows -- stuff?
44877 if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) {
44878 node.parentNode.removeChild(node);
44881 //Roo.log(node.tagName);
44882 // remove - but keep children..
44883 if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) {
44884 //Roo.log('-- removed');
44885 while (node.childNodes.length) {
44886 var cn = node.childNodes[0];
44887 node.removeChild(cn);
44888 node.parentNode.insertBefore(cn, node);
44889 // move node to parent - and clean it..
44890 this.cleanWord(cn);
44892 node.parentNode.removeChild(node);
44893 /// no need to iterate chidlren = it's got none..
44894 //this.iterateChildren(node, this.cleanWord);
44898 if (node.className.length) {
44900 var cn = node.className.split(/\W+/);
44902 Roo.each(cn, function(cls) {
44903 if (cls.match(/Mso[a-zA-Z]+/)) {
44908 node.className = cna.length ? cna.join(' ') : '';
44910 node.removeAttribute("class");
44914 if (node.hasAttribute("lang")) {
44915 node.removeAttribute("lang");
44918 if (node.hasAttribute("style")) {
44920 var styles = node.getAttribute("style").split(";");
44922 Roo.each(styles, function(s) {
44923 if (!s.match(/:/)) {
44926 var kv = s.split(":");
44927 if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) {
44930 // what ever is left... we allow.
44933 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
44934 if (!nstyle.length) {
44935 node.removeAttribute('style');
44938 this.iterateChildren(node, this.cleanWord);
44944 * iterateChildren of a Node, calling fn each time, using this as the scole..
44945 * @param {DomNode} node node to iterate children of.
44946 * @param {Function} fn method of this class to call on each item.
44948 iterateChildren : function(node, fn)
44950 if (!node.childNodes.length) {
44953 for (var i = node.childNodes.length-1; i > -1 ; i--) {
44954 fn.call(this, node.childNodes[i])
44960 * cleanTableWidths.
44962 * Quite often pasting from word etc.. results in tables with column and widths.
44963 * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them..
44966 cleanTableWidths : function(node)
44971 this.cleanTableWidths(this.doc.body);
44976 if (node.nodeName == "#text" || node.nodeName == "#comment") {
44979 Roo.log(node.tagName);
44980 if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) {
44981 this.iterateChildren(node, this.cleanTableWidths);
44984 if (node.hasAttribute('width')) {
44985 node.removeAttribute('width');
44989 if (node.hasAttribute("style")) {
44992 var styles = node.getAttribute("style").split(";");
44994 Roo.each(styles, function(s) {
44995 if (!s.match(/:/)) {
44998 var kv = s.split(":");
44999 if (kv[0].match(/^\s*(width|min-width)\s*$/)) {
45002 // what ever is left... we allow.
45005 node.setAttribute("style", nstyle.length ? nstyle.join(';') : '');
45006 if (!nstyle.length) {
45007 node.removeAttribute('style');
45011 this.iterateChildren(node, this.cleanTableWidths);
45019 domToHTML : function(currentElement, depth, nopadtext) {
45021 depth = depth || 0;
45022 nopadtext = nopadtext || false;
45024 if (!currentElement) {
45025 return this.domToHTML(this.doc.body);
45028 //Roo.log(currentElement);
45030 var allText = false;
45031 var nodeName = currentElement.nodeName;
45032 var tagName = Roo.util.Format.htmlEncode(currentElement.tagName);
45034 if (nodeName == '#text') {
45036 return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim();
45041 if (nodeName != 'BODY') {
45044 // Prints the node tagName, such as <A>, <IMG>, etc
45047 for(i = 0; i < currentElement.attributes.length;i++) {
45049 var aname = currentElement.attributes.item(i).name;
45050 if (!currentElement.attributes.item(i).value.length) {
45053 attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' );
45056 ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">";
45065 if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) {
45068 if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code?
45073 // Traverse the tree
45075 var currentElementChild = currentElement.childNodes.item(i);
45076 var allText = true;
45077 var innerHTML = '';
45079 while (currentElementChild) {
45080 // Formatting code (indent the tree so it looks nice on the screen)
45081 var nopad = nopadtext;
45082 if (lastnode == 'SPAN') {
45086 if (currentElementChild.nodeName == '#text') {
45087 var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue);
45088 toadd = nopadtext ? toadd : toadd.trim();
45089 if (!nopad && toadd.length > 80) {
45090 innerHTML += "\n" + (new Array( depth + 1 )).join( " " );
45092 innerHTML += toadd;
45095 currentElementChild = currentElement.childNodes.item(i);
45101 innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " );
45103 // Recursively traverse the tree structure of the child node
45104 innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext);
45105 lastnode = currentElementChild.nodeName;
45107 currentElementChild=currentElement.childNodes.item(i);
45113 // The remaining code is mostly for formatting the tree
45114 ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " );
45119 ret+= "</"+tagName+">";
45125 applyBlacklists : function()
45127 var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : [];
45128 var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : [];
45132 Roo.each(Roo.HtmlEditorCore.white, function(tag) {
45133 if (b.indexOf(tag) > -1) {
45136 this.white.push(tag);
45140 Roo.each(w, function(tag) {
45141 if (b.indexOf(tag) > -1) {
45144 if (this.white.indexOf(tag) > -1) {
45147 this.white.push(tag);
45152 Roo.each(Roo.HtmlEditorCore.black, function(tag) {
45153 if (w.indexOf(tag) > -1) {
45156 this.black.push(tag);
45160 Roo.each(b, function(tag) {
45161 if (w.indexOf(tag) > -1) {
45164 if (this.black.indexOf(tag) > -1) {
45167 this.black.push(tag);
45172 w = typeof(this.owner.cwhite) != 'undefined' && this.owner.cwhite ? this.owner.cwhite : [];
45173 b = typeof(this.owner.cblack) != 'undefined' && this.owner.cblack ? this.owner.cblack : [];
45177 Roo.each(Roo.HtmlEditorCore.cwhite, function(tag) {
45178 if (b.indexOf(tag) > -1) {
45181 this.cwhite.push(tag);
45185 Roo.each(w, function(tag) {
45186 if (b.indexOf(tag) > -1) {
45189 if (this.cwhite.indexOf(tag) > -1) {
45192 this.cwhite.push(tag);
45197 Roo.each(Roo.HtmlEditorCore.cblack, function(tag) {
45198 if (w.indexOf(tag) > -1) {
45201 this.cblack.push(tag);
45205 Roo.each(b, function(tag) {
45206 if (w.indexOf(tag) > -1) {
45209 if (this.cblack.indexOf(tag) > -1) {
45212 this.cblack.push(tag);
45217 setStylesheets : function(stylesheets)
45219 if(typeof(stylesheets) == 'string'){
45220 Roo.get(this.iframe.contentDocument.head).createChild({
45222 rel : 'stylesheet',
45231 Roo.each(stylesheets, function(s) {
45236 Roo.get(_this.iframe.contentDocument.head).createChild({
45238 rel : 'stylesheet',
45247 removeStylesheets : function()
45251 Roo.each(Roo.get(_this.iframe.contentDocument.head).select('link[rel=stylesheet]', true).elements, function(s){
45256 setStyle : function(style)
45258 Roo.get(this.iframe.contentDocument.head).createChild({
45267 // hide stuff that is not compatible
45281 * @event specialkey
45285 * @cfg {String} fieldClass @hide
45288 * @cfg {String} focusClass @hide
45291 * @cfg {String} autoCreate @hide
45294 * @cfg {String} inputType @hide
45297 * @cfg {String} invalidClass @hide
45300 * @cfg {String} invalidText @hide
45303 * @cfg {String} msgFx @hide
45306 * @cfg {String} validateOnBlur @hide
45310 Roo.HtmlEditorCore.white = [
45311 'area', 'br', 'img', 'input', 'hr', 'wbr',
45313 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
45314 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
45315 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
45316 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
45317 'table', 'ul', 'xmp',
45319 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
45322 'dir', 'menu', 'ol', 'ul', 'dl',
45328 Roo.HtmlEditorCore.black = [
45329 // 'embed', 'object', // enable - backend responsiblity to clean thiese
45331 'base', 'basefont', 'bgsound', 'blink', 'body',
45332 'frame', 'frameset', 'head', 'html', 'ilayer',
45333 'iframe', 'layer', 'link', 'meta', 'object',
45334 'script', 'style' ,'title', 'xml' // clean later..
45336 Roo.HtmlEditorCore.clean = [
45337 'script', 'style', 'title', 'xml'
45339 Roo.HtmlEditorCore.remove = [
45344 Roo.HtmlEditorCore.ablack = [
45348 Roo.HtmlEditorCore.aclean = [
45349 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
45353 Roo.HtmlEditorCore.pwhite= [
45354 'http', 'https', 'mailto'
45357 // white listed style attributes.
45358 Roo.HtmlEditorCore.cwhite= [
45359 // 'text-align', /// default is to allow most things..
45365 // black listed style attributes.
45366 Roo.HtmlEditorCore.cblack= [
45367 // 'font-size' -- this can be set by the project
45371 Roo.HtmlEditorCore.swapCodes =[
45372 [ 8211, "–" ],
45373 [ 8212, "—" ],
45382 //<script type="text/javascript">
45385 * Ext JS Library 1.1.1
45386 * Copyright(c) 2006-2007, Ext JS, LLC.
45392 Roo.form.HtmlEditor = function(config){
45396 Roo.form.HtmlEditor.superclass.constructor.call(this, config);
45398 if (!this.toolbars) {
45399 this.toolbars = [];
45401 this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
45407 * @class Roo.form.HtmlEditor
45408 * @extends Roo.form.Field
45409 * Provides a lightweight HTML Editor component.
45411 * This has been tested on Fireforx / Chrome.. IE may not be so great..
45413 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
45414 * supported by this editor.</b><br/><br/>
45415 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
45416 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
45418 Roo.extend(Roo.form.HtmlEditor, Roo.form.Field, {
45420 * @cfg {Boolean} clearUp
45424 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
45429 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
45434 * @cfg {Number} height (in pixels)
45438 * @cfg {Number} width (in pixels)
45443 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
45446 stylesheets: false,
45450 * @cfg {Array} blacklist of css styles style attributes (blacklist overrides whitelist)
45455 * @cfg {Array} whitelist of css styles style attributes (blacklist overrides whitelist)
45461 * @cfg {Array} blacklist of html tags - in addition to standard blacklist.
45466 * @cfg {Array} whitelist of html tags - in addition to statndard whitelist
45474 // private properties
45475 validationEvent : false,
45477 initialized : false,
45480 onFocus : Roo.emptyFn,
45482 hideMode:'offsets',
45484 actionMode : 'container', // defaults to hiding it...
45486 defaultAutoCreate : { // modified by initCompnoent..
45488 style:"width:500px;height:300px;",
45489 autocomplete: "new-password"
45493 initComponent : function(){
45496 * @event initialize
45497 * Fires when the editor is fully initialized (including the iframe)
45498 * @param {HtmlEditor} this
45503 * Fires when the editor is first receives the focus. Any insertion must wait
45504 * until after this event.
45505 * @param {HtmlEditor} this
45509 * @event beforesync
45510 * Fires before the textarea is updated with content from the editor iframe. Return false
45511 * to cancel the sync.
45512 * @param {HtmlEditor} this
45513 * @param {String} html
45517 * @event beforepush
45518 * Fires before the iframe editor is updated with content from the textarea. Return false
45519 * to cancel the push.
45520 * @param {HtmlEditor} this
45521 * @param {String} html
45526 * Fires when the textarea is updated with content from the editor iframe.
45527 * @param {HtmlEditor} this
45528 * @param {String} html
45533 * Fires when the iframe editor is updated with content from the textarea.
45534 * @param {HtmlEditor} this
45535 * @param {String} html
45539 * @event editmodechange
45540 * Fires when the editor switches edit modes
45541 * @param {HtmlEditor} this
45542 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
45544 editmodechange: true,
45546 * @event editorevent
45547 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
45548 * @param {HtmlEditor} this
45552 * @event firstfocus
45553 * Fires when on first focus - needed by toolbars..
45554 * @param {HtmlEditor} this
45559 * Auto save the htmlEditor value as a file into Events
45560 * @param {HtmlEditor} this
45564 * @event savedpreview
45565 * preview the saved version of htmlEditor
45566 * @param {HtmlEditor} this
45568 savedpreview: true,
45571 * @event stylesheetsclick
45572 * Fires when press the Sytlesheets button
45573 * @param {Roo.HtmlEditorCore} this
45575 stylesheetsclick: true
45577 this.defaultAutoCreate = {
45579 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
45580 autocomplete: "new-password"
45585 * Protected method that will not generally be called directly. It
45586 * is called when the editor creates its toolbar. Override this method if you need to
45587 * add custom toolbar buttons.
45588 * @param {HtmlEditor} editor
45590 createToolbar : function(editor){
45591 Roo.log("create toolbars");
45592 if (!editor.toolbars || !editor.toolbars.length) {
45593 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
45596 for (var i =0 ; i < editor.toolbars.length;i++) {
45597 editor.toolbars[i] = Roo.factory(
45598 typeof(editor.toolbars[i]) == 'string' ?
45599 { xtype: editor.toolbars[i]} : editor.toolbars[i],
45600 Roo.form.HtmlEditor);
45601 editor.toolbars[i].init(editor);
45609 onRender : function(ct, position)
45612 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
45614 this.wrap = this.el.wrap({
45615 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
45618 this.editorcore.onRender(ct, position);
45620 if (this.resizable) {
45621 this.resizeEl = new Roo.Resizable(this.wrap, {
45625 minHeight : this.height,
45626 height: this.height,
45627 handles : this.resizable,
45630 resize : function(r, w, h) {
45631 _t.onResize(w,h); // -something
45637 this.createToolbar(this);
45641 this.setSize(this.wrap.getSize());
45643 if (this.resizeEl) {
45644 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
45645 // should trigger onReize..
45648 this.keyNav = new Roo.KeyNav(this.el, {
45650 "tab" : function(e){
45651 e.preventDefault();
45653 var value = this.getValue();
45655 var start = this.el.dom.selectionStart;
45656 var end = this.el.dom.selectionEnd;
45660 this.setValue(value.substring(0, start) + "\t" + value.substring(end));
45661 this.el.dom.setSelectionRange(end + 1, end + 1);
45665 var f = value.substring(0, start).split("\t");
45667 if(f.pop().length != 0){
45671 this.setValue(f.join("\t") + value.substring(end));
45672 this.el.dom.setSelectionRange(start - 1, start - 1);
45676 "home" : function(e){
45677 e.preventDefault();
45679 var curr = this.el.dom.selectionStart;
45680 var lines = this.getValue().split("\n");
45687 this.el.dom.setSelectionRange(0, 0);
45693 for (var i = 0; i < lines.length;i++) {
45694 pos += lines[i].length;
45704 pos -= lines[i].length;
45710 this.el.dom.setSelectionRange(pos, pos);
45714 this.el.dom.selectionStart = pos;
45715 this.el.dom.selectionEnd = curr;
45718 "end" : function(e){
45719 e.preventDefault();
45721 var curr = this.el.dom.selectionStart;
45722 var lines = this.getValue().split("\n");
45729 this.el.dom.setSelectionRange(this.getValue().length, this.getValue().length);
45735 for (var i = 0; i < lines.length;i++) {
45737 pos += lines[i].length;
45751 this.el.dom.setSelectionRange(pos, pos);
45755 this.el.dom.selectionStart = curr;
45756 this.el.dom.selectionEnd = pos;
45761 doRelay : function(foo, bar, hname){
45762 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
45768 // if(this.autosave && this.w){
45769 // this.autoSaveFn = setInterval(this.autosave, 1000);
45774 onResize : function(w, h)
45776 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
45781 if(typeof w == 'number'){
45782 var aw = w - this.wrap.getFrameWidth('lr');
45783 this.el.setWidth(this.adjustWidth('textarea', aw));
45786 if(typeof h == 'number'){
45788 for (var i =0; i < this.toolbars.length;i++) {
45789 // fixme - ask toolbars for heights?
45790 tbh += this.toolbars[i].tb.el.getHeight();
45791 if (this.toolbars[i].footer) {
45792 tbh += this.toolbars[i].footer.el.getHeight();
45799 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
45800 ah -= 5; // knock a few pixes off for look..
45802 this.el.setHeight(this.adjustWidth('textarea', ah));
45806 Roo.log('onResize:' + [w,h,ew,eh].join(',') );
45807 this.editorcore.onResize(ew,eh);
45812 * Toggles the editor between standard and source edit mode.
45813 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
45815 toggleSourceEdit : function(sourceEditMode)
45817 this.editorcore.toggleSourceEdit(sourceEditMode);
45819 if(this.editorcore.sourceEditMode){
45820 Roo.log('editor - showing textarea');
45823 // Roo.log(this.syncValue());
45824 this.editorcore.syncValue();
45825 this.el.removeClass('x-hidden');
45826 this.el.dom.removeAttribute('tabIndex');
45829 for (var i = 0; i < this.toolbars.length; i++) {
45830 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45831 this.toolbars[i].tb.hide();
45832 this.toolbars[i].footer.hide();
45837 Roo.log('editor - hiding textarea');
45839 // Roo.log(this.pushValue());
45840 this.editorcore.pushValue();
45842 this.el.addClass('x-hidden');
45843 this.el.dom.setAttribute('tabIndex', -1);
45845 for (var i = 0; i < this.toolbars.length; i++) {
45846 if(this.toolbars[i] instanceof Roo.form.HtmlEditor.ToolbarContext){
45847 this.toolbars[i].tb.show();
45848 this.toolbars[i].footer.show();
45852 //this.deferFocus();
45855 this.setSize(this.wrap.getSize());
45856 this.onResize(this.wrap.getSize().width, this.wrap.getSize().height);
45858 this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
45861 // private (for BoxComponent)
45862 adjustSize : Roo.BoxComponent.prototype.adjustSize,
45864 // private (for BoxComponent)
45865 getResizeEl : function(){
45869 // private (for BoxComponent)
45870 getPositionEl : function(){
45875 initEvents : function(){
45876 this.originalValue = this.getValue();
45880 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45883 markInvalid : Roo.emptyFn,
45885 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
45888 clearInvalid : Roo.emptyFn,
45890 setValue : function(v){
45891 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
45892 this.editorcore.pushValue();
45897 deferFocus : function(){
45898 this.focus.defer(10, this);
45902 focus : function(){
45903 this.editorcore.focus();
45909 onDestroy : function(){
45915 for (var i =0; i < this.toolbars.length;i++) {
45916 // fixme - ask toolbars for heights?
45917 this.toolbars[i].onDestroy();
45920 this.wrap.dom.innerHTML = '';
45921 this.wrap.remove();
45926 onFirstFocus : function(){
45927 //Roo.log("onFirstFocus");
45928 this.editorcore.onFirstFocus();
45929 for (var i =0; i < this.toolbars.length;i++) {
45930 this.toolbars[i].onFirstFocus();
45936 syncValue : function()
45938 this.editorcore.syncValue();
45941 pushValue : function()
45943 this.editorcore.pushValue();
45946 setStylesheets : function(stylesheets)
45948 this.editorcore.setStylesheets(stylesheets);
45951 removeStylesheets : function()
45953 this.editorcore.removeStylesheets();
45957 // hide stuff that is not compatible
45971 * @event specialkey
45975 * @cfg {String} fieldClass @hide
45978 * @cfg {String} focusClass @hide
45981 * @cfg {String} autoCreate @hide
45984 * @cfg {String} inputType @hide
45987 * @cfg {String} invalidClass @hide
45990 * @cfg {String} invalidText @hide
45993 * @cfg {String} msgFx @hide
45996 * @cfg {String} validateOnBlur @hide
46000 // <script type="text/javascript">
46003 * Ext JS Library 1.1.1
46004 * Copyright(c) 2006-2007, Ext JS, LLC.
46010 * @class Roo.form.HtmlEditorToolbar1
46015 new Roo.form.HtmlEditor({
46018 new Roo.form.HtmlEditorToolbar1({
46019 disable : { fonts: 1 , format: 1, ..., ... , ...],
46025 * @cfg {Object} disable List of elements to disable..
46026 * @cfg {Array} btns List of additional buttons.
46030 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
46033 Roo.form.HtmlEditor.ToolbarStandard = function(config)
46036 Roo.apply(this, config);
46038 // default disabled, based on 'good practice'..
46039 this.disable = this.disable || {};
46040 Roo.applyIf(this.disable, {
46043 specialElements : true
46047 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46048 // dont call parent... till later.
46051 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
46058 editorcore : false,
46060 * @cfg {Object} disable List of toolbar elements to disable
46067 * @cfg {String} createLinkText The default text for the create link prompt
46069 createLinkText : 'Please enter the URL for the link:',
46071 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
46073 defaultLinkValue : 'http:/'+'/',
46077 * @cfg {Array} fontFamilies An array of available font families
46095 // "á" , ?? a acute?
46100 "°" // , // degrees
46102 // "é" , // e ecute
46103 // "ú" , // u ecute?
46106 specialElements : [
46108 text: "Insert Table",
46111 ihtml : '<table><tr><td>Cell</td></tr></table>'
46115 text: "Insert Image",
46118 ihtml : '<img src="about:blank"/>'
46127 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
46128 "input:submit", "input:button", "select", "textarea", "label" ],
46131 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
46133 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
46142 * @cfg {String} defaultFont default font to use.
46144 defaultFont: 'tahoma',
46146 fontSelect : false,
46149 formatCombo : false,
46151 init : function(editor)
46153 this.editor = editor;
46154 this.editorcore = editor.editorcore ? editor.editorcore : editor;
46155 var editorcore = this.editorcore;
46159 var fid = editorcore.frameId;
46161 function btn(id, toggle, handler){
46162 var xid = fid + '-'+ id ;
46166 cls : 'x-btn-icon x-edit-'+id,
46167 enableToggle:toggle !== false,
46168 scope: _t, // was editor...
46169 handler:handler||_t.relayBtnCmd,
46170 clickEvent:'mousedown',
46171 tooltip: etb.buttonTips[id] || undefined, ///tips ???
46178 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
46180 // stop form submits
46181 tb.el.on('click', function(e){
46182 e.preventDefault(); // what does this do?
46185 if(!this.disable.font) { // && !Roo.isSafari){
46186 /* why no safari for fonts
46187 editor.fontSelect = tb.el.createChild({
46190 cls:'x-font-select',
46191 html: this.createFontOptions()
46194 editor.fontSelect.on('change', function(){
46195 var font = editor.fontSelect.dom.value;
46196 editor.relayCmd('fontname', font);
46197 editor.deferFocus();
46201 editor.fontSelect.dom,
46207 if(!this.disable.formats){
46208 this.formatCombo = new Roo.form.ComboBox({
46209 store: new Roo.data.SimpleStore({
46212 data : this.formats // from states.js
46216 //autoCreate : {tag: "div", size: "20"},
46217 displayField:'tag',
46221 triggerAction: 'all',
46222 emptyText:'Add tag',
46223 selectOnFocus:true,
46226 'select': function(c, r, i) {
46227 editorcore.insertTag(r.get('tag'));
46233 tb.addField(this.formatCombo);
46237 if(!this.disable.format){
46242 btn('strikethrough')
46245 if(!this.disable.fontSize){
46250 btn('increasefontsize', false, editorcore.adjustFont),
46251 btn('decreasefontsize', false, editorcore.adjustFont)
46256 if(!this.disable.colors){
46259 id:editorcore.frameId +'-forecolor',
46260 cls:'x-btn-icon x-edit-forecolor',
46261 clickEvent:'mousedown',
46262 tooltip: this.buttonTips['forecolor'] || undefined,
46264 menu : new Roo.menu.ColorMenu({
46265 allowReselect: true,
46266 focus: Roo.emptyFn,
46269 selectHandler: function(cp, color){
46270 editorcore.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
46271 editor.deferFocus();
46274 clickEvent:'mousedown'
46277 id:editorcore.frameId +'backcolor',
46278 cls:'x-btn-icon x-edit-backcolor',
46279 clickEvent:'mousedown',
46280 tooltip: this.buttonTips['backcolor'] || undefined,
46282 menu : new Roo.menu.ColorMenu({
46283 focus: Roo.emptyFn,
46286 allowReselect: true,
46287 selectHandler: function(cp, color){
46289 editorcore.execCmd('useCSS', false);
46290 editorcore.execCmd('hilitecolor', color);
46291 editorcore.execCmd('useCSS', true);
46292 editor.deferFocus();
46294 editorcore.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
46295 Roo.isSafari || Roo.isIE ? '#'+color : color);
46296 editor.deferFocus();
46300 clickEvent:'mousedown'
46305 // now add all the items...
46308 if(!this.disable.alignments){
46311 btn('justifyleft'),
46312 btn('justifycenter'),
46313 btn('justifyright')
46317 //if(!Roo.isSafari){
46318 if(!this.disable.links){
46321 btn('createlink', false, this.createLink) /// MOVE TO HERE?!!?!?!?!
46325 if(!this.disable.lists){
46328 btn('insertorderedlist'),
46329 btn('insertunorderedlist')
46332 if(!this.disable.sourceEdit){
46335 btn('sourceedit', true, function(btn){
46336 this.toggleSourceEdit(btn.pressed);
46343 // special menu.. - needs to be tidied up..
46344 if (!this.disable.special) {
46347 cls: 'x-edit-none',
46353 for (var i =0; i < this.specialChars.length; i++) {
46354 smenu.menu.items.push({
46356 html: this.specialChars[i],
46357 handler: function(a,b) {
46358 editorcore.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
46359 //editor.insertAtCursor(a.html);
46373 if (!this.disable.cleanStyles) {
46375 cls: 'x-btn-icon x-btn-clear',
46381 for (var i =0; i < this.cleanStyles.length; i++) {
46382 cmenu.menu.items.push({
46383 actiontype : this.cleanStyles[i],
46384 html: 'Remove ' + this.cleanStyles[i],
46385 handler: function(a,b) {
46388 var c = Roo.get(editorcore.doc.body);
46389 c.select('[style]').each(function(s) {
46390 s.dom.style.removeProperty(a.actiontype);
46392 editorcore.syncValue();
46397 cmenu.menu.items.push({
46398 actiontype : 'tablewidths',
46399 html: 'Remove Table Widths',
46400 handler: function(a,b) {
46401 editorcore.cleanTableWidths();
46402 editorcore.syncValue();
46406 cmenu.menu.items.push({
46407 actiontype : 'word',
46408 html: 'Remove MS Word Formating',
46409 handler: function(a,b) {
46410 editorcore.cleanWord();
46411 editorcore.syncValue();
46416 cmenu.menu.items.push({
46417 actiontype : 'all',
46418 html: 'Remove All Styles',
46419 handler: function(a,b) {
46421 var c = Roo.get(editorcore.doc.body);
46422 c.select('[style]').each(function(s) {
46423 s.dom.removeAttribute('style');
46425 editorcore.syncValue();
46430 cmenu.menu.items.push({
46431 actiontype : 'all',
46432 html: 'Remove All CSS Classes',
46433 handler: function(a,b) {
46435 var c = Roo.get(editorcore.doc.body);
46436 c.select('[class]').each(function(s) {
46437 s.dom.removeAttribute('class');
46439 editorcore.cleanWord();
46440 editorcore.syncValue();
46445 cmenu.menu.items.push({
46446 actiontype : 'tidy',
46447 html: 'Tidy HTML Source',
46448 handler: function(a,b) {
46449 editorcore.doc.body.innerHTML = editorcore.domToHTML();
46450 editorcore.syncValue();
46459 if (!this.disable.specialElements) {
46462 cls: 'x-edit-none',
46467 for (var i =0; i < this.specialElements.length; i++) {
46468 semenu.menu.items.push(
46470 handler: function(a,b) {
46471 editor.insertAtCursor(this.ihtml);
46473 }, this.specialElements[i])
46485 for(var i =0; i< this.btns.length;i++) {
46486 var b = Roo.factory(this.btns[i],Roo.form);
46487 b.cls = 'x-edit-none';
46489 if(typeof(this.btns[i].cls) != 'undefined' && this.btns[i].cls.indexOf('x-init-enable') !== -1){
46490 b.cls += ' x-init-enable';
46493 b.scope = editorcore;
46501 // disable everything...
46503 this.tb.items.each(function(item){
46506 item.id != editorcore.frameId+ '-sourceedit' &&
46507 (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)
46513 this.rendered = true;
46515 // the all the btns;
46516 editor.on('editorevent', this.updateToolbar, this);
46517 // other toolbars need to implement this..
46518 //editor.on('editmodechange', this.updateToolbar, this);
46522 relayBtnCmd : function(btn) {
46523 this.editorcore.relayCmd(btn.cmd);
46525 // private used internally
46526 createLink : function(){
46527 Roo.log("create link?");
46528 var url = prompt(this.createLinkText, this.defaultLinkValue);
46529 if(url && url != 'http:/'+'/'){
46530 this.editorcore.relayCmd('createlink', url);
46536 * Protected method that will not generally be called directly. It triggers
46537 * a toolbar update by reading the markup state of the current selection in the editor.
46539 updateToolbar: function(){
46541 if(!this.editorcore.activated){
46542 this.editor.onFirstFocus();
46546 var btns = this.tb.items.map,
46547 doc = this.editorcore.doc,
46548 frameId = this.editorcore.frameId;
46550 if(!this.disable.font && !Roo.isSafari){
46552 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
46553 if(name != this.fontSelect.dom.value){
46554 this.fontSelect.dom.value = name;
46558 if(!this.disable.format){
46559 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
46560 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
46561 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
46562 btns[frameId + '-strikethrough'].toggle(doc.queryCommandState('strikethrough'));
46564 if(!this.disable.alignments){
46565 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
46566 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
46567 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
46569 if(!Roo.isSafari && !this.disable.lists){
46570 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
46571 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
46574 var ans = this.editorcore.getAllAncestors();
46575 if (this.formatCombo) {
46578 var store = this.formatCombo.store;
46579 this.formatCombo.setValue("");
46580 for (var i =0; i < ans.length;i++) {
46581 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
46583 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
46591 // hides menus... - so this cant be on a menu...
46592 Roo.menu.MenuMgr.hideAll();
46594 //this.editorsyncValue();
46598 createFontOptions : function(){
46599 var buf = [], fs = this.fontFamilies, ff, lc;
46603 for(var i = 0, len = fs.length; i< len; i++){
46605 lc = ff.toLowerCase();
46607 '<option value="',lc,'" style="font-family:',ff,';"',
46608 (this.defaultFont == lc ? ' selected="true">' : '>'),
46613 return buf.join('');
46616 toggleSourceEdit : function(sourceEditMode){
46618 Roo.log("toolbar toogle");
46619 if(sourceEditMode === undefined){
46620 sourceEditMode = !this.sourceEditMode;
46622 this.sourceEditMode = sourceEditMode === true;
46623 var btn = this.tb.items.get(this.editorcore.frameId +'-sourceedit');
46624 // just toggle the button?
46625 if(btn.pressed !== this.sourceEditMode){
46626 btn.toggle(this.sourceEditMode);
46630 if(sourceEditMode){
46631 Roo.log("disabling buttons");
46632 this.tb.items.each(function(item){
46633 if(item.cmd != 'sourceedit' && (typeof(item.cls) != 'undefined' && item.cls.indexOf('x-init-enable') === -1)){
46639 Roo.log("enabling buttons");
46640 if(this.editorcore.initialized){
46641 this.tb.items.each(function(item){
46647 Roo.log("calling toggole on editor");
46648 // tell the editor that it's been pressed..
46649 this.editor.toggleSourceEdit(sourceEditMode);
46653 * Object collection of toolbar tooltips for the buttons in the editor. The key
46654 * is the command id associated with that button and the value is a valid QuickTips object.
46659 title: 'Bold (Ctrl+B)',
46660 text: 'Make the selected text bold.',
46661 cls: 'x-html-editor-tip'
46664 title: 'Italic (Ctrl+I)',
46665 text: 'Make the selected text italic.',
46666 cls: 'x-html-editor-tip'
46674 title: 'Bold (Ctrl+B)',
46675 text: 'Make the selected text bold.',
46676 cls: 'x-html-editor-tip'
46679 title: 'Italic (Ctrl+I)',
46680 text: 'Make the selected text italic.',
46681 cls: 'x-html-editor-tip'
46684 title: 'Underline (Ctrl+U)',
46685 text: 'Underline the selected text.',
46686 cls: 'x-html-editor-tip'
46689 title: 'Strikethrough',
46690 text: 'Strikethrough the selected text.',
46691 cls: 'x-html-editor-tip'
46693 increasefontsize : {
46694 title: 'Grow Text',
46695 text: 'Increase the font size.',
46696 cls: 'x-html-editor-tip'
46698 decreasefontsize : {
46699 title: 'Shrink Text',
46700 text: 'Decrease the font size.',
46701 cls: 'x-html-editor-tip'
46704 title: 'Text Highlight Color',
46705 text: 'Change the background color of the selected text.',
46706 cls: 'x-html-editor-tip'
46709 title: 'Font Color',
46710 text: 'Change the color of the selected text.',
46711 cls: 'x-html-editor-tip'
46714 title: 'Align Text Left',
46715 text: 'Align text to the left.',
46716 cls: 'x-html-editor-tip'
46719 title: 'Center Text',
46720 text: 'Center text in the editor.',
46721 cls: 'x-html-editor-tip'
46724 title: 'Align Text Right',
46725 text: 'Align text to the right.',
46726 cls: 'x-html-editor-tip'
46728 insertunorderedlist : {
46729 title: 'Bullet List',
46730 text: 'Start a bulleted list.',
46731 cls: 'x-html-editor-tip'
46733 insertorderedlist : {
46734 title: 'Numbered List',
46735 text: 'Start a numbered list.',
46736 cls: 'x-html-editor-tip'
46739 title: 'Hyperlink',
46740 text: 'Make the selected text a hyperlink.',
46741 cls: 'x-html-editor-tip'
46744 title: 'Source Edit',
46745 text: 'Switch to source editing mode.',
46746 cls: 'x-html-editor-tip'
46750 onDestroy : function(){
46753 this.tb.items.each(function(item){
46755 item.menu.removeAll();
46757 item.menu.el.destroy();
46765 onFirstFocus: function() {
46766 this.tb.items.each(function(item){
46775 // <script type="text/javascript">
46778 * Ext JS Library 1.1.1
46779 * Copyright(c) 2006-2007, Ext JS, LLC.
46786 * @class Roo.form.HtmlEditor.ToolbarContext
46791 new Roo.form.HtmlEditor({
46794 { xtype: 'ToolbarStandard', styles : {} }
46795 { xtype: 'ToolbarContext', disable : {} }
46801 * @config : {Object} disable List of elements to disable.. (not done yet.)
46802 * @config : {Object} styles Map of styles available.
46806 Roo.form.HtmlEditor.ToolbarContext = function(config)
46809 Roo.apply(this, config);
46810 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
46811 // dont call parent... till later.
46812 this.styles = this.styles || {};
46817 Roo.form.HtmlEditor.ToolbarContext.types = {
46829 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
46895 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
46900 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
46910 style : 'fontFamily',
46911 displayField: 'display',
46912 optname : 'font-family',
46961 // should we really allow this??
46962 // should this just be
46973 style : 'fontFamily',
46974 displayField: 'display',
46975 optname : 'font-family',
46982 style : 'fontFamily',
46983 displayField: 'display',
46984 optname : 'font-family',
46991 style : 'fontFamily',
46992 displayField: 'display',
46993 optname : 'font-family',
47004 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
47005 Roo.form.HtmlEditor.ToolbarContext.stores = false;
47007 Roo.form.HtmlEditor.ToolbarContext.options = {
47009 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
47010 [ 'Courier New', 'Courier New'],
47011 [ 'Tahoma', 'Tahoma'],
47012 [ 'Times New Roman,serif', 'Times'],
47013 [ 'Verdana','Verdana' ]
47017 // fixme - these need to be configurable..
47020 //Roo.form.HtmlEditor.ToolbarContext.types
47023 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
47030 editorcore : false,
47032 * @cfg {Object} disable List of toolbar elements to disable
47037 * @cfg {Object} styles List of styles
47038 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
47040 * These must be defined in the page, so they get rendered correctly..
47051 init : function(editor)
47053 this.editor = editor;
47054 this.editorcore = editor.editorcore ? editor.editorcore : editor;
47055 var editorcore = this.editorcore;
47057 var fid = editorcore.frameId;
47059 function btn(id, toggle, handler){
47060 var xid = fid + '-'+ id ;
47064 cls : 'x-btn-icon x-edit-'+id,
47065 enableToggle:toggle !== false,
47066 scope: editorcore, // was editor...
47067 handler:handler||editorcore.relayBtnCmd,
47068 clickEvent:'mousedown',
47069 tooltip: etb.buttonTips[id] || undefined, ///tips ???
47073 // create a new element.
47074 var wdiv = editor.wrap.createChild({
47076 }, editor.wrap.dom.firstChild.nextSibling, true);
47078 // can we do this more than once??
47080 // stop form submits
47083 // disable everything...
47084 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47085 this.toolbars = {};
47087 for (var i in ty) {
47089 this.toolbars[i] = this.buildToolbar(ty[i],i);
47091 this.tb = this.toolbars.BODY;
47093 this.buildFooter();
47094 this.footer.show();
47095 editor.on('hide', function( ) { this.footer.hide() }, this);
47096 editor.on('show', function( ) { this.footer.show() }, this);
47099 this.rendered = true;
47101 // the all the btns;
47102 editor.on('editorevent', this.updateToolbar, this);
47103 // other toolbars need to implement this..
47104 //editor.on('editmodechange', this.updateToolbar, this);
47110 * Protected method that will not generally be called directly. It triggers
47111 * a toolbar update by reading the markup state of the current selection in the editor.
47113 * Note you can force an update by calling on('editorevent', scope, false)
47115 updateToolbar: function(editor,ev,sel){
47118 // capture mouse up - this is handy for selecting images..
47119 // perhaps should go somewhere else...
47120 if(!this.editorcore.activated){
47121 this.editor.onFirstFocus();
47127 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
47128 // selectNode - might want to handle IE?
47130 (ev.type == 'mouseup' || ev.type == 'click' ) &&
47131 ev.target && ev.target.tagName == 'IMG') {
47132 // they have click on an image...
47133 // let's see if we can change the selection...
47136 var nodeRange = sel.ownerDocument.createRange();
47138 nodeRange.selectNode(sel);
47140 nodeRange.selectNodeContents(sel);
47142 //nodeRange.collapse(true);
47143 var s = this.editorcore.win.getSelection();
47144 s.removeAllRanges();
47145 s.addRange(nodeRange);
47149 var updateFooter = sel ? false : true;
47152 var ans = this.editorcore.getAllAncestors();
47155 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
47158 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editorcore.doc.body;
47159 sel = sel ? sel : this.editorcore.doc.body;
47160 sel = sel.tagName.length ? sel : this.editorcore.doc.body;
47163 // pick a menu that exists..
47164 var tn = sel.tagName.toUpperCase();
47165 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
47167 tn = sel.tagName.toUpperCase();
47169 var lastSel = this.tb.selectedNode;
47171 this.tb.selectedNode = sel;
47173 // if current menu does not match..
47175 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode) || ev === false) {
47178 ///console.log("show: " + tn);
47179 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
47182 this.tb.items.first().el.innerHTML = tn + ': ';
47185 // update attributes
47186 if (this.tb.fields) {
47187 this.tb.fields.each(function(e) {
47189 e.setValue(sel.style[e.stylename]);
47192 e.setValue(sel.getAttribute(e.attrname));
47196 var hasStyles = false;
47197 for(var i in this.styles) {
47204 var st = this.tb.fields.item(0);
47206 st.store.removeAll();
47209 var cn = sel.className.split(/\s+/);
47212 if (this.styles['*']) {
47214 Roo.each(this.styles['*'], function(v) {
47215 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47218 if (this.styles[tn]) {
47219 Roo.each(this.styles[tn], function(v) {
47220 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
47224 st.store.loadData(avs);
47228 // flag our selected Node.
47229 this.tb.selectedNode = sel;
47232 Roo.menu.MenuMgr.hideAll();
47236 if (!updateFooter) {
47237 //this.footDisp.dom.innerHTML = '';
47240 // update the footer
47244 this.footerEls = ans.reverse();
47245 Roo.each(this.footerEls, function(a,i) {
47246 if (!a) { return; }
47247 html += html.length ? ' > ' : '';
47249 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
47254 var sz = this.footDisp.up('td').getSize();
47255 this.footDisp.dom.style.width = (sz.width -10) + 'px';
47256 this.footDisp.dom.style.marginLeft = '5px';
47258 this.footDisp.dom.style.overflow = 'hidden';
47260 this.footDisp.dom.innerHTML = html;
47262 //this.editorsyncValue();
47269 onDestroy : function(){
47272 this.tb.items.each(function(item){
47274 item.menu.removeAll();
47276 item.menu.el.destroy();
47284 onFirstFocus: function() {
47285 // need to do this for all the toolbars..
47286 this.tb.items.each(function(item){
47290 buildToolbar: function(tlist, nm)
47292 var editor = this.editor;
47293 var editorcore = this.editorcore;
47294 // create a new element.
47295 var wdiv = editor.wrap.createChild({
47297 }, editor.wrap.dom.firstChild.nextSibling, true);
47300 var tb = new Roo.Toolbar(wdiv);
47303 tb.add(nm+ ": ");
47306 for(var i in this.styles) {
47311 if (styles && styles.length) {
47313 // this needs a multi-select checkbox...
47314 tb.addField( new Roo.form.ComboBox({
47315 store: new Roo.data.SimpleStore({
47317 fields: ['val', 'selected'],
47320 name : '-roo-edit-className',
47321 attrname : 'className',
47322 displayField: 'val',
47326 triggerAction: 'all',
47327 emptyText:'Select Style',
47328 selectOnFocus:true,
47331 'select': function(c, r, i) {
47332 // initial support only for on class per el..
47333 tb.selectedNode.className = r ? r.get('val') : '';
47334 editorcore.syncValue();
47341 var tbc = Roo.form.HtmlEditor.ToolbarContext;
47342 var tbops = tbc.options;
47344 for (var i in tlist) {
47346 var item = tlist[i];
47347 tb.add(item.title + ": ");
47350 //optname == used so you can configure the options available..
47351 var opts = item.opts ? item.opts : false;
47352 if (item.optname) {
47353 opts = tbops[item.optname];
47358 // opts == pulldown..
47359 tb.addField( new Roo.form.ComboBox({
47360 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
47362 fields: ['val', 'display'],
47365 name : '-roo-edit-' + i,
47367 stylename : item.style ? item.style : false,
47368 displayField: item.displayField ? item.displayField : 'val',
47369 valueField : 'val',
47371 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
47373 triggerAction: 'all',
47374 emptyText:'Select',
47375 selectOnFocus:true,
47376 width: item.width ? item.width : 130,
47378 'select': function(c, r, i) {
47380 tb.selectedNode.style[c.stylename] = r.get('val');
47383 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
47392 tb.addField( new Roo.form.TextField({
47395 //allowBlank:false,
47400 tb.addField( new Roo.form.TextField({
47401 name: '-roo-edit-' + i,
47408 'change' : function(f, nv, ov) {
47409 tb.selectedNode.setAttribute(f.attrname, nv);
47410 editorcore.syncValue();
47423 text: 'Stylesheets',
47426 click : function ()
47428 _this.editor.fireEvent('stylesheetsclick', _this.editor);
47436 text: 'Remove Tag',
47439 click : function ()
47442 // undo does not work.
47444 var sn = tb.selectedNode;
47446 var pn = sn.parentNode;
47448 var stn = sn.childNodes[0];
47449 var en = sn.childNodes[sn.childNodes.length - 1 ];
47450 while (sn.childNodes.length) {
47451 var node = sn.childNodes[0];
47452 sn.removeChild(node);
47454 pn.insertBefore(node, sn);
47457 pn.removeChild(sn);
47458 var range = editorcore.createRange();
47460 range.setStart(stn,0);
47461 range.setEnd(en,0); //????
47462 //range.selectNode(sel);
47465 var selection = editorcore.getSelection();
47466 selection.removeAllRanges();
47467 selection.addRange(range);
47471 //_this.updateToolbar(null, null, pn);
47472 _this.updateToolbar(null, null, null);
47473 _this.footDisp.dom.innerHTML = '';
47483 tb.el.on('click', function(e){
47484 e.preventDefault(); // what does this do?
47486 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
47489 // dont need to disable them... as they will get hidden
47494 buildFooter : function()
47497 var fel = this.editor.wrap.createChild();
47498 this.footer = new Roo.Toolbar(fel);
47499 // toolbar has scrolly on left / right?
47500 var footDisp= new Roo.Toolbar.Fill();
47506 handler : function() {
47507 _t.footDisp.scrollTo('left',0,true)
47511 this.footer.add( footDisp );
47516 handler : function() {
47518 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
47522 var fel = Roo.get(footDisp.el);
47523 fel.addClass('x-editor-context');
47524 this.footDispWrap = fel;
47525 this.footDispWrap.overflow = 'hidden';
47527 this.footDisp = fel.createChild();
47528 this.footDispWrap.on('click', this.onContextClick, this)
47532 onContextClick : function (ev,dom)
47534 ev.preventDefault();
47535 var cn = dom.className;
47537 if (!cn.match(/x-ed-loc-/)) {
47540 var n = cn.split('-').pop();
47541 var ans = this.footerEls;
47545 var range = this.editorcore.createRange();
47547 range.selectNodeContents(sel);
47548 //range.selectNode(sel);
47551 var selection = this.editorcore.getSelection();
47552 selection.removeAllRanges();
47553 selection.addRange(range);
47557 this.updateToolbar(null, null, sel);
47574 * Ext JS Library 1.1.1
47575 * Copyright(c) 2006-2007, Ext JS, LLC.
47577 * Originally Released Under LGPL - original licence link has changed is not relivant.
47580 * <script type="text/javascript">
47584 * @class Roo.form.BasicForm
47585 * @extends Roo.util.Observable
47586 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
47588 * @param {String/HTMLElement/Roo.Element} el The form element or its id
47589 * @param {Object} config Configuration options
47591 Roo.form.BasicForm = function(el, config){
47592 this.allItems = [];
47593 this.childForms = [];
47594 Roo.apply(this, config);
47596 * The Roo.form.Field items in this form.
47597 * @type MixedCollection
47601 this.items = new Roo.util.MixedCollection(false, function(o){
47602 return o.id || (o.id = Roo.id());
47606 * @event beforeaction
47607 * Fires before any action is performed. Return false to cancel the action.
47608 * @param {Form} this
47609 * @param {Action} action The action to be performed
47611 beforeaction: true,
47613 * @event actionfailed
47614 * Fires when an action fails.
47615 * @param {Form} this
47616 * @param {Action} action The action that failed
47618 actionfailed : true,
47620 * @event actioncomplete
47621 * Fires when an action is completed.
47622 * @param {Form} this
47623 * @param {Action} action The action that completed
47625 actioncomplete : true
47630 Roo.form.BasicForm.superclass.constructor.call(this);
47632 Roo.form.BasicForm.popover.apply();
47635 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
47637 * @cfg {String} method
47638 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
47641 * @cfg {DataReader} reader
47642 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
47643 * This is optional as there is built-in support for processing JSON.
47646 * @cfg {DataReader} errorReader
47647 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
47648 * This is completely optional as there is built-in support for processing JSON.
47651 * @cfg {String} url
47652 * The URL to use for form actions if one isn't supplied in the action options.
47655 * @cfg {Boolean} fileUpload
47656 * Set to true if this form is a file upload.
47660 * @cfg {Object} baseParams
47661 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
47666 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
47671 activeAction : null,
47674 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
47675 * or setValues() data instead of when the form was first created.
47677 trackResetOnLoad : false,
47681 * childForms - used for multi-tab forms
47684 childForms : false,
47687 * allItems - full list of fields.
47693 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
47694 * element by passing it or its id or mask the form itself by passing in true.
47697 waitMsgTarget : false,
47702 disableMask : false,
47705 * @cfg {Boolean} errorMask (true|false) default false
47710 * @cfg {Number} maskOffset Default 100
47715 initEl : function(el){
47716 this.el = Roo.get(el);
47717 this.id = this.el.id || Roo.id();
47718 this.el.on('submit', this.onSubmit, this);
47719 this.el.addClass('x-form');
47723 onSubmit : function(e){
47728 * Returns true if client-side validation on the form is successful.
47731 isValid : function(){
47733 var target = false;
47734 this.items.each(function(f){
47741 if(!target && f.el.isVisible(true)){
47746 if(this.errorMask && !valid){
47747 Roo.form.BasicForm.popover.mask(this, target);
47753 * Returns array of invalid form fields.
47757 invalidFields : function()
47760 this.items.each(function(f){
47773 * DEPRICATED Returns true if any fields in this form have changed since their original load.
47776 isDirty : function(){
47778 this.items.each(function(f){
47788 * Returns true if any fields in this form have changed since their original load. (New version)
47792 hasChanged : function()
47795 this.items.each(function(f){
47796 if(f.hasChanged()){
47805 * Resets all hasChanged to 'false' -
47806 * The old 'isDirty' used 'original value..' however this breaks reset() and a few other things.
47807 * So hasChanged storage is only to be used for this purpose
47810 resetHasChanged : function()
47812 this.items.each(function(f){
47813 f.resetHasChanged();
47820 * Performs a predefined action (submit or load) or custom actions you define on this form.
47821 * @param {String} actionName The name of the action type
47822 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
47823 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
47824 * accept other config options):
47826 Property Type Description
47827 ---------------- --------------- ----------------------------------------------------------------------------------
47828 url String The url for the action (defaults to the form's url)
47829 method String The form method to use (defaults to the form's method, or POST if not defined)
47830 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
47831 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
47832 validate the form on the client (defaults to false)
47834 * @return {BasicForm} this
47836 doAction : function(action, options){
47837 if(typeof action == 'string'){
47838 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
47840 if(this.fireEvent('beforeaction', this, action) !== false){
47841 this.beforeAction(action);
47842 action.run.defer(100, action);
47848 * Shortcut to do a submit action.
47849 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47850 * @return {BasicForm} this
47852 submit : function(options){
47853 this.doAction('submit', options);
47858 * Shortcut to do a load action.
47859 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
47860 * @return {BasicForm} this
47862 load : function(options){
47863 this.doAction('load', options);
47868 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
47869 * @param {Record} record The record to edit
47870 * @return {BasicForm} this
47872 updateRecord : function(record){
47873 record.beginEdit();
47874 var fs = record.fields;
47875 fs.each(function(f){
47876 var field = this.findField(f.name);
47878 record.set(f.name, field.getValue());
47886 * Loads an Roo.data.Record into this form.
47887 * @param {Record} record The record to load
47888 * @return {BasicForm} this
47890 loadRecord : function(record){
47891 this.setValues(record.data);
47896 beforeAction : function(action){
47897 var o = action.options;
47899 if(!this.disableMask) {
47900 if(this.waitMsgTarget === true){
47901 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
47902 }else if(this.waitMsgTarget){
47903 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
47904 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
47906 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
47914 afterAction : function(action, success){
47915 this.activeAction = null;
47916 var o = action.options;
47918 if(!this.disableMask) {
47919 if(this.waitMsgTarget === true){
47921 }else if(this.waitMsgTarget){
47922 this.waitMsgTarget.unmask();
47924 Roo.MessageBox.updateProgress(1);
47925 Roo.MessageBox.hide();
47933 Roo.callback(o.success, o.scope, [this, action]);
47934 this.fireEvent('actioncomplete', this, action);
47938 // failure condition..
47939 // we have a scenario where updates need confirming.
47940 // eg. if a locking scenario exists..
47941 // we look for { errors : { needs_confirm : true }} in the response.
47943 (typeof(action.result) != 'undefined') &&
47944 (typeof(action.result.errors) != 'undefined') &&
47945 (typeof(action.result.errors.needs_confirm) != 'undefined')
47948 Roo.MessageBox.confirm(
47949 "Change requires confirmation",
47950 action.result.errorMsg,
47955 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
47965 Roo.callback(o.failure, o.scope, [this, action]);
47966 // show an error message if no failed handler is set..
47967 if (!this.hasListener('actionfailed')) {
47968 Roo.MessageBox.alert("Error",
47969 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
47970 action.result.errorMsg :
47971 "Saving Failed, please check your entries or try again"
47975 this.fireEvent('actionfailed', this, action);
47981 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
47982 * @param {String} id The value to search for
47985 findField : function(id){
47986 var field = this.items.get(id);
47988 this.items.each(function(f){
47989 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
47995 return field || null;
47999 * Add a secondary form to this one,
48000 * Used to provide tabbed forms. One form is primary, with hidden values
48001 * which mirror the elements from the other forms.
48003 * @param {Roo.form.Form} form to add.
48006 addForm : function(form)
48009 if (this.childForms.indexOf(form) > -1) {
48013 this.childForms.push(form);
48015 Roo.each(form.allItems, function (fe) {
48017 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
48018 if (this.findField(n)) { // already added..
48021 var add = new Roo.form.Hidden({
48024 add.render(this.el);
48031 * Mark fields in this form invalid in bulk.
48032 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
48033 * @return {BasicForm} this
48035 markInvalid : function(errors){
48036 if(errors instanceof Array){
48037 for(var i = 0, len = errors.length; i < len; i++){
48038 var fieldError = errors[i];
48039 var f = this.findField(fieldError.id);
48041 f.markInvalid(fieldError.msg);
48047 if(typeof errors[id] != 'function' && (field = this.findField(id))){
48048 field.markInvalid(errors[id]);
48052 Roo.each(this.childForms || [], function (f) {
48053 f.markInvalid(errors);
48060 * Set values for fields in this form in bulk.
48061 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
48062 * @return {BasicForm} this
48064 setValues : function(values){
48065 if(values instanceof Array){ // array of objects
48066 for(var i = 0, len = values.length; i < len; i++){
48068 var f = this.findField(v.id);
48070 f.setValue(v.value);
48071 if(this.trackResetOnLoad){
48072 f.originalValue = f.getValue();
48076 }else{ // object hash
48079 if(typeof values[id] != 'function' && (field = this.findField(id))){
48081 if (field.setFromData &&
48082 field.valueField &&
48083 field.displayField &&
48084 // combos' with local stores can
48085 // be queried via setValue()
48086 // to set their value..
48087 (field.store && !field.store.isLocal)
48091 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
48092 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
48093 field.setFromData(sd);
48096 field.setValue(values[id]);
48100 if(this.trackResetOnLoad){
48101 field.originalValue = field.getValue();
48106 this.resetHasChanged();
48109 Roo.each(this.childForms || [], function (f) {
48110 f.setValues(values);
48111 f.resetHasChanged();
48118 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
48119 * they are returned as an array.
48120 * @param {Boolean} asString
48123 getValues : function(asString){
48124 if (this.childForms) {
48125 // copy values from the child forms
48126 Roo.each(this.childForms, function (f) {
48127 this.setValues(f.getValues());
48132 if (typeof(FormData) != 'undefined' && asString !== true) {
48133 // this relies on a 'recent' version of chrome apparently...
48135 var fd = (new FormData(this.el.dom)).entries();
48137 var ent = fd.next();
48138 while (!ent.done) {
48139 ret[ent.value[0]] = ent.value[1]; // not sure how this will handle duplicates..
48150 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
48151 if(asString === true){
48154 return Roo.urlDecode(fs);
48158 * Returns the fields in this form as an object with key/value pairs.
48159 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
48162 getFieldValues : function(with_hidden)
48164 if (this.childForms) {
48165 // copy values from the child forms
48166 // should this call getFieldValues - probably not as we do not currently copy
48167 // hidden fields when we generate..
48168 Roo.each(this.childForms, function (f) {
48169 this.setValues(f.getValues());
48174 this.items.each(function(f){
48175 if (!f.getName()) {
48178 var v = f.getValue();
48179 if (f.inputType =='radio') {
48180 if (typeof(ret[f.getName()]) == 'undefined') {
48181 ret[f.getName()] = ''; // empty..
48184 if (!f.el.dom.checked) {
48188 v = f.el.dom.value;
48192 // not sure if this supported any more..
48193 if ((typeof(v) == 'object') && f.getRawValue) {
48194 v = f.getRawValue() ; // dates..
48196 // combo boxes where name != hiddenName...
48197 if (f.name != f.getName()) {
48198 ret[f.name] = f.getRawValue();
48200 ret[f.getName()] = v;
48207 * Clears all invalid messages in this form.
48208 * @return {BasicForm} this
48210 clearInvalid : function(){
48211 this.items.each(function(f){
48215 Roo.each(this.childForms || [], function (f) {
48224 * Resets this form.
48225 * @return {BasicForm} this
48227 reset : function(){
48228 this.items.each(function(f){
48232 Roo.each(this.childForms || [], function (f) {
48235 this.resetHasChanged();
48241 * Add Roo.form components to this form.
48242 * @param {Field} field1
48243 * @param {Field} field2 (optional)
48244 * @param {Field} etc (optional)
48245 * @return {BasicForm} this
48248 this.items.addAll(Array.prototype.slice.call(arguments, 0));
48254 * Removes a field from the items collection (does NOT remove its markup).
48255 * @param {Field} field
48256 * @return {BasicForm} this
48258 remove : function(field){
48259 this.items.remove(field);
48264 * Looks at the fields in this form, checks them for an id attribute,
48265 * and calls applyTo on the existing dom element with that id.
48266 * @return {BasicForm} this
48268 render : function(){
48269 this.items.each(function(f){
48270 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
48278 * Calls {@link Ext#apply} for all fields in this form with the passed object.
48279 * @param {Object} values
48280 * @return {BasicForm} this
48282 applyToFields : function(o){
48283 this.items.each(function(f){
48290 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
48291 * @param {Object} values
48292 * @return {BasicForm} this
48294 applyIfToFields : function(o){
48295 this.items.each(function(f){
48303 Roo.BasicForm = Roo.form.BasicForm;
48305 Roo.apply(Roo.form.BasicForm, {
48319 intervalID : false,
48325 if(this.isApplied){
48330 top : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-top-mask" }, true),
48331 left : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-left-mask" }, true),
48332 bottom : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-bottom-mask" }, true),
48333 right : Roo.DomHelper.append(Roo.get(document.body), { tag: "div", cls:"x-dlg-mask roo-form-right-mask" }, true)
48336 this.maskEl.top.enableDisplayMode("block");
48337 this.maskEl.left.enableDisplayMode("block");
48338 this.maskEl.bottom.enableDisplayMode("block");
48339 this.maskEl.right.enableDisplayMode("block");
48341 Roo.get(document.body).on('click', function(){
48345 Roo.get(document.body).on('touchstart', function(){
48349 this.isApplied = true
48352 mask : function(form, target)
48356 this.target = target;
48358 if(!this.form.errorMask || !target.el){
48362 var scrollable = this.target.el.findScrollableParent() || this.target.el.findParent('div.x-layout-active-content', 100, true) || Roo.get(document.body);
48364 var ot = this.target.el.calcOffsetsTo(scrollable);
48366 var scrollTo = ot[1] - this.form.maskOffset;
48368 scrollTo = Math.min(scrollTo, scrollable.dom.scrollHeight);
48370 scrollable.scrollTo('top', scrollTo);
48372 var el = this.target.wrap || this.target.el;
48374 var box = el.getBox();
48376 this.maskEl.top.setStyle('position', 'absolute');
48377 this.maskEl.top.setStyle('z-index', 10000);
48378 this.maskEl.top.setSize(Roo.lib.Dom.getDocumentWidth(), box.y - this.padding);
48379 this.maskEl.top.setLeft(0);
48380 this.maskEl.top.setTop(0);
48381 this.maskEl.top.show();
48383 this.maskEl.left.setStyle('position', 'absolute');
48384 this.maskEl.left.setStyle('z-index', 10000);
48385 this.maskEl.left.setSize(box.x - this.padding, box.height + this.padding * 2);
48386 this.maskEl.left.setLeft(0);
48387 this.maskEl.left.setTop(box.y - this.padding);
48388 this.maskEl.left.show();
48390 this.maskEl.bottom.setStyle('position', 'absolute');
48391 this.maskEl.bottom.setStyle('z-index', 10000);
48392 this.maskEl.bottom.setSize(Roo.lib.Dom.getDocumentWidth(), Roo.lib.Dom.getDocumentHeight() - box.bottom - this.padding);
48393 this.maskEl.bottom.setLeft(0);
48394 this.maskEl.bottom.setTop(box.bottom + this.padding);
48395 this.maskEl.bottom.show();
48397 this.maskEl.right.setStyle('position', 'absolute');
48398 this.maskEl.right.setStyle('z-index', 10000);
48399 this.maskEl.right.setSize(Roo.lib.Dom.getDocumentWidth() - box.right - this.padding, box.height + this.padding * 2);
48400 this.maskEl.right.setLeft(box.right + this.padding);
48401 this.maskEl.right.setTop(box.y - this.padding);
48402 this.maskEl.right.show();
48404 this.intervalID = window.setInterval(function() {
48405 Roo.form.BasicForm.popover.unmask();
48408 window.onwheel = function(){ return false;};
48410 (function(){ this.isMasked = true; }).defer(500, this);
48414 unmask : function()
48416 if(!this.isApplied || !this.isMasked || !this.form || !this.target || !this.form.errorMask){
48420 this.maskEl.top.setStyle('position', 'absolute');
48421 this.maskEl.top.setSize(0, 0).setXY([0, 0]);
48422 this.maskEl.top.hide();
48424 this.maskEl.left.setStyle('position', 'absolute');
48425 this.maskEl.left.setSize(0, 0).setXY([0, 0]);
48426 this.maskEl.left.hide();
48428 this.maskEl.bottom.setStyle('position', 'absolute');
48429 this.maskEl.bottom.setSize(0, 0).setXY([0, 0]);
48430 this.maskEl.bottom.hide();
48432 this.maskEl.right.setStyle('position', 'absolute');
48433 this.maskEl.right.setSize(0, 0).setXY([0, 0]);
48434 this.maskEl.right.hide();
48436 window.onwheel = function(){ return true;};
48438 if(this.intervalID){
48439 window.clearInterval(this.intervalID);
48440 this.intervalID = false;
48443 this.isMasked = false;
48451 * Ext JS Library 1.1.1
48452 * Copyright(c) 2006-2007, Ext JS, LLC.
48454 * Originally Released Under LGPL - original licence link has changed is not relivant.
48457 * <script type="text/javascript">
48461 * @class Roo.form.Form
48462 * @extends Roo.form.BasicForm
48463 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
48465 * @param {Object} config Configuration options
48467 Roo.form.Form = function(config){
48469 if (config.items) {
48470 xitems = config.items;
48471 delete config.items;
48475 Roo.form.Form.superclass.constructor.call(this, null, config);
48476 this.url = this.url || this.action;
48478 this.root = new Roo.form.Layout(Roo.applyIf({
48482 this.active = this.root;
48484 * Array of all the buttons that have been added to this form via {@link addButton}
48488 this.allItems = [];
48491 * @event clientvalidation
48492 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
48493 * @param {Form} this
48494 * @param {Boolean} valid true if the form has passed client-side validation
48496 clientvalidation: true,
48499 * Fires when the form is rendered
48500 * @param {Roo.form.Form} form
48505 if (this.progressUrl) {
48506 // push a hidden field onto the list of fields..
48510 name : 'UPLOAD_IDENTIFIER'
48515 Roo.each(xitems, this.addxtype, this);
48519 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
48521 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
48524 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
48527 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
48529 buttonAlign:'center',
48532 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
48537 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
48538 * This property cascades to child containers if not set.
48543 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
48544 * fires a looping event with that state. This is required to bind buttons to the valid
48545 * state using the config value formBind:true on the button.
48547 monitorValid : false,
48550 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
48555 * @cfg {String} progressUrl - Url to return progress data
48558 progressUrl : false,
48560 * @cfg {boolean|FormData} formData - true to use new 'FormData' post, or set to a new FormData({dom form}) Object, if
48561 * sending a formdata with extra parameters - eg uploaded elements.
48567 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
48568 * fields are added and the column is closed. If no fields are passed the column remains open
48569 * until end() is called.
48570 * @param {Object} config The config to pass to the column
48571 * @param {Field} field1 (optional)
48572 * @param {Field} field2 (optional)
48573 * @param {Field} etc (optional)
48574 * @return Column The column container object
48576 column : function(c){
48577 var col = new Roo.form.Column(c);
48579 if(arguments.length > 1){ // duplicate code required because of Opera
48580 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48587 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
48588 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
48589 * until end() is called.
48590 * @param {Object} config The config to pass to the fieldset
48591 * @param {Field} field1 (optional)
48592 * @param {Field} field2 (optional)
48593 * @param {Field} etc (optional)
48594 * @return FieldSet The fieldset container object
48596 fieldset : function(c){
48597 var fs = new Roo.form.FieldSet(c);
48599 if(arguments.length > 1){ // duplicate code required because of Opera
48600 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48607 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
48608 * fields are added and the container is closed. If no fields are passed the container remains open
48609 * until end() is called.
48610 * @param {Object} config The config to pass to the Layout
48611 * @param {Field} field1 (optional)
48612 * @param {Field} field2 (optional)
48613 * @param {Field} etc (optional)
48614 * @return Layout The container object
48616 container : function(c){
48617 var l = new Roo.form.Layout(c);
48619 if(arguments.length > 1){ // duplicate code required because of Opera
48620 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
48627 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
48628 * @param {Object} container A Roo.form.Layout or subclass of Layout
48629 * @return {Form} this
48631 start : function(c){
48632 // cascade label info
48633 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
48634 this.active.stack.push(c);
48635 c.ownerCt = this.active;
48641 * Closes the current open container
48642 * @return {Form} this
48645 if(this.active == this.root){
48648 this.active = this.active.ownerCt;
48653 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
48654 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
48655 * as the label of the field.
48656 * @param {Field} field1
48657 * @param {Field} field2 (optional)
48658 * @param {Field} etc. (optional)
48659 * @return {Form} this
48662 this.active.stack.push.apply(this.active.stack, arguments);
48663 this.allItems.push.apply(this.allItems,arguments);
48665 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
48666 if(a[i].isFormField){
48671 Roo.form.Form.superclass.add.apply(this, r);
48681 * Find any element that has been added to a form, using it's ID or name
48682 * This can include framesets, columns etc. along with regular fields..
48683 * @param {String} id - id or name to find.
48685 * @return {Element} e - or false if nothing found.
48687 findbyId : function(id)
48693 Roo.each(this.allItems, function(f){
48694 if (f.id == id || f.name == id ){
48705 * Render this form into the passed container. This should only be called once!
48706 * @param {String/HTMLElement/Element} container The element this component should be rendered into
48707 * @return {Form} this
48709 render : function(ct)
48715 var o = this.autoCreate || {
48717 method : this.method || 'POST',
48718 id : this.id || Roo.id()
48720 this.initEl(ct.createChild(o));
48722 this.root.render(this.el);
48726 this.items.each(function(f){
48727 f.render('x-form-el-'+f.id);
48730 if(this.buttons.length > 0){
48731 // tables are required to maintain order and for correct IE layout
48732 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
48733 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
48734 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
48736 var tr = tb.getElementsByTagName('tr')[0];
48737 for(var i = 0, len = this.buttons.length; i < len; i++) {
48738 var b = this.buttons[i];
48739 var td = document.createElement('td');
48740 td.className = 'x-form-btn-td';
48741 b.render(tr.appendChild(td));
48744 if(this.monitorValid){ // initialize after render
48745 this.startMonitoring();
48747 this.fireEvent('rendered', this);
48752 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
48753 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
48754 * object or a valid Roo.DomHelper element config
48755 * @param {Function} handler The function called when the button is clicked
48756 * @param {Object} scope (optional) The scope of the handler function
48757 * @return {Roo.Button}
48759 addButton : function(config, handler, scope){
48763 minWidth: this.minButtonWidth,
48766 if(typeof config == "string"){
48769 Roo.apply(bc, config);
48771 var btn = new Roo.Button(null, bc);
48772 this.buttons.push(btn);
48777 * Adds a series of form elements (using the xtype property as the factory method.
48778 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
48779 * @param {Object} config
48782 addxtype : function()
48784 var ar = Array.prototype.slice.call(arguments, 0);
48786 for(var i = 0; i < ar.length; i++) {
48788 continue; // skip -- if this happends something invalid got sent, we
48789 // should ignore it, as basically that interface element will not show up
48790 // and that should be pretty obvious!!
48793 if (Roo.form[ar[i].xtype]) {
48795 var fe = Roo.factory(ar[i], Roo.form);
48801 fe.store.form = this;
48806 this.allItems.push(fe);
48807 if (fe.items && fe.addxtype) {
48808 fe.addxtype.apply(fe, fe.items);
48818 // console.log('adding ' + ar[i].xtype);
48820 if (ar[i].xtype == 'Button') {
48821 //console.log('adding button');
48822 //console.log(ar[i]);
48823 this.addButton(ar[i]);
48824 this.allItems.push(fe);
48828 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
48829 alert('end is not supported on xtype any more, use items');
48831 // //console.log('adding end');
48839 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
48840 * option "monitorValid"
48842 startMonitoring : function(){
48845 Roo.TaskMgr.start({
48846 run : this.bindHandler,
48847 interval : this.monitorPoll || 200,
48854 * Stops monitoring of the valid state of this form
48856 stopMonitoring : function(){
48857 this.bound = false;
48861 bindHandler : function(){
48863 return false; // stops binding
48866 this.items.each(function(f){
48867 if(!f.isValid(true)){
48872 for(var i = 0, len = this.buttons.length; i < len; i++){
48873 var btn = this.buttons[i];
48874 if(btn.formBind === true && btn.disabled === valid){
48875 btn.setDisabled(!valid);
48878 this.fireEvent('clientvalidation', this, valid);
48892 Roo.Form = Roo.form.Form;
48895 * Ext JS Library 1.1.1
48896 * Copyright(c) 2006-2007, Ext JS, LLC.
48898 * Originally Released Under LGPL - original licence link has changed is not relivant.
48901 * <script type="text/javascript">
48904 // as we use this in bootstrap.
48905 Roo.namespace('Roo.form');
48907 * @class Roo.form.Action
48908 * Internal Class used to handle form actions
48910 * @param {Roo.form.BasicForm} el The form element or its id
48911 * @param {Object} config Configuration options
48916 // define the action interface
48917 Roo.form.Action = function(form, options){
48919 this.options = options || {};
48922 * Client Validation Failed
48925 Roo.form.Action.CLIENT_INVALID = 'client';
48927 * Server Validation Failed
48930 Roo.form.Action.SERVER_INVALID = 'server';
48932 * Connect to Server Failed
48935 Roo.form.Action.CONNECT_FAILURE = 'connect';
48937 * Reading Data from Server Failed
48940 Roo.form.Action.LOAD_FAILURE = 'load';
48942 Roo.form.Action.prototype = {
48944 failureType : undefined,
48945 response : undefined,
48946 result : undefined,
48948 // interface method
48949 run : function(options){
48953 // interface method
48954 success : function(response){
48958 // interface method
48959 handleResponse : function(response){
48963 // default connection failure
48964 failure : function(response){
48966 this.response = response;
48967 this.failureType = Roo.form.Action.CONNECT_FAILURE;
48968 this.form.afterAction(this, false);
48971 processResponse : function(response){
48972 this.response = response;
48973 if(!response.responseText){
48976 this.result = this.handleResponse(response);
48977 return this.result;
48980 // utility functions used internally
48981 getUrl : function(appendParams){
48982 var url = this.options.url || this.form.url || this.form.el.dom.action;
48984 var p = this.getParams();
48986 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
48992 getMethod : function(){
48993 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
48996 getParams : function(){
48997 var bp = this.form.baseParams;
48998 var p = this.options.params;
49000 if(typeof p == "object"){
49001 p = Roo.urlEncode(Roo.applyIf(p, bp));
49002 }else if(typeof p == 'string' && bp){
49003 p += '&' + Roo.urlEncode(bp);
49006 p = Roo.urlEncode(bp);
49011 createCallback : function(){
49013 success: this.success,
49014 failure: this.failure,
49016 timeout: (this.form.timeout*1000),
49017 upload: this.form.fileUpload ? this.success : undefined
49022 Roo.form.Action.Submit = function(form, options){
49023 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
49026 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
49029 haveProgress : false,
49030 uploadComplete : false,
49032 // uploadProgress indicator.
49033 uploadProgress : function()
49035 if (!this.form.progressUrl) {
49039 if (!this.haveProgress) {
49040 Roo.MessageBox.progress("Uploading", "Uploading");
49042 if (this.uploadComplete) {
49043 Roo.MessageBox.hide();
49047 this.haveProgress = true;
49049 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
49051 var c = new Roo.data.Connection();
49053 url : this.form.progressUrl,
49058 success : function(req){
49059 //console.log(data);
49063 rdata = Roo.decode(req.responseText)
49065 Roo.log("Invalid data from server..");
49069 if (!rdata || !rdata.success) {
49071 Roo.MessageBox.alert(Roo.encode(rdata));
49074 var data = rdata.data;
49076 if (this.uploadComplete) {
49077 Roo.MessageBox.hide();
49082 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
49083 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
49086 this.uploadProgress.defer(2000,this);
49089 failure: function(data) {
49090 Roo.log('progress url failed ');
49101 // run get Values on the form, so it syncs any secondary forms.
49102 this.form.getValues();
49104 var o = this.options;
49105 var method = this.getMethod();
49106 var isPost = method == 'POST';
49107 if(o.clientValidation === false || this.form.isValid()){
49109 if (this.form.progressUrl) {
49110 this.form.findField('UPLOAD_IDENTIFIER').setValue(
49111 (new Date() * 1) + '' + Math.random());
49116 Roo.Ajax.request(Roo.apply(this.createCallback(), {
49117 form:this.form.el.dom,
49118 url:this.getUrl(!isPost),
49120 params:isPost ? this.getParams() : null,
49121 isUpload: this.form.fileUpload,
49122 formData : this.form.formData
49125 this.uploadProgress();
49127 }else if (o.clientValidation !== false){ // client validation failed
49128 this.failureType = Roo.form.Action.CLIENT_INVALID;
49129 this.form.afterAction(this, false);
49133 success : function(response)
49135 this.uploadComplete= true;
49136 if (this.haveProgress) {
49137 Roo.MessageBox.hide();
49141 var result = this.processResponse(response);
49142 if(result === true || result.success){
49143 this.form.afterAction(this, true);
49147 this.form.markInvalid(result.errors);
49148 this.failureType = Roo.form.Action.SERVER_INVALID;
49150 this.form.afterAction(this, false);
49152 failure : function(response)
49154 this.uploadComplete= true;
49155 if (this.haveProgress) {
49156 Roo.MessageBox.hide();
49159 this.response = response;
49160 this.failureType = Roo.form.Action.CONNECT_FAILURE;
49161 this.form.afterAction(this, false);
49164 handleResponse : function(response){
49165 if(this.form.errorReader){
49166 var rs = this.form.errorReader.read(response);
49169 for(var i = 0, len = rs.records.length; i < len; i++) {
49170 var r = rs.records[i];
49171 errors[i] = r.data;
49174 if(errors.length < 1){
49178 success : rs.success,
49184 ret = Roo.decode(response.responseText);
49188 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
49198 Roo.form.Action.Load = function(form, options){
49199 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
49200 this.reader = this.form.reader;
49203 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
49208 Roo.Ajax.request(Roo.apply(
49209 this.createCallback(), {
49210 method:this.getMethod(),
49211 url:this.getUrl(false),
49212 params:this.getParams()
49216 success : function(response){
49218 var result = this.processResponse(response);
49219 if(result === true || !result.success || !result.data){
49220 this.failureType = Roo.form.Action.LOAD_FAILURE;
49221 this.form.afterAction(this, false);
49224 this.form.clearInvalid();
49225 this.form.setValues(result.data);
49226 this.form.afterAction(this, true);
49229 handleResponse : function(response){
49230 if(this.form.reader){
49231 var rs = this.form.reader.read(response);
49232 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
49234 success : rs.success,
49238 return Roo.decode(response.responseText);
49242 Roo.form.Action.ACTION_TYPES = {
49243 'load' : Roo.form.Action.Load,
49244 'submit' : Roo.form.Action.Submit
49247 * Ext JS Library 1.1.1
49248 * Copyright(c) 2006-2007, Ext JS, LLC.
49250 * Originally Released Under LGPL - original licence link has changed is not relivant.
49253 * <script type="text/javascript">
49257 * @class Roo.form.Layout
49258 * @extends Roo.Component
49259 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
49261 * @param {Object} config Configuration options
49263 Roo.form.Layout = function(config){
49265 if (config.items) {
49266 xitems = config.items;
49267 delete config.items;
49269 Roo.form.Layout.superclass.constructor.call(this, config);
49271 Roo.each(xitems, this.addxtype, this);
49275 Roo.extend(Roo.form.Layout, Roo.Component, {
49277 * @cfg {String/Object} autoCreate
49278 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
49281 * @cfg {String/Object/Function} style
49282 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
49283 * a function which returns such a specification.
49286 * @cfg {String} labelAlign
49287 * Valid values are "left," "top" and "right" (defaults to "left")
49290 * @cfg {Number} labelWidth
49291 * Fixed width in pixels of all field labels (defaults to undefined)
49294 * @cfg {Boolean} clear
49295 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
49299 * @cfg {String} labelSeparator
49300 * The separator to use after field labels (defaults to ':')
49302 labelSeparator : ':',
49304 * @cfg {Boolean} hideLabels
49305 * True to suppress the display of field labels in this layout (defaults to false)
49307 hideLabels : false,
49310 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
49315 onRender : function(ct, position){
49316 if(this.el){ // from markup
49317 this.el = Roo.get(this.el);
49318 }else { // generate
49319 var cfg = this.getAutoCreate();
49320 this.el = ct.createChild(cfg, position);
49323 this.el.applyStyles(this.style);
49325 if(this.labelAlign){
49326 this.el.addClass('x-form-label-'+this.labelAlign);
49328 if(this.hideLabels){
49329 this.labelStyle = "display:none";
49330 this.elementStyle = "padding-left:0;";
49332 if(typeof this.labelWidth == 'number'){
49333 this.labelStyle = "width:"+this.labelWidth+"px;";
49334 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
49336 if(this.labelAlign == 'top'){
49337 this.labelStyle = "width:auto;";
49338 this.elementStyle = "padding-left:0;";
49341 var stack = this.stack;
49342 var slen = stack.length;
49344 if(!this.fieldTpl){
49345 var t = new Roo.Template(
49346 '<div class="x-form-item {5}">',
49347 '<label for="{0}" style="{2}">{1}{4}</label>',
49348 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49350 '</div><div class="x-form-clear-left"></div>'
49352 t.disableFormats = true;
49354 Roo.form.Layout.prototype.fieldTpl = t;
49356 for(var i = 0; i < slen; i++) {
49357 if(stack[i].isFormField){
49358 this.renderField(stack[i]);
49360 this.renderComponent(stack[i]);
49365 this.el.createChild({cls:'x-form-clear'});
49370 renderField : function(f){
49371 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
49374 f.labelStyle||this.labelStyle||'', //2
49375 this.elementStyle||'', //3
49376 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
49377 f.itemCls||this.itemCls||'' //5
49378 ], true).getPrevSibling());
49382 renderComponent : function(c){
49383 c.render(c.isLayout ? this.el : this.el.createChild());
49386 * Adds a object form elements (using the xtype property as the factory method.)
49387 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
49388 * @param {Object} config
49390 addxtype : function(o)
49392 // create the lement.
49393 o.form = this.form;
49394 var fe = Roo.factory(o, Roo.form);
49395 this.form.allItems.push(fe);
49396 this.stack.push(fe);
49398 if (fe.isFormField) {
49399 this.form.items.add(fe);
49407 * @class Roo.form.Column
49408 * @extends Roo.form.Layout
49409 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
49411 * @param {Object} config Configuration options
49413 Roo.form.Column = function(config){
49414 Roo.form.Column.superclass.constructor.call(this, config);
49417 Roo.extend(Roo.form.Column, Roo.form.Layout, {
49419 * @cfg {Number/String} width
49420 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49423 * @cfg {String/Object} autoCreate
49424 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
49428 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
49431 onRender : function(ct, position){
49432 Roo.form.Column.superclass.onRender.call(this, ct, position);
49434 this.el.setWidth(this.width);
49441 * @class Roo.form.Row
49442 * @extends Roo.form.Layout
49443 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
49445 * @param {Object} config Configuration options
49449 Roo.form.Row = function(config){
49450 Roo.form.Row.superclass.constructor.call(this, config);
49453 Roo.extend(Roo.form.Row, Roo.form.Layout, {
49455 * @cfg {Number/String} width
49456 * The fixed width of the column in pixels or CSS value (defaults to "auto")
49459 * @cfg {Number/String} height
49460 * The fixed height of the column in pixels or CSS value (defaults to "auto")
49462 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
49466 onRender : function(ct, position){
49467 //console.log('row render');
49469 var t = new Roo.Template(
49470 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
49471 '<label for="{0}" style="{2}">{1}{4}</label>',
49472 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
49476 t.disableFormats = true;
49478 Roo.form.Layout.prototype.rowTpl = t;
49480 this.fieldTpl = this.rowTpl;
49482 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
49483 var labelWidth = 100;
49485 if ((this.labelAlign != 'top')) {
49486 if (typeof this.labelWidth == 'number') {
49487 labelWidth = this.labelWidth
49489 this.padWidth = 20 + labelWidth;
49493 Roo.form.Column.superclass.onRender.call(this, ct, position);
49495 this.el.setWidth(this.width);
49498 this.el.setHeight(this.height);
49503 renderField : function(f){
49504 f.fieldEl = this.fieldTpl.append(this.el, [
49505 f.id, f.fieldLabel,
49506 f.labelStyle||this.labelStyle||'',
49507 this.elementStyle||'',
49508 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
49509 f.itemCls||this.itemCls||'',
49510 f.width ? f.width + this.padWidth : 160 + this.padWidth
49517 * @class Roo.form.FieldSet
49518 * @extends Roo.form.Layout
49519 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
49521 * @param {Object} config Configuration options
49523 Roo.form.FieldSet = function(config){
49524 Roo.form.FieldSet.superclass.constructor.call(this, config);
49527 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
49529 * @cfg {String} legend
49530 * The text to display as the legend for the FieldSet (defaults to '')
49533 * @cfg {String/Object} autoCreate
49534 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
49538 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
49541 onRender : function(ct, position){
49542 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
49544 this.setLegend(this.legend);
49549 setLegend : function(text){
49551 this.el.child('legend').update(text);
49556 * Ext JS Library 1.1.1
49557 * Copyright(c) 2006-2007, Ext JS, LLC.
49559 * Originally Released Under LGPL - original licence link has changed is not relivant.
49562 * <script type="text/javascript">
49565 * @class Roo.form.VTypes
49566 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
49569 Roo.form.VTypes = function(){
49570 // closure these in so they are only created once.
49571 var alpha = /^[a-zA-Z_]+$/;
49572 var alphanum = /^[a-zA-Z0-9_]+$/;
49573 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,24}$/;
49574 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
49576 // All these messages and functions are configurable
49579 * The function used to validate email addresses
49580 * @param {String} value The email address
49582 'email' : function(v){
49583 return email.test(v);
49586 * The error text to display when the email validation function returns false
49589 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
49591 * The keystroke filter mask to be applied on email input
49594 'emailMask' : /[a-z0-9_\.\-@]/i,
49597 * The function used to validate URLs
49598 * @param {String} value The URL
49600 'url' : function(v){
49601 return url.test(v);
49604 * The error text to display when the url validation function returns false
49607 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
49610 * The function used to validate alpha values
49611 * @param {String} value The value
49613 'alpha' : function(v){
49614 return alpha.test(v);
49617 * The error text to display when the alpha validation function returns false
49620 'alphaText' : 'This field should only contain letters and _',
49622 * The keystroke filter mask to be applied on alpha input
49625 'alphaMask' : /[a-z_]/i,
49628 * The function used to validate alphanumeric values
49629 * @param {String} value The value
49631 'alphanum' : function(v){
49632 return alphanum.test(v);
49635 * The error text to display when the alphanumeric validation function returns false
49638 'alphanumText' : 'This field should only contain letters, numbers and _',
49640 * The keystroke filter mask to be applied on alphanumeric input
49643 'alphanumMask' : /[a-z0-9_]/i
49645 }();//<script type="text/javascript">
49648 * @class Roo.form.FCKeditor
49649 * @extends Roo.form.TextArea
49650 * Wrapper around the FCKEditor http://www.fckeditor.net
49652 * Creates a new FCKeditor
49653 * @param {Object} config Configuration options
49655 Roo.form.FCKeditor = function(config){
49656 Roo.form.FCKeditor.superclass.constructor.call(this, config);
49659 * @event editorinit
49660 * Fired when the editor is initialized - you can add extra handlers here..
49661 * @param {FCKeditor} this
49662 * @param {Object} the FCK object.
49669 Roo.form.FCKeditor.editors = { };
49670 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
49672 //defaultAutoCreate : {
49673 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
49677 * @cfg {Object} fck options - see fck manual for details.
49682 * @cfg {Object} fck toolbar set (Basic or Default)
49684 toolbarSet : 'Basic',
49686 * @cfg {Object} fck BasePath
49688 basePath : '/fckeditor/',
49696 onRender : function(ct, position)
49699 this.defaultAutoCreate = {
49701 style:"width:300px;height:60px;",
49702 autocomplete: "new-password"
49705 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
49708 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
49709 if(this.preventScrollbars){
49710 this.el.setStyle("overflow", "hidden");
49712 this.el.setHeight(this.growMin);
49715 //console.log('onrender' + this.getId() );
49716 Roo.form.FCKeditor.editors[this.getId()] = this;
49719 this.replaceTextarea() ;
49723 getEditor : function() {
49724 return this.fckEditor;
49727 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
49728 * @param {Mixed} value The value to set
49732 setValue : function(value)
49734 //console.log('setValue: ' + value);
49736 if(typeof(value) == 'undefined') { // not sure why this is happending...
49739 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49741 //if(!this.el || !this.getEditor()) {
49742 // this.value = value;
49743 //this.setValue.defer(100,this,[value]);
49747 if(!this.getEditor()) {
49751 this.getEditor().SetData(value);
49758 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
49759 * @return {Mixed} value The field value
49761 getValue : function()
49764 if (this.frame && this.frame.dom.style.display == 'none') {
49765 return Roo.form.FCKeditor.superclass.getValue.call(this);
49768 if(!this.el || !this.getEditor()) {
49770 // this.getValue.defer(100,this);
49775 var value=this.getEditor().GetData();
49776 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
49777 return Roo.form.FCKeditor.superclass.getValue.call(this);
49783 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
49784 * @return {Mixed} value The field value
49786 getRawValue : function()
49788 if (this.frame && this.frame.dom.style.display == 'none') {
49789 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49792 if(!this.el || !this.getEditor()) {
49793 //this.getRawValue.defer(100,this);
49800 var value=this.getEditor().GetData();
49801 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
49802 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
49806 setSize : function(w,h) {
49810 //if (this.frame && this.frame.dom.style.display == 'none') {
49811 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49814 //if(!this.el || !this.getEditor()) {
49815 // this.setSize.defer(100,this, [w,h]);
49821 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
49823 this.frame.dom.setAttribute('width', w);
49824 this.frame.dom.setAttribute('height', h);
49825 this.frame.setSize(w,h);
49829 toggleSourceEdit : function(value) {
49833 this.el.dom.style.display = value ? '' : 'none';
49834 this.frame.dom.style.display = value ? 'none' : '';
49839 focus: function(tag)
49841 if (this.frame.dom.style.display == 'none') {
49842 return Roo.form.FCKeditor.superclass.focus.call(this);
49844 if(!this.el || !this.getEditor()) {
49845 this.focus.defer(100,this, [tag]);
49852 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
49853 this.getEditor().Focus();
49855 if (!this.getEditor().Selection.GetSelection()) {
49856 this.focus.defer(100,this, [tag]);
49861 var r = this.getEditor().EditorDocument.createRange();
49862 r.setStart(tgs[0],0);
49863 r.setEnd(tgs[0],0);
49864 this.getEditor().Selection.GetSelection().removeAllRanges();
49865 this.getEditor().Selection.GetSelection().addRange(r);
49866 this.getEditor().Focus();
49873 replaceTextarea : function()
49875 if ( document.getElementById( this.getId() + '___Frame' ) ) {
49878 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
49880 // We must check the elements firstly using the Id and then the name.
49881 var oTextarea = document.getElementById( this.getId() );
49883 var colElementsByName = document.getElementsByName( this.getId() ) ;
49885 oTextarea.style.display = 'none' ;
49887 if ( oTextarea.tabIndex ) {
49888 this.TabIndex = oTextarea.tabIndex ;
49891 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
49892 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
49893 this.frame = Roo.get(this.getId() + '___Frame')
49896 _getConfigHtml : function()
49900 for ( var o in this.fckconfig ) {
49901 sConfig += sConfig.length > 0 ? '&' : '';
49902 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
49905 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
49909 _getIFrameHtml : function()
49911 var sFile = 'fckeditor.html' ;
49912 /* no idea what this is about..
49915 if ( (/fcksource=true/i).test( window.top.location.search ) )
49916 sFile = 'fckeditor.original.html' ;
49921 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
49922 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
49925 var html = '<iframe id="' + this.getId() +
49926 '___Frame" src="' + sLink +
49927 '" width="' + this.width +
49928 '" height="' + this.height + '"' +
49929 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
49930 ' frameborder="0" scrolling="no"></iframe>' ;
49935 _insertHtmlBefore : function( html, element )
49937 if ( element.insertAdjacentHTML ) {
49939 element.insertAdjacentHTML( 'beforeBegin', html ) ;
49941 var oRange = document.createRange() ;
49942 oRange.setStartBefore( element ) ;
49943 var oFragment = oRange.createContextualFragment( html );
49944 element.parentNode.insertBefore( oFragment, element ) ;
49957 //Roo.reg('fckeditor', Roo.form.FCKeditor);
49959 function FCKeditor_OnComplete(editorInstance){
49960 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
49961 f.fckEditor = editorInstance;
49962 //console.log("loaded");
49963 f.fireEvent('editorinit', f, editorInstance);
49983 //<script type="text/javascript">
49985 * @class Roo.form.GridField
49986 * @extends Roo.form.Field
49987 * Embed a grid (or editable grid into a form)
49990 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
49992 * xgrid.store = Roo.data.Store
49993 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
49994 * xgrid.store.reader = Roo.data.JsonReader
49998 * Creates a new GridField
49999 * @param {Object} config Configuration options
50001 Roo.form.GridField = function(config){
50002 Roo.form.GridField.superclass.constructor.call(this, config);
50006 Roo.extend(Roo.form.GridField, Roo.form.Field, {
50008 * @cfg {Number} width - used to restrict width of grid..
50012 * @cfg {Number} height - used to restrict height of grid..
50016 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
50022 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50023 * {tag: "input", type: "checkbox", autocomplete: "off"})
50025 // defaultAutoCreate : { tag: 'div' },
50026 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'new-password'},
50028 * @cfg {String} addTitle Text to include for adding a title.
50032 onResize : function(){
50033 Roo.form.Field.superclass.onResize.apply(this, arguments);
50036 initEvents : function(){
50037 // Roo.form.Checkbox.superclass.initEvents.call(this);
50038 // has no events...
50043 getResizeEl : function(){
50047 getPositionEl : function(){
50052 onRender : function(ct, position){
50054 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
50055 var style = this.style;
50058 Roo.form.GridField.superclass.onRender.call(this, ct, position);
50059 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
50060 this.viewEl = this.wrap.createChild({ tag: 'div' });
50062 this.viewEl.applyStyles(style);
50065 this.viewEl.setWidth(this.width);
50068 this.viewEl.setHeight(this.height);
50070 //if(this.inputValue !== undefined){
50071 //this.setValue(this.value);
50074 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
50077 this.grid.render();
50078 this.grid.getDataSource().on('remove', this.refreshValue, this);
50079 this.grid.getDataSource().on('update', this.refreshValue, this);
50080 this.grid.on('afteredit', this.refreshValue, this);
50086 * Sets the value of the item.
50087 * @param {String} either an object or a string..
50089 setValue : function(v){
50091 v = v || []; // empty set..
50092 // this does not seem smart - it really only affects memoryproxy grids..
50093 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
50094 var ds = this.grid.getDataSource();
50095 // assumes a json reader..
50097 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
50098 ds.loadData( data);
50100 // clear selection so it does not get stale.
50101 if (this.grid.sm) {
50102 this.grid.sm.clearSelections();
50105 Roo.form.GridField.superclass.setValue.call(this, v);
50106 this.refreshValue();
50107 // should load data in the grid really....
50111 refreshValue: function() {
50113 this.grid.getDataSource().each(function(r) {
50116 this.el.dom.value = Roo.encode(val);
50124 * Ext JS Library 1.1.1
50125 * Copyright(c) 2006-2007, Ext JS, LLC.
50127 * Originally Released Under LGPL - original licence link has changed is not relivant.
50130 * <script type="text/javascript">
50133 * @class Roo.form.DisplayField
50134 * @extends Roo.form.Field
50135 * A generic Field to display non-editable data.
50136 * @cfg {Boolean} closable (true|false) default false
50138 * Creates a new Display Field item.
50139 * @param {Object} config Configuration options
50141 Roo.form.DisplayField = function(config){
50142 Roo.form.DisplayField.superclass.constructor.call(this, config);
50147 * Fires after the click the close btn
50148 * @param {Roo.form.DisplayField} this
50154 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
50155 inputType: 'hidden',
50161 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50163 focusClass : undefined,
50165 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50167 fieldClass: 'x-form-field',
50170 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
50172 valueRenderer: undefined,
50176 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50177 * {tag: "input", type: "checkbox", autocomplete: "off"})
50180 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
50184 onResize : function(){
50185 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
50189 initEvents : function(){
50190 // Roo.form.Checkbox.superclass.initEvents.call(this);
50191 // has no events...
50194 this.closeEl.on('click', this.onClose, this);
50200 getResizeEl : function(){
50204 getPositionEl : function(){
50209 onRender : function(ct, position){
50211 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
50212 //if(this.inputValue !== undefined){
50213 this.wrap = this.el.wrap();
50215 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
50218 this.closeEl = this.wrap.createChild({ tag: 'div', cls: 'x-dlg-close'});
50221 if (this.bodyStyle) {
50222 this.viewEl.applyStyles(this.bodyStyle);
50224 //this.viewEl.setStyle('padding', '2px');
50226 this.setValue(this.value);
50231 initValue : Roo.emptyFn,
50236 onClick : function(){
50241 * Sets the checked state of the checkbox.
50242 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
50244 setValue : function(v){
50246 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
50247 // this might be called before we have a dom element..
50248 if (!this.viewEl) {
50251 this.viewEl.dom.innerHTML = html;
50252 Roo.form.DisplayField.superclass.setValue.call(this, v);
50256 onClose : function(e)
50258 e.preventDefault();
50260 this.fireEvent('close', this);
50269 * @class Roo.form.DayPicker
50270 * @extends Roo.form.Field
50271 * A Day picker show [M] [T] [W] ....
50273 * Creates a new Day Picker
50274 * @param {Object} config Configuration options
50276 Roo.form.DayPicker= function(config){
50277 Roo.form.DayPicker.superclass.constructor.call(this, config);
50281 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
50283 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
50285 focusClass : undefined,
50287 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
50289 fieldClass: "x-form-field",
50292 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
50293 * {tag: "input", type: "checkbox", autocomplete: "off"})
50295 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "new-password"},
50298 actionMode : 'viewEl',
50302 inputType : 'hidden',
50305 inputElement: false, // real input element?
50306 basedOn: false, // ????
50308 isFormField: true, // not sure where this is needed!!!!
50310 onResize : function(){
50311 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
50312 if(!this.boxLabel){
50313 this.el.alignTo(this.wrap, 'c-c');
50317 initEvents : function(){
50318 Roo.form.Checkbox.superclass.initEvents.call(this);
50319 this.el.on("click", this.onClick, this);
50320 this.el.on("change", this.onClick, this);
50324 getResizeEl : function(){
50328 getPositionEl : function(){
50334 onRender : function(ct, position){
50335 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
50337 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
50339 var r1 = '<table><tr>';
50340 var r2 = '<tr class="x-form-daypick-icons">';
50341 for (var i=0; i < 7; i++) {
50342 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
50343 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
50346 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
50347 viewEl.select('img').on('click', this.onClick, this);
50348 this.viewEl = viewEl;
50351 // this will not work on Chrome!!!
50352 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
50353 this.el.on('propertychange', this.setFromHidden, this); //ie
50361 initValue : Roo.emptyFn,
50364 * Returns the checked state of the checkbox.
50365 * @return {Boolean} True if checked, else false
50367 getValue : function(){
50368 return this.el.dom.value;
50373 onClick : function(e){
50374 //this.setChecked(!this.checked);
50375 Roo.get(e.target).toggleClass('x-menu-item-checked');
50376 this.refreshValue();
50377 //if(this.el.dom.checked != this.checked){
50378 // this.setValue(this.el.dom.checked);
50383 refreshValue : function()
50386 this.viewEl.select('img',true).each(function(e,i,n) {
50387 val += e.is(".x-menu-item-checked") ? String(n) : '';
50389 this.setValue(val, true);
50393 * Sets the checked state of the checkbox.
50394 * On is always based on a string comparison between inputValue and the param.
50395 * @param {Boolean/String} value - the value to set
50396 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
50398 setValue : function(v,suppressEvent){
50399 if (!this.el.dom) {
50402 var old = this.el.dom.value ;
50403 this.el.dom.value = v;
50404 if (suppressEvent) {
50408 // update display..
50409 this.viewEl.select('img',true).each(function(e,i,n) {
50411 var on = e.is(".x-menu-item-checked");
50412 var newv = v.indexOf(String(n)) > -1;
50414 e.toggleClass('x-menu-item-checked');
50420 this.fireEvent('change', this, v, old);
50425 // handle setting of hidden value by some other method!!?!?
50426 setFromHidden: function()
50431 //console.log("SET FROM HIDDEN");
50432 //alert('setFrom hidden');
50433 this.setValue(this.el.dom.value);
50436 onDestroy : function()
50439 Roo.get(this.viewEl).remove();
50442 Roo.form.DayPicker.superclass.onDestroy.call(this);
50446 * RooJS Library 1.1.1
50447 * Copyright(c) 2008-2011 Alan Knowles
50454 * @class Roo.form.ComboCheck
50455 * @extends Roo.form.ComboBox
50456 * A combobox for multiple select items.
50458 * FIXME - could do with a reset button..
50461 * Create a new ComboCheck
50462 * @param {Object} config Configuration options
50464 Roo.form.ComboCheck = function(config){
50465 Roo.form.ComboCheck.superclass.constructor.call(this, config);
50466 // should verify some data...
50468 // hiddenName = required..
50469 // displayField = required
50470 // valudField == required
50471 var req= [ 'hiddenName', 'displayField', 'valueField' ];
50473 Roo.each(req, function(e) {
50474 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
50475 throw "Roo.form.ComboCheck : missing value for: " + e;
50482 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
50487 selectedClass: 'x-menu-item-checked',
50490 onRender : function(ct, position){
50496 var cls = 'x-combo-list';
50499 this.tpl = new Roo.Template({
50500 html : '<div class="'+cls+'-item x-menu-check-item">' +
50501 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
50502 '<span>{' + this.displayField + '}</span>' +
50509 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
50510 this.view.singleSelect = false;
50511 this.view.multiSelect = true;
50512 this.view.toggleSelect = true;
50513 this.pageTb.add(new Roo.Toolbar.Fill(), {
50516 handler: function()
50523 onViewOver : function(e, t){
50529 onViewClick : function(doFocus,index){
50533 select: function () {
50534 //Roo.log("SELECT CALLED");
50537 selectByValue : function(xv, scrollIntoView){
50538 var ar = this.getValueArray();
50541 Roo.each(ar, function(v) {
50542 if(v === undefined || v === null){
50545 var r = this.findRecord(this.valueField, v);
50547 sels.push(this.store.indexOf(r))
50551 this.view.select(sels);
50557 onSelect : function(record, index){
50558 // Roo.log("onselect Called");
50559 // this is only called by the clear button now..
50560 this.view.clearSelections();
50561 this.setValue('[]');
50562 if (this.value != this.valueBefore) {
50563 this.fireEvent('change', this, this.value, this.valueBefore);
50564 this.valueBefore = this.value;
50567 getValueArray : function()
50572 //Roo.log(this.value);
50573 if (typeof(this.value) == 'undefined') {
50576 var ar = Roo.decode(this.value);
50577 return ar instanceof Array ? ar : []; //?? valid?
50580 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
50585 expand : function ()
50588 Roo.form.ComboCheck.superclass.expand.call(this);
50589 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
50590 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
50595 collapse : function(){
50596 Roo.form.ComboCheck.superclass.collapse.call(this);
50597 var sl = this.view.getSelectedIndexes();
50598 var st = this.store;
50602 Roo.each(sl, function(i) {
50604 nv.push(r.get(this.valueField));
50606 this.setValue(Roo.encode(nv));
50607 if (this.value != this.valueBefore) {
50609 this.fireEvent('change', this, this.value, this.valueBefore);
50610 this.valueBefore = this.value;
50615 setValue : function(v){
50619 var vals = this.getValueArray();
50621 Roo.each(vals, function(k) {
50622 var r = this.findRecord(this.valueField, k);
50624 tv.push(r.data[this.displayField]);
50625 }else if(this.valueNotFoundText !== undefined){
50626 tv.push( this.valueNotFoundText );
50631 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
50632 this.hiddenField.value = v;
50638 * Ext JS Library 1.1.1
50639 * Copyright(c) 2006-2007, Ext JS, LLC.
50641 * Originally Released Under LGPL - original licence link has changed is not relivant.
50644 * <script type="text/javascript">
50648 * @class Roo.form.Signature
50649 * @extends Roo.form.Field
50653 * @param {Object} config Configuration options
50656 Roo.form.Signature = function(config){
50657 Roo.form.Signature.superclass.constructor.call(this, config);
50659 this.addEvents({// not in used??
50662 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
50663 * @param {Roo.form.Signature} combo This combo box
50668 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
50669 * @param {Roo.form.ComboBox} combo This combo box
50670 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
50676 Roo.extend(Roo.form.Signature, Roo.form.Field, {
50678 * @cfg {Object} labels Label to use when rendering a form.
50682 * confirm : "Confirm"
50687 confirm : "Confirm"
50690 * @cfg {Number} width The signature panel width (defaults to 300)
50694 * @cfg {Number} height The signature panel height (defaults to 100)
50698 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
50700 allowBlank : false,
50703 // {Object} signPanel The signature SVG panel element (defaults to {})
50705 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
50706 isMouseDown : false,
50707 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
50708 isConfirmed : false,
50709 // {String} signatureTmp SVG mapping string (defaults to empty string)
50713 defaultAutoCreate : { // modified by initCompnoent..
50719 onRender : function(ct, position){
50721 Roo.form.Signature.superclass.onRender.call(this, ct, position);
50723 this.wrap = this.el.wrap({
50724 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
50727 this.createToolbar(this);
50728 this.signPanel = this.wrap.createChild({
50730 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
50734 this.svgID = Roo.id();
50735 this.svgEl = this.signPanel.createChild({
50736 xmlns : 'http://www.w3.org/2000/svg',
50738 id : this.svgID + "-svg",
50740 height: this.height,
50741 viewBox: '0 0 '+this.width+' '+this.height,
50745 id: this.svgID + "-svg-r",
50747 height: this.height,
50752 id: this.svgID + "-svg-l",
50754 y1: (this.height*0.8), // start set the line in 80% of height
50755 x2: this.width, // end
50756 y2: (this.height*0.8), // end set the line in 80% of height
50758 'stroke-width': "1",
50759 'stroke-dasharray': "3",
50760 'shape-rendering': "crispEdges",
50761 'pointer-events': "none"
50765 id: this.svgID + "-svg-p",
50767 'stroke-width': "3",
50769 'pointer-events': 'none'
50774 this.svgBox = this.svgEl.dom.getScreenCTM();
50776 createSVG : function(){
50777 var svg = this.signPanel;
50778 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
50781 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
50782 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
50783 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
50784 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
50785 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
50786 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
50787 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
50790 isTouchEvent : function(e){
50791 return e.type.match(/^touch/);
50793 getCoords : function (e) {
50794 var pt = this.svgEl.dom.createSVGPoint();
50797 if (this.isTouchEvent(e)) {
50798 pt.x = e.targetTouches[0].clientX;
50799 pt.y = e.targetTouches[0].clientY;
50801 var a = this.svgEl.dom.getScreenCTM();
50802 var b = a.inverse();
50803 var mx = pt.matrixTransform(b);
50804 return mx.x + ',' + mx.y;
50806 //mouse event headler
50807 down : function (e) {
50808 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
50809 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
50811 this.isMouseDown = true;
50813 e.preventDefault();
50815 move : function (e) {
50816 if (this.isMouseDown) {
50817 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
50818 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
50821 e.preventDefault();
50823 up : function (e) {
50824 this.isMouseDown = false;
50825 var sp = this.signatureTmp.split(' ');
50828 if(!sp[sp.length-2].match(/^L/)){
50832 this.signatureTmp = sp.join(" ");
50835 if(this.getValue() != this.signatureTmp){
50836 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50837 this.isConfirmed = false;
50839 e.preventDefault();
50843 * Protected method that will not generally be called directly. It
50844 * is called when the editor creates its toolbar. Override this method if you need to
50845 * add custom toolbar buttons.
50846 * @param {HtmlEditor} editor
50848 createToolbar : function(editor){
50849 function btn(id, toggle, handler){
50850 var xid = fid + '-'+ id ;
50854 cls : 'x-btn-icon x-edit-'+id,
50855 enableToggle:toggle !== false,
50856 scope: editor, // was editor...
50857 handler:handler||editor.relayBtnCmd,
50858 clickEvent:'mousedown',
50859 tooltip: etb.buttonTips[id] || undefined, ///tips ???
50865 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
50869 cls : ' x-signature-btn x-signature-'+id,
50870 scope: editor, // was editor...
50871 handler: this.reset,
50872 clickEvent:'mousedown',
50873 text: this.labels.clear
50880 cls : ' x-signature-btn x-signature-'+id,
50881 scope: editor, // was editor...
50882 handler: this.confirmHandler,
50883 clickEvent:'mousedown',
50884 text: this.labels.confirm
50891 * when user is clicked confirm then show this image.....
50893 * @return {String} Image Data URI
50895 getImageDataURI : function(){
50896 var svg = this.svgEl.dom.parentNode.innerHTML;
50897 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
50902 * @return {Boolean} this.isConfirmed
50904 getConfirmed : function(){
50905 return this.isConfirmed;
50909 * @return {Number} this.width
50911 getWidth : function(){
50916 * @return {Number} this.height
50918 getHeight : function(){
50919 return this.height;
50922 getSignature : function(){
50923 return this.signatureTmp;
50926 reset : function(){
50927 this.signatureTmp = '';
50928 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50929 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
50930 this.isConfirmed = false;
50931 Roo.form.Signature.superclass.reset.call(this);
50933 setSignature : function(s){
50934 this.signatureTmp = s;
50935 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
50936 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
50938 this.isConfirmed = false;
50939 Roo.form.Signature.superclass.reset.call(this);
50942 // Roo.log(this.signPanel.dom.contentWindow.up())
50945 setConfirmed : function(){
50949 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
50952 confirmHandler : function(){
50953 if(!this.getSignature()){
50957 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
50958 this.setValue(this.getSignature());
50959 this.isConfirmed = true;
50961 this.fireEvent('confirm', this);
50964 // Subclasses should provide the validation implementation by overriding this
50965 validateValue : function(value){
50966 if(this.allowBlank){
50970 if(this.isConfirmed){
50977 * Ext JS Library 1.1.1
50978 * Copyright(c) 2006-2007, Ext JS, LLC.
50980 * Originally Released Under LGPL - original licence link has changed is not relivant.
50983 * <script type="text/javascript">
50988 * @class Roo.form.ComboBox
50989 * @extends Roo.form.TriggerField
50990 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
50992 * Create a new ComboBox.
50993 * @param {Object} config Configuration options
50995 Roo.form.Select = function(config){
50996 Roo.form.Select.superclass.constructor.call(this, config);
51000 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
51002 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
51005 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
51006 * rendering into an Roo.Editor, defaults to false)
51009 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
51010 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
51013 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
51016 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
51017 * the dropdown list (defaults to undefined, with no header element)
51021 * @cfg {String/Roo.Template} tpl The template to use to render the output
51025 defaultAutoCreate : {tag: "select" },
51027 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
51029 listWidth: undefined,
51031 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
51032 * mode = 'remote' or 'text' if mode = 'local')
51034 displayField: undefined,
51036 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
51037 * mode = 'remote' or 'value' if mode = 'local').
51038 * Note: use of a valueField requires the user make a selection
51039 * in order for a value to be mapped.
51041 valueField: undefined,
51045 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
51046 * field's data value (defaults to the underlying DOM element's name)
51048 hiddenName: undefined,
51050 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
51054 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
51056 selectedClass: 'x-combo-selected',
51058 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
51059 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
51060 * which displays a downward arrow icon).
51062 triggerClass : 'x-form-arrow-trigger',
51064 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
51068 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
51069 * anchor positions (defaults to 'tl-bl')
51071 listAlign: 'tl-bl?',
51073 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
51077 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
51078 * query specified by the allQuery config option (defaults to 'query')
51080 triggerAction: 'query',
51082 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
51083 * (defaults to 4, does not apply if editable = false)
51087 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
51088 * delay (typeAheadDelay) if it matches a known value (defaults to false)
51092 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
51093 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
51097 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
51098 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
51102 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
51103 * when editable = true (defaults to false)
51105 selectOnFocus:false,
51107 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
51109 queryParam: 'query',
51111 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
51112 * when mode = 'remote' (defaults to 'Loading...')
51114 loadingText: 'Loading...',
51116 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
51120 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
51124 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
51125 * traditional select (defaults to true)
51129 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
51133 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
51137 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
51138 * listWidth has a higher value)
51142 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
51143 * allow the user to set arbitrary text into the field (defaults to false)
51145 forceSelection:false,
51147 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
51148 * if typeAhead = true (defaults to 250)
51150 typeAheadDelay : 250,
51152 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
51153 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
51155 valueNotFoundText : undefined,
51158 * @cfg {String} defaultValue The value displayed after loading the store.
51163 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
51165 blockFocus : false,
51168 * @cfg {Boolean} disableClear Disable showing of clear button.
51170 disableClear : false,
51172 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
51174 alwaysQuery : false,
51180 // element that contains real text value.. (when hidden is used..)
51183 onRender : function(ct, position){
51184 Roo.form.Field.prototype.onRender.call(this, ct, position);
51187 this.store.on('beforeload', this.onBeforeLoad, this);
51188 this.store.on('load', this.onLoad, this);
51189 this.store.on('loadexception', this.onLoadException, this);
51190 this.store.load({});
51198 initEvents : function(){
51199 //Roo.form.ComboBox.superclass.initEvents.call(this);
51203 onDestroy : function(){
51206 this.store.un('beforeload', this.onBeforeLoad, this);
51207 this.store.un('load', this.onLoad, this);
51208 this.store.un('loadexception', this.onLoadException, this);
51210 //Roo.form.ComboBox.superclass.onDestroy.call(this);
51214 fireKey : function(e){
51215 if(e.isNavKeyPress() && !this.list.isVisible()){
51216 this.fireEvent("specialkey", this, e);
51221 onResize: function(w, h){
51229 * Allow or prevent the user from directly editing the field text. If false is passed,
51230 * the user will only be able to select from the items defined in the dropdown list. This method
51231 * is the runtime equivalent of setting the 'editable' config option at config time.
51232 * @param {Boolean} value True to allow the user to directly edit the field text
51234 setEditable : function(value){
51239 onBeforeLoad : function(){
51241 Roo.log("Select before load");
51244 this.innerList.update(this.loadingText ?
51245 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
51246 //this.restrictHeight();
51247 this.selectedIndex = -1;
51251 onLoad : function(){
51254 var dom = this.el.dom;
51255 dom.innerHTML = '';
51256 var od = dom.ownerDocument;
51258 if (this.emptyText) {
51259 var op = od.createElement('option');
51260 op.setAttribute('value', '');
51261 op.innerHTML = String.format('{0}', this.emptyText);
51262 dom.appendChild(op);
51264 if(this.store.getCount() > 0){
51266 var vf = this.valueField;
51267 var df = this.displayField;
51268 this.store.data.each(function(r) {
51269 // which colmsn to use... testing - cdoe / title..
51270 var op = od.createElement('option');
51271 op.setAttribute('value', r.data[vf]);
51272 op.innerHTML = String.format('{0}', r.data[df]);
51273 dom.appendChild(op);
51275 if (typeof(this.defaultValue != 'undefined')) {
51276 this.setValue(this.defaultValue);
51281 //this.onEmptyResults();
51286 onLoadException : function()
51288 dom.innerHTML = '';
51290 Roo.log("Select on load exception");
51294 Roo.log(this.store.reader.jsonData);
51295 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
51296 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
51302 onTypeAhead : function(){
51307 onSelect : function(record, index){
51308 Roo.log('on select?');
51310 if(this.fireEvent('beforeselect', this, record, index) !== false){
51311 this.setFromData(index > -1 ? record.data : false);
51313 this.fireEvent('select', this, record, index);
51318 * Returns the currently selected field value or empty string if no value is set.
51319 * @return {String} value The selected value
51321 getValue : function(){
51322 var dom = this.el.dom;
51323 this.value = dom.options[dom.selectedIndex].value;
51329 * Clears any text/value currently set in the field
51331 clearValue : function(){
51333 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
51338 * Sets the specified value into the field. If the value finds a match, the corresponding record text
51339 * will be displayed in the field. If the value does not match the data value of an existing item,
51340 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
51341 * Otherwise the field will be blank (although the value will still be set).
51342 * @param {String} value The value to match
51344 setValue : function(v){
51345 var d = this.el.dom;
51346 for (var i =0; i < d.options.length;i++) {
51347 if (v == d.options[i].value) {
51348 d.selectedIndex = i;
51356 * @property {Object} the last set data for the element
51361 * Sets the value of the field based on a object which is related to the record format for the store.
51362 * @param {Object} value the value to set as. or false on reset?
51364 setFromData : function(o){
51365 Roo.log('setfrom data?');
51371 reset : function(){
51375 findRecord : function(prop, value){
51380 if(this.store.getCount() > 0){
51381 this.store.each(function(r){
51382 if(r.data[prop] == value){
51392 getName: function()
51394 // returns hidden if it's set..
51395 if (!this.rendered) {return ''};
51396 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
51404 onEmptyResults : function(){
51405 Roo.log('empty results');
51410 * Returns true if the dropdown list is expanded, else false.
51412 isExpanded : function(){
51417 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
51418 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51419 * @param {String} value The data value of the item to select
51420 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51421 * selected item if it is not currently in view (defaults to true)
51422 * @return {Boolean} True if the value matched an item in the list, else false
51424 selectByValue : function(v, scrollIntoView){
51425 Roo.log('select By Value');
51428 if(v !== undefined && v !== null){
51429 var r = this.findRecord(this.valueField || this.displayField, v);
51431 this.select(this.store.indexOf(r), scrollIntoView);
51439 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
51440 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
51441 * @param {Number} index The zero-based index of the list item to select
51442 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
51443 * selected item if it is not currently in view (defaults to true)
51445 select : function(index, scrollIntoView){
51446 Roo.log('select ');
51449 this.selectedIndex = index;
51450 this.view.select(index);
51451 if(scrollIntoView !== false){
51452 var el = this.view.getNode(index);
51454 this.innerList.scrollChildIntoView(el, false);
51462 validateBlur : function(){
51469 initQuery : function(){
51470 this.doQuery(this.getRawValue());
51474 doForce : function(){
51475 if(this.el.dom.value.length > 0){
51476 this.el.dom.value =
51477 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
51483 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
51484 * query allowing the query action to be canceled if needed.
51485 * @param {String} query The SQL query to execute
51486 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
51487 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
51488 * saved in the current store (defaults to false)
51490 doQuery : function(q, forceAll){
51492 Roo.log('doQuery?');
51493 if(q === undefined || q === null){
51498 forceAll: forceAll,
51502 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
51506 forceAll = qe.forceAll;
51507 if(forceAll === true || (q.length >= this.minChars)){
51508 if(this.lastQuery != q || this.alwaysQuery){
51509 this.lastQuery = q;
51510 if(this.mode == 'local'){
51511 this.selectedIndex = -1;
51513 this.store.clearFilter();
51515 this.store.filter(this.displayField, q);
51519 this.store.baseParams[this.queryParam] = q;
51521 params: this.getParams(q)
51526 this.selectedIndex = -1;
51533 getParams : function(q){
51535 //p[this.queryParam] = q;
51538 p.limit = this.pageSize;
51544 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
51546 collapse : function(){
51551 collapseIf : function(e){
51556 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
51558 expand : function(){
51566 * @cfg {Boolean} grow
51570 * @cfg {Number} growMin
51574 * @cfg {Number} growMax
51582 setWidth : function()
51586 getResizeEl : function(){
51589 });//<script type="text/javasscript">
51593 * @class Roo.DDView
51594 * A DnD enabled version of Roo.View.
51595 * @param {Element/String} container The Element in which to create the View.
51596 * @param {String} tpl The template string used to create the markup for each element of the View
51597 * @param {Object} config The configuration properties. These include all the config options of
51598 * {@link Roo.View} plus some specific to this class.<br>
51600 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
51601 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
51603 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
51604 .x-view-drag-insert-above {
51605 border-top:1px dotted #3366cc;
51607 .x-view-drag-insert-below {
51608 border-bottom:1px dotted #3366cc;
51614 Roo.DDView = function(container, tpl, config) {
51615 Roo.DDView.superclass.constructor.apply(this, arguments);
51616 this.getEl().setStyle("outline", "0px none");
51617 this.getEl().unselectable();
51618 if (this.dragGroup) {
51619 this.setDraggable(this.dragGroup.split(","));
51621 if (this.dropGroup) {
51622 this.setDroppable(this.dropGroup.split(","));
51624 if (this.deletable) {
51625 this.setDeletable();
51627 this.isDirtyFlag = false;
51633 Roo.extend(Roo.DDView, Roo.View, {
51634 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
51635 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
51636 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
51637 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
51641 reset: Roo.emptyFn,
51643 clearInvalid: Roo.form.Field.prototype.clearInvalid,
51645 validate: function() {
51649 destroy: function() {
51650 this.purgeListeners();
51651 this.getEl.removeAllListeners();
51652 this.getEl().remove();
51653 if (this.dragZone) {
51654 if (this.dragZone.destroy) {
51655 this.dragZone.destroy();
51658 if (this.dropZone) {
51659 if (this.dropZone.destroy) {
51660 this.dropZone.destroy();
51665 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
51666 getName: function() {
51670 /** Loads the View from a JSON string representing the Records to put into the Store. */
51671 setValue: function(v) {
51673 throw "DDView.setValue(). DDView must be constructed with a valid Store";
51676 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
51677 this.store.proxy = new Roo.data.MemoryProxy(data);
51681 /** @return {String} a parenthesised list of the ids of the Records in the View. */
51682 getValue: function() {
51684 this.store.each(function(rec) {
51685 result += rec.id + ',';
51687 return result.substr(0, result.length - 1) + ')';
51690 getIds: function() {
51691 var i = 0, result = new Array(this.store.getCount());
51692 this.store.each(function(rec) {
51693 result[i++] = rec.id;
51698 isDirty: function() {
51699 return this.isDirtyFlag;
51703 * Part of the Roo.dd.DropZone interface. If no target node is found, the
51704 * whole Element becomes the target, and this causes the drop gesture to append.
51706 getTargetFromEvent : function(e) {
51707 var target = e.getTarget();
51708 while ((target !== null) && (target.parentNode != this.el.dom)) {
51709 target = target.parentNode;
51712 target = this.el.dom.lastChild || this.el.dom;
51718 * Create the drag data which consists of an object which has the property "ddel" as
51719 * the drag proxy element.
51721 getDragData : function(e) {
51722 var target = this.findItemFromChild(e.getTarget());
51724 this.handleSelection(e);
51725 var selNodes = this.getSelectedNodes();
51728 copy: this.copy || (this.allowCopy && e.ctrlKey),
51732 var selectedIndices = this.getSelectedIndexes();
51733 for (var i = 0; i < selectedIndices.length; i++) {
51734 dragData.records.push(this.store.getAt(selectedIndices[i]));
51736 if (selNodes.length == 1) {
51737 dragData.ddel = target.cloneNode(true); // the div element
51739 var div = document.createElement('div'); // create the multi element drag "ghost"
51740 div.className = 'multi-proxy';
51741 for (var i = 0, len = selNodes.length; i < len; i++) {
51742 div.appendChild(selNodes[i].cloneNode(true));
51744 dragData.ddel = div;
51746 //console.log(dragData)
51747 //console.log(dragData.ddel.innerHTML)
51750 //console.log('nodragData')
51754 /** Specify to which ddGroup items in this DDView may be dragged. */
51755 setDraggable: function(ddGroup) {
51756 if (ddGroup instanceof Array) {
51757 Roo.each(ddGroup, this.setDraggable, this);
51760 if (this.dragZone) {
51761 this.dragZone.addToGroup(ddGroup);
51763 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
51764 containerScroll: true,
51768 // Draggability implies selection. DragZone's mousedown selects the element.
51769 if (!this.multiSelect) { this.singleSelect = true; }
51771 // Wire the DragZone's handlers up to methods in *this*
51772 this.dragZone.getDragData = this.getDragData.createDelegate(this);
51776 /** Specify from which ddGroup this DDView accepts drops. */
51777 setDroppable: function(ddGroup) {
51778 if (ddGroup instanceof Array) {
51779 Roo.each(ddGroup, this.setDroppable, this);
51782 if (this.dropZone) {
51783 this.dropZone.addToGroup(ddGroup);
51785 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
51786 containerScroll: true,
51790 // Wire the DropZone's handlers up to methods in *this*
51791 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
51792 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
51793 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
51794 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
51795 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
51799 /** Decide whether to drop above or below a View node. */
51800 getDropPoint : function(e, n, dd){
51801 if (n == this.el.dom) { return "above"; }
51802 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
51803 var c = t + (b - t) / 2;
51804 var y = Roo.lib.Event.getPageY(e);
51812 onNodeEnter : function(n, dd, e, data){
51816 onNodeOver : function(n, dd, e, data){
51817 var pt = this.getDropPoint(e, n, dd);
51818 // set the insert point style on the target node
51819 var dragElClass = this.dropNotAllowed;
51822 if (pt == "above"){
51823 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
51824 targetElClass = "x-view-drag-insert-above";
51826 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
51827 targetElClass = "x-view-drag-insert-below";
51829 if (this.lastInsertClass != targetElClass){
51830 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
51831 this.lastInsertClass = targetElClass;
51834 return dragElClass;
51837 onNodeOut : function(n, dd, e, data){
51838 this.removeDropIndicators(n);
51841 onNodeDrop : function(n, dd, e, data){
51842 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
51845 var pt = this.getDropPoint(e, n, dd);
51846 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
51847 if (pt == "below") { insertAt++; }
51848 for (var i = 0; i < data.records.length; i++) {
51849 var r = data.records[i];
51850 var dup = this.store.getById(r.id);
51851 if (dup && (dd != this.dragZone)) {
51852 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
51855 this.store.insert(insertAt++, r.copy());
51857 data.source.isDirtyFlag = true;
51859 this.store.insert(insertAt++, r);
51861 this.isDirtyFlag = true;
51864 this.dragZone.cachedTarget = null;
51868 removeDropIndicators : function(n){
51870 Roo.fly(n).removeClass([
51871 "x-view-drag-insert-above",
51872 "x-view-drag-insert-below"]);
51873 this.lastInsertClass = "_noclass";
51878 * Utility method. Add a delete option to the DDView's context menu.
51879 * @param {String} imageUrl The URL of the "delete" icon image.
51881 setDeletable: function(imageUrl) {
51882 if (!this.singleSelect && !this.multiSelect) {
51883 this.singleSelect = true;
51885 var c = this.getContextMenu();
51886 this.contextMenu.on("itemclick", function(item) {
51889 this.remove(this.getSelectedIndexes());
51893 this.contextMenu.add({
51900 /** Return the context menu for this DDView. */
51901 getContextMenu: function() {
51902 if (!this.contextMenu) {
51903 // Create the View's context menu
51904 this.contextMenu = new Roo.menu.Menu({
51905 id: this.id + "-contextmenu"
51907 this.el.on("contextmenu", this.showContextMenu, this);
51909 return this.contextMenu;
51912 disableContextMenu: function() {
51913 if (this.contextMenu) {
51914 this.el.un("contextmenu", this.showContextMenu, this);
51918 showContextMenu: function(e, item) {
51919 item = this.findItemFromChild(e.getTarget());
51922 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
51923 this.contextMenu.showAt(e.getXY());
51928 * Remove {@link Roo.data.Record}s at the specified indices.
51929 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
51931 remove: function(selectedIndices) {
51932 selectedIndices = [].concat(selectedIndices);
51933 for (var i = 0; i < selectedIndices.length; i++) {
51934 var rec = this.store.getAt(selectedIndices[i]);
51935 this.store.remove(rec);
51940 * Double click fires the event, but also, if this is draggable, and there is only one other
51941 * related DropZone, it transfers the selected node.
51943 onDblClick : function(e){
51944 var item = this.findItemFromChild(e.getTarget());
51946 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
51949 if (this.dragGroup) {
51950 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
51951 while (targets.indexOf(this.dropZone) > -1) {
51952 targets.remove(this.dropZone);
51954 if (targets.length == 1) {
51955 this.dragZone.cachedTarget = null;
51956 var el = Roo.get(targets[0].getEl());
51957 var box = el.getBox(true);
51958 targets[0].onNodeDrop(el.dom, {
51960 xy: [box.x, box.y + box.height - 1]
51961 }, null, this.getDragData(e));
51967 handleSelection: function(e) {
51968 this.dragZone.cachedTarget = null;
51969 var item = this.findItemFromChild(e.getTarget());
51971 this.clearSelections(true);
51974 if (item && (this.multiSelect || this.singleSelect)){
51975 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
51976 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
51977 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
51978 this.unselect(item);
51980 this.select(item, this.multiSelect && e.ctrlKey);
51981 this.lastSelection = item;
51986 onItemClick : function(item, index, e){
51987 if(this.fireEvent("beforeclick", this, index, item, e) === false){
51993 unselect : function(nodeInfo, suppressEvent){
51994 var node = this.getNode(nodeInfo);
51995 if(node && this.isSelected(node)){
51996 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
51997 Roo.fly(node).removeClass(this.selectedClass);
51998 this.selections.remove(node);
51999 if(!suppressEvent){
52000 this.fireEvent("selectionchange", this, this.selections);
52008 * Ext JS Library 1.1.1
52009 * Copyright(c) 2006-2007, Ext JS, LLC.
52011 * Originally Released Under LGPL - original licence link has changed is not relivant.
52014 * <script type="text/javascript">
52018 * @class Roo.LayoutManager
52019 * @extends Roo.util.Observable
52020 * Base class for layout managers.
52022 Roo.LayoutManager = function(container, config){
52023 Roo.LayoutManager.superclass.constructor.call(this);
52024 this.el = Roo.get(container);
52025 // ie scrollbar fix
52026 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
52027 document.body.scroll = "no";
52028 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
52029 this.el.position('relative');
52031 this.id = this.el.id;
52032 this.el.addClass("x-layout-container");
52033 /** false to disable window resize monitoring @type Boolean */
52034 this.monitorWindowResize = true;
52039 * Fires when a layout is performed.
52040 * @param {Roo.LayoutManager} this
52044 * @event regionresized
52045 * Fires when the user resizes a region.
52046 * @param {Roo.LayoutRegion} region The resized region
52047 * @param {Number} newSize The new size (width for east/west, height for north/south)
52049 "regionresized" : true,
52051 * @event regioncollapsed
52052 * Fires when a region is collapsed.
52053 * @param {Roo.LayoutRegion} region The collapsed region
52055 "regioncollapsed" : true,
52057 * @event regionexpanded
52058 * Fires when a region is expanded.
52059 * @param {Roo.LayoutRegion} region The expanded region
52061 "regionexpanded" : true
52063 this.updating = false;
52064 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
52067 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
52069 * Returns true if this layout is currently being updated
52070 * @return {Boolean}
52072 isUpdating : function(){
52073 return this.updating;
52077 * Suspend the LayoutManager from doing auto-layouts while
52078 * making multiple add or remove calls
52080 beginUpdate : function(){
52081 this.updating = true;
52085 * Restore auto-layouts and optionally disable the manager from performing a layout
52086 * @param {Boolean} noLayout true to disable a layout update
52088 endUpdate : function(noLayout){
52089 this.updating = false;
52095 layout: function(){
52099 onRegionResized : function(region, newSize){
52100 this.fireEvent("regionresized", region, newSize);
52104 onRegionCollapsed : function(region){
52105 this.fireEvent("regioncollapsed", region);
52108 onRegionExpanded : function(region){
52109 this.fireEvent("regionexpanded", region);
52113 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
52114 * performs box-model adjustments.
52115 * @return {Object} The size as an object {width: (the width), height: (the height)}
52117 getViewSize : function(){
52119 if(this.el.dom != document.body){
52120 size = this.el.getSize();
52122 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
52124 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
52125 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
52130 * Returns the Element this layout is bound to.
52131 * @return {Roo.Element}
52133 getEl : function(){
52138 * Returns the specified region.
52139 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
52140 * @return {Roo.LayoutRegion}
52142 getRegion : function(target){
52143 return this.regions[target.toLowerCase()];
52146 onWindowResize : function(){
52147 if(this.monitorWindowResize){
52153 * Ext JS Library 1.1.1
52154 * Copyright(c) 2006-2007, Ext JS, LLC.
52156 * Originally Released Under LGPL - original licence link has changed is not relivant.
52159 * <script type="text/javascript">
52162 * @class Roo.BorderLayout
52163 * @extends Roo.LayoutManager
52164 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
52165 * please see: <br><br>
52166 * <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>
52167 * <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>
52170 var layout = new Roo.BorderLayout(document.body, {
52204 preferredTabWidth: 150
52209 var CP = Roo.ContentPanel;
52211 layout.beginUpdate();
52212 layout.add("north", new CP("north", "North"));
52213 layout.add("south", new CP("south", {title: "South", closable: true}));
52214 layout.add("west", new CP("west", {title: "West"}));
52215 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
52216 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
52217 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
52218 layout.getRegion("center").showPanel("center1");
52219 layout.endUpdate();
52222 <b>The container the layout is rendered into can be either the body element or any other element.
52223 If it is not the body element, the container needs to either be an absolute positioned element,
52224 or you will need to add "position:relative" to the css of the container. You will also need to specify
52225 the container size if it is not the body element.</b>
52228 * Create a new BorderLayout
52229 * @param {String/HTMLElement/Element} container The container this layout is bound to
52230 * @param {Object} config Configuration options
52232 Roo.BorderLayout = function(container, config){
52233 config = config || {};
52234 Roo.BorderLayout.superclass.constructor.call(this, container, config);
52235 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
52236 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
52237 var target = this.factory.validRegions[i];
52238 if(config[target]){
52239 this.addRegion(target, config[target]);
52244 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
52246 * Creates and adds a new region if it doesn't already exist.
52247 * @param {String} target The target region key (north, south, east, west or center).
52248 * @param {Object} config The regions config object
52249 * @return {BorderLayoutRegion} The new region
52251 addRegion : function(target, config){
52252 if(!this.regions[target]){
52253 var r = this.factory.create(target, this, config);
52254 this.bindRegion(target, r);
52256 return this.regions[target];
52260 bindRegion : function(name, r){
52261 this.regions[name] = r;
52262 r.on("visibilitychange", this.layout, this);
52263 r.on("paneladded", this.layout, this);
52264 r.on("panelremoved", this.layout, this);
52265 r.on("invalidated", this.layout, this);
52266 r.on("resized", this.onRegionResized, this);
52267 r.on("collapsed", this.onRegionCollapsed, this);
52268 r.on("expanded", this.onRegionExpanded, this);
52272 * Performs a layout update.
52274 layout : function(){
52275 if(this.updating) {
52278 var size = this.getViewSize();
52279 var w = size.width;
52280 var h = size.height;
52285 //var x = 0, y = 0;
52287 var rs = this.regions;
52288 var north = rs["north"];
52289 var south = rs["south"];
52290 var west = rs["west"];
52291 var east = rs["east"];
52292 var center = rs["center"];
52293 //if(this.hideOnLayout){ // not supported anymore
52294 //c.el.setStyle("display", "none");
52296 if(north && north.isVisible()){
52297 var b = north.getBox();
52298 var m = north.getMargins();
52299 b.width = w - (m.left+m.right);
52302 centerY = b.height + b.y + m.bottom;
52303 centerH -= centerY;
52304 north.updateBox(this.safeBox(b));
52306 if(south && south.isVisible()){
52307 var b = south.getBox();
52308 var m = south.getMargins();
52309 b.width = w - (m.left+m.right);
52311 var totalHeight = (b.height + m.top + m.bottom);
52312 b.y = h - totalHeight + m.top;
52313 centerH -= totalHeight;
52314 south.updateBox(this.safeBox(b));
52316 if(west && west.isVisible()){
52317 var b = west.getBox();
52318 var m = west.getMargins();
52319 b.height = centerH - (m.top+m.bottom);
52321 b.y = centerY + m.top;
52322 var totalWidth = (b.width + m.left + m.right);
52323 centerX += totalWidth;
52324 centerW -= totalWidth;
52325 west.updateBox(this.safeBox(b));
52327 if(east && east.isVisible()){
52328 var b = east.getBox();
52329 var m = east.getMargins();
52330 b.height = centerH - (m.top+m.bottom);
52331 var totalWidth = (b.width + m.left + m.right);
52332 b.x = w - totalWidth + m.left;
52333 b.y = centerY + m.top;
52334 centerW -= totalWidth;
52335 east.updateBox(this.safeBox(b));
52338 var m = center.getMargins();
52340 x: centerX + m.left,
52341 y: centerY + m.top,
52342 width: centerW - (m.left+m.right),
52343 height: centerH - (m.top+m.bottom)
52345 //if(this.hideOnLayout){
52346 //center.el.setStyle("display", "block");
52348 center.updateBox(this.safeBox(centerBox));
52351 this.fireEvent("layout", this);
52355 safeBox : function(box){
52356 box.width = Math.max(0, box.width);
52357 box.height = Math.max(0, box.height);
52362 * Adds a ContentPanel (or subclass) to this layout.
52363 * @param {String} target The target region key (north, south, east, west or center).
52364 * @param {Roo.ContentPanel} panel The panel to add
52365 * @return {Roo.ContentPanel} The added panel
52367 add : function(target, panel){
52369 target = target.toLowerCase();
52370 return this.regions[target].add(panel);
52374 * Remove a ContentPanel (or subclass) to this layout.
52375 * @param {String} target The target region key (north, south, east, west or center).
52376 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
52377 * @return {Roo.ContentPanel} The removed panel
52379 remove : function(target, panel){
52380 target = target.toLowerCase();
52381 return this.regions[target].remove(panel);
52385 * Searches all regions for a panel with the specified id
52386 * @param {String} panelId
52387 * @return {Roo.ContentPanel} The panel or null if it wasn't found
52389 findPanel : function(panelId){
52390 var rs = this.regions;
52391 for(var target in rs){
52392 if(typeof rs[target] != "function"){
52393 var p = rs[target].getPanel(panelId);
52403 * Searches all regions for a panel with the specified id and activates (shows) it.
52404 * @param {String/ContentPanel} panelId The panels id or the panel itself
52405 * @return {Roo.ContentPanel} The shown panel or null
52407 showPanel : function(panelId) {
52408 var rs = this.regions;
52409 for(var target in rs){
52410 var r = rs[target];
52411 if(typeof r != "function"){
52412 if(r.hasPanel(panelId)){
52413 return r.showPanel(panelId);
52421 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
52422 * @param {Roo.state.Provider} provider (optional) An alternate state provider
52424 restoreState : function(provider){
52426 provider = Roo.state.Manager;
52428 var sm = new Roo.LayoutStateManager();
52429 sm.init(this, provider);
52433 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
52434 * object should contain properties for each region to add ContentPanels to, and each property's value should be
52435 * a valid ContentPanel config object. Example:
52437 // Create the main layout
52438 var layout = new Roo.BorderLayout('main-ct', {
52449 // Create and add multiple ContentPanels at once via configs
52452 id: 'source-files',
52454 title:'Ext Source Files',
52467 * @param {Object} regions An object containing ContentPanel configs by region name
52469 batchAdd : function(regions){
52470 this.beginUpdate();
52471 for(var rname in regions){
52472 var lr = this.regions[rname];
52474 this.addTypedPanels(lr, regions[rname]);
52481 addTypedPanels : function(lr, ps){
52482 if(typeof ps == 'string'){
52483 lr.add(new Roo.ContentPanel(ps));
52485 else if(ps instanceof Array){
52486 for(var i =0, len = ps.length; i < len; i++){
52487 this.addTypedPanels(lr, ps[i]);
52490 else if(!ps.events){ // raw config?
52492 delete ps.el; // prevent conflict
52493 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
52495 else { // panel object assumed!
52500 * Adds a xtype elements to the layout.
52504 xtype : 'ContentPanel',
52511 xtype : 'NestedLayoutPanel',
52517 items : [ ... list of content panels or nested layout panels.. ]
52521 * @param {Object} cfg Xtype definition of item to add.
52523 addxtype : function(cfg)
52525 // basically accepts a pannel...
52526 // can accept a layout region..!?!?
52527 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
52529 if (!cfg.xtype.match(/Panel$/)) {
52534 if (typeof(cfg.region) == 'undefined') {
52535 Roo.log("Failed to add Panel, region was not set");
52539 var region = cfg.region;
52545 xitems = cfg.items;
52552 case 'ContentPanel': // ContentPanel (el, cfg)
52553 case 'ScrollPanel': // ContentPanel (el, cfg)
52555 if(cfg.autoCreate) {
52556 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52558 var el = this.el.createChild();
52559 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
52562 this.add(region, ret);
52566 case 'TreePanel': // our new panel!
52567 cfg.el = this.el.createChild();
52568 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52569 this.add(region, ret);
52572 case 'NestedLayoutPanel':
52573 // create a new Layout (which is a Border Layout...
52574 var el = this.el.createChild();
52575 var clayout = cfg.layout;
52577 clayout.items = clayout.items || [];
52578 // replace this exitems with the clayout ones..
52579 xitems = clayout.items;
52582 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
52583 cfg.background = false;
52585 var layout = new Roo.BorderLayout(el, clayout);
52587 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
52588 //console.log('adding nested layout panel ' + cfg.toSource());
52589 this.add(region, ret);
52590 nb = {}; /// find first...
52595 // needs grid and region
52597 //var el = this.getRegion(region).el.createChild();
52598 var el = this.el.createChild();
52599 // create the grid first...
52601 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
52603 if (region == 'center' && this.active ) {
52604 cfg.background = false;
52606 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
52608 this.add(region, ret);
52609 if (cfg.background) {
52610 ret.on('activate', function(gp) {
52611 if (!gp.grid.rendered) {
52626 if (typeof(Roo[cfg.xtype]) != 'undefined') {
52628 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
52629 this.add(region, ret);
52632 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
52636 // GridPanel (grid, cfg)
52639 this.beginUpdate();
52643 Roo.each(xitems, function(i) {
52644 region = nb && i.region ? i.region : false;
52646 var add = ret.addxtype(i);
52649 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
52650 if (!i.background) {
52651 abn[region] = nb[region] ;
52658 // make the last non-background panel active..
52659 //if (nb) { Roo.log(abn); }
52662 for(var r in abn) {
52663 region = this.getRegion(r);
52665 // tried using nb[r], but it does not work..
52667 region.showPanel(abn[r]);
52678 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
52679 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
52680 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
52681 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
52684 var CP = Roo.ContentPanel;
52686 var layout = Roo.BorderLayout.create({
52690 panels: [new CP("north", "North")]
52699 panels: [new CP("west", {title: "West"})]
52708 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
52717 panels: [new CP("south", {title: "South", closable: true})]
52724 preferredTabWidth: 150,
52726 new CP("center1", {title: "Close Me", closable: true}),
52727 new CP("center2", {title: "Center Panel", closable: false})
52732 layout.getRegion("center").showPanel("center1");
52737 Roo.BorderLayout.create = function(config, targetEl){
52738 var layout = new Roo.BorderLayout(targetEl || document.body, config);
52739 layout.beginUpdate();
52740 var regions = Roo.BorderLayout.RegionFactory.validRegions;
52741 for(var j = 0, jlen = regions.length; j < jlen; j++){
52742 var lr = regions[j];
52743 if(layout.regions[lr] && config[lr].panels){
52744 var r = layout.regions[lr];
52745 var ps = config[lr].panels;
52746 layout.addTypedPanels(r, ps);
52749 layout.endUpdate();
52754 Roo.BorderLayout.RegionFactory = {
52756 validRegions : ["north","south","east","west","center"],
52759 create : function(target, mgr, config){
52760 target = target.toLowerCase();
52761 if(config.lightweight || config.basic){
52762 return new Roo.BasicLayoutRegion(mgr, config, target);
52766 return new Roo.NorthLayoutRegion(mgr, config);
52768 return new Roo.SouthLayoutRegion(mgr, config);
52770 return new Roo.EastLayoutRegion(mgr, config);
52772 return new Roo.WestLayoutRegion(mgr, config);
52774 return new Roo.CenterLayoutRegion(mgr, config);
52776 throw 'Layout region "'+target+'" not supported.';
52780 * Ext JS Library 1.1.1
52781 * Copyright(c) 2006-2007, Ext JS, LLC.
52783 * Originally Released Under LGPL - original licence link has changed is not relivant.
52786 * <script type="text/javascript">
52790 * @class Roo.BasicLayoutRegion
52791 * @extends Roo.util.Observable
52792 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
52793 * and does not have a titlebar, tabs or any other features. All it does is size and position
52794 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
52796 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
52798 this.position = pos;
52801 * @scope Roo.BasicLayoutRegion
52805 * @event beforeremove
52806 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
52807 * @param {Roo.LayoutRegion} this
52808 * @param {Roo.ContentPanel} panel The panel
52809 * @param {Object} e The cancel event object
52811 "beforeremove" : true,
52813 * @event invalidated
52814 * Fires when the layout for this region is changed.
52815 * @param {Roo.LayoutRegion} this
52817 "invalidated" : true,
52819 * @event visibilitychange
52820 * Fires when this region is shown or hidden
52821 * @param {Roo.LayoutRegion} this
52822 * @param {Boolean} visibility true or false
52824 "visibilitychange" : true,
52826 * @event paneladded
52827 * Fires when a panel is added.
52828 * @param {Roo.LayoutRegion} this
52829 * @param {Roo.ContentPanel} panel The panel
52831 "paneladded" : true,
52833 * @event panelremoved
52834 * Fires when a panel is removed.
52835 * @param {Roo.LayoutRegion} this
52836 * @param {Roo.ContentPanel} panel The panel
52838 "panelremoved" : true,
52840 * @event beforecollapse
52841 * Fires when this region before collapse.
52842 * @param {Roo.LayoutRegion} this
52844 "beforecollapse" : true,
52847 * Fires when this region is collapsed.
52848 * @param {Roo.LayoutRegion} this
52850 "collapsed" : true,
52853 * Fires when this region is expanded.
52854 * @param {Roo.LayoutRegion} this
52859 * Fires when this region is slid into view.
52860 * @param {Roo.LayoutRegion} this
52862 "slideshow" : true,
52865 * Fires when this region slides out of view.
52866 * @param {Roo.LayoutRegion} this
52868 "slidehide" : true,
52870 * @event panelactivated
52871 * Fires when a panel is activated.
52872 * @param {Roo.LayoutRegion} this
52873 * @param {Roo.ContentPanel} panel The activated panel
52875 "panelactivated" : true,
52878 * Fires when the user resizes this region.
52879 * @param {Roo.LayoutRegion} this
52880 * @param {Number} newSize The new size (width for east/west, height for north/south)
52884 /** A collection of panels in this region. @type Roo.util.MixedCollection */
52885 this.panels = new Roo.util.MixedCollection();
52886 this.panels.getKey = this.getPanelId.createDelegate(this);
52888 this.activePanel = null;
52889 // ensure listeners are added...
52891 if (config.listeners || config.events) {
52892 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
52893 listeners : config.listeners || {},
52894 events : config.events || {}
52898 if(skipConfig !== true){
52899 this.applyConfig(config);
52903 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
52904 getPanelId : function(p){
52908 applyConfig : function(config){
52909 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
52910 this.config = config;
52915 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
52916 * the width, for horizontal (north, south) the height.
52917 * @param {Number} newSize The new width or height
52919 resizeTo : function(newSize){
52920 var el = this.el ? this.el :
52921 (this.activePanel ? this.activePanel.getEl() : null);
52923 switch(this.position){
52926 el.setWidth(newSize);
52927 this.fireEvent("resized", this, newSize);
52931 el.setHeight(newSize);
52932 this.fireEvent("resized", this, newSize);
52938 getBox : function(){
52939 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
52942 getMargins : function(){
52943 return this.margins;
52946 updateBox : function(box){
52948 var el = this.activePanel.getEl();
52949 el.dom.style.left = box.x + "px";
52950 el.dom.style.top = box.y + "px";
52951 this.activePanel.setSize(box.width, box.height);
52955 * Returns the container element for this region.
52956 * @return {Roo.Element}
52958 getEl : function(){
52959 return this.activePanel;
52963 * Returns true if this region is currently visible.
52964 * @return {Boolean}
52966 isVisible : function(){
52967 return this.activePanel ? true : false;
52970 setActivePanel : function(panel){
52971 panel = this.getPanel(panel);
52972 if(this.activePanel && this.activePanel != panel){
52973 this.activePanel.setActiveState(false);
52974 this.activePanel.getEl().setLeftTop(-10000,-10000);
52976 this.activePanel = panel;
52977 panel.setActiveState(true);
52979 panel.setSize(this.box.width, this.box.height);
52981 this.fireEvent("panelactivated", this, panel);
52982 this.fireEvent("invalidated");
52986 * Show the specified panel.
52987 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
52988 * @return {Roo.ContentPanel} The shown panel or null
52990 showPanel : function(panel){
52991 if(panel = this.getPanel(panel)){
52992 this.setActivePanel(panel);
52998 * Get the active panel for this region.
52999 * @return {Roo.ContentPanel} The active panel or null
53001 getActivePanel : function(){
53002 return this.activePanel;
53006 * Add the passed ContentPanel(s)
53007 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53008 * @return {Roo.ContentPanel} The panel added (if only one was added)
53010 add : function(panel){
53011 if(arguments.length > 1){
53012 for(var i = 0, len = arguments.length; i < len; i++) {
53013 this.add(arguments[i]);
53017 if(this.hasPanel(panel)){
53018 this.showPanel(panel);
53021 var el = panel.getEl();
53022 if(el.dom.parentNode != this.mgr.el.dom){
53023 this.mgr.el.dom.appendChild(el.dom);
53025 if(panel.setRegion){
53026 panel.setRegion(this);
53028 this.panels.add(panel);
53029 el.setStyle("position", "absolute");
53030 if(!panel.background){
53031 this.setActivePanel(panel);
53032 if(this.config.initialSize && this.panels.getCount()==1){
53033 this.resizeTo(this.config.initialSize);
53036 this.fireEvent("paneladded", this, panel);
53041 * Returns true if the panel is in this region.
53042 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53043 * @return {Boolean}
53045 hasPanel : function(panel){
53046 if(typeof panel == "object"){ // must be panel obj
53047 panel = panel.getId();
53049 return this.getPanel(panel) ? true : false;
53053 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53054 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53055 * @param {Boolean} preservePanel Overrides the config preservePanel option
53056 * @return {Roo.ContentPanel} The panel that was removed
53058 remove : function(panel, preservePanel){
53059 panel = this.getPanel(panel);
53064 this.fireEvent("beforeremove", this, panel, e);
53065 if(e.cancel === true){
53068 var panelId = panel.getId();
53069 this.panels.removeKey(panelId);
53074 * Returns the panel specified or null if it's not in this region.
53075 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
53076 * @return {Roo.ContentPanel}
53078 getPanel : function(id){
53079 if(typeof id == "object"){ // must be panel obj
53082 return this.panels.get(id);
53086 * Returns this regions position (north/south/east/west/center).
53089 getPosition: function(){
53090 return this.position;
53094 * Ext JS Library 1.1.1
53095 * Copyright(c) 2006-2007, Ext JS, LLC.
53097 * Originally Released Under LGPL - original licence link has changed is not relivant.
53100 * <script type="text/javascript">
53104 * @class Roo.LayoutRegion
53105 * @extends Roo.BasicLayoutRegion
53106 * This class represents a region in a layout manager.
53107 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
53108 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
53109 * @cfg {Boolean} floatable False to disable floating (defaults to true)
53110 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
53111 * @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})
53112 * @cfg {String} tabPosition (top|bottom) "top" or "bottom" (defaults to "bottom")
53113 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
53114 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
53115 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
53116 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
53117 * @cfg {String} title The title for the region (overrides panel titles)
53118 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
53119 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
53120 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
53121 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
53122 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
53123 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
53124 * the space available, similar to FireFox 1.5 tabs (defaults to false)
53125 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
53126 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
53127 * @cfg {Boolean} showPin True to show a pin button
53128 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
53129 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
53130 * @cfg {Boolean} disableTabTips True to disable tab tooltips
53131 * @cfg {Number} width For East/West panels
53132 * @cfg {Number} height For North/South panels
53133 * @cfg {Boolean} split To show the splitter
53134 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
53136 Roo.LayoutRegion = function(mgr, config, pos){
53137 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
53138 var dh = Roo.DomHelper;
53139 /** This region's container element
53140 * @type Roo.Element */
53141 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
53142 /** This region's title element
53143 * @type Roo.Element */
53145 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
53146 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
53147 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
53149 this.titleEl.enableDisplayMode();
53150 /** This region's title text element
53151 * @type HTMLElement */
53152 this.titleTextEl = this.titleEl.dom.firstChild;
53153 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
53154 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
53155 this.closeBtn.enableDisplayMode();
53156 this.closeBtn.on("click", this.closeClicked, this);
53157 this.closeBtn.hide();
53159 this.createBody(config);
53160 this.visible = true;
53161 this.collapsed = false;
53163 if(config.hideWhenEmpty){
53165 this.on("paneladded", this.validateVisibility, this);
53166 this.on("panelremoved", this.validateVisibility, this);
53168 this.applyConfig(config);
53171 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
53173 createBody : function(){
53174 /** This region's body element
53175 * @type Roo.Element */
53176 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
53179 applyConfig : function(c){
53180 if(c.collapsible && this.position != "center" && !this.collapsedEl){
53181 var dh = Roo.DomHelper;
53182 if(c.titlebar !== false){
53183 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
53184 this.collapseBtn.on("click", this.collapse, this);
53185 this.collapseBtn.enableDisplayMode();
53187 if(c.showPin === true || this.showPin){
53188 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
53189 this.stickBtn.enableDisplayMode();
53190 this.stickBtn.on("click", this.expand, this);
53191 this.stickBtn.hide();
53194 /** This region's collapsed element
53195 * @type Roo.Element */
53196 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
53197 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
53199 if(c.floatable !== false){
53200 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
53201 this.collapsedEl.on("click", this.collapseClick, this);
53204 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
53205 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
53206 id: "message", unselectable: "on", style:{"float":"left"}});
53207 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
53209 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
53210 this.expandBtn.on("click", this.expand, this);
53212 if(this.collapseBtn){
53213 this.collapseBtn.setVisible(c.collapsible == true);
53215 this.cmargins = c.cmargins || this.cmargins ||
53216 (this.position == "west" || this.position == "east" ?
53217 {top: 0, left: 2, right:2, bottom: 0} :
53218 {top: 2, left: 0, right:0, bottom: 2});
53219 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
53220 this.bottomTabs = c.tabPosition != "top";
53221 this.autoScroll = c.autoScroll || false;
53222 if(this.autoScroll){
53223 this.bodyEl.setStyle("overflow", "auto");
53225 this.bodyEl.setStyle("overflow", "hidden");
53227 //if(c.titlebar !== false){
53228 if((!c.titlebar && !c.title) || c.titlebar === false){
53229 this.titleEl.hide();
53231 this.titleEl.show();
53233 this.titleTextEl.innerHTML = c.title;
53237 this.duration = c.duration || .30;
53238 this.slideDuration = c.slideDuration || .45;
53241 this.collapse(true);
53248 * Returns true if this region is currently visible.
53249 * @return {Boolean}
53251 isVisible : function(){
53252 return this.visible;
53256 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
53257 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
53259 setCollapsedTitle : function(title){
53260 title = title || " ";
53261 if(this.collapsedTitleTextEl){
53262 this.collapsedTitleTextEl.innerHTML = title;
53266 getBox : function(){
53268 if(!this.collapsed){
53269 b = this.el.getBox(false, true);
53271 b = this.collapsedEl.getBox(false, true);
53276 getMargins : function(){
53277 return this.collapsed ? this.cmargins : this.margins;
53280 highlight : function(){
53281 this.el.addClass("x-layout-panel-dragover");
53284 unhighlight : function(){
53285 this.el.removeClass("x-layout-panel-dragover");
53288 updateBox : function(box){
53290 if(!this.collapsed){
53291 this.el.dom.style.left = box.x + "px";
53292 this.el.dom.style.top = box.y + "px";
53293 this.updateBody(box.width, box.height);
53295 this.collapsedEl.dom.style.left = box.x + "px";
53296 this.collapsedEl.dom.style.top = box.y + "px";
53297 this.collapsedEl.setSize(box.width, box.height);
53300 this.tabs.autoSizeTabs();
53304 updateBody : function(w, h){
53306 this.el.setWidth(w);
53307 w -= this.el.getBorderWidth("rl");
53308 if(this.config.adjustments){
53309 w += this.config.adjustments[0];
53313 this.el.setHeight(h);
53314 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
53315 h -= this.el.getBorderWidth("tb");
53316 if(this.config.adjustments){
53317 h += this.config.adjustments[1];
53319 this.bodyEl.setHeight(h);
53321 h = this.tabs.syncHeight(h);
53324 if(this.panelSize){
53325 w = w !== null ? w : this.panelSize.width;
53326 h = h !== null ? h : this.panelSize.height;
53328 if(this.activePanel){
53329 var el = this.activePanel.getEl();
53330 w = w !== null ? w : el.getWidth();
53331 h = h !== null ? h : el.getHeight();
53332 this.panelSize = {width: w, height: h};
53333 this.activePanel.setSize(w, h);
53335 if(Roo.isIE && this.tabs){
53336 this.tabs.el.repaint();
53341 * Returns the container element for this region.
53342 * @return {Roo.Element}
53344 getEl : function(){
53349 * Hides this region.
53352 if(!this.collapsed){
53353 this.el.dom.style.left = "-2000px";
53356 this.collapsedEl.dom.style.left = "-2000px";
53357 this.collapsedEl.hide();
53359 this.visible = false;
53360 this.fireEvent("visibilitychange", this, false);
53364 * Shows this region if it was previously hidden.
53367 if(!this.collapsed){
53370 this.collapsedEl.show();
53372 this.visible = true;
53373 this.fireEvent("visibilitychange", this, true);
53376 closeClicked : function(){
53377 if(this.activePanel){
53378 this.remove(this.activePanel);
53382 collapseClick : function(e){
53384 e.stopPropagation();
53387 e.stopPropagation();
53393 * Collapses this region.
53394 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
53396 collapse : function(skipAnim, skipCheck){
53397 if(this.collapsed) {
53401 if(skipCheck || this.fireEvent("beforecollapse", this) != false){
53403 this.collapsed = true;
53405 this.split.el.hide();
53407 if(this.config.animate && skipAnim !== true){
53408 this.fireEvent("invalidated", this);
53409 this.animateCollapse();
53411 this.el.setLocation(-20000,-20000);
53413 this.collapsedEl.show();
53414 this.fireEvent("collapsed", this);
53415 this.fireEvent("invalidated", this);
53421 animateCollapse : function(){
53426 * Expands this region if it was previously collapsed.
53427 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
53428 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
53430 expand : function(e, skipAnim){
53432 e.stopPropagation();
53434 if(!this.collapsed || this.el.hasActiveFx()) {
53438 this.afterSlideIn();
53441 this.collapsed = false;
53442 if(this.config.animate && skipAnim !== true){
53443 this.animateExpand();
53447 this.split.el.show();
53449 this.collapsedEl.setLocation(-2000,-2000);
53450 this.collapsedEl.hide();
53451 this.fireEvent("invalidated", this);
53452 this.fireEvent("expanded", this);
53456 animateExpand : function(){
53460 initTabs : function()
53462 this.bodyEl.setStyle("overflow", "hidden");
53463 var ts = new Roo.TabPanel(
53466 tabPosition: this.bottomTabs ? 'bottom' : 'top',
53467 disableTooltips: this.config.disableTabTips,
53468 toolbar : this.config.toolbar
53471 if(this.config.hideTabs){
53472 ts.stripWrap.setDisplayed(false);
53475 ts.resizeTabs = this.config.resizeTabs === true;
53476 ts.minTabWidth = this.config.minTabWidth || 40;
53477 ts.maxTabWidth = this.config.maxTabWidth || 250;
53478 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
53479 ts.monitorResize = false;
53480 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53481 ts.bodyEl.addClass('x-layout-tabs-body');
53482 this.panels.each(this.initPanelAsTab, this);
53485 initPanelAsTab : function(panel){
53486 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
53487 this.config.closeOnTab && panel.isClosable());
53488 if(panel.tabTip !== undefined){
53489 ti.setTooltip(panel.tabTip);
53491 ti.on("activate", function(){
53492 this.setActivePanel(panel);
53494 if(this.config.closeOnTab){
53495 ti.on("beforeclose", function(t, e){
53497 this.remove(panel);
53503 updatePanelTitle : function(panel, title){
53504 if(this.activePanel == panel){
53505 this.updateTitle(title);
53508 var ti = this.tabs.getTab(panel.getEl().id);
53510 if(panel.tabTip !== undefined){
53511 ti.setTooltip(panel.tabTip);
53516 updateTitle : function(title){
53517 if(this.titleTextEl && !this.config.title){
53518 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
53522 setActivePanel : function(panel){
53523 panel = this.getPanel(panel);
53524 if(this.activePanel && this.activePanel != panel){
53525 this.activePanel.setActiveState(false);
53527 this.activePanel = panel;
53528 panel.setActiveState(true);
53529 if(this.panelSize){
53530 panel.setSize(this.panelSize.width, this.panelSize.height);
53533 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
53535 this.updateTitle(panel.getTitle());
53537 this.fireEvent("invalidated", this);
53539 this.fireEvent("panelactivated", this, panel);
53543 * Shows the specified panel.
53544 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
53545 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
53547 showPanel : function(panel)
53549 panel = this.getPanel(panel);
53552 var tab = this.tabs.getTab(panel.getEl().id);
53553 if(tab.isHidden()){
53554 this.tabs.unhideTab(tab.id);
53558 this.setActivePanel(panel);
53565 * Get the active panel for this region.
53566 * @return {Roo.ContentPanel} The active panel or null
53568 getActivePanel : function(){
53569 return this.activePanel;
53572 validateVisibility : function(){
53573 if(this.panels.getCount() < 1){
53574 this.updateTitle(" ");
53575 this.closeBtn.hide();
53578 if(!this.isVisible()){
53585 * Adds the passed ContentPanel(s) to this region.
53586 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
53587 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
53589 add : function(panel){
53590 if(arguments.length > 1){
53591 for(var i = 0, len = arguments.length; i < len; i++) {
53592 this.add(arguments[i]);
53596 if(this.hasPanel(panel)){
53597 this.showPanel(panel);
53600 panel.setRegion(this);
53601 this.panels.add(panel);
53602 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
53603 this.bodyEl.dom.appendChild(panel.getEl().dom);
53604 if(panel.background !== true){
53605 this.setActivePanel(panel);
53607 this.fireEvent("paneladded", this, panel);
53613 this.initPanelAsTab(panel);
53615 if(panel.background !== true){
53616 this.tabs.activate(panel.getEl().id);
53618 this.fireEvent("paneladded", this, panel);
53623 * Hides the tab for the specified panel.
53624 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53626 hidePanel : function(panel){
53627 if(this.tabs && (panel = this.getPanel(panel))){
53628 this.tabs.hideTab(panel.getEl().id);
53633 * Unhides the tab for a previously hidden panel.
53634 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53636 unhidePanel : function(panel){
53637 if(this.tabs && (panel = this.getPanel(panel))){
53638 this.tabs.unhideTab(panel.getEl().id);
53642 clearPanels : function(){
53643 while(this.panels.getCount() > 0){
53644 this.remove(this.panels.first());
53649 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
53650 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
53651 * @param {Boolean} preservePanel Overrides the config preservePanel option
53652 * @return {Roo.ContentPanel} The panel that was removed
53654 remove : function(panel, preservePanel){
53655 panel = this.getPanel(panel);
53660 this.fireEvent("beforeremove", this, panel, e);
53661 if(e.cancel === true){
53664 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
53665 var panelId = panel.getId();
53666 this.panels.removeKey(panelId);
53668 document.body.appendChild(panel.getEl().dom);
53671 this.tabs.removeTab(panel.getEl().id);
53672 }else if (!preservePanel){
53673 this.bodyEl.dom.removeChild(panel.getEl().dom);
53675 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
53676 var p = this.panels.first();
53677 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
53678 tempEl.appendChild(p.getEl().dom);
53679 this.bodyEl.update("");
53680 this.bodyEl.dom.appendChild(p.getEl().dom);
53682 this.updateTitle(p.getTitle());
53684 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
53685 this.setActivePanel(p);
53687 panel.setRegion(null);
53688 if(this.activePanel == panel){
53689 this.activePanel = null;
53691 if(this.config.autoDestroy !== false && preservePanel !== true){
53692 try{panel.destroy();}catch(e){}
53694 this.fireEvent("panelremoved", this, panel);
53699 * Returns the TabPanel component used by this region
53700 * @return {Roo.TabPanel}
53702 getTabs : function(){
53706 createTool : function(parentEl, className){
53707 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
53708 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
53709 btn.addClassOnOver("x-layout-tools-button-over");
53714 * Ext JS Library 1.1.1
53715 * Copyright(c) 2006-2007, Ext JS, LLC.
53717 * Originally Released Under LGPL - original licence link has changed is not relivant.
53720 * <script type="text/javascript">
53726 * @class Roo.SplitLayoutRegion
53727 * @extends Roo.LayoutRegion
53728 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
53730 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
53731 this.cursor = cursor;
53732 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
53735 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
53736 splitTip : "Drag to resize.",
53737 collapsibleSplitTip : "Drag to resize. Double click to hide.",
53738 useSplitTips : false,
53740 applyConfig : function(config){
53741 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
53744 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
53745 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
53746 /** The SplitBar for this region
53747 * @type Roo.SplitBar */
53748 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
53749 this.split.on("moved", this.onSplitMove, this);
53750 this.split.useShim = config.useShim === true;
53751 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
53752 if(this.useSplitTips){
53753 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
53755 if(config.collapsible){
53756 this.split.el.on("dblclick", this.collapse, this);
53759 if(typeof config.minSize != "undefined"){
53760 this.split.minSize = config.minSize;
53762 if(typeof config.maxSize != "undefined"){
53763 this.split.maxSize = config.maxSize;
53765 if(config.hideWhenEmpty || config.hidden || config.collapsed){
53766 this.hideSplitter();
53771 getHMaxSize : function(){
53772 var cmax = this.config.maxSize || 10000;
53773 var center = this.mgr.getRegion("center");
53774 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
53777 getVMaxSize : function(){
53778 var cmax = this.config.maxSize || 10000;
53779 var center = this.mgr.getRegion("center");
53780 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
53783 onSplitMove : function(split, newSize){
53784 this.fireEvent("resized", this, newSize);
53788 * Returns the {@link Roo.SplitBar} for this region.
53789 * @return {Roo.SplitBar}
53791 getSplitBar : function(){
53796 this.hideSplitter();
53797 Roo.SplitLayoutRegion.superclass.hide.call(this);
53800 hideSplitter : function(){
53802 this.split.el.setLocation(-2000,-2000);
53803 this.split.el.hide();
53809 this.split.el.show();
53811 Roo.SplitLayoutRegion.superclass.show.call(this);
53814 beforeSlide: function(){
53815 if(Roo.isGecko){// firefox overflow auto bug workaround
53816 this.bodyEl.clip();
53818 this.tabs.bodyEl.clip();
53820 if(this.activePanel){
53821 this.activePanel.getEl().clip();
53823 if(this.activePanel.beforeSlide){
53824 this.activePanel.beforeSlide();
53830 afterSlide : function(){
53831 if(Roo.isGecko){// firefox overflow auto bug workaround
53832 this.bodyEl.unclip();
53834 this.tabs.bodyEl.unclip();
53836 if(this.activePanel){
53837 this.activePanel.getEl().unclip();
53838 if(this.activePanel.afterSlide){
53839 this.activePanel.afterSlide();
53845 initAutoHide : function(){
53846 if(this.autoHide !== false){
53847 if(!this.autoHideHd){
53848 var st = new Roo.util.DelayedTask(this.slideIn, this);
53849 this.autoHideHd = {
53850 "mouseout": function(e){
53851 if(!e.within(this.el, true)){
53855 "mouseover" : function(e){
53861 this.el.on(this.autoHideHd);
53865 clearAutoHide : function(){
53866 if(this.autoHide !== false){
53867 this.el.un("mouseout", this.autoHideHd.mouseout);
53868 this.el.un("mouseover", this.autoHideHd.mouseover);
53872 clearMonitor : function(){
53873 Roo.get(document).un("click", this.slideInIf, this);
53876 // these names are backwards but not changed for compat
53877 slideOut : function(){
53878 if(this.isSlid || this.el.hasActiveFx()){
53881 this.isSlid = true;
53882 if(this.collapseBtn){
53883 this.collapseBtn.hide();
53885 this.closeBtnState = this.closeBtn.getStyle('display');
53886 this.closeBtn.hide();
53888 this.stickBtn.show();
53891 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
53892 this.beforeSlide();
53893 this.el.setStyle("z-index", 10001);
53894 this.el.slideIn(this.getSlideAnchor(), {
53895 callback: function(){
53897 this.initAutoHide();
53898 Roo.get(document).on("click", this.slideInIf, this);
53899 this.fireEvent("slideshow", this);
53906 afterSlideIn : function(){
53907 this.clearAutoHide();
53908 this.isSlid = false;
53909 this.clearMonitor();
53910 this.el.setStyle("z-index", "");
53911 if(this.collapseBtn){
53912 this.collapseBtn.show();
53914 this.closeBtn.setStyle('display', this.closeBtnState);
53916 this.stickBtn.hide();
53918 this.fireEvent("slidehide", this);
53921 slideIn : function(cb){
53922 if(!this.isSlid || this.el.hasActiveFx()){
53926 this.isSlid = false;
53927 this.beforeSlide();
53928 this.el.slideOut(this.getSlideAnchor(), {
53929 callback: function(){
53930 this.el.setLeftTop(-10000, -10000);
53932 this.afterSlideIn();
53940 slideInIf : function(e){
53941 if(!e.within(this.el)){
53946 animateCollapse : function(){
53947 this.beforeSlide();
53948 this.el.setStyle("z-index", 20000);
53949 var anchor = this.getSlideAnchor();
53950 this.el.slideOut(anchor, {
53951 callback : function(){
53952 this.el.setStyle("z-index", "");
53953 this.collapsedEl.slideIn(anchor, {duration:.3});
53955 this.el.setLocation(-10000,-10000);
53957 this.fireEvent("collapsed", this);
53964 animateExpand : function(){
53965 this.beforeSlide();
53966 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
53967 this.el.setStyle("z-index", 20000);
53968 this.collapsedEl.hide({
53971 this.el.slideIn(this.getSlideAnchor(), {
53972 callback : function(){
53973 this.el.setStyle("z-index", "");
53976 this.split.el.show();
53978 this.fireEvent("invalidated", this);
53979 this.fireEvent("expanded", this);
54007 getAnchor : function(){
54008 return this.anchors[this.position];
54011 getCollapseAnchor : function(){
54012 return this.canchors[this.position];
54015 getSlideAnchor : function(){
54016 return this.sanchors[this.position];
54019 getAlignAdj : function(){
54020 var cm = this.cmargins;
54021 switch(this.position){
54037 getExpandAdj : function(){
54038 var c = this.collapsedEl, cm = this.cmargins;
54039 switch(this.position){
54041 return [-(cm.right+c.getWidth()+cm.left), 0];
54044 return [cm.right+c.getWidth()+cm.left, 0];
54047 return [0, -(cm.top+cm.bottom+c.getHeight())];
54050 return [0, cm.top+cm.bottom+c.getHeight()];
54056 * Ext JS Library 1.1.1
54057 * Copyright(c) 2006-2007, Ext JS, LLC.
54059 * Originally Released Under LGPL - original licence link has changed is not relivant.
54062 * <script type="text/javascript">
54065 * These classes are private internal classes
54067 Roo.CenterLayoutRegion = function(mgr, config){
54068 Roo.LayoutRegion.call(this, mgr, config, "center");
54069 this.visible = true;
54070 this.minWidth = config.minWidth || 20;
54071 this.minHeight = config.minHeight || 20;
54074 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
54076 // center panel can't be hidden
54080 // center panel can't be hidden
54083 getMinWidth: function(){
54084 return this.minWidth;
54087 getMinHeight: function(){
54088 return this.minHeight;
54093 Roo.NorthLayoutRegion = function(mgr, config){
54094 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
54096 this.split.placement = Roo.SplitBar.TOP;
54097 this.split.orientation = Roo.SplitBar.VERTICAL;
54098 this.split.el.addClass("x-layout-split-v");
54100 var size = config.initialSize || config.height;
54101 if(typeof size != "undefined"){
54102 this.el.setHeight(size);
54105 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
54106 orientation: Roo.SplitBar.VERTICAL,
54107 getBox : function(){
54108 if(this.collapsed){
54109 return this.collapsedEl.getBox();
54111 var box = this.el.getBox();
54113 box.height += this.split.el.getHeight();
54118 updateBox : function(box){
54119 if(this.split && !this.collapsed){
54120 box.height -= this.split.el.getHeight();
54121 this.split.el.setLeft(box.x);
54122 this.split.el.setTop(box.y+box.height);
54123 this.split.el.setWidth(box.width);
54125 if(this.collapsed){
54126 this.updateBody(box.width, null);
54128 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54132 Roo.SouthLayoutRegion = function(mgr, config){
54133 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
54135 this.split.placement = Roo.SplitBar.BOTTOM;
54136 this.split.orientation = Roo.SplitBar.VERTICAL;
54137 this.split.el.addClass("x-layout-split-v");
54139 var size = config.initialSize || config.height;
54140 if(typeof size != "undefined"){
54141 this.el.setHeight(size);
54144 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
54145 orientation: Roo.SplitBar.VERTICAL,
54146 getBox : function(){
54147 if(this.collapsed){
54148 return this.collapsedEl.getBox();
54150 var box = this.el.getBox();
54152 var sh = this.split.el.getHeight();
54159 updateBox : function(box){
54160 if(this.split && !this.collapsed){
54161 var sh = this.split.el.getHeight();
54164 this.split.el.setLeft(box.x);
54165 this.split.el.setTop(box.y-sh);
54166 this.split.el.setWidth(box.width);
54168 if(this.collapsed){
54169 this.updateBody(box.width, null);
54171 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54175 Roo.EastLayoutRegion = function(mgr, config){
54176 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
54178 this.split.placement = Roo.SplitBar.RIGHT;
54179 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54180 this.split.el.addClass("x-layout-split-h");
54182 var size = config.initialSize || config.width;
54183 if(typeof size != "undefined"){
54184 this.el.setWidth(size);
54187 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
54188 orientation: Roo.SplitBar.HORIZONTAL,
54189 getBox : function(){
54190 if(this.collapsed){
54191 return this.collapsedEl.getBox();
54193 var box = this.el.getBox();
54195 var sw = this.split.el.getWidth();
54202 updateBox : function(box){
54203 if(this.split && !this.collapsed){
54204 var sw = this.split.el.getWidth();
54206 this.split.el.setLeft(box.x);
54207 this.split.el.setTop(box.y);
54208 this.split.el.setHeight(box.height);
54211 if(this.collapsed){
54212 this.updateBody(null, box.height);
54214 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54218 Roo.WestLayoutRegion = function(mgr, config){
54219 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
54221 this.split.placement = Roo.SplitBar.LEFT;
54222 this.split.orientation = Roo.SplitBar.HORIZONTAL;
54223 this.split.el.addClass("x-layout-split-h");
54225 var size = config.initialSize || config.width;
54226 if(typeof size != "undefined"){
54227 this.el.setWidth(size);
54230 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
54231 orientation: Roo.SplitBar.HORIZONTAL,
54232 getBox : function(){
54233 if(this.collapsed){
54234 return this.collapsedEl.getBox();
54236 var box = this.el.getBox();
54238 box.width += this.split.el.getWidth();
54243 updateBox : function(box){
54244 if(this.split && !this.collapsed){
54245 var sw = this.split.el.getWidth();
54247 this.split.el.setLeft(box.x+box.width);
54248 this.split.el.setTop(box.y);
54249 this.split.el.setHeight(box.height);
54251 if(this.collapsed){
54252 this.updateBody(null, box.height);
54254 Roo.LayoutRegion.prototype.updateBox.call(this, box);
54259 * Ext JS Library 1.1.1
54260 * Copyright(c) 2006-2007, Ext JS, LLC.
54262 * Originally Released Under LGPL - original licence link has changed is not relivant.
54265 * <script type="text/javascript">
54270 * Private internal class for reading and applying state
54272 Roo.LayoutStateManager = function(layout){
54273 // default empty state
54282 Roo.LayoutStateManager.prototype = {
54283 init : function(layout, provider){
54284 this.provider = provider;
54285 var state = provider.get(layout.id+"-layout-state");
54287 var wasUpdating = layout.isUpdating();
54289 layout.beginUpdate();
54291 for(var key in state){
54292 if(typeof state[key] != "function"){
54293 var rstate = state[key];
54294 var r = layout.getRegion(key);
54297 r.resizeTo(rstate.size);
54299 if(rstate.collapsed == true){
54302 r.expand(null, true);
54308 layout.endUpdate();
54310 this.state = state;
54312 this.layout = layout;
54313 layout.on("regionresized", this.onRegionResized, this);
54314 layout.on("regioncollapsed", this.onRegionCollapsed, this);
54315 layout.on("regionexpanded", this.onRegionExpanded, this);
54318 storeState : function(){
54319 this.provider.set(this.layout.id+"-layout-state", this.state);
54322 onRegionResized : function(region, newSize){
54323 this.state[region.getPosition()].size = newSize;
54327 onRegionCollapsed : function(region){
54328 this.state[region.getPosition()].collapsed = true;
54332 onRegionExpanded : function(region){
54333 this.state[region.getPosition()].collapsed = false;
54338 * Ext JS Library 1.1.1
54339 * Copyright(c) 2006-2007, Ext JS, LLC.
54341 * Originally Released Under LGPL - original licence link has changed is not relivant.
54344 * <script type="text/javascript">
54347 * @class Roo.ContentPanel
54348 * @extends Roo.util.Observable
54349 * A basic ContentPanel element.
54350 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
54351 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
54352 * @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
54353 * @cfg {Boolean} closable True if the panel can be closed/removed
54354 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
54355 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
54356 * @cfg {Toolbar} toolbar A toolbar for this panel
54357 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
54358 * @cfg {String} title The title for this panel
54359 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
54360 * @cfg {String} url Calls {@link #setUrl} with this value
54361 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
54362 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
54363 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
54364 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
54365 * @cfg {String} style Extra style to add to the content panel
54368 * Create a new ContentPanel.
54369 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
54370 * @param {String/Object} config A string to set only the title or a config object
54371 * @param {String} content (optional) Set the HTML content for this panel
54372 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
54374 Roo.ContentPanel = function(el, config, content){
54378 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
54382 if (config && config.parentLayout) {
54383 el = config.parentLayout.el.createChild();
54386 if(el.autoCreate){ // xtype is available if this is called from factory
54390 this.el = Roo.get(el);
54391 if(!this.el && config && config.autoCreate){
54392 if(typeof config.autoCreate == "object"){
54393 if(!config.autoCreate.id){
54394 config.autoCreate.id = config.id||el;
54396 this.el = Roo.DomHelper.append(document.body,
54397 config.autoCreate, true);
54399 this.el = Roo.DomHelper.append(document.body,
54400 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
54405 this.closable = false;
54406 this.loaded = false;
54407 this.active = false;
54408 if(typeof config == "string"){
54409 this.title = config;
54411 Roo.apply(this, config);
54414 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
54415 this.wrapEl = this.el.wrap();
54416 this.toolbar.container = this.el.insertSibling(false, 'before');
54417 this.toolbar = new Roo.Toolbar(this.toolbar);
54420 // xtype created footer. - not sure if will work as we normally have to render first..
54421 if (this.footer && !this.footer.el && this.footer.xtype) {
54422 if (!this.wrapEl) {
54423 this.wrapEl = this.el.wrap();
54426 this.footer.container = this.wrapEl.createChild();
54428 this.footer = Roo.factory(this.footer, Roo);
54433 this.resizeEl = Roo.get(this.resizeEl, true);
54435 this.resizeEl = this.el;
54437 // handle view.xtype
54445 * Fires when this panel is activated.
54446 * @param {Roo.ContentPanel} this
54450 * @event deactivate
54451 * Fires when this panel is activated.
54452 * @param {Roo.ContentPanel} this
54454 "deactivate" : true,
54458 * Fires when this panel is resized if fitToFrame is true.
54459 * @param {Roo.ContentPanel} this
54460 * @param {Number} width The width after any component adjustments
54461 * @param {Number} height The height after any component adjustments
54467 * Fires when this tab is created
54468 * @param {Roo.ContentPanel} this
54478 if(this.autoScroll){
54479 this.resizeEl.setStyle("overflow", "auto");
54481 // fix randome scrolling
54482 this.el.on('scroll', function() {
54483 Roo.log('fix random scolling');
54484 this.scrollTo('top',0);
54487 content = content || this.content;
54489 this.setContent(content);
54491 if(config && config.url){
54492 this.setUrl(this.url, this.params, this.loadOnce);
54497 Roo.ContentPanel.superclass.constructor.call(this);
54499 if (this.view && typeof(this.view.xtype) != 'undefined') {
54500 this.view.el = this.el.appendChild(document.createElement("div"));
54501 this.view = Roo.factory(this.view);
54502 this.view.render && this.view.render(false, '');
54506 this.fireEvent('render', this);
54509 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
54511 setRegion : function(region){
54512 this.region = region;
54514 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
54516 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
54521 * Returns the toolbar for this Panel if one was configured.
54522 * @return {Roo.Toolbar}
54524 getToolbar : function(){
54525 return this.toolbar;
54528 setActiveState : function(active){
54529 this.active = active;
54531 this.fireEvent("deactivate", this);
54533 this.fireEvent("activate", this);
54537 * Updates this panel's element
54538 * @param {String} content The new content
54539 * @param {Boolean} loadScripts (optional) true to look for and process scripts
54541 setContent : function(content, loadScripts){
54542 this.el.update(content, loadScripts);
54545 ignoreResize : function(w, h){
54546 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
54549 this.lastSize = {width: w, height: h};
54554 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
54555 * @return {Roo.UpdateManager} The UpdateManager
54557 getUpdateManager : function(){
54558 return this.el.getUpdateManager();
54561 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
54562 * @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:
54565 url: "your-url.php",
54566 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
54567 callback: yourFunction,
54568 scope: yourObject, //(optional scope)
54571 text: "Loading...",
54576 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
54577 * 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.
54578 * @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}
54579 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
54580 * @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.
54581 * @return {Roo.ContentPanel} this
54584 var um = this.el.getUpdateManager();
54585 um.update.apply(um, arguments);
54591 * 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.
54592 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
54593 * @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)
54594 * @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)
54595 * @return {Roo.UpdateManager} The UpdateManager
54597 setUrl : function(url, params, loadOnce){
54598 if(this.refreshDelegate){
54599 this.removeListener("activate", this.refreshDelegate);
54601 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
54602 this.on("activate", this.refreshDelegate);
54603 return this.el.getUpdateManager();
54606 _handleRefresh : function(url, params, loadOnce){
54607 if(!loadOnce || !this.loaded){
54608 var updater = this.el.getUpdateManager();
54609 updater.update(url, params, this._setLoaded.createDelegate(this));
54613 _setLoaded : function(){
54614 this.loaded = true;
54618 * Returns this panel's id
54621 getId : function(){
54626 * Returns this panel's element - used by regiosn to add.
54627 * @return {Roo.Element}
54629 getEl : function(){
54630 return this.wrapEl || this.el;
54633 adjustForComponents : function(width, height)
54635 //Roo.log('adjustForComponents ');
54636 if(this.resizeEl != this.el){
54637 width -= this.el.getFrameWidth('lr');
54638 height -= this.el.getFrameWidth('tb');
54641 var te = this.toolbar.getEl();
54642 height -= te.getHeight();
54643 te.setWidth(width);
54646 var te = this.footer.getEl();
54647 //Roo.log("footer:" + te.getHeight());
54649 height -= te.getHeight();
54650 te.setWidth(width);
54654 if(this.adjustments){
54655 width += this.adjustments[0];
54656 height += this.adjustments[1];
54658 return {"width": width, "height": height};
54661 setSize : function(width, height){
54662 if(this.fitToFrame && !this.ignoreResize(width, height)){
54663 if(this.fitContainer && this.resizeEl != this.el){
54664 this.el.setSize(width, height);
54666 var size = this.adjustForComponents(width, height);
54667 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
54668 this.fireEvent('resize', this, size.width, size.height);
54673 * Returns this panel's title
54676 getTitle : function(){
54681 * Set this panel's title
54682 * @param {String} title
54684 setTitle : function(title){
54685 this.title = title;
54687 this.region.updatePanelTitle(this, title);
54692 * Returns true is this panel was configured to be closable
54693 * @return {Boolean}
54695 isClosable : function(){
54696 return this.closable;
54699 beforeSlide : function(){
54701 this.resizeEl.clip();
54704 afterSlide : function(){
54706 this.resizeEl.unclip();
54710 * Force a content refresh from the URL specified in the {@link #setUrl} method.
54711 * Will fail silently if the {@link #setUrl} method has not been called.
54712 * This does not activate the panel, just updates its content.
54714 refresh : function(){
54715 if(this.refreshDelegate){
54716 this.loaded = false;
54717 this.refreshDelegate();
54722 * Destroys this panel
54724 destroy : function(){
54725 this.el.removeAllListeners();
54726 var tempEl = document.createElement("span");
54727 tempEl.appendChild(this.el.dom);
54728 tempEl.innerHTML = "";
54734 * form - if the content panel contains a form - this is a reference to it.
54735 * @type {Roo.form.Form}
54739 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
54740 * This contains a reference to it.
54746 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
54756 * @param {Object} cfg Xtype definition of item to add.
54759 addxtype : function(cfg) {
54761 if (cfg.xtype.match(/^Form$/)) {
54764 //if (this.footer) {
54765 // el = this.footer.container.insertSibling(false, 'before');
54767 el = this.el.createChild();
54770 this.form = new Roo.form.Form(cfg);
54773 if ( this.form.allItems.length) {
54774 this.form.render(el.dom);
54778 // should only have one of theses..
54779 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
54780 // views.. should not be just added - used named prop 'view''
54782 cfg.el = this.el.appendChild(document.createElement("div"));
54785 var ret = new Roo.factory(cfg);
54787 ret.render && ret.render(false, ''); // render blank..
54796 * @class Roo.GridPanel
54797 * @extends Roo.ContentPanel
54799 * Create a new GridPanel.
54800 * @param {Roo.grid.Grid} grid The grid for this panel
54801 * @param {String/Object} config A string to set only the panel's title, or a config object
54803 Roo.GridPanel = function(grid, config){
54806 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
54807 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
54809 this.wrapper.dom.appendChild(grid.getGridEl().dom);
54811 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
54814 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
54816 // xtype created footer. - not sure if will work as we normally have to render first..
54817 if (this.footer && !this.footer.el && this.footer.xtype) {
54819 this.footer.container = this.grid.getView().getFooterPanel(true);
54820 this.footer.dataSource = this.grid.dataSource;
54821 this.footer = Roo.factory(this.footer, Roo);
54825 grid.monitorWindowResize = false; // turn off autosizing
54826 grid.autoHeight = false;
54827 grid.autoWidth = false;
54829 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
54832 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
54833 getId : function(){
54834 return this.grid.id;
54838 * Returns the grid for this panel
54839 * @return {Roo.grid.Grid}
54841 getGrid : function(){
54845 setSize : function(width, height){
54846 if(!this.ignoreResize(width, height)){
54847 var grid = this.grid;
54848 var size = this.adjustForComponents(width, height);
54849 grid.getGridEl().setSize(size.width, size.height);
54854 beforeSlide : function(){
54855 this.grid.getView().scroller.clip();
54858 afterSlide : function(){
54859 this.grid.getView().scroller.unclip();
54862 destroy : function(){
54863 this.grid.destroy();
54865 Roo.GridPanel.superclass.destroy.call(this);
54871 * @class Roo.NestedLayoutPanel
54872 * @extends Roo.ContentPanel
54874 * Create a new NestedLayoutPanel.
54877 * @param {Roo.BorderLayout} layout The layout for this panel
54878 * @param {String/Object} config A string to set only the title or a config object
54880 Roo.NestedLayoutPanel = function(layout, config)
54882 // construct with only one argument..
54883 /* FIXME - implement nicer consturctors
54884 if (layout.layout) {
54886 layout = config.layout;
54887 delete config.layout;
54889 if (layout.xtype && !layout.getEl) {
54890 // then layout needs constructing..
54891 layout = Roo.factory(layout, Roo);
54896 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
54898 layout.monitorWindowResize = false; // turn off autosizing
54899 this.layout = layout;
54900 this.layout.getEl().addClass("x-layout-nested-layout");
54907 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
54909 setSize : function(width, height){
54910 if(!this.ignoreResize(width, height)){
54911 var size = this.adjustForComponents(width, height);
54912 var el = this.layout.getEl();
54913 el.setSize(size.width, size.height);
54914 var touch = el.dom.offsetWidth;
54915 this.layout.layout();
54916 // ie requires a double layout on the first pass
54917 if(Roo.isIE && !this.initialized){
54918 this.initialized = true;
54919 this.layout.layout();
54924 // activate all subpanels if not currently active..
54926 setActiveState : function(active){
54927 this.active = active;
54929 this.fireEvent("deactivate", this);
54933 this.fireEvent("activate", this);
54934 // not sure if this should happen before or after..
54935 if (!this.layout) {
54936 return; // should not happen..
54939 for (var r in this.layout.regions) {
54940 reg = this.layout.getRegion(r);
54941 if (reg.getActivePanel()) {
54942 //reg.showPanel(reg.getActivePanel()); // force it to activate..
54943 reg.setActivePanel(reg.getActivePanel());
54946 if (!reg.panels.length) {
54949 reg.showPanel(reg.getPanel(0));
54958 * Returns the nested BorderLayout for this panel
54959 * @return {Roo.BorderLayout}
54961 getLayout : function(){
54962 return this.layout;
54966 * Adds a xtype elements to the layout of the nested panel
54970 xtype : 'ContentPanel',
54977 xtype : 'NestedLayoutPanel',
54983 items : [ ... list of content panels or nested layout panels.. ]
54987 * @param {Object} cfg Xtype definition of item to add.
54989 addxtype : function(cfg) {
54990 return this.layout.addxtype(cfg);
54995 Roo.ScrollPanel = function(el, config, content){
54996 config = config || {};
54997 config.fitToFrame = true;
54998 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
55000 this.el.dom.style.overflow = "hidden";
55001 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
55002 this.el.removeClass("x-layout-inactive-content");
55003 this.el.on("mousewheel", this.onWheel, this);
55005 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
55006 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
55007 up.unselectable(); down.unselectable();
55008 up.on("click", this.scrollUp, this);
55009 down.on("click", this.scrollDown, this);
55010 up.addClassOnOver("x-scroller-btn-over");
55011 down.addClassOnOver("x-scroller-btn-over");
55012 up.addClassOnClick("x-scroller-btn-click");
55013 down.addClassOnClick("x-scroller-btn-click");
55014 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
55016 this.resizeEl = this.el;
55017 this.el = wrap; this.up = up; this.down = down;
55020 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
55022 wheelIncrement : 5,
55023 scrollUp : function(){
55024 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
55027 scrollDown : function(){
55028 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
55031 afterScroll : function(){
55032 var el = this.resizeEl;
55033 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
55034 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
55035 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
55038 setSize : function(){
55039 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
55040 this.afterScroll();
55043 onWheel : function(e){
55044 var d = e.getWheelDelta();
55045 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
55046 this.afterScroll();
55050 setContent : function(content, loadScripts){
55051 this.resizeEl.update(content, loadScripts);
55065 * @class Roo.TreePanel
55066 * @extends Roo.ContentPanel
55068 * Create a new TreePanel. - defaults to fit/scoll contents.
55069 * @param {String/Object} config A string to set only the panel's title, or a config object
55070 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
55072 Roo.TreePanel = function(config){
55073 var el = config.el;
55074 var tree = config.tree;
55075 delete config.tree;
55076 delete config.el; // hopefull!
55078 // wrapper for IE7 strict & safari scroll issue
55080 var treeEl = el.createChild();
55081 config.resizeEl = treeEl;
55085 Roo.TreePanel.superclass.constructor.call(this, el, config);
55088 this.tree = new Roo.tree.TreePanel(treeEl , tree);
55089 //console.log(tree);
55090 this.on('activate', function()
55092 if (this.tree.rendered) {
55095 //console.log('render tree');
55096 this.tree.render();
55098 // this should not be needed.. - it's actually the 'el' that resizes?
55099 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
55101 //this.on('resize', function (cp, w, h) {
55102 // this.tree.innerCt.setWidth(w);
55103 // this.tree.innerCt.setHeight(h);
55104 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
55111 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
55128 * Ext JS Library 1.1.1
55129 * Copyright(c) 2006-2007, Ext JS, LLC.
55131 * Originally Released Under LGPL - original licence link has changed is not relivant.
55134 * <script type="text/javascript">
55139 * @class Roo.ReaderLayout
55140 * @extends Roo.BorderLayout
55141 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
55142 * center region containing two nested regions (a top one for a list view and one for item preview below),
55143 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
55144 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
55145 * expedites the setup of the overall layout and regions for this common application style.
55148 var reader = new Roo.ReaderLayout();
55149 var CP = Roo.ContentPanel; // shortcut for adding
55151 reader.beginUpdate();
55152 reader.add("north", new CP("north", "North"));
55153 reader.add("west", new CP("west", {title: "West"}));
55154 reader.add("east", new CP("east", {title: "East"}));
55156 reader.regions.listView.add(new CP("listView", "List"));
55157 reader.regions.preview.add(new CP("preview", "Preview"));
55158 reader.endUpdate();
55161 * Create a new ReaderLayout
55162 * @param {Object} config Configuration options
55163 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
55164 * document.body if omitted)
55166 Roo.ReaderLayout = function(config, renderTo){
55167 var c = config || {size:{}};
55168 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
55169 north: c.north !== false ? Roo.apply({
55173 }, c.north) : false,
55174 west: c.west !== false ? Roo.apply({
55182 margins:{left:5,right:0,bottom:5,top:5},
55183 cmargins:{left:5,right:5,bottom:5,top:5}
55184 }, c.west) : false,
55185 east: c.east !== false ? Roo.apply({
55193 margins:{left:0,right:5,bottom:5,top:5},
55194 cmargins:{left:5,right:5,bottom:5,top:5}
55195 }, c.east) : false,
55196 center: Roo.apply({
55197 tabPosition: 'top',
55201 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
55205 this.el.addClass('x-reader');
55207 this.beginUpdate();
55209 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
55210 south: c.preview !== false ? Roo.apply({
55217 cmargins:{top:5,left:0, right:0, bottom:0}
55218 }, c.preview) : false,
55219 center: Roo.apply({
55225 this.add('center', new Roo.NestedLayoutPanel(inner,
55226 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
55230 this.regions.preview = inner.getRegion('south');
55231 this.regions.listView = inner.getRegion('center');
55234 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
55236 * Ext JS Library 1.1.1
55237 * Copyright(c) 2006-2007, Ext JS, LLC.
55239 * Originally Released Under LGPL - original licence link has changed is not relivant.
55242 * <script type="text/javascript">
55246 * @class Roo.grid.Grid
55247 * @extends Roo.util.Observable
55248 * This class represents the primary interface of a component based grid control.
55249 * <br><br>Usage:<pre><code>
55250 var grid = new Roo.grid.Grid("my-container-id", {
55253 selModel: mySelectionModel,
55254 autoSizeColumns: true,
55255 monitorWindowResize: false,
55256 trackMouseOver: true
55261 * <b>Common Problems:</b><br/>
55262 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
55263 * element will correct this<br/>
55264 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
55265 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
55266 * are unpredictable.<br/>
55267 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
55268 * grid to calculate dimensions/offsets.<br/>
55270 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
55271 * The container MUST have some type of size defined for the grid to fill. The container will be
55272 * automatically set to position relative if it isn't already.
55273 * @param {Object} config A config object that sets properties on this grid.
55275 Roo.grid.Grid = function(container, config){
55276 // initialize the container
55277 this.container = Roo.get(container);
55278 this.container.update("");
55279 this.container.setStyle("overflow", "hidden");
55280 this.container.addClass('x-grid-container');
55282 this.id = this.container.id;
55284 Roo.apply(this, config);
55285 // check and correct shorthanded configs
55287 this.dataSource = this.ds;
55291 this.colModel = this.cm;
55295 this.selModel = this.sm;
55299 if (this.selModel) {
55300 this.selModel = Roo.factory(this.selModel, Roo.grid);
55301 this.sm = this.selModel;
55302 this.sm.xmodule = this.xmodule || false;
55304 if (typeof(this.colModel.config) == 'undefined') {
55305 this.colModel = new Roo.grid.ColumnModel(this.colModel);
55306 this.cm = this.colModel;
55307 this.cm.xmodule = this.xmodule || false;
55309 if (this.dataSource) {
55310 this.dataSource= Roo.factory(this.dataSource, Roo.data);
55311 this.ds = this.dataSource;
55312 this.ds.xmodule = this.xmodule || false;
55319 this.container.setWidth(this.width);
55323 this.container.setHeight(this.height);
55330 * The raw click event for the entire grid.
55331 * @param {Roo.EventObject} e
55336 * The raw dblclick event for the entire grid.
55337 * @param {Roo.EventObject} e
55341 * @event contextmenu
55342 * The raw contextmenu event for the entire grid.
55343 * @param {Roo.EventObject} e
55345 "contextmenu" : true,
55348 * The raw mousedown event for the entire grid.
55349 * @param {Roo.EventObject} e
55351 "mousedown" : true,
55354 * The raw mouseup event for the entire grid.
55355 * @param {Roo.EventObject} e
55360 * The raw mouseover event for the entire grid.
55361 * @param {Roo.EventObject} e
55363 "mouseover" : true,
55366 * The raw mouseout event for the entire grid.
55367 * @param {Roo.EventObject} e
55372 * The raw keypress event for the entire grid.
55373 * @param {Roo.EventObject} e
55378 * The raw keydown event for the entire grid.
55379 * @param {Roo.EventObject} e
55387 * Fires when a cell is clicked
55388 * @param {Grid} this
55389 * @param {Number} rowIndex
55390 * @param {Number} columnIndex
55391 * @param {Roo.EventObject} e
55393 "cellclick" : true,
55395 * @event celldblclick
55396 * Fires when a cell is double clicked
55397 * @param {Grid} this
55398 * @param {Number} rowIndex
55399 * @param {Number} columnIndex
55400 * @param {Roo.EventObject} e
55402 "celldblclick" : true,
55405 * Fires when a row is clicked
55406 * @param {Grid} this
55407 * @param {Number} rowIndex
55408 * @param {Roo.EventObject} e
55412 * @event rowdblclick
55413 * Fires when a row is double clicked
55414 * @param {Grid} this
55415 * @param {Number} rowIndex
55416 * @param {Roo.EventObject} e
55418 "rowdblclick" : true,
55420 * @event headerclick
55421 * Fires when a header is clicked
55422 * @param {Grid} this
55423 * @param {Number} columnIndex
55424 * @param {Roo.EventObject} e
55426 "headerclick" : true,
55428 * @event headerdblclick
55429 * Fires when a header cell is double clicked
55430 * @param {Grid} this
55431 * @param {Number} columnIndex
55432 * @param {Roo.EventObject} e
55434 "headerdblclick" : true,
55436 * @event rowcontextmenu
55437 * Fires when a row is right clicked
55438 * @param {Grid} this
55439 * @param {Number} rowIndex
55440 * @param {Roo.EventObject} e
55442 "rowcontextmenu" : true,
55444 * @event cellcontextmenu
55445 * Fires when a cell is right clicked
55446 * @param {Grid} this
55447 * @param {Number} rowIndex
55448 * @param {Number} cellIndex
55449 * @param {Roo.EventObject} e
55451 "cellcontextmenu" : true,
55453 * @event headercontextmenu
55454 * Fires when a header is right clicked
55455 * @param {Grid} this
55456 * @param {Number} columnIndex
55457 * @param {Roo.EventObject} e
55459 "headercontextmenu" : true,
55461 * @event bodyscroll
55462 * Fires when the body element is scrolled
55463 * @param {Number} scrollLeft
55464 * @param {Number} scrollTop
55466 "bodyscroll" : true,
55468 * @event columnresize
55469 * Fires when the user resizes a column
55470 * @param {Number} columnIndex
55471 * @param {Number} newSize
55473 "columnresize" : true,
55475 * @event columnmove
55476 * Fires when the user moves a column
55477 * @param {Number} oldIndex
55478 * @param {Number} newIndex
55480 "columnmove" : true,
55483 * Fires when row(s) start being dragged
55484 * @param {Grid} this
55485 * @param {Roo.GridDD} dd The drag drop object
55486 * @param {event} e The raw browser event
55488 "startdrag" : true,
55491 * Fires when a drag operation is complete
55492 * @param {Grid} this
55493 * @param {Roo.GridDD} dd The drag drop object
55494 * @param {event} e The raw browser event
55499 * Fires when dragged row(s) are dropped on a valid DD target
55500 * @param {Grid} this
55501 * @param {Roo.GridDD} dd The drag drop object
55502 * @param {String} targetId The target drag drop object
55503 * @param {event} e The raw browser event
55508 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
55509 * @param {Grid} this
55510 * @param {Roo.GridDD} dd The drag drop object
55511 * @param {String} targetId The target drag drop object
55512 * @param {event} e The raw browser event
55517 * Fires when the dragged row(s) first cross another DD target while being dragged
55518 * @param {Grid} this
55519 * @param {Roo.GridDD} dd The drag drop object
55520 * @param {String} targetId The target drag drop object
55521 * @param {event} e The raw browser event
55523 "dragenter" : true,
55526 * Fires when the dragged row(s) leave another DD target while being dragged
55527 * @param {Grid} this
55528 * @param {Roo.GridDD} dd The drag drop object
55529 * @param {String} targetId The target drag drop object
55530 * @param {event} e The raw browser event
55535 * Fires when a row is rendered, so you can change add a style to it.
55536 * @param {GridView} gridview The grid view
55537 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
55543 * Fires when the grid is rendered
55544 * @param {Grid} grid
55549 Roo.grid.Grid.superclass.constructor.call(this);
55551 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
55554 * @cfg {String} ddGroup - drag drop group.
55557 * @cfg {String} dragGroup - drag group (?? not sure if needed.)
55561 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
55563 minColumnWidth : 25,
55566 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
55567 * <b>on initial render.</b> It is more efficient to explicitly size the columns
55568 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
55570 autoSizeColumns : false,
55573 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
55575 autoSizeHeaders : true,
55578 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
55580 monitorWindowResize : true,
55583 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
55584 * rows measured to get a columns size. Default is 0 (all rows).
55586 maxRowsToMeasure : 0,
55589 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
55591 trackMouseOver : true,
55594 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
55597 * @cfg {Boolean} enableDrop True to enable drop of elements. Default is false. (double check if this is needed?)
55601 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
55603 enableDragDrop : false,
55606 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
55608 enableColumnMove : true,
55611 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
55613 enableColumnHide : true,
55616 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
55618 enableRowHeightSync : false,
55621 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
55626 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
55628 autoHeight : false,
55631 * @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.
55633 autoExpandColumn : false,
55636 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
55639 autoExpandMin : 50,
55642 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
55644 autoExpandMax : 1000,
55647 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
55652 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
55656 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
55666 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
55667 * of a fixed width. Default is false.
55670 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
55675 * @cfg {String} ddText Configures the text is the drag proxy (defaults to "%0 selected row(s)").
55676 * %0 is replaced with the number of selected rows.
55678 ddText : "{0} selected row{1}",
55682 * Called once after all setup has been completed and the grid is ready to be rendered.
55683 * @return {Roo.grid.Grid} this
55685 render : function()
55687 var c = this.container;
55688 // try to detect autoHeight/width mode
55689 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
55690 this.autoHeight = true;
55692 var view = this.getView();
55695 c.on("click", this.onClick, this);
55696 c.on("dblclick", this.onDblClick, this);
55697 c.on("contextmenu", this.onContextMenu, this);
55698 c.on("keydown", this.onKeyDown, this);
55700 c.on("touchstart", this.onTouchStart, this);
55703 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
55705 this.getSelectionModel().init(this);
55710 this.loadMask = new Roo.LoadMask(this.container,
55711 Roo.apply({store:this.dataSource}, this.loadMask));
55715 if (this.toolbar && this.toolbar.xtype) {
55716 this.toolbar.container = this.getView().getHeaderPanel(true);
55717 this.toolbar = new Roo.Toolbar(this.toolbar);
55719 if (this.footer && this.footer.xtype) {
55720 this.footer.dataSource = this.getDataSource();
55721 this.footer.container = this.getView().getFooterPanel(true);
55722 this.footer = Roo.factory(this.footer, Roo);
55724 if (this.dropTarget && this.dropTarget.xtype) {
55725 delete this.dropTarget.xtype;
55726 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
55730 this.rendered = true;
55731 this.fireEvent('render', this);
55736 * Reconfigures the grid to use a different Store and Column Model.
55737 * The View will be bound to the new objects and refreshed.
55738 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
55739 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
55741 reconfigure : function(dataSource, colModel){
55743 this.loadMask.destroy();
55744 this.loadMask = new Roo.LoadMask(this.container,
55745 Roo.apply({store:dataSource}, this.loadMask));
55747 this.view.bind(dataSource, colModel);
55748 this.dataSource = dataSource;
55749 this.colModel = colModel;
55750 this.view.refresh(true);
55754 * Add's a column, default at the end..
55756 * @param {int} position to add (default end)
55757 * @param {Array} of objects of column configuration see {@link Roo.grid.ColumnModel}
55759 addColumns : function(pos, ar)
55762 for (var i =0;i< ar.length;i++) {
55764 cfg.id = typeof(cfg.id) == 'undefined' ? Roo.id() : cfg.id; // don't normally use this..
55765 this.cm.lookup[cfg.id] = cfg;
55769 if (typeof(pos) == 'undefined' || pos >= this.cm.config.length) {
55770 pos = this.cm.config.length; //this.cm.config.push(cfg);
55772 pos = Math.max(0,pos);
55775 this.cm.config.splice.apply(this.cm.config, ar);
55779 this.view.generateRules(this.cm);
55780 this.view.refresh(true);
55788 onKeyDown : function(e){
55789 this.fireEvent("keydown", e);
55793 * Destroy this grid.
55794 * @param {Boolean} removeEl True to remove the element
55796 destroy : function(removeEl, keepListeners){
55798 this.loadMask.destroy();
55800 var c = this.container;
55801 c.removeAllListeners();
55802 this.view.destroy();
55803 this.colModel.purgeListeners();
55804 if(!keepListeners){
55805 this.purgeListeners();
55808 if(removeEl === true){
55814 processEvent : function(name, e){
55815 // does this fire select???
55816 //Roo.log('grid:processEvent ' + name);
55818 if (name != 'touchstart' ) {
55819 this.fireEvent(name, e);
55822 var t = e.getTarget();
55824 var header = v.findHeaderIndex(t);
55825 if(header !== false){
55826 var ename = name == 'touchstart' ? 'click' : name;
55828 this.fireEvent("header" + ename, this, header, e);
55830 var row = v.findRowIndex(t);
55831 var cell = v.findCellIndex(t);
55832 if (name == 'touchstart') {
55833 // first touch is always a click.
55834 // hopefull this happens after selection is updated.?
55837 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
55838 var cs = this.selModel.getSelectedCell();
55839 if (row == cs[0] && cell == cs[1]){
55843 if (typeof(this.selModel.getSelections) != 'undefined') {
55844 var cs = this.selModel.getSelections();
55845 var ds = this.dataSource;
55846 if (cs.length == 1 && ds.getAt(row) == cs[0]){
55857 this.fireEvent("row" + name, this, row, e);
55858 if(cell !== false){
55859 this.fireEvent("cell" + name, this, row, cell, e);
55866 onClick : function(e){
55867 this.processEvent("click", e);
55870 onTouchStart : function(e){
55871 this.processEvent("touchstart", e);
55875 onContextMenu : function(e, t){
55876 this.processEvent("contextmenu", e);
55880 onDblClick : function(e){
55881 this.processEvent("dblclick", e);
55885 walkCells : function(row, col, step, fn, scope){
55886 var cm = this.colModel, clen = cm.getColumnCount();
55887 var ds = this.dataSource, rlen = ds.getCount(), first = true;
55899 if(fn.call(scope || this, row, col, cm) === true){
55917 if(fn.call(scope || this, row, col, cm) === true){
55929 getSelections : function(){
55930 return this.selModel.getSelections();
55934 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
55935 * but if manual update is required this method will initiate it.
55937 autoSize : function(){
55939 this.view.layout();
55940 if(this.view.adjustForScroll){
55941 this.view.adjustForScroll();
55947 * Returns the grid's underlying element.
55948 * @return {Element} The element
55950 getGridEl : function(){
55951 return this.container;
55954 // private for compatibility, overridden by editor grid
55955 stopEditing : function(){},
55958 * Returns the grid's SelectionModel.
55959 * @return {SelectionModel}
55961 getSelectionModel : function(){
55962 if(!this.selModel){
55963 this.selModel = new Roo.grid.RowSelectionModel();
55965 return this.selModel;
55969 * Returns the grid's DataSource.
55970 * @return {DataSource}
55972 getDataSource : function(){
55973 return this.dataSource;
55977 * Returns the grid's ColumnModel.
55978 * @return {ColumnModel}
55980 getColumnModel : function(){
55981 return this.colModel;
55985 * Returns the grid's GridView object.
55986 * @return {GridView}
55988 getView : function(){
55990 this.view = new Roo.grid.GridView(this.viewConfig);
55991 this.relayEvents(this.view, [
55992 "beforerowremoved", "beforerowsinserted",
55993 "beforerefresh", "rowremoved",
55994 "rowsinserted", "rowupdated" ,"refresh"
56000 * Called to get grid's drag proxy text, by default returns this.ddText.
56001 * Override this to put something different in the dragged text.
56004 getDragDropText : function(){
56005 var count = this.selModel.getCount();
56006 return String.format(this.ddText, count, count == 1 ? '' : 's');
56011 * Ext JS Library 1.1.1
56012 * Copyright(c) 2006-2007, Ext JS, LLC.
56014 * Originally Released Under LGPL - original licence link has changed is not relivant.
56017 * <script type="text/javascript">
56020 Roo.grid.AbstractGridView = function(){
56024 "beforerowremoved" : true,
56025 "beforerowsinserted" : true,
56026 "beforerefresh" : true,
56027 "rowremoved" : true,
56028 "rowsinserted" : true,
56029 "rowupdated" : true,
56032 Roo.grid.AbstractGridView.superclass.constructor.call(this);
56035 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
56036 rowClass : "x-grid-row",
56037 cellClass : "x-grid-cell",
56038 tdClass : "x-grid-td",
56039 hdClass : "x-grid-hd",
56040 splitClass : "x-grid-hd-split",
56042 init: function(grid){
56044 var cid = this.grid.getGridEl().id;
56045 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
56046 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
56047 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
56048 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
56051 getColumnRenderers : function(){
56052 var renderers = [];
56053 var cm = this.grid.colModel;
56054 var colCount = cm.getColumnCount();
56055 for(var i = 0; i < colCount; i++){
56056 renderers[i] = cm.getRenderer(i);
56061 getColumnIds : function(){
56063 var cm = this.grid.colModel;
56064 var colCount = cm.getColumnCount();
56065 for(var i = 0; i < colCount; i++){
56066 ids[i] = cm.getColumnId(i);
56071 getDataIndexes : function(){
56072 if(!this.indexMap){
56073 this.indexMap = this.buildIndexMap();
56075 return this.indexMap.colToData;
56078 getColumnIndexByDataIndex : function(dataIndex){
56079 if(!this.indexMap){
56080 this.indexMap = this.buildIndexMap();
56082 return this.indexMap.dataToCol[dataIndex];
56086 * Set a css style for a column dynamically.
56087 * @param {Number} colIndex The index of the column
56088 * @param {String} name The css property name
56089 * @param {String} value The css value
56091 setCSSStyle : function(colIndex, name, value){
56092 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
56093 Roo.util.CSS.updateRule(selector, name, value);
56096 generateRules : function(cm){
56097 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
56098 Roo.util.CSS.removeStyleSheet(rulesId);
56099 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56100 var cid = cm.getColumnId(i);
56101 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
56102 this.tdSelector, cid, " {\n}\n",
56103 this.hdSelector, cid, " {\n}\n",
56104 this.splitSelector, cid, " {\n}\n");
56106 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56110 * Ext JS Library 1.1.1
56111 * Copyright(c) 2006-2007, Ext JS, LLC.
56113 * Originally Released Under LGPL - original licence link has changed is not relivant.
56116 * <script type="text/javascript">
56120 // This is a support class used internally by the Grid components
56121 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
56123 this.view = grid.getView();
56124 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56125 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
56127 this.setHandleElId(Roo.id(hd));
56128 this.setOuterHandleElId(Roo.id(hd2));
56130 this.scroll = false;
56132 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
56134 getDragData : function(e){
56135 var t = Roo.lib.Event.getTarget(e);
56136 var h = this.view.findHeaderCell(t);
56138 return {ddel: h.firstChild, header:h};
56143 onInitDrag : function(e){
56144 this.view.headersDisabled = true;
56145 var clone = this.dragData.ddel.cloneNode(true);
56146 clone.id = Roo.id();
56147 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
56148 this.proxy.update(clone);
56152 afterValidDrop : function(){
56154 setTimeout(function(){
56155 v.headersDisabled = false;
56159 afterInvalidDrop : function(){
56161 setTimeout(function(){
56162 v.headersDisabled = false;
56168 * Ext JS Library 1.1.1
56169 * Copyright(c) 2006-2007, Ext JS, LLC.
56171 * Originally Released Under LGPL - original licence link has changed is not relivant.
56174 * <script type="text/javascript">
56177 // This is a support class used internally by the Grid components
56178 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
56180 this.view = grid.getView();
56181 // split the proxies so they don't interfere with mouse events
56182 this.proxyTop = Roo.DomHelper.append(document.body, {
56183 cls:"col-move-top", html:" "
56185 this.proxyBottom = Roo.DomHelper.append(document.body, {
56186 cls:"col-move-bottom", html:" "
56188 this.proxyTop.hide = this.proxyBottom.hide = function(){
56189 this.setLeftTop(-100,-100);
56190 this.setStyle("visibility", "hidden");
56192 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
56193 // temporarily disabled
56194 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
56195 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
56197 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
56198 proxyOffsets : [-4, -9],
56199 fly: Roo.Element.fly,
56201 getTargetFromEvent : function(e){
56202 var t = Roo.lib.Event.getTarget(e);
56203 var cindex = this.view.findCellIndex(t);
56204 if(cindex !== false){
56205 return this.view.getHeaderCell(cindex);
56210 nextVisible : function(h){
56211 var v = this.view, cm = this.grid.colModel;
56214 if(!cm.isHidden(v.getCellIndex(h))){
56222 prevVisible : function(h){
56223 var v = this.view, cm = this.grid.colModel;
56226 if(!cm.isHidden(v.getCellIndex(h))){
56234 positionIndicator : function(h, n, e){
56235 var x = Roo.lib.Event.getPageX(e);
56236 var r = Roo.lib.Dom.getRegion(n.firstChild);
56237 var px, pt, py = r.top + this.proxyOffsets[1];
56238 if((r.right - x) <= (r.right-r.left)/2){
56239 px = r.right+this.view.borderWidth;
56245 var oldIndex = this.view.getCellIndex(h);
56246 var newIndex = this.view.getCellIndex(n);
56248 if(this.grid.colModel.isFixed(newIndex)){
56252 var locked = this.grid.colModel.isLocked(newIndex);
56257 if(oldIndex < newIndex){
56260 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
56263 px += this.proxyOffsets[0];
56264 this.proxyTop.setLeftTop(px, py);
56265 this.proxyTop.show();
56266 if(!this.bottomOffset){
56267 this.bottomOffset = this.view.mainHd.getHeight();
56269 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
56270 this.proxyBottom.show();
56274 onNodeEnter : function(n, dd, e, data){
56275 if(data.header != n){
56276 this.positionIndicator(data.header, n, e);
56280 onNodeOver : function(n, dd, e, data){
56281 var result = false;
56282 if(data.header != n){
56283 result = this.positionIndicator(data.header, n, e);
56286 this.proxyTop.hide();
56287 this.proxyBottom.hide();
56289 return result ? this.dropAllowed : this.dropNotAllowed;
56292 onNodeOut : function(n, dd, e, data){
56293 this.proxyTop.hide();
56294 this.proxyBottom.hide();
56297 onNodeDrop : function(n, dd, e, data){
56298 var h = data.header;
56300 var cm = this.grid.colModel;
56301 var x = Roo.lib.Event.getPageX(e);
56302 var r = Roo.lib.Dom.getRegion(n.firstChild);
56303 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
56304 var oldIndex = this.view.getCellIndex(h);
56305 var newIndex = this.view.getCellIndex(n);
56306 var locked = cm.isLocked(newIndex);
56310 if(oldIndex < newIndex){
56313 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
56316 cm.setLocked(oldIndex, locked, true);
56317 cm.moveColumn(oldIndex, newIndex);
56318 this.grid.fireEvent("columnmove", oldIndex, newIndex);
56326 * Ext JS Library 1.1.1
56327 * Copyright(c) 2006-2007, Ext JS, LLC.
56329 * Originally Released Under LGPL - original licence link has changed is not relivant.
56332 * <script type="text/javascript">
56336 * @class Roo.grid.GridView
56337 * @extends Roo.util.Observable
56340 * @param {Object} config
56342 Roo.grid.GridView = function(config){
56343 Roo.grid.GridView.superclass.constructor.call(this);
56346 Roo.apply(this, config);
56349 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
56351 unselectable : 'unselectable="on"',
56352 unselectableCls : 'x-unselectable',
56355 rowClass : "x-grid-row",
56357 cellClass : "x-grid-col",
56359 tdClass : "x-grid-td",
56361 hdClass : "x-grid-hd",
56363 splitClass : "x-grid-split",
56365 sortClasses : ["sort-asc", "sort-desc"],
56367 enableMoveAnim : false,
56371 dh : Roo.DomHelper,
56373 fly : Roo.Element.fly,
56375 css : Roo.util.CSS,
56381 scrollIncrement : 22,
56383 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
56385 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
56387 bind : function(ds, cm){
56389 this.ds.un("load", this.onLoad, this);
56390 this.ds.un("datachanged", this.onDataChange, this);
56391 this.ds.un("add", this.onAdd, this);
56392 this.ds.un("remove", this.onRemove, this);
56393 this.ds.un("update", this.onUpdate, this);
56394 this.ds.un("clear", this.onClear, this);
56397 ds.on("load", this.onLoad, this);
56398 ds.on("datachanged", this.onDataChange, this);
56399 ds.on("add", this.onAdd, this);
56400 ds.on("remove", this.onRemove, this);
56401 ds.on("update", this.onUpdate, this);
56402 ds.on("clear", this.onClear, this);
56407 this.cm.un("widthchange", this.onColWidthChange, this);
56408 this.cm.un("headerchange", this.onHeaderChange, this);
56409 this.cm.un("hiddenchange", this.onHiddenChange, this);
56410 this.cm.un("columnmoved", this.onColumnMove, this);
56411 this.cm.un("columnlockchange", this.onColumnLock, this);
56414 this.generateRules(cm);
56415 cm.on("widthchange", this.onColWidthChange, this);
56416 cm.on("headerchange", this.onHeaderChange, this);
56417 cm.on("hiddenchange", this.onHiddenChange, this);
56418 cm.on("columnmoved", this.onColumnMove, this);
56419 cm.on("columnlockchange", this.onColumnLock, this);
56424 init: function(grid){
56425 Roo.grid.GridView.superclass.init.call(this, grid);
56427 this.bind(grid.dataSource, grid.colModel);
56429 grid.on("headerclick", this.handleHeaderClick, this);
56431 if(grid.trackMouseOver){
56432 grid.on("mouseover", this.onRowOver, this);
56433 grid.on("mouseout", this.onRowOut, this);
56435 grid.cancelTextSelection = function(){};
56436 this.gridId = grid.id;
56438 var tpls = this.templates || {};
56441 tpls.master = new Roo.Template(
56442 '<div class="x-grid" hidefocus="true">',
56443 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
56444 '<div class="x-grid-topbar"></div>',
56445 '<div class="x-grid-scroller"><div></div></div>',
56446 '<div class="x-grid-locked">',
56447 '<div class="x-grid-header">{lockedHeader}</div>',
56448 '<div class="x-grid-body">{lockedBody}</div>',
56450 '<div class="x-grid-viewport">',
56451 '<div class="x-grid-header">{header}</div>',
56452 '<div class="x-grid-body">{body}</div>',
56454 '<div class="x-grid-bottombar"></div>',
56456 '<div class="x-grid-resize-proxy"> </div>',
56459 tpls.master.disableformats = true;
56463 tpls.header = new Roo.Template(
56464 '<table border="0" cellspacing="0" cellpadding="0">',
56465 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
56468 tpls.header.disableformats = true;
56470 tpls.header.compile();
56473 tpls.hcell = new Roo.Template(
56474 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
56475 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
56478 tpls.hcell.disableFormats = true;
56480 tpls.hcell.compile();
56483 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
56484 this.unselectableCls + '" ' + this.unselectable +'> </div>');
56485 tpls.hsplit.disableFormats = true;
56487 tpls.hsplit.compile();
56490 tpls.body = new Roo.Template(
56491 '<table border="0" cellspacing="0" cellpadding="0">',
56492 "<tbody>{rows}</tbody>",
56495 tpls.body.disableFormats = true;
56497 tpls.body.compile();
56500 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
56501 tpls.row.disableFormats = true;
56503 tpls.row.compile();
56506 tpls.cell = new Roo.Template(
56507 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
56508 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
56509 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
56512 tpls.cell.disableFormats = true;
56514 tpls.cell.compile();
56516 this.templates = tpls;
56519 // remap these for backwards compat
56520 onColWidthChange : function(){
56521 this.updateColumns.apply(this, arguments);
56523 onHeaderChange : function(){
56524 this.updateHeaders.apply(this, arguments);
56526 onHiddenChange : function(){
56527 this.handleHiddenChange.apply(this, arguments);
56529 onColumnMove : function(){
56530 this.handleColumnMove.apply(this, arguments);
56532 onColumnLock : function(){
56533 this.handleLockChange.apply(this, arguments);
56536 onDataChange : function(){
56538 this.updateHeaderSortState();
56541 onClear : function(){
56545 onUpdate : function(ds, record){
56546 this.refreshRow(record);
56549 refreshRow : function(record){
56550 var ds = this.ds, index;
56551 if(typeof record == 'number'){
56553 record = ds.getAt(index);
56555 index = ds.indexOf(record);
56557 this.insertRows(ds, index, index, true);
56558 this.onRemove(ds, record, index+1, true);
56559 this.syncRowHeights(index, index);
56561 this.fireEvent("rowupdated", this, index, record);
56564 onAdd : function(ds, records, index){
56565 this.insertRows(ds, index, index + (records.length-1));
56568 onRemove : function(ds, record, index, isUpdate){
56569 if(isUpdate !== true){
56570 this.fireEvent("beforerowremoved", this, index, record);
56572 var bt = this.getBodyTable(), lt = this.getLockedTable();
56573 if(bt.rows[index]){
56574 bt.firstChild.removeChild(bt.rows[index]);
56576 if(lt.rows[index]){
56577 lt.firstChild.removeChild(lt.rows[index]);
56579 if(isUpdate !== true){
56580 this.stripeRows(index);
56581 this.syncRowHeights(index, index);
56583 this.fireEvent("rowremoved", this, index, record);
56587 onLoad : function(){
56588 this.scrollToTop();
56592 * Scrolls the grid to the top
56594 scrollToTop : function(){
56596 this.scroller.dom.scrollTop = 0;
56602 * Gets a panel in the header of the grid that can be used for toolbars etc.
56603 * After modifying the contents of this panel a call to grid.autoSize() may be
56604 * required to register any changes in size.
56605 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
56606 * @return Roo.Element
56608 getHeaderPanel : function(doShow){
56610 this.headerPanel.show();
56612 return this.headerPanel;
56616 * Gets a panel in the footer of the grid that can be used for toolbars etc.
56617 * After modifying the contents of this panel a call to grid.autoSize() may be
56618 * required to register any changes in size.
56619 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
56620 * @return Roo.Element
56622 getFooterPanel : function(doShow){
56624 this.footerPanel.show();
56626 return this.footerPanel;
56629 initElements : function(){
56630 var E = Roo.Element;
56631 var el = this.grid.getGridEl().dom.firstChild;
56632 var cs = el.childNodes;
56634 this.el = new E(el);
56636 this.focusEl = new E(el.firstChild);
56637 this.focusEl.swallowEvent("click", true);
56639 this.headerPanel = new E(cs[1]);
56640 this.headerPanel.enableDisplayMode("block");
56642 this.scroller = new E(cs[2]);
56643 this.scrollSizer = new E(this.scroller.dom.firstChild);
56645 this.lockedWrap = new E(cs[3]);
56646 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
56647 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
56649 this.mainWrap = new E(cs[4]);
56650 this.mainHd = new E(this.mainWrap.dom.firstChild);
56651 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
56653 this.footerPanel = new E(cs[5]);
56654 this.footerPanel.enableDisplayMode("block");
56656 this.resizeProxy = new E(cs[6]);
56658 this.headerSelector = String.format(
56659 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
56660 this.lockedHd.id, this.mainHd.id
56663 this.splitterSelector = String.format(
56664 '#{0} div.x-grid-split, #{1} div.x-grid-split',
56665 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
56668 idToCssName : function(s)
56670 return s.replace(/[^a-z0-9]+/ig, '-');
56673 getHeaderCell : function(index){
56674 return Roo.DomQuery.select(this.headerSelector)[index];
56677 getHeaderCellMeasure : function(index){
56678 return this.getHeaderCell(index).firstChild;
56681 getHeaderCellText : function(index){
56682 return this.getHeaderCell(index).firstChild.firstChild;
56685 getLockedTable : function(){
56686 return this.lockedBody.dom.firstChild;
56689 getBodyTable : function(){
56690 return this.mainBody.dom.firstChild;
56693 getLockedRow : function(index){
56694 return this.getLockedTable().rows[index];
56697 getRow : function(index){
56698 return this.getBodyTable().rows[index];
56701 getRowComposite : function(index){
56703 this.rowEl = new Roo.CompositeElementLite();
56705 var els = [], lrow, mrow;
56706 if(lrow = this.getLockedRow(index)){
56709 if(mrow = this.getRow(index)){
56712 this.rowEl.elements = els;
56716 * Gets the 'td' of the cell
56718 * @param {Integer} rowIndex row to select
56719 * @param {Integer} colIndex column to select
56723 getCell : function(rowIndex, colIndex){
56724 var locked = this.cm.getLockedCount();
56726 if(colIndex < locked){
56727 source = this.lockedBody.dom.firstChild;
56729 source = this.mainBody.dom.firstChild;
56730 colIndex -= locked;
56732 return source.rows[rowIndex].childNodes[colIndex];
56735 getCellText : function(rowIndex, colIndex){
56736 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
56739 getCellBox : function(cell){
56740 var b = this.fly(cell).getBox();
56741 if(Roo.isOpera){ // opera fails to report the Y
56742 b.y = cell.offsetTop + this.mainBody.getY();
56747 getCellIndex : function(cell){
56748 var id = String(cell.className).match(this.cellRE);
56750 return parseInt(id[1], 10);
56755 findHeaderIndex : function(n){
56756 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56757 return r ? this.getCellIndex(r) : false;
56760 findHeaderCell : function(n){
56761 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
56762 return r ? r : false;
56765 findRowIndex : function(n){
56769 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
56770 return r ? r.rowIndex : false;
56773 findCellIndex : function(node){
56774 var stop = this.el.dom;
56775 while(node && node != stop){
56776 if(this.findRE.test(node.className)){
56777 return this.getCellIndex(node);
56779 node = node.parentNode;
56784 getColumnId : function(index){
56785 return this.cm.getColumnId(index);
56788 getSplitters : function()
56790 if(this.splitterSelector){
56791 return Roo.DomQuery.select(this.splitterSelector);
56797 getSplitter : function(index){
56798 return this.getSplitters()[index];
56801 onRowOver : function(e, t){
56803 if((row = this.findRowIndex(t)) !== false){
56804 this.getRowComposite(row).addClass("x-grid-row-over");
56808 onRowOut : function(e, t){
56810 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
56811 this.getRowComposite(row).removeClass("x-grid-row-over");
56815 renderHeaders : function(){
56817 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
56818 var cb = [], lb = [], sb = [], lsb = [], p = {};
56819 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56820 p.cellId = "x-grid-hd-0-" + i;
56821 p.splitId = "x-grid-csplit-0-" + i;
56822 p.id = cm.getColumnId(i);
56823 p.value = cm.getColumnHeader(i) || "";
56824 p.title = cm.getColumnTooltip(i) || (''+p.value).match(/\</) ? '' : p.value || "";
56825 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
56826 if(!cm.isLocked(i)){
56827 cb[cb.length] = ct.apply(p);
56828 sb[sb.length] = st.apply(p);
56830 lb[lb.length] = ct.apply(p);
56831 lsb[lsb.length] = st.apply(p);
56834 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
56835 ht.apply({cells: cb.join(""), splits:sb.join("")})];
56838 updateHeaders : function(){
56839 var html = this.renderHeaders();
56840 this.lockedHd.update(html[0]);
56841 this.mainHd.update(html[1]);
56845 * Focuses the specified row.
56846 * @param {Number} row The row index
56848 focusRow : function(row)
56850 //Roo.log('GridView.focusRow');
56851 var x = this.scroller.dom.scrollLeft;
56852 this.focusCell(row, 0, false);
56853 this.scroller.dom.scrollLeft = x;
56857 * Focuses the specified cell.
56858 * @param {Number} row The row index
56859 * @param {Number} col The column index
56860 * @param {Boolean} hscroll false to disable horizontal scrolling
56862 focusCell : function(row, col, hscroll)
56864 //Roo.log('GridView.focusCell');
56865 var el = this.ensureVisible(row, col, hscroll);
56866 this.focusEl.alignTo(el, "tl-tl");
56868 this.focusEl.focus();
56870 this.focusEl.focus.defer(1, this.focusEl);
56875 * Scrolls the specified cell into view
56876 * @param {Number} row The row index
56877 * @param {Number} col The column index
56878 * @param {Boolean} hscroll false to disable horizontal scrolling
56880 ensureVisible : function(row, col, hscroll)
56882 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
56883 //return null; //disable for testing.
56884 if(typeof row != "number"){
56885 row = row.rowIndex;
56887 if(row < 0 && row >= this.ds.getCount()){
56890 col = (col !== undefined ? col : 0);
56891 var cm = this.grid.colModel;
56892 while(cm.isHidden(col)){
56896 var el = this.getCell(row, col);
56900 var c = this.scroller.dom;
56902 var ctop = parseInt(el.offsetTop, 10);
56903 var cleft = parseInt(el.offsetLeft, 10);
56904 var cbot = ctop + el.offsetHeight;
56905 var cright = cleft + el.offsetWidth;
56907 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
56908 var stop = parseInt(c.scrollTop, 10);
56909 var sleft = parseInt(c.scrollLeft, 10);
56910 var sbot = stop + ch;
56911 var sright = sleft + c.clientWidth;
56913 Roo.log('GridView.ensureVisible:' +
56915 ' c.clientHeight:' + c.clientHeight +
56916 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
56924 c.scrollTop = ctop;
56925 //Roo.log("set scrolltop to ctop DISABLE?");
56926 }else if(cbot > sbot){
56927 //Roo.log("set scrolltop to cbot-ch");
56928 c.scrollTop = cbot-ch;
56931 if(hscroll !== false){
56933 c.scrollLeft = cleft;
56934 }else if(cright > sright){
56935 c.scrollLeft = cright-c.clientWidth;
56942 updateColumns : function(){
56943 this.grid.stopEditing();
56944 var cm = this.grid.colModel, colIds = this.getColumnIds();
56945 //var totalWidth = cm.getTotalWidth();
56947 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56948 //if(cm.isHidden(i)) continue;
56949 var w = cm.getColumnWidth(i);
56950 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56951 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
56953 this.updateSplitters();
56956 generateRules : function(cm){
56957 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
56958 Roo.util.CSS.removeStyleSheet(rulesId);
56959 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56960 var cid = cm.getColumnId(i);
56962 if(cm.config[i].align){
56963 align = 'text-align:'+cm.config[i].align+';';
56966 if(cm.isHidden(i)){
56967 hidden = 'display:none;';
56969 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
56971 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
56972 this.hdSelector, cid, " {\n", align, width, "}\n",
56973 this.tdSelector, cid, " {\n",hidden,"\n}\n",
56974 this.splitSelector, cid, " {\n", hidden , "\n}\n");
56976 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
56979 updateSplitters : function(){
56980 var cm = this.cm, s = this.getSplitters();
56981 if(s){ // splitters not created yet
56982 var pos = 0, locked = true;
56983 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
56984 if(cm.isHidden(i)) {
56987 var w = cm.getColumnWidth(i); // make sure it's a number
56988 if(!cm.isLocked(i) && locked){
56993 s[i].style.left = (pos-this.splitOffset) + "px";
56998 handleHiddenChange : function(colModel, colIndex, hidden){
57000 this.hideColumn(colIndex);
57002 this.unhideColumn(colIndex);
57006 hideColumn : function(colIndex){
57007 var cid = this.getColumnId(colIndex);
57008 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
57009 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
57011 this.updateHeaders();
57013 this.updateSplitters();
57017 unhideColumn : function(colIndex){
57018 var cid = this.getColumnId(colIndex);
57019 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
57020 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
57023 this.updateHeaders();
57025 this.updateSplitters();
57029 insertRows : function(dm, firstRow, lastRow, isUpdate){
57030 if(firstRow == 0 && lastRow == dm.getCount()-1){
57034 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
57036 var s = this.getScrollState();
57037 var markup = this.renderRows(firstRow, lastRow);
57038 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
57039 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
57040 this.restoreScroll(s);
57042 this.fireEvent("rowsinserted", this, firstRow, lastRow);
57043 this.syncRowHeights(firstRow, lastRow);
57044 this.stripeRows(firstRow);
57050 bufferRows : function(markup, target, index){
57051 var before = null, trows = target.rows, tbody = target.tBodies[0];
57052 if(index < trows.length){
57053 before = trows[index];
57055 var b = document.createElement("div");
57056 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
57057 var rows = b.firstChild.rows;
57058 for(var i = 0, len = rows.length; i < len; i++){
57060 tbody.insertBefore(rows[0], before);
57062 tbody.appendChild(rows[0]);
57069 deleteRows : function(dm, firstRow, lastRow){
57070 if(dm.getRowCount()<1){
57071 this.fireEvent("beforerefresh", this);
57072 this.mainBody.update("");
57073 this.lockedBody.update("");
57074 this.fireEvent("refresh", this);
57076 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
57077 var bt = this.getBodyTable();
57078 var tbody = bt.firstChild;
57079 var rows = bt.rows;
57080 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
57081 tbody.removeChild(rows[firstRow]);
57083 this.stripeRows(firstRow);
57084 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
57088 updateRows : function(dataSource, firstRow, lastRow){
57089 var s = this.getScrollState();
57091 this.restoreScroll(s);
57094 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
57098 this.updateHeaderSortState();
57101 getScrollState : function(){
57103 var sb = this.scroller.dom;
57104 return {left: sb.scrollLeft, top: sb.scrollTop};
57107 stripeRows : function(startRow){
57108 if(!this.grid.stripeRows || this.ds.getCount() < 1){
57111 startRow = startRow || 0;
57112 var rows = this.getBodyTable().rows;
57113 var lrows = this.getLockedTable().rows;
57114 var cls = ' x-grid-row-alt ';
57115 for(var i = startRow, len = rows.length; i < len; i++){
57116 var row = rows[i], lrow = lrows[i];
57117 var isAlt = ((i+1) % 2 == 0);
57118 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
57119 if(isAlt == hasAlt){
57123 row.className += " x-grid-row-alt";
57125 row.className = row.className.replace("x-grid-row-alt", "");
57128 lrow.className = row.className;
57133 restoreScroll : function(state){
57134 //Roo.log('GridView.restoreScroll');
57135 var sb = this.scroller.dom;
57136 sb.scrollLeft = state.left;
57137 sb.scrollTop = state.top;
57141 syncScroll : function(){
57142 //Roo.log('GridView.syncScroll');
57143 var sb = this.scroller.dom;
57144 var sh = this.mainHd.dom;
57145 var bs = this.mainBody.dom;
57146 var lv = this.lockedBody.dom;
57147 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
57148 lv.scrollTop = bs.scrollTop = sb.scrollTop;
57151 handleScroll : function(e){
57153 var sb = this.scroller.dom;
57154 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
57158 handleWheel : function(e){
57159 var d = e.getWheelDelta();
57160 this.scroller.dom.scrollTop -= d*22;
57161 // set this here to prevent jumpy scrolling on large tables
57162 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
57166 renderRows : function(startRow, endRow){
57167 // pull in all the crap needed to render rows
57168 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
57169 var colCount = cm.getColumnCount();
57171 if(ds.getCount() < 1){
57175 // build a map for all the columns
57177 for(var i = 0; i < colCount; i++){
57178 var name = cm.getDataIndex(i);
57180 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
57181 renderer : cm.getRenderer(i),
57182 id : cm.getColumnId(i),
57183 locked : cm.isLocked(i),
57184 has_editor : cm.isCellEditable(i)
57188 startRow = startRow || 0;
57189 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
57191 // records to render
57192 var rs = ds.getRange(startRow, endRow);
57194 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
57197 // As much as I hate to duplicate code, this was branched because FireFox really hates
57198 // [].join("") on strings. The performance difference was substantial enough to
57199 // branch this function
57200 doRender : Roo.isGecko ?
57201 function(cs, rs, ds, startRow, colCount, stripe){
57202 var ts = this.templates, ct = ts.cell, rt = ts.row;
57204 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57206 var hasListener = this.grid.hasListener('rowclass');
57208 for(var j = 0, len = rs.length; j < len; j++){
57209 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
57210 for(var i = 0; i < colCount; i++){
57212 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57214 p.css = p.attr = "";
57215 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57216 if(p.value == undefined || p.value === "") {
57217 p.value = " ";
57220 p.css += ' x-grid-editable-cell';
57222 if(c.dirty && typeof r.modified[c.name] !== 'undefined'){
57223 p.css += ' x-grid-dirty-cell';
57225 var markup = ct.apply(p);
57233 if(stripe && ((rowIndex+1) % 2 == 0)){
57234 alt.push("x-grid-row-alt")
57237 alt.push( " x-grid-dirty-row");
57240 if(this.getRowClass){
57241 alt.push(this.getRowClass(r, rowIndex));
57247 rowIndex : rowIndex,
57250 this.grid.fireEvent('rowclass', this, rowcfg);
57251 alt.push(rowcfg.rowClass);
57253 rp.alt = alt.join(" ");
57254 lbuf+= rt.apply(rp);
57256 buf+= rt.apply(rp);
57258 return [lbuf, buf];
57260 function(cs, rs, ds, startRow, colCount, stripe){
57261 var ts = this.templates, ct = ts.cell, rt = ts.row;
57263 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
57264 var hasListener = this.grid.hasListener('rowclass');
57267 for(var j = 0, len = rs.length; j < len; j++){
57268 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
57269 for(var i = 0; i < colCount; i++){
57271 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
57273 p.css = p.attr = "";
57274 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
57275 if(p.value == undefined || p.value === "") {
57276 p.value = " ";
57280 p.css += ' x-grid-editable-cell';
57282 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
57283 p.css += ' x-grid-dirty-cell'
57286 var markup = ct.apply(p);
57288 cb[cb.length] = markup;
57290 lcb[lcb.length] = markup;
57294 if(stripe && ((rowIndex+1) % 2 == 0)){
57295 alt.push( "x-grid-row-alt");
57298 alt.push(" x-grid-dirty-row");
57301 if(this.getRowClass){
57302 alt.push( this.getRowClass(r, rowIndex));
57308 rowIndex : rowIndex,
57311 this.grid.fireEvent('rowclass', this, rowcfg);
57312 alt.push(rowcfg.rowClass);
57315 rp.alt = alt.join(" ");
57316 rp.cells = lcb.join("");
57317 lbuf[lbuf.length] = rt.apply(rp);
57318 rp.cells = cb.join("");
57319 buf[buf.length] = rt.apply(rp);
57321 return [lbuf.join(""), buf.join("")];
57324 renderBody : function(){
57325 var markup = this.renderRows();
57326 var bt = this.templates.body;
57327 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
57331 * Refreshes the grid
57332 * @param {Boolean} headersToo
57334 refresh : function(headersToo){
57335 this.fireEvent("beforerefresh", this);
57336 this.grid.stopEditing();
57337 var result = this.renderBody();
57338 this.lockedBody.update(result[0]);
57339 this.mainBody.update(result[1]);
57340 if(headersToo === true){
57341 this.updateHeaders();
57342 this.updateColumns();
57343 this.updateSplitters();
57344 this.updateHeaderSortState();
57346 this.syncRowHeights();
57348 this.fireEvent("refresh", this);
57351 handleColumnMove : function(cm, oldIndex, newIndex){
57352 this.indexMap = null;
57353 var s = this.getScrollState();
57354 this.refresh(true);
57355 this.restoreScroll(s);
57356 this.afterMove(newIndex);
57359 afterMove : function(colIndex){
57360 if(this.enableMoveAnim && Roo.enableFx){
57361 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
57363 // if multisort - fix sortOrder, and reload..
57364 if (this.grid.dataSource.multiSort) {
57365 // the we can call sort again..
57366 var dm = this.grid.dataSource;
57367 var cm = this.grid.colModel;
57369 for(var i = 0; i < cm.config.length; i++ ) {
57371 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
57372 continue; // dont' bother, it's not in sort list or being set.
57375 so.push(cm.config[i].dataIndex);
57378 dm.load(dm.lastOptions);
57385 updateCell : function(dm, rowIndex, dataIndex){
57386 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
57387 if(typeof colIndex == "undefined"){ // not present in grid
57390 var cm = this.grid.colModel;
57391 var cell = this.getCell(rowIndex, colIndex);
57392 var cellText = this.getCellText(rowIndex, colIndex);
57395 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
57396 id : cm.getColumnId(colIndex),
57397 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
57399 var renderer = cm.getRenderer(colIndex);
57400 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
57401 if(typeof val == "undefined" || val === "") {
57404 cellText.innerHTML = val;
57405 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
57406 this.syncRowHeights(rowIndex, rowIndex);
57409 calcColumnWidth : function(colIndex, maxRowsToMeasure){
57411 if(this.grid.autoSizeHeaders){
57412 var h = this.getHeaderCellMeasure(colIndex);
57413 maxWidth = Math.max(maxWidth, h.scrollWidth);
57416 if(this.cm.isLocked(colIndex)){
57417 tb = this.getLockedTable();
57420 tb = this.getBodyTable();
57421 index = colIndex - this.cm.getLockedCount();
57424 var rows = tb.rows;
57425 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
57426 for(var i = 0; i < stopIndex; i++){
57427 var cell = rows[i].childNodes[index].firstChild;
57428 maxWidth = Math.max(maxWidth, cell.scrollWidth);
57431 return maxWidth + /*margin for error in IE*/ 5;
57434 * Autofit a column to its content.
57435 * @param {Number} colIndex
57436 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
57438 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
57439 if(this.cm.isHidden(colIndex)){
57440 return; // can't calc a hidden column
57443 var cid = this.cm.getColumnId(colIndex);
57444 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
57445 if(this.grid.autoSizeHeaders){
57446 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
57449 var newWidth = this.calcColumnWidth(colIndex);
57450 this.cm.setColumnWidth(colIndex,
57451 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
57452 if(!suppressEvent){
57453 this.grid.fireEvent("columnresize", colIndex, newWidth);
57458 * Autofits all columns to their content and then expands to fit any extra space in the grid
57460 autoSizeColumns : function(){
57461 var cm = this.grid.colModel;
57462 var colCount = cm.getColumnCount();
57463 for(var i = 0; i < colCount; i++){
57464 this.autoSizeColumn(i, true, true);
57466 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
57469 this.updateColumns();
57475 * Autofits all columns to the grid's width proportionate with their current size
57476 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
57478 fitColumns : function(reserveScrollSpace){
57479 var cm = this.grid.colModel;
57480 var colCount = cm.getColumnCount();
57484 for (i = 0; i < colCount; i++){
57485 if(!cm.isHidden(i) && !cm.isFixed(i)){
57486 w = cm.getColumnWidth(i);
57492 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
57493 if(reserveScrollSpace){
57496 var frac = (avail - cm.getTotalWidth())/width;
57497 while (cols.length){
57500 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
57502 this.updateColumns();
57506 onRowSelect : function(rowIndex){
57507 var row = this.getRowComposite(rowIndex);
57508 row.addClass("x-grid-row-selected");
57511 onRowDeselect : function(rowIndex){
57512 var row = this.getRowComposite(rowIndex);
57513 row.removeClass("x-grid-row-selected");
57516 onCellSelect : function(row, col){
57517 var cell = this.getCell(row, col);
57519 Roo.fly(cell).addClass("x-grid-cell-selected");
57523 onCellDeselect : function(row, col){
57524 var cell = this.getCell(row, col);
57526 Roo.fly(cell).removeClass("x-grid-cell-selected");
57530 updateHeaderSortState : function(){
57532 // sort state can be single { field: xxx, direction : yyy}
57533 // or { xxx=>ASC , yyy : DESC ..... }
57536 if (!this.ds.multiSort) {
57537 var state = this.ds.getSortState();
57541 mstate[state.field] = state.direction;
57542 // FIXME... - this is not used here.. but might be elsewhere..
57543 this.sortState = state;
57546 mstate = this.ds.sortToggle;
57548 //remove existing sort classes..
57550 var sc = this.sortClasses;
57551 var hds = this.el.select(this.headerSelector).removeClass(sc);
57553 for(var f in mstate) {
57555 var sortColumn = this.cm.findColumnIndex(f);
57557 if(sortColumn != -1){
57558 var sortDir = mstate[f];
57559 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
57568 handleHeaderClick : function(g, index,e){
57570 Roo.log("header click");
57573 // touch events on header are handled by context
57574 this.handleHdCtx(g,index,e);
57579 if(this.headersDisabled){
57582 var dm = g.dataSource, cm = g.colModel;
57583 if(!cm.isSortable(index)){
57588 if (dm.multiSort) {
57589 // update the sortOrder
57591 for(var i = 0; i < cm.config.length; i++ ) {
57593 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
57594 continue; // dont' bother, it's not in sort list or being set.
57597 so.push(cm.config[i].dataIndex);
57603 dm.sort(cm.getDataIndex(index));
57607 destroy : function(){
57609 this.colMenu.removeAll();
57610 Roo.menu.MenuMgr.unregister(this.colMenu);
57611 this.colMenu.getEl().remove();
57612 delete this.colMenu;
57615 this.hmenu.removeAll();
57616 Roo.menu.MenuMgr.unregister(this.hmenu);
57617 this.hmenu.getEl().remove();
57620 if(this.grid.enableColumnMove){
57621 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57623 for(var dd in dds){
57624 if(!dds[dd].config.isTarget && dds[dd].dragElId){
57625 var elid = dds[dd].dragElId;
57627 Roo.get(elid).remove();
57628 } else if(dds[dd].config.isTarget){
57629 dds[dd].proxyTop.remove();
57630 dds[dd].proxyBottom.remove();
57633 if(Roo.dd.DDM.locationCache[dd]){
57634 delete Roo.dd.DDM.locationCache[dd];
57637 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
57640 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
57641 this.bind(null, null);
57642 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
57645 handleLockChange : function(){
57646 this.refresh(true);
57649 onDenyColumnLock : function(){
57653 onDenyColumnHide : function(){
57657 handleHdMenuClick : function(item){
57658 var index = this.hdCtxIndex;
57659 var cm = this.cm, ds = this.ds;
57662 ds.sort(cm.getDataIndex(index), "ASC");
57665 ds.sort(cm.getDataIndex(index), "DESC");
57668 var lc = cm.getLockedCount();
57669 if(cm.getColumnCount(true) <= lc+1){
57670 this.onDenyColumnLock();
57674 cm.setLocked(index, true, true);
57675 cm.moveColumn(index, lc);
57676 this.grid.fireEvent("columnmove", index, lc);
57678 cm.setLocked(index, true);
57682 var lc = cm.getLockedCount();
57683 if((lc-1) != index){
57684 cm.setLocked(index, false, true);
57685 cm.moveColumn(index, lc-1);
57686 this.grid.fireEvent("columnmove", index, lc-1);
57688 cm.setLocked(index, false);
57691 case 'wider': // used to expand cols on touch..
57693 var cw = cm.getColumnWidth(index);
57694 cw += (item.id == 'wider' ? 1 : -1) * 50;
57695 cw = Math.max(0, cw);
57696 cw = Math.min(cw,4000);
57697 cm.setColumnWidth(index, cw);
57701 index = cm.getIndexById(item.id.substr(4));
57703 if(item.checked && cm.getColumnCount(true) <= 1){
57704 this.onDenyColumnHide();
57707 cm.setHidden(index, item.checked);
57713 beforeColMenuShow : function(){
57714 var cm = this.cm, colCount = cm.getColumnCount();
57715 this.colMenu.removeAll();
57716 for(var i = 0; i < colCount; i++){
57717 this.colMenu.add(new Roo.menu.CheckItem({
57718 id: "col-"+cm.getColumnId(i),
57719 text: cm.getColumnHeader(i),
57720 checked: !cm.isHidden(i),
57726 handleHdCtx : function(g, index, e){
57728 var hd = this.getHeaderCell(index);
57729 this.hdCtxIndex = index;
57730 var ms = this.hmenu.items, cm = this.cm;
57731 ms.get("asc").setDisabled(!cm.isSortable(index));
57732 ms.get("desc").setDisabled(!cm.isSortable(index));
57733 if(this.grid.enableColLock !== false){
57734 ms.get("lock").setDisabled(cm.isLocked(index));
57735 ms.get("unlock").setDisabled(!cm.isLocked(index));
57737 this.hmenu.show(hd, "tl-bl");
57740 handleHdOver : function(e){
57741 var hd = this.findHeaderCell(e.getTarget());
57742 if(hd && !this.headersDisabled){
57743 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
57744 this.fly(hd).addClass("x-grid-hd-over");
57749 handleHdOut : function(e){
57750 var hd = this.findHeaderCell(e.getTarget());
57752 this.fly(hd).removeClass("x-grid-hd-over");
57756 handleSplitDblClick : function(e, t){
57757 var i = this.getCellIndex(t);
57758 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
57759 this.autoSizeColumn(i, true);
57764 render : function(){
57767 var colCount = cm.getColumnCount();
57769 if(this.grid.monitorWindowResize === true){
57770 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
57772 var header = this.renderHeaders();
57773 var body = this.templates.body.apply({rows:""});
57774 var html = this.templates.master.apply({
57777 lockedHeader: header[0],
57781 //this.updateColumns();
57783 this.grid.getGridEl().dom.innerHTML = html;
57785 this.initElements();
57787 // a kludge to fix the random scolling effect in webkit
57788 this.el.on("scroll", function() {
57789 this.el.dom.scrollTop=0; // hopefully not recursive..
57792 this.scroller.on("scroll", this.handleScroll, this);
57793 this.lockedBody.on("mousewheel", this.handleWheel, this);
57794 this.mainBody.on("mousewheel", this.handleWheel, this);
57796 this.mainHd.on("mouseover", this.handleHdOver, this);
57797 this.mainHd.on("mouseout", this.handleHdOut, this);
57798 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
57799 {delegate: "."+this.splitClass});
57801 this.lockedHd.on("mouseover", this.handleHdOver, this);
57802 this.lockedHd.on("mouseout", this.handleHdOut, this);
57803 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
57804 {delegate: "."+this.splitClass});
57806 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
57807 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57810 this.updateSplitters();
57812 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
57813 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57814 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
57817 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
57818 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
57820 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
57821 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
57823 if(this.grid.enableColLock !== false){
57824 this.hmenu.add('-',
57825 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
57826 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
57830 this.hmenu.add('-',
57831 {id:"wider", text: this.columnsWiderText},
57832 {id:"narrow", text: this.columnsNarrowText }
57838 if(this.grid.enableColumnHide !== false){
57840 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
57841 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
57842 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
57844 this.hmenu.add('-',
57845 {id:"columns", text: this.columnsText, menu: this.colMenu}
57848 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
57850 this.grid.on("headercontextmenu", this.handleHdCtx, this);
57853 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
57854 this.dd = new Roo.grid.GridDragZone(this.grid, {
57855 ddGroup : this.grid.ddGroup || 'GridDD'
57861 for(var i = 0; i < colCount; i++){
57862 if(cm.isHidden(i)){
57863 this.hideColumn(i);
57865 if(cm.config[i].align){
57866 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
57867 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
57871 this.updateHeaderSortState();
57873 this.beforeInitialResize();
57876 // two part rendering gives faster view to the user
57877 this.renderPhase2.defer(1, this);
57880 renderPhase2 : function(){
57881 // render the rows now
57883 if(this.grid.autoSizeColumns){
57884 this.autoSizeColumns();
57888 beforeInitialResize : function(){
57892 onColumnSplitterMoved : function(i, w){
57893 this.userResized = true;
57894 var cm = this.grid.colModel;
57895 cm.setColumnWidth(i, w, true);
57896 var cid = cm.getColumnId(i);
57897 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57898 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
57899 this.updateSplitters();
57901 this.grid.fireEvent("columnresize", i, w);
57904 syncRowHeights : function(startIndex, endIndex){
57905 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
57906 startIndex = startIndex || 0;
57907 var mrows = this.getBodyTable().rows;
57908 var lrows = this.getLockedTable().rows;
57909 var len = mrows.length-1;
57910 endIndex = Math.min(endIndex || len, len);
57911 for(var i = startIndex; i <= endIndex; i++){
57912 var m = mrows[i], l = lrows[i];
57913 var h = Math.max(m.offsetHeight, l.offsetHeight);
57914 m.style.height = l.style.height = h + "px";
57919 layout : function(initialRender, is2ndPass)
57922 var auto = g.autoHeight;
57923 var scrollOffset = 16;
57924 var c = g.getGridEl(), cm = this.cm,
57925 expandCol = g.autoExpandColumn,
57927 //c.beginMeasure();
57929 if(!c.dom.offsetWidth){ // display:none?
57931 this.lockedWrap.show();
57932 this.mainWrap.show();
57937 var hasLock = this.cm.isLocked(0);
57939 var tbh = this.headerPanel.getHeight();
57940 var bbh = this.footerPanel.getHeight();
57943 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
57944 var newHeight = ch + c.getBorderWidth("tb");
57946 newHeight = Math.min(g.maxHeight, newHeight);
57948 c.setHeight(newHeight);
57952 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
57955 var s = this.scroller;
57957 var csize = c.getSize(true);
57959 this.el.setSize(csize.width, csize.height);
57961 this.headerPanel.setWidth(csize.width);
57962 this.footerPanel.setWidth(csize.width);
57964 var hdHeight = this.mainHd.getHeight();
57965 var vw = csize.width;
57966 var vh = csize.height - (tbh + bbh);
57970 var bt = this.getBodyTable();
57972 if(cm.getLockedCount() == cm.config.length){
57973 bt = this.getLockedTable();
57976 var ltWidth = hasLock ?
57977 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
57979 var scrollHeight = bt.offsetHeight;
57980 var scrollWidth = ltWidth + bt.offsetWidth;
57981 var vscroll = false, hscroll = false;
57983 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
57985 var lw = this.lockedWrap, mw = this.mainWrap;
57986 var lb = this.lockedBody, mb = this.mainBody;
57988 setTimeout(function(){
57989 var t = s.dom.offsetTop;
57990 var w = s.dom.clientWidth,
57991 h = s.dom.clientHeight;
57994 lw.setSize(ltWidth, h);
57996 mw.setLeftTop(ltWidth, t);
57997 mw.setSize(w-ltWidth, h);
57999 lb.setHeight(h-hdHeight);
58000 mb.setHeight(h-hdHeight);
58002 if(is2ndPass !== true && !gv.userResized && expandCol){
58003 // high speed resize without full column calculation
58005 var ci = cm.getIndexById(expandCol);
58007 ci = cm.findColumnIndex(expandCol);
58009 ci = Math.max(0, ci); // make sure it's got at least the first col.
58010 var expandId = cm.getColumnId(ci);
58011 var tw = cm.getTotalWidth(false);
58012 var currentWidth = cm.getColumnWidth(ci);
58013 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
58014 if(currentWidth != cw){
58015 cm.setColumnWidth(ci, cw, true);
58016 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
58017 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
58018 gv.updateSplitters();
58019 gv.layout(false, true);
58031 onWindowResize : function(){
58032 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
58038 appendFooter : function(parentEl){
58042 sortAscText : "Sort Ascending",
58043 sortDescText : "Sort Descending",
58044 lockText : "Lock Column",
58045 unlockText : "Unlock Column",
58046 columnsText : "Columns",
58048 columnsWiderText : "Wider",
58049 columnsNarrowText : "Thinner"
58053 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
58054 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
58055 this.proxy.el.addClass('x-grid3-col-dd');
58058 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
58059 handleMouseDown : function(e){
58063 callHandleMouseDown : function(e){
58064 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
58069 * Ext JS Library 1.1.1
58070 * Copyright(c) 2006-2007, Ext JS, LLC.
58072 * Originally Released Under LGPL - original licence link has changed is not relivant.
58075 * <script type="text/javascript">
58078 * @extends Roo.dd.DDProxy
58079 * @class Roo.grid.SplitDragZone
58080 * Support for Column Header resizing
58082 * @param {Object} config
58085 // This is a support class used internally by the Grid components
58086 Roo.grid.SplitDragZone = function(grid, hd, hd2){
58088 this.view = grid.getView();
58089 this.proxy = this.view.resizeProxy;
58090 Roo.grid.SplitDragZone.superclass.constructor.call(
58093 "gridSplitters" + this.grid.getGridEl().id, // SGROUP
58095 dragElId : Roo.id(this.proxy.dom),
58100 this.setHandleElId(Roo.id(hd));
58101 if (hd2 !== false) {
58102 this.setOuterHandleElId(Roo.id(hd2));
58105 this.scroll = false;
58107 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
58108 fly: Roo.Element.fly,
58110 b4StartDrag : function(x, y){
58111 this.view.headersDisabled = true;
58112 var h = this.view.mainWrap ? this.view.mainWrap.getHeight() : (
58113 this.view.headEl.getHeight() + this.view.bodyEl.getHeight()
58115 this.proxy.setHeight(h);
58117 // for old system colWidth really stored the actual width?
58118 // in bootstrap we tried using xs/ms/etc.. to do % sizing?
58119 // which in reality did not work.. - it worked only for fixed sizes
58120 // for resizable we need to use actual sizes.
58121 var w = this.cm.getColumnWidth(this.cellIndex);
58122 if (!this.view.mainWrap) {
58124 w = this.view.getHeaderIndex(this.cellIndex).getWidth();
58129 // this was w-this.grid.minColumnWidth;
58130 // doesnt really make sense? - w = thie curren width or the rendered one?
58131 var minw = Math.max(w-this.grid.minColumnWidth, 0);
58132 this.resetConstraints();
58133 this.setXConstraint(minw, 1000);
58134 this.setYConstraint(0, 0);
58135 this.minX = x - minw;
58136 this.maxX = x + 1000;
58138 if (!this.view.mainWrap) { // this is Bootstrap code..
58139 this.getDragEl().style.display='block';
58142 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
58146 handleMouseDown : function(e){
58147 ev = Roo.EventObject.setEvent(e);
58148 var t = this.fly(ev.getTarget());
58149 if(t.hasClass("x-grid-split")){
58150 this.cellIndex = this.view.getCellIndex(t.dom);
58151 this.split = t.dom;
58152 this.cm = this.grid.colModel;
58153 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
58154 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
58159 endDrag : function(e){
58160 this.view.headersDisabled = false;
58161 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
58162 var diff = endX - this.startPos;
58163 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
58166 autoOffset : function(){
58167 this.setDelta(0,0);
58171 * Ext JS Library 1.1.1
58172 * Copyright(c) 2006-2007, Ext JS, LLC.
58174 * Originally Released Under LGPL - original licence link has changed is not relivant.
58177 * <script type="text/javascript">
58181 // This is a support class used internally by the Grid components
58182 Roo.grid.GridDragZone = function(grid, config){
58183 this.view = grid.getView();
58184 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
58185 if(this.view.lockedBody){
58186 this.setHandleElId(Roo.id(this.view.mainBody.dom));
58187 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
58189 this.scroll = false;
58191 this.ddel = document.createElement('div');
58192 this.ddel.className = 'x-grid-dd-wrap';
58195 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
58196 ddGroup : "GridDD",
58198 getDragData : function(e){
58199 var t = Roo.lib.Event.getTarget(e);
58200 var rowIndex = this.view.findRowIndex(t);
58201 var sm = this.grid.selModel;
58203 //Roo.log(rowIndex);
58205 if (sm.getSelectedCell) {
58206 // cell selection..
58207 if (!sm.getSelectedCell()) {
58210 if (rowIndex != sm.getSelectedCell()[0]) {
58215 if (sm.getSelections && sm.getSelections().length < 1) {
58220 // before it used to all dragging of unseleted... - now we dont do that.
58221 if(rowIndex !== false){
58226 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
58228 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
58231 if (e.hasModifier()){
58232 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
58235 Roo.log("getDragData");
58240 rowIndex: rowIndex,
58241 selections: sm.getSelections ? sm.getSelections() : (
58242 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : [])
58249 onInitDrag : function(e){
58250 var data = this.dragData;
58251 this.ddel.innerHTML = this.grid.getDragDropText();
58252 this.proxy.update(this.ddel);
58253 // fire start drag?
58256 afterRepair : function(){
58257 this.dragging = false;
58260 getRepairXY : function(e, data){
58264 onEndDrag : function(data, e){
58268 onValidDrop : function(dd, e, id){
58273 beforeInvalidDrop : function(e, id){
58278 * Ext JS Library 1.1.1
58279 * Copyright(c) 2006-2007, Ext JS, LLC.
58281 * Originally Released Under LGPL - original licence link has changed is not relivant.
58284 * <script type="text/javascript">
58289 * @class Roo.grid.ColumnModel
58290 * @extends Roo.util.Observable
58291 * This is the default implementation of a ColumnModel used by the Grid. It defines
58292 * the columns in the grid.
58295 var colModel = new Roo.grid.ColumnModel([
58296 {header: "Ticker", width: 60, sortable: true, locked: true},
58297 {header: "Company Name", width: 150, sortable: true},
58298 {header: "Market Cap.", width: 100, sortable: true},
58299 {header: "$ Sales", width: 100, sortable: true, renderer: money},
58300 {header: "Employees", width: 100, sortable: true, resizable: false}
58305 * The config options listed for this class are options which may appear in each
58306 * individual column definition.
58307 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
58309 * @param {Object} config An Array of column config objects. See this class's
58310 * config objects for details.
58312 Roo.grid.ColumnModel = function(config){
58314 * The config passed into the constructor
58316 this.config = []; //config;
58319 // if no id, create one
58320 // if the column does not have a dataIndex mapping,
58321 // map it to the order it is in the config
58322 for(var i = 0, len = config.length; i < len; i++){
58323 this.addColumn(config[i]);
58328 * The width of columns which have no width specified (defaults to 100)
58331 this.defaultWidth = 100;
58334 * Default sortable of columns which have no sortable specified (defaults to false)
58337 this.defaultSortable = false;
58341 * @event widthchange
58342 * Fires when the width of a column changes.
58343 * @param {ColumnModel} this
58344 * @param {Number} columnIndex The column index
58345 * @param {Number} newWidth The new width
58347 "widthchange": true,
58349 * @event headerchange
58350 * Fires when the text of a header changes.
58351 * @param {ColumnModel} this
58352 * @param {Number} columnIndex The column index
58353 * @param {Number} newText The new header text
58355 "headerchange": true,
58357 * @event hiddenchange
58358 * Fires when a column is hidden or "unhidden".
58359 * @param {ColumnModel} this
58360 * @param {Number} columnIndex The column index
58361 * @param {Boolean} hidden true if hidden, false otherwise
58363 "hiddenchange": true,
58365 * @event columnmoved
58366 * Fires when a column is moved.
58367 * @param {ColumnModel} this
58368 * @param {Number} oldIndex
58369 * @param {Number} newIndex
58371 "columnmoved" : true,
58373 * @event columlockchange
58374 * Fires when a column's locked state is changed
58375 * @param {ColumnModel} this
58376 * @param {Number} colIndex
58377 * @param {Boolean} locked true if locked
58379 "columnlockchange" : true
58381 Roo.grid.ColumnModel.superclass.constructor.call(this);
58383 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
58385 * @cfg {String} header The header text to display in the Grid view.
58388 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
58389 * {@link Roo.data.Record} definition from which to draw the column's value. If not
58390 * specified, the column's index is used as an index into the Record's data Array.
58393 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
58394 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
58397 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
58398 * Defaults to the value of the {@link #defaultSortable} property.
58399 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
58402 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
58405 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
58408 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
58411 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
58414 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
58415 * given the cell's data value. See {@link #setRenderer}. If not specified, the
58416 * default renderer returns the escaped data value. If an object is returned (bootstrap only)
58417 * then it is treated as a Roo Component object instance, and it is rendered after the initial row is rendered
58420 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
58423 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
58426 * @cfg {String} valign (Optional) Set the CSS vertical-align property of the column (eg. middle, top, bottom etc). Defaults to undefined.
58429 * @cfg {String} cursor (Optional)
58432 * @cfg {String} tooltip (Optional)
58435 * @cfg {Number} xs (Optional)
58438 * @cfg {Number} sm (Optional)
58441 * @cfg {Number} md (Optional)
58444 * @cfg {Number} lg (Optional)
58447 * Returns the id of the column at the specified index.
58448 * @param {Number} index The column index
58449 * @return {String} the id
58451 getColumnId : function(index){
58452 return this.config[index].id;
58456 * Returns the column for a specified id.
58457 * @param {String} id The column id
58458 * @return {Object} the column
58460 getColumnById : function(id){
58461 return this.lookup[id];
58466 * Returns the column Object for a specified dataIndex.
58467 * @param {String} dataIndex The column dataIndex
58468 * @return {Object|Boolean} the column or false if not found
58470 getColumnByDataIndex: function(dataIndex){
58471 var index = this.findColumnIndex(dataIndex);
58472 return index > -1 ? this.config[index] : false;
58476 * Returns the index for a specified column id.
58477 * @param {String} id The column id
58478 * @return {Number} the index, or -1 if not found
58480 getIndexById : function(id){
58481 for(var i = 0, len = this.config.length; i < len; i++){
58482 if(this.config[i].id == id){
58490 * Returns the index for a specified column dataIndex.
58491 * @param {String} dataIndex The column dataIndex
58492 * @return {Number} the index, or -1 if not found
58495 findColumnIndex : function(dataIndex){
58496 for(var i = 0, len = this.config.length; i < len; i++){
58497 if(this.config[i].dataIndex == dataIndex){
58505 moveColumn : function(oldIndex, newIndex){
58506 var c = this.config[oldIndex];
58507 this.config.splice(oldIndex, 1);
58508 this.config.splice(newIndex, 0, c);
58509 this.dataMap = null;
58510 this.fireEvent("columnmoved", this, oldIndex, newIndex);
58513 isLocked : function(colIndex){
58514 return this.config[colIndex].locked === true;
58517 setLocked : function(colIndex, value, suppressEvent){
58518 if(this.isLocked(colIndex) == value){
58521 this.config[colIndex].locked = value;
58522 if(!suppressEvent){
58523 this.fireEvent("columnlockchange", this, colIndex, value);
58527 getTotalLockedWidth : function(){
58528 var totalWidth = 0;
58529 for(var i = 0; i < this.config.length; i++){
58530 if(this.isLocked(i) && !this.isHidden(i)){
58531 this.totalWidth += this.getColumnWidth(i);
58537 getLockedCount : function(){
58538 for(var i = 0, len = this.config.length; i < len; i++){
58539 if(!this.isLocked(i)){
58544 return this.config.length;
58548 * Returns the number of columns.
58551 getColumnCount : function(visibleOnly){
58552 if(visibleOnly === true){
58554 for(var i = 0, len = this.config.length; i < len; i++){
58555 if(!this.isHidden(i)){
58561 return this.config.length;
58565 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
58566 * @param {Function} fn
58567 * @param {Object} scope (optional)
58568 * @return {Array} result
58570 getColumnsBy : function(fn, scope){
58572 for(var i = 0, len = this.config.length; i < len; i++){
58573 var c = this.config[i];
58574 if(fn.call(scope||this, c, i) === true){
58582 * Returns true if the specified column is sortable.
58583 * @param {Number} col The column index
58584 * @return {Boolean}
58586 isSortable : function(col){
58587 if(typeof this.config[col].sortable == "undefined"){
58588 return this.defaultSortable;
58590 return this.config[col].sortable;
58594 * Returns the rendering (formatting) function defined for the column.
58595 * @param {Number} col The column index.
58596 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
58598 getRenderer : function(col){
58599 if(!this.config[col].renderer){
58600 return Roo.grid.ColumnModel.defaultRenderer;
58602 return this.config[col].renderer;
58606 * Sets the rendering (formatting) function for a column.
58607 * @param {Number} col The column index
58608 * @param {Function} fn The function to use to process the cell's raw data
58609 * to return HTML markup for the grid view. The render function is called with
58610 * the following parameters:<ul>
58611 * <li>Data value.</li>
58612 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
58613 * <li>css A CSS style string to apply to the table cell.</li>
58614 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
58615 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
58616 * <li>Row index</li>
58617 * <li>Column index</li>
58618 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
58620 setRenderer : function(col, fn){
58621 this.config[col].renderer = fn;
58625 * Returns the width for the specified column.
58626 * @param {Number} col The column index
58629 getColumnWidth : function(col){
58630 return this.config[col].width * 1 || this.defaultWidth;
58634 * Sets the width for a column.
58635 * @param {Number} col The column index
58636 * @param {Number} width The new width
58638 setColumnWidth : function(col, width, suppressEvent){
58639 this.config[col].width = width;
58640 this.totalWidth = null;
58641 if(!suppressEvent){
58642 this.fireEvent("widthchange", this, col, width);
58647 * Returns the total width of all columns.
58648 * @param {Boolean} includeHidden True to include hidden column widths
58651 getTotalWidth : function(includeHidden){
58652 if(!this.totalWidth){
58653 this.totalWidth = 0;
58654 for(var i = 0, len = this.config.length; i < len; i++){
58655 if(includeHidden || !this.isHidden(i)){
58656 this.totalWidth += this.getColumnWidth(i);
58660 return this.totalWidth;
58664 * Returns the header for the specified column.
58665 * @param {Number} col The column index
58668 getColumnHeader : function(col){
58669 return this.config[col].header;
58673 * Sets the header for a column.
58674 * @param {Number} col The column index
58675 * @param {String} header The new header
58677 setColumnHeader : function(col, header){
58678 this.config[col].header = header;
58679 this.fireEvent("headerchange", this, col, header);
58683 * Returns the tooltip for the specified column.
58684 * @param {Number} col The column index
58687 getColumnTooltip : function(col){
58688 return this.config[col].tooltip;
58691 * Sets the tooltip for a column.
58692 * @param {Number} col The column index
58693 * @param {String} tooltip The new tooltip
58695 setColumnTooltip : function(col, tooltip){
58696 this.config[col].tooltip = tooltip;
58700 * Returns the dataIndex for the specified column.
58701 * @param {Number} col The column index
58704 getDataIndex : function(col){
58705 return this.config[col].dataIndex;
58709 * Sets the dataIndex for a column.
58710 * @param {Number} col The column index
58711 * @param {Number} dataIndex The new dataIndex
58713 setDataIndex : function(col, dataIndex){
58714 this.config[col].dataIndex = dataIndex;
58720 * Returns true if the cell is editable.
58721 * @param {Number} colIndex The column index
58722 * @param {Number} rowIndex The row index - this is nto actually used..?
58723 * @return {Boolean}
58725 isCellEditable : function(colIndex, rowIndex){
58726 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
58730 * Returns the editor defined for the cell/column.
58731 * return false or null to disable editing.
58732 * @param {Number} colIndex The column index
58733 * @param {Number} rowIndex The row index
58736 getCellEditor : function(colIndex, rowIndex){
58737 return this.config[colIndex].editor;
58741 * Sets if a column is editable.
58742 * @param {Number} col The column index
58743 * @param {Boolean} editable True if the column is editable
58745 setEditable : function(col, editable){
58746 this.config[col].editable = editable;
58751 * Returns true if the column is hidden.
58752 * @param {Number} colIndex The column index
58753 * @return {Boolean}
58755 isHidden : function(colIndex){
58756 return this.config[colIndex].hidden;
58761 * Returns true if the column width cannot be changed
58763 isFixed : function(colIndex){
58764 return this.config[colIndex].fixed;
58768 * Returns true if the column can be resized
58769 * @return {Boolean}
58771 isResizable : function(colIndex){
58772 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
58775 * Sets if a column is hidden.
58776 * @param {Number} colIndex The column index
58777 * @param {Boolean} hidden True if the column is hidden
58779 setHidden : function(colIndex, hidden){
58780 this.config[colIndex].hidden = hidden;
58781 this.totalWidth = null;
58782 this.fireEvent("hiddenchange", this, colIndex, hidden);
58786 * Sets the editor for a column.
58787 * @param {Number} col The column index
58788 * @param {Object} editor The editor object
58790 setEditor : function(col, editor){
58791 this.config[col].editor = editor;
58794 * Add a column (experimental...) - defaults to adding to the end..
58795 * @param {Object} config
58797 addColumn : function(c)
58800 var i = this.config.length;
58801 this.config[i] = c;
58803 if(typeof c.dataIndex == "undefined"){
58806 if(typeof c.renderer == "string"){
58807 c.renderer = Roo.util.Format[c.renderer];
58809 if(typeof c.id == "undefined"){
58812 if(c.editor && c.editor.xtype){
58813 c.editor = Roo.factory(c.editor, Roo.grid);
58815 if(c.editor && c.editor.isFormField){
58816 c.editor = new Roo.grid.GridEditor(c.editor);
58818 this.lookup[c.id] = c;
58823 Roo.grid.ColumnModel.defaultRenderer = function(value)
58825 if(typeof value == "object") {
58828 if(typeof value == "string" && value.length < 1){
58832 return String.format("{0}", value);
58835 // Alias for backwards compatibility
58836 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
58839 * Ext JS Library 1.1.1
58840 * Copyright(c) 2006-2007, Ext JS, LLC.
58842 * Originally Released Under LGPL - original licence link has changed is not relivant.
58845 * <script type="text/javascript">
58849 * @class Roo.grid.AbstractSelectionModel
58850 * @extends Roo.util.Observable
58851 * Abstract base class for grid SelectionModels. It provides the interface that should be
58852 * implemented by descendant classes. This class should not be directly instantiated.
58855 Roo.grid.AbstractSelectionModel = function(){
58856 this.locked = false;
58857 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
58860 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
58861 /** @ignore Called by the grid automatically. Do not call directly. */
58862 init : function(grid){
58868 * Locks the selections.
58871 this.locked = true;
58875 * Unlocks the selections.
58877 unlock : function(){
58878 this.locked = false;
58882 * Returns true if the selections are locked.
58883 * @return {Boolean}
58885 isLocked : function(){
58886 return this.locked;
58890 * Ext JS Library 1.1.1
58891 * Copyright(c) 2006-2007, Ext JS, LLC.
58893 * Originally Released Under LGPL - original licence link has changed is not relivant.
58896 * <script type="text/javascript">
58899 * @extends Roo.grid.AbstractSelectionModel
58900 * @class Roo.grid.RowSelectionModel
58901 * The default SelectionModel used by {@link Roo.grid.Grid}.
58902 * It supports multiple selections and keyboard selection/navigation.
58904 * @param {Object} config
58906 Roo.grid.RowSelectionModel = function(config){
58907 Roo.apply(this, config);
58908 this.selections = new Roo.util.MixedCollection(false, function(o){
58913 this.lastActive = false;
58917 * @event selectionchange
58918 * Fires when the selection changes
58919 * @param {SelectionModel} this
58921 "selectionchange" : true,
58923 * @event afterselectionchange
58924 * Fires after the selection changes (eg. by key press or clicking)
58925 * @param {SelectionModel} this
58927 "afterselectionchange" : true,
58929 * @event beforerowselect
58930 * Fires when a row is selected being selected, return false to cancel.
58931 * @param {SelectionModel} this
58932 * @param {Number} rowIndex The selected index
58933 * @param {Boolean} keepExisting False if other selections will be cleared
58935 "beforerowselect" : true,
58938 * Fires when a row is selected.
58939 * @param {SelectionModel} this
58940 * @param {Number} rowIndex The selected index
58941 * @param {Roo.data.Record} r The record
58943 "rowselect" : true,
58945 * @event rowdeselect
58946 * Fires when a row is deselected.
58947 * @param {SelectionModel} this
58948 * @param {Number} rowIndex The selected index
58950 "rowdeselect" : true
58952 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
58953 this.locked = false;
58956 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
58958 * @cfg {Boolean} singleSelect
58959 * True to allow selection of only one row at a time (defaults to false)
58961 singleSelect : false,
58964 initEvents : function(){
58966 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
58967 this.grid.on("mousedown", this.handleMouseDown, this);
58968 }else{ // allow click to work like normal
58969 this.grid.on("rowclick", this.handleDragableRowClick, this);
58971 // bootstrap does not have a view..
58972 var view = this.grid.view ? this.grid.view : this.grid;
58973 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
58974 "up" : function(e){
58976 this.selectPrevious(e.shiftKey);
58977 }else if(this.last !== false && this.lastActive !== false){
58978 var last = this.last;
58979 this.selectRange(this.last, this.lastActive-1);
58980 view.focusRow(this.lastActive);
58981 if(last !== false){
58985 this.selectFirstRow();
58987 this.fireEvent("afterselectionchange", this);
58989 "down" : function(e){
58991 this.selectNext(e.shiftKey);
58992 }else if(this.last !== false && this.lastActive !== false){
58993 var last = this.last;
58994 this.selectRange(this.last, this.lastActive+1);
58995 view.focusRow(this.lastActive);
58996 if(last !== false){
59000 this.selectFirstRow();
59002 this.fireEvent("afterselectionchange", this);
59008 view.on("refresh", this.onRefresh, this);
59009 view.on("rowupdated", this.onRowUpdated, this);
59010 view.on("rowremoved", this.onRemove, this);
59014 onRefresh : function(){
59015 var ds = this.grid.ds, i, v = this.grid.view;
59016 var s = this.selections;
59017 s.each(function(r){
59018 if((i = ds.indexOfId(r.id)) != -1){
59020 s.add(ds.getAt(i)); // updating the selection relate data
59028 onRemove : function(v, index, r){
59029 this.selections.remove(r);
59033 onRowUpdated : function(v, index, r){
59034 if(this.isSelected(r)){
59035 v.onRowSelect(index);
59041 * @param {Array} records The records to select
59042 * @param {Boolean} keepExisting (optional) True to keep existing selections
59044 selectRecords : function(records, keepExisting){
59046 this.clearSelections();
59048 var ds = this.grid.ds;
59049 for(var i = 0, len = records.length; i < len; i++){
59050 this.selectRow(ds.indexOf(records[i]), true);
59055 * Gets the number of selected rows.
59058 getCount : function(){
59059 return this.selections.length;
59063 * Selects the first row in the grid.
59065 selectFirstRow : function(){
59070 * Select the last row.
59071 * @param {Boolean} keepExisting (optional) True to keep existing selections
59073 selectLastRow : function(keepExisting){
59074 this.selectRow(this.grid.ds.getCount() - 1, keepExisting);
59078 * Selects the row immediately following the last selected row.
59079 * @param {Boolean} keepExisting (optional) True to keep existing selections
59081 selectNext : function(keepExisting){
59082 if(this.last !== false && (this.last+1) < this.grid.ds.getCount()){
59083 this.selectRow(this.last+1, keepExisting);
59084 var view = this.grid.view ? this.grid.view : this.grid;
59085 view.focusRow(this.last);
59090 * Selects the row that precedes the last selected row.
59091 * @param {Boolean} keepExisting (optional) True to keep existing selections
59093 selectPrevious : function(keepExisting){
59095 this.selectRow(this.last-1, keepExisting);
59096 var view = this.grid.view ? this.grid.view : this.grid;
59097 view.focusRow(this.last);
59102 * Returns the selected records
59103 * @return {Array} Array of selected records
59105 getSelections : function(){
59106 return [].concat(this.selections.items);
59110 * Returns the first selected record.
59113 getSelected : function(){
59114 return this.selections.itemAt(0);
59119 * Clears all selections.
59121 clearSelections : function(fast){
59126 var ds = this.grid.ds;
59127 var s = this.selections;
59128 s.each(function(r){
59129 this.deselectRow(ds.indexOfId(r.id));
59133 this.selections.clear();
59140 * Selects all rows.
59142 selectAll : function(){
59146 this.selections.clear();
59147 for(var i = 0, len = this.grid.ds.getCount(); i < len; i++){
59148 this.selectRow(i, true);
59153 * Returns True if there is a selection.
59154 * @return {Boolean}
59156 hasSelection : function(){
59157 return this.selections.length > 0;
59161 * Returns True if the specified row is selected.
59162 * @param {Number/Record} record The record or index of the record to check
59163 * @return {Boolean}
59165 isSelected : function(index){
59166 var r = typeof index == "number" ? this.grid.ds.getAt(index) : index;
59167 return (r && this.selections.key(r.id) ? true : false);
59171 * Returns True if the specified record id is selected.
59172 * @param {String} id The id of record to check
59173 * @return {Boolean}
59175 isIdSelected : function(id){
59176 return (this.selections.key(id) ? true : false);
59180 handleMouseDown : function(e, t)
59182 var view = this.grid.view ? this.grid.view : this.grid;
59184 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
59187 if(e.shiftKey && this.last !== false){
59188 var last = this.last;
59189 this.selectRange(last, rowIndex, e.ctrlKey);
59190 this.last = last; // reset the last
59191 view.focusRow(rowIndex);
59193 var isSelected = this.isSelected(rowIndex);
59194 if(e.button !== 0 && isSelected){
59195 view.focusRow(rowIndex);
59196 }else if(e.ctrlKey && isSelected){
59197 this.deselectRow(rowIndex);
59198 }else if(!isSelected){
59199 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
59200 view.focusRow(rowIndex);
59203 this.fireEvent("afterselectionchange", this);
59206 handleDragableRowClick : function(grid, rowIndex, e)
59208 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
59209 this.selectRow(rowIndex, false);
59210 var view = this.grid.view ? this.grid.view : this.grid;
59211 view.focusRow(rowIndex);
59212 this.fireEvent("afterselectionchange", this);
59217 * Selects multiple rows.
59218 * @param {Array} rows Array of the indexes of the row to select
59219 * @param {Boolean} keepExisting (optional) True to keep existing selections
59221 selectRows : function(rows, keepExisting){
59223 this.clearSelections();
59225 for(var i = 0, len = rows.length; i < len; i++){
59226 this.selectRow(rows[i], true);
59231 * Selects a range of rows. All rows in between startRow and endRow are also selected.
59232 * @param {Number} startRow The index of the first row in the range
59233 * @param {Number} endRow The index of the last row in the range
59234 * @param {Boolean} keepExisting (optional) True to retain existing selections
59236 selectRange : function(startRow, endRow, keepExisting){
59241 this.clearSelections();
59243 if(startRow <= endRow){
59244 for(var i = startRow; i <= endRow; i++){
59245 this.selectRow(i, true);
59248 for(var i = startRow; i >= endRow; i--){
59249 this.selectRow(i, true);
59255 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
59256 * @param {Number} startRow The index of the first row in the range
59257 * @param {Number} endRow The index of the last row in the range
59259 deselectRange : function(startRow, endRow, preventViewNotify){
59263 for(var i = startRow; i <= endRow; i++){
59264 this.deselectRow(i, preventViewNotify);
59270 * @param {Number} row The index of the row to select
59271 * @param {Boolean} keepExisting (optional) True to keep existing selections
59273 selectRow : function(index, keepExisting, preventViewNotify){
59274 if(this.locked || (index < 0 || index >= this.grid.ds.getCount())) {
59277 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
59278 if(!keepExisting || this.singleSelect){
59279 this.clearSelections();
59281 var r = this.grid.ds.getAt(index);
59282 this.selections.add(r);
59283 this.last = this.lastActive = index;
59284 if(!preventViewNotify){
59285 var view = this.grid.view ? this.grid.view : this.grid;
59286 view.onRowSelect(index);
59288 this.fireEvent("rowselect", this, index, r);
59289 this.fireEvent("selectionchange", this);
59295 * @param {Number} row The index of the row to deselect
59297 deselectRow : function(index, preventViewNotify){
59301 if(this.last == index){
59304 if(this.lastActive == index){
59305 this.lastActive = false;
59307 var r = this.grid.ds.getAt(index);
59308 this.selections.remove(r);
59309 if(!preventViewNotify){
59310 var view = this.grid.view ? this.grid.view : this.grid;
59311 view.onRowDeselect(index);
59313 this.fireEvent("rowdeselect", this, index);
59314 this.fireEvent("selectionchange", this);
59318 restoreLast : function(){
59320 this.last = this._last;
59325 acceptsNav : function(row, col, cm){
59326 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59330 onEditorKey : function(field, e){
59331 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
59336 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59338 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59340 }else if(k == e.ENTER && !e.ctrlKey){
59344 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
59346 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
59348 }else if(k == e.ESC){
59352 g.startEditing(newCell[0], newCell[1]);
59357 * Ext JS Library 1.1.1
59358 * Copyright(c) 2006-2007, Ext JS, LLC.
59360 * Originally Released Under LGPL - original licence link has changed is not relivant.
59363 * <script type="text/javascript">
59366 * @class Roo.grid.CellSelectionModel
59367 * @extends Roo.grid.AbstractSelectionModel
59368 * This class provides the basic implementation for cell selection in a grid.
59370 * @param {Object} config The object containing the configuration of this model.
59371 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
59373 Roo.grid.CellSelectionModel = function(config){
59374 Roo.apply(this, config);
59376 this.selection = null;
59380 * @event beforerowselect
59381 * Fires before a cell is selected.
59382 * @param {SelectionModel} this
59383 * @param {Number} rowIndex The selected row index
59384 * @param {Number} colIndex The selected cell index
59386 "beforecellselect" : true,
59388 * @event cellselect
59389 * Fires when a cell is selected.
59390 * @param {SelectionModel} this
59391 * @param {Number} rowIndex The selected row index
59392 * @param {Number} colIndex The selected cell index
59394 "cellselect" : true,
59396 * @event selectionchange
59397 * Fires when the active selection changes.
59398 * @param {SelectionModel} this
59399 * @param {Object} selection null for no selection or an object (o) with two properties
59401 <li>o.record: the record object for the row the selection is in</li>
59402 <li>o.cell: An array of [rowIndex, columnIndex]</li>
59405 "selectionchange" : true,
59408 * Fires when the tab (or enter) was pressed on the last editable cell
59409 * You can use this to trigger add new row.
59410 * @param {SelectionModel} this
59414 * @event beforeeditnext
59415 * Fires before the next editable sell is made active
59416 * You can use this to skip to another cell or fire the tabend
59417 * if you set cell to false
59418 * @param {Object} eventdata object : { cell : [ row, col ] }
59420 "beforeeditnext" : true
59422 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
59425 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
59427 enter_is_tab: false,
59430 initEvents : function(){
59431 this.grid.on("mousedown", this.handleMouseDown, this);
59432 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
59433 var view = this.grid.view;
59434 view.on("refresh", this.onViewChange, this);
59435 view.on("rowupdated", this.onRowUpdated, this);
59436 view.on("beforerowremoved", this.clearSelections, this);
59437 view.on("beforerowsinserted", this.clearSelections, this);
59438 if(this.grid.isEditor){
59439 this.grid.on("beforeedit", this.beforeEdit, this);
59444 beforeEdit : function(e){
59445 this.select(e.row, e.column, false, true, e.record);
59449 onRowUpdated : function(v, index, r){
59450 if(this.selection && this.selection.record == r){
59451 v.onCellSelect(index, this.selection.cell[1]);
59456 onViewChange : function(){
59457 this.clearSelections(true);
59461 * Returns the currently selected cell,.
59462 * @return {Array} The selected cell (row, column) or null if none selected.
59464 getSelectedCell : function(){
59465 return this.selection ? this.selection.cell : null;
59469 * Clears all selections.
59470 * @param {Boolean} true to prevent the gridview from being notified about the change.
59472 clearSelections : function(preventNotify){
59473 var s = this.selection;
59475 if(preventNotify !== true){
59476 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
59478 this.selection = null;
59479 this.fireEvent("selectionchange", this, null);
59484 * Returns true if there is a selection.
59485 * @return {Boolean}
59487 hasSelection : function(){
59488 return this.selection ? true : false;
59492 handleMouseDown : function(e, t){
59493 var v = this.grid.getView();
59494 if(this.isLocked()){
59497 var row = v.findRowIndex(t);
59498 var cell = v.findCellIndex(t);
59499 if(row !== false && cell !== false){
59500 this.select(row, cell);
59506 * @param {Number} rowIndex
59507 * @param {Number} collIndex
59509 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
59510 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
59511 this.clearSelections();
59512 r = r || this.grid.dataSource.getAt(rowIndex);
59515 cell : [rowIndex, colIndex]
59517 if(!preventViewNotify){
59518 var v = this.grid.getView();
59519 v.onCellSelect(rowIndex, colIndex);
59520 if(preventFocus !== true){
59521 v.focusCell(rowIndex, colIndex);
59524 this.fireEvent("cellselect", this, rowIndex, colIndex);
59525 this.fireEvent("selectionchange", this, this.selection);
59530 isSelectable : function(rowIndex, colIndex, cm){
59531 return !cm.isHidden(colIndex);
59535 handleKeyDown : function(e){
59536 //Roo.log('Cell Sel Model handleKeyDown');
59537 if(!e.isNavKeyPress()){
59540 var g = this.grid, s = this.selection;
59543 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
59545 this.select(cell[0], cell[1]);
59550 var walk = function(row, col, step){
59551 return g.walkCells(row, col, step, sm.isSelectable, sm);
59553 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
59560 // handled by onEditorKey
59561 if (g.isEditor && g.editing) {
59565 newCell = walk(r, c-1, -1);
59567 newCell = walk(r, c+1, 1);
59572 newCell = walk(r+1, c, 1);
59576 newCell = walk(r-1, c, -1);
59580 newCell = walk(r, c+1, 1);
59584 newCell = walk(r, c-1, -1);
59589 if(g.isEditor && !g.editing){
59590 g.startEditing(r, c);
59599 this.select(newCell[0], newCell[1]);
59605 acceptsNav : function(row, col, cm){
59606 return !cm.isHidden(col) && cm.isCellEditable(col, row);
59610 * @param {Number} field (not used) - as it's normally used as a listener
59611 * @param {Number} e - event - fake it by using
59613 * var e = Roo.EventObjectImpl.prototype;
59614 * e.keyCode = e.TAB
59618 onEditorKey : function(field, e){
59620 var k = e.getKey(),
59623 ed = g.activeEditor,
59625 ///Roo.log('onEditorKey' + k);
59628 if (this.enter_is_tab && k == e.ENTER) {
59634 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
59636 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59642 } else if(k == e.ENTER && !e.ctrlKey){
59645 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
59647 } else if(k == e.ESC){
59652 var ecall = { cell : newCell, forward : forward };
59653 this.fireEvent('beforeeditnext', ecall );
59654 newCell = ecall.cell;
59655 forward = ecall.forward;
59659 //Roo.log('next cell after edit');
59660 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
59661 } else if (forward) {
59662 // tabbed past last
59663 this.fireEvent.defer(100, this, ['tabend',this]);
59668 * Ext JS Library 1.1.1
59669 * Copyright(c) 2006-2007, Ext JS, LLC.
59671 * Originally Released Under LGPL - original licence link has changed is not relivant.
59674 * <script type="text/javascript">
59678 * @class Roo.grid.EditorGrid
59679 * @extends Roo.grid.Grid
59680 * Class for creating and editable grid.
59681 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
59682 * The container MUST have some type of size defined for the grid to fill. The container will be
59683 * automatically set to position relative if it isn't already.
59684 * @param {Object} dataSource The data model to bind to
59685 * @param {Object} colModel The column model with info about this grid's columns
59687 Roo.grid.EditorGrid = function(container, config){
59688 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
59689 this.getGridEl().addClass("xedit-grid");
59691 if(!this.selModel){
59692 this.selModel = new Roo.grid.CellSelectionModel();
59695 this.activeEditor = null;
59699 * @event beforeedit
59700 * Fires before cell editing is triggered. The edit event object has the following properties <br />
59701 * <ul style="padding:5px;padding-left:16px;">
59702 * <li>grid - This grid</li>
59703 * <li>record - The record being edited</li>
59704 * <li>field - The field name being edited</li>
59705 * <li>value - The value for the field being edited.</li>
59706 * <li>row - The grid row index</li>
59707 * <li>column - The grid column index</li>
59708 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59710 * @param {Object} e An edit event (see above for description)
59712 "beforeedit" : true,
59715 * Fires after a cell is edited. <br />
59716 * <ul style="padding:5px;padding-left:16px;">
59717 * <li>grid - This grid</li>
59718 * <li>record - The record being edited</li>
59719 * <li>field - The field name being edited</li>
59720 * <li>value - The value being set</li>
59721 * <li>originalValue - The original value for the field, before the edit.</li>
59722 * <li>row - The grid row index</li>
59723 * <li>column - The grid column index</li>
59725 * @param {Object} e An edit event (see above for description)
59727 "afteredit" : true,
59729 * @event validateedit
59730 * Fires after a cell is edited, but before the value is set in the record.
59731 * You can use this to modify the value being set in the field, Return false
59732 * to cancel the change. The edit event object has the following properties <br />
59733 * <ul style="padding:5px;padding-left:16px;">
59734 * <li>editor - This editor</li>
59735 * <li>grid - This grid</li>
59736 * <li>record - The record being edited</li>
59737 * <li>field - The field name being edited</li>
59738 * <li>value - The value being set</li>
59739 * <li>originalValue - The original value for the field, before the edit.</li>
59740 * <li>row - The grid row index</li>
59741 * <li>column - The grid column index</li>
59742 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
59744 * @param {Object} e An edit event (see above for description)
59746 "validateedit" : true
59748 this.on("bodyscroll", this.stopEditing, this);
59749 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
59752 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
59754 * @cfg {Number} clicksToEdit
59755 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
59762 trackMouseOver: false, // causes very odd FF errors
59764 onCellDblClick : function(g, row, col){
59765 this.startEditing(row, col);
59768 onEditComplete : function(ed, value, startValue){
59769 this.editing = false;
59770 this.activeEditor = null;
59771 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
59773 var field = this.colModel.getDataIndex(ed.col);
59778 originalValue: startValue,
59785 var cell = Roo.get(this.view.getCell(ed.row,ed.col));
59788 if(String(value) !== String(startValue)){
59790 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
59791 r.set(field, e.value);
59792 // if we are dealing with a combo box..
59793 // then we also set the 'name' colum to be the displayField
59794 if (ed.field.displayField && ed.field.name) {
59795 r.set(ed.field.name, ed.field.el.dom.value);
59798 delete e.cancel; //?? why!!!
59799 this.fireEvent("afteredit", e);
59802 this.fireEvent("afteredit", e); // always fire it!
59804 this.view.focusCell(ed.row, ed.col);
59808 * Starts editing the specified for the specified row/column
59809 * @param {Number} rowIndex
59810 * @param {Number} colIndex
59812 startEditing : function(row, col){
59813 this.stopEditing();
59814 if(this.colModel.isCellEditable(col, row)){
59815 this.view.ensureVisible(row, col, true);
59817 var r = this.dataSource.getAt(row);
59818 var field = this.colModel.getDataIndex(col);
59819 var cell = Roo.get(this.view.getCell(row,col));
59824 value: r.data[field],
59829 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
59830 this.editing = true;
59831 var ed = this.colModel.getCellEditor(col, row);
59837 ed.render(ed.parentEl || document.body);
59843 (function(){ // complex but required for focus issues in safari, ie and opera
59847 ed.on("complete", this.onEditComplete, this, {single: true});
59848 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
59849 this.activeEditor = ed;
59850 var v = r.data[field];
59851 ed.startEdit(this.view.getCell(row, col), v);
59852 // combo's with 'displayField and name set
59853 if (ed.field.displayField && ed.field.name) {
59854 ed.field.el.dom.value = r.data[ed.field.name];
59858 }).defer(50, this);
59864 * Stops any active editing
59866 stopEditing : function(){
59867 if(this.activeEditor){
59868 this.activeEditor.completeEdit();
59870 this.activeEditor = null;
59874 * Called to get grid's drag proxy text, by default returns this.ddText.
59877 getDragDropText : function(){
59878 var count = this.selModel.getSelectedCell() ? 1 : 0;
59879 return String.format(this.ddText, count, count == 1 ? '' : 's');
59884 * Ext JS Library 1.1.1
59885 * Copyright(c) 2006-2007, Ext JS, LLC.
59887 * Originally Released Under LGPL - original licence link has changed is not relivant.
59890 * <script type="text/javascript">
59893 // private - not really -- you end up using it !
59894 // This is a support class used internally by the Grid components
59897 * @class Roo.grid.GridEditor
59898 * @extends Roo.Editor
59899 * Class for creating and editable grid elements.
59900 * @param {Object} config any settings (must include field)
59902 Roo.grid.GridEditor = function(field, config){
59903 if (!config && field.field) {
59905 field = Roo.factory(config.field, Roo.form);
59907 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
59908 field.monitorTab = false;
59911 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
59914 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
59917 alignment: "tl-tl",
59920 cls: "x-small-editor x-grid-editor",
59925 * Ext JS Library 1.1.1
59926 * Copyright(c) 2006-2007, Ext JS, LLC.
59928 * Originally Released Under LGPL - original licence link has changed is not relivant.
59931 * <script type="text/javascript">
59936 Roo.grid.PropertyRecord = Roo.data.Record.create([
59937 {name:'name',type:'string'}, 'value'
59941 Roo.grid.PropertyStore = function(grid, source){
59943 this.store = new Roo.data.Store({
59944 recordType : Roo.grid.PropertyRecord
59946 this.store.on('update', this.onUpdate, this);
59948 this.setSource(source);
59950 Roo.grid.PropertyStore.superclass.constructor.call(this);
59955 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
59956 setSource : function(o){
59958 this.store.removeAll();
59961 if(this.isEditableValue(o[k])){
59962 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
59965 this.store.loadRecords({records: data}, {}, true);
59968 onUpdate : function(ds, record, type){
59969 if(type == Roo.data.Record.EDIT){
59970 var v = record.data['value'];
59971 var oldValue = record.modified['value'];
59972 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
59973 this.source[record.id] = v;
59975 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
59982 getProperty : function(row){
59983 return this.store.getAt(row);
59986 isEditableValue: function(val){
59987 if(val && val instanceof Date){
59989 }else if(typeof val == 'object' || typeof val == 'function'){
59995 setValue : function(prop, value){
59996 this.source[prop] = value;
59997 this.store.getById(prop).set('value', value);
60000 getSource : function(){
60001 return this.source;
60005 Roo.grid.PropertyColumnModel = function(grid, store){
60008 g.PropertyColumnModel.superclass.constructor.call(this, [
60009 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
60010 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
60012 this.store = store;
60013 this.bselect = Roo.DomHelper.append(document.body, {
60014 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
60015 {tag: 'option', value: 'true', html: 'true'},
60016 {tag: 'option', value: 'false', html: 'false'}
60019 Roo.id(this.bselect);
60022 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
60023 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
60024 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
60025 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
60026 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
60028 this.renderCellDelegate = this.renderCell.createDelegate(this);
60029 this.renderPropDelegate = this.renderProp.createDelegate(this);
60032 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
60036 valueText : 'Value',
60038 dateFormat : 'm/j/Y',
60041 renderDate : function(dateVal){
60042 return dateVal.dateFormat(this.dateFormat);
60045 renderBool : function(bVal){
60046 return bVal ? 'true' : 'false';
60049 isCellEditable : function(colIndex, rowIndex){
60050 return colIndex == 1;
60053 getRenderer : function(col){
60055 this.renderCellDelegate : this.renderPropDelegate;
60058 renderProp : function(v){
60059 return this.getPropertyName(v);
60062 renderCell : function(val){
60064 if(val instanceof Date){
60065 rv = this.renderDate(val);
60066 }else if(typeof val == 'boolean'){
60067 rv = this.renderBool(val);
60069 return Roo.util.Format.htmlEncode(rv);
60072 getPropertyName : function(name){
60073 var pn = this.grid.propertyNames;
60074 return pn && pn[name] ? pn[name] : name;
60077 getCellEditor : function(colIndex, rowIndex){
60078 var p = this.store.getProperty(rowIndex);
60079 var n = p.data['name'], val = p.data['value'];
60081 if(typeof(this.grid.customEditors[n]) == 'string'){
60082 return this.editors[this.grid.customEditors[n]];
60084 if(typeof(this.grid.customEditors[n]) != 'undefined'){
60085 return this.grid.customEditors[n];
60087 if(val instanceof Date){
60088 return this.editors['date'];
60089 }else if(typeof val == 'number'){
60090 return this.editors['number'];
60091 }else if(typeof val == 'boolean'){
60092 return this.editors['boolean'];
60094 return this.editors['string'];
60100 * @class Roo.grid.PropertyGrid
60101 * @extends Roo.grid.EditorGrid
60102 * This class represents the interface of a component based property grid control.
60103 * <br><br>Usage:<pre><code>
60104 var grid = new Roo.grid.PropertyGrid("my-container-id", {
60112 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60113 * The container MUST have some type of size defined for the grid to fill. The container will be
60114 * automatically set to position relative if it isn't already.
60115 * @param {Object} config A config object that sets properties on this grid.
60117 Roo.grid.PropertyGrid = function(container, config){
60118 config = config || {};
60119 var store = new Roo.grid.PropertyStore(this);
60120 this.store = store;
60121 var cm = new Roo.grid.PropertyColumnModel(this, store);
60122 store.store.sort('name', 'ASC');
60123 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
60126 enableColLock:false,
60127 enableColumnMove:false,
60129 trackMouseOver: false,
60132 this.getGridEl().addClass('x-props-grid');
60133 this.lastEditRow = null;
60134 this.on('columnresize', this.onColumnResize, this);
60137 * @event beforepropertychange
60138 * Fires before a property changes (return false to stop?)
60139 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60140 * @param {String} id Record Id
60141 * @param {String} newval New Value
60142 * @param {String} oldval Old Value
60144 "beforepropertychange": true,
60146 * @event propertychange
60147 * Fires after a property changes
60148 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
60149 * @param {String} id Record Id
60150 * @param {String} newval New Value
60151 * @param {String} oldval Old Value
60153 "propertychange": true
60155 this.customEditors = this.customEditors || {};
60157 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
60160 * @cfg {Object} customEditors map of colnames=> custom editors.
60161 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
60162 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
60163 * false disables editing of the field.
60167 * @cfg {Object} propertyNames map of property Names to their displayed value
60170 render : function(){
60171 Roo.grid.PropertyGrid.superclass.render.call(this);
60172 this.autoSize.defer(100, this);
60175 autoSize : function(){
60176 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
60178 this.view.fitColumns();
60182 onColumnResize : function(){
60183 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
60187 * Sets the data for the Grid
60188 * accepts a Key => Value object of all the elements avaiable.
60189 * @param {Object} data to appear in grid.
60191 setSource : function(source){
60192 this.store.setSource(source);
60196 * Gets all the data from the grid.
60197 * @return {Object} data data stored in grid
60199 getSource : function(){
60200 return this.store.getSource();
60209 * @class Roo.grid.Calendar
60210 * @extends Roo.util.Grid
60211 * This class extends the Grid to provide a calendar widget
60212 * <br><br>Usage:<pre><code>
60213 var grid = new Roo.grid.Calendar("my-container-id", {
60216 selModel: mySelectionModel,
60217 autoSizeColumns: true,
60218 monitorWindowResize: false,
60219 trackMouseOver: true
60220 eventstore : real data store..
60226 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
60227 * The container MUST have some type of size defined for the grid to fill. The container will be
60228 * automatically set to position relative if it isn't already.
60229 * @param {Object} config A config object that sets properties on this grid.
60231 Roo.grid.Calendar = function(container, config){
60232 // initialize the container
60233 this.container = Roo.get(container);
60234 this.container.update("");
60235 this.container.setStyle("overflow", "hidden");
60236 this.container.addClass('x-grid-container');
60238 this.id = this.container.id;
60240 Roo.apply(this, config);
60241 // check and correct shorthanded configs
60245 for (var r = 0;r < 6;r++) {
60248 for (var c =0;c < 7;c++) {
60252 if (this.eventStore) {
60253 this.eventStore= Roo.factory(this.eventStore, Roo.data);
60254 this.eventStore.on('load',this.onLoad, this);
60255 this.eventStore.on('beforeload',this.clearEvents, this);
60259 this.dataSource = new Roo.data.Store({
60260 proxy: new Roo.data.MemoryProxy(rows),
60261 reader: new Roo.data.ArrayReader({}, [
60262 'weekday0', 'weekday1', 'weekday2', 'weekday3', 'weekday4', 'weekday5', 'weekday6' ])
60265 this.dataSource.load();
60266 this.ds = this.dataSource;
60267 this.ds.xmodule = this.xmodule || false;
60270 var cellRender = function(v,x,r)
60272 return String.format(
60273 '<div class="fc-day fc-widget-content"><div>' +
60274 '<div class="fc-event-container"></div>' +
60275 '<div class="fc-day-number">{0}</div>'+
60277 '<div class="fc-day-content"><div style="position:relative"></div></div>' +
60278 '</div></div>', v);
60283 this.colModel = new Roo.grid.ColumnModel( [
60285 xtype: 'ColumnModel',
60287 dataIndex : 'weekday0',
60289 renderer : cellRender
60292 xtype: 'ColumnModel',
60294 dataIndex : 'weekday1',
60296 renderer : cellRender
60299 xtype: 'ColumnModel',
60301 dataIndex : 'weekday2',
60302 header : 'Tuesday',
60303 renderer : cellRender
60306 xtype: 'ColumnModel',
60308 dataIndex : 'weekday3',
60309 header : 'Wednesday',
60310 renderer : cellRender
60313 xtype: 'ColumnModel',
60315 dataIndex : 'weekday4',
60316 header : 'Thursday',
60317 renderer : cellRender
60320 xtype: 'ColumnModel',
60322 dataIndex : 'weekday5',
60324 renderer : cellRender
60327 xtype: 'ColumnModel',
60329 dataIndex : 'weekday6',
60330 header : 'Saturday',
60331 renderer : cellRender
60334 this.cm = this.colModel;
60335 this.cm.xmodule = this.xmodule || false;
60339 //this.selModel = new Roo.grid.CellSelectionModel();
60340 //this.sm = this.selModel;
60341 //this.selModel.init(this);
60345 this.container.setWidth(this.width);
60349 this.container.setHeight(this.height);
60356 * The raw click event for the entire grid.
60357 * @param {Roo.EventObject} e
60362 * The raw dblclick event for the entire grid.
60363 * @param {Roo.EventObject} e
60367 * @event contextmenu
60368 * The raw contextmenu event for the entire grid.
60369 * @param {Roo.EventObject} e
60371 "contextmenu" : true,
60374 * The raw mousedown event for the entire grid.
60375 * @param {Roo.EventObject} e
60377 "mousedown" : true,
60380 * The raw mouseup event for the entire grid.
60381 * @param {Roo.EventObject} e
60386 * The raw mouseover event for the entire grid.
60387 * @param {Roo.EventObject} e
60389 "mouseover" : true,
60392 * The raw mouseout event for the entire grid.
60393 * @param {Roo.EventObject} e
60398 * The raw keypress event for the entire grid.
60399 * @param {Roo.EventObject} e
60404 * The raw keydown event for the entire grid.
60405 * @param {Roo.EventObject} e
60413 * Fires when a cell is clicked
60414 * @param {Grid} this
60415 * @param {Number} rowIndex
60416 * @param {Number} columnIndex
60417 * @param {Roo.EventObject} e
60419 "cellclick" : true,
60421 * @event celldblclick
60422 * Fires when a cell is double clicked
60423 * @param {Grid} this
60424 * @param {Number} rowIndex
60425 * @param {Number} columnIndex
60426 * @param {Roo.EventObject} e
60428 "celldblclick" : true,
60431 * Fires when a row is clicked
60432 * @param {Grid} this
60433 * @param {Number} rowIndex
60434 * @param {Roo.EventObject} e
60438 * @event rowdblclick
60439 * Fires when a row is double clicked
60440 * @param {Grid} this
60441 * @param {Number} rowIndex
60442 * @param {Roo.EventObject} e
60444 "rowdblclick" : true,
60446 * @event headerclick
60447 * Fires when a header is clicked
60448 * @param {Grid} this
60449 * @param {Number} columnIndex
60450 * @param {Roo.EventObject} e
60452 "headerclick" : true,
60454 * @event headerdblclick
60455 * Fires when a header cell is double clicked
60456 * @param {Grid} this
60457 * @param {Number} columnIndex
60458 * @param {Roo.EventObject} e
60460 "headerdblclick" : true,
60462 * @event rowcontextmenu
60463 * Fires when a row is right clicked
60464 * @param {Grid} this
60465 * @param {Number} rowIndex
60466 * @param {Roo.EventObject} e
60468 "rowcontextmenu" : true,
60470 * @event cellcontextmenu
60471 * Fires when a cell is right clicked
60472 * @param {Grid} this
60473 * @param {Number} rowIndex
60474 * @param {Number} cellIndex
60475 * @param {Roo.EventObject} e
60477 "cellcontextmenu" : true,
60479 * @event headercontextmenu
60480 * Fires when a header is right clicked
60481 * @param {Grid} this
60482 * @param {Number} columnIndex
60483 * @param {Roo.EventObject} e
60485 "headercontextmenu" : true,
60487 * @event bodyscroll
60488 * Fires when the body element is scrolled
60489 * @param {Number} scrollLeft
60490 * @param {Number} scrollTop
60492 "bodyscroll" : true,
60494 * @event columnresize
60495 * Fires when the user resizes a column
60496 * @param {Number} columnIndex
60497 * @param {Number} newSize
60499 "columnresize" : true,
60501 * @event columnmove
60502 * Fires when the user moves a column
60503 * @param {Number} oldIndex
60504 * @param {Number} newIndex
60506 "columnmove" : true,
60509 * Fires when row(s) start being dragged
60510 * @param {Grid} this
60511 * @param {Roo.GridDD} dd The drag drop object
60512 * @param {event} e The raw browser event
60514 "startdrag" : true,
60517 * Fires when a drag operation is complete
60518 * @param {Grid} this
60519 * @param {Roo.GridDD} dd The drag drop object
60520 * @param {event} e The raw browser event
60525 * Fires when dragged row(s) are dropped on a valid DD target
60526 * @param {Grid} this
60527 * @param {Roo.GridDD} dd The drag drop object
60528 * @param {String} targetId The target drag drop object
60529 * @param {event} e The raw browser event
60534 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
60535 * @param {Grid} this
60536 * @param {Roo.GridDD} dd The drag drop object
60537 * @param {String} targetId The target drag drop object
60538 * @param {event} e The raw browser event
60543 * Fires when the dragged row(s) first cross another DD target while being dragged
60544 * @param {Grid} this
60545 * @param {Roo.GridDD} dd The drag drop object
60546 * @param {String} targetId The target drag drop object
60547 * @param {event} e The raw browser event
60549 "dragenter" : true,
60552 * Fires when the dragged row(s) leave another DD target while being dragged
60553 * @param {Grid} this
60554 * @param {Roo.GridDD} dd The drag drop object
60555 * @param {String} targetId The target drag drop object
60556 * @param {event} e The raw browser event
60561 * Fires when a row is rendered, so you can change add a style to it.
60562 * @param {GridView} gridview The grid view
60563 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
60569 * Fires when the grid is rendered
60570 * @param {Grid} grid
60575 * Fires when a date is selected
60576 * @param {DatePicker} this
60577 * @param {Date} date The selected date
60581 * @event monthchange
60582 * Fires when the displayed month changes
60583 * @param {DatePicker} this
60584 * @param {Date} date The selected month
60586 'monthchange': true,
60588 * @event evententer
60589 * Fires when mouse over an event
60590 * @param {Calendar} this
60591 * @param {event} Event
60593 'evententer': true,
60595 * @event eventleave
60596 * Fires when the mouse leaves an
60597 * @param {Calendar} this
60600 'eventleave': true,
60602 * @event eventclick
60603 * Fires when the mouse click an
60604 * @param {Calendar} this
60607 'eventclick': true,
60609 * @event eventrender
60610 * Fires before each cell is rendered, so you can modify the contents, like cls / title / qtip
60611 * @param {Calendar} this
60612 * @param {data} data to be modified
60614 'eventrender': true
60618 Roo.grid.Grid.superclass.constructor.call(this);
60619 this.on('render', function() {
60620 this.view.el.addClass('x-grid-cal');
60622 (function() { this.setDate(new Date()); }).defer(100,this); //default today..
60626 if (!Roo.grid.Calendar.style) {
60627 Roo.grid.Calendar.style = Roo.util.CSS.createStyleSheet({
60630 '.x-grid-cal .x-grid-col' : {
60631 height: 'auto !important',
60632 'vertical-align': 'top'
60634 '.x-grid-cal .fc-event-hori' : {
60645 Roo.extend(Roo.grid.Calendar, Roo.grid.Grid, {
60647 * @cfg {Store} eventStore The store that loads events.
60652 activeDate : false,
60655 monitorWindowResize : false,
60658 resizeColumns : function() {
60659 var col = (this.view.el.getWidth() / 7) - 3;
60660 // loop through cols, and setWidth
60661 for(var i =0 ; i < 7 ; i++){
60662 this.cm.setColumnWidth(i, col);
60665 setDate :function(date) {
60667 Roo.log('setDate?');
60669 this.resizeColumns();
60670 var vd = this.activeDate;
60671 this.activeDate = date;
60672 // if(vd && this.el){
60673 // var t = date.getTime();
60674 // if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
60675 // Roo.log('using add remove');
60677 // this.fireEvent('monthchange', this, date);
60679 // this.cells.removeClass("fc-state-highlight");
60680 // this.cells.each(function(c){
60681 // if(c.dateValue == t){
60682 // c.addClass("fc-state-highlight");
60683 // setTimeout(function(){
60684 // try{c.dom.firstChild.focus();}catch(e){}
60694 var days = date.getDaysInMonth();
60696 var firstOfMonth = date.getFirstDateOfMonth();
60697 var startingPos = firstOfMonth.getDay()-this.startDay;
60699 if(startingPos < this.startDay){
60703 var pm = date.add(Date.MONTH, -1);
60704 var prevStart = pm.getDaysInMonth()-startingPos;
60708 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60710 this.textNodes = this.view.el.query('.x-grid-row .x-grid-col .x-grid-cell-text');
60711 //this.cells.addClassOnOver('fc-state-hover');
60713 var cells = this.cells.elements;
60714 var textEls = this.textNodes;
60716 //Roo.each(cells, function(cell){
60717 // cell.removeClass([ 'fc-past', 'fc-other-month', 'fc-future', 'fc-state-highlight', 'fc-state-disabled']);
60720 days += startingPos;
60722 // convert everything to numbers so it's fast
60723 var day = 86400000;
60724 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
60727 //Roo.log(prevStart);
60729 var today = new Date().clearTime().getTime();
60730 var sel = date.clearTime().getTime();
60731 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
60732 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
60733 var ddMatch = this.disabledDatesRE;
60734 var ddText = this.disabledDatesText;
60735 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
60736 var ddaysText = this.disabledDaysText;
60737 var format = this.format;
60739 var setCellClass = function(cal, cell){
60741 //Roo.log('set Cell Class');
60743 var t = d.getTime();
60748 cell.dateValue = t;
60750 cell.className += " fc-today";
60751 cell.className += " fc-state-highlight";
60752 cell.title = cal.todayText;
60755 // disable highlight in other month..
60756 cell.className += " fc-state-highlight";
60761 //cell.className = " fc-state-disabled";
60762 cell.title = cal.minText;
60766 //cell.className = " fc-state-disabled";
60767 cell.title = cal.maxText;
60771 if(ddays.indexOf(d.getDay()) != -1){
60772 // cell.title = ddaysText;
60773 // cell.className = " fc-state-disabled";
60776 if(ddMatch && format){
60777 var fvalue = d.dateFormat(format);
60778 if(ddMatch.test(fvalue)){
60779 cell.title = ddText.replace("%0", fvalue);
60780 cell.className = " fc-state-disabled";
60784 if (!cell.initialClassName) {
60785 cell.initialClassName = cell.dom.className;
60788 cell.dom.className = cell.initialClassName + ' ' + cell.className;
60793 for(; i < startingPos; i++) {
60794 cells[i].dayName = (++prevStart);
60795 Roo.log(textEls[i]);
60796 d.setDate(d.getDate()+1);
60798 //cells[i].className = "fc-past fc-other-month";
60799 setCellClass(this, cells[i]);
60804 for(; i < days; i++){
60805 intDay = i - startingPos + 1;
60806 cells[i].dayName = (intDay);
60807 d.setDate(d.getDate()+1);
60809 cells[i].className = ''; // "x-date-active";
60810 setCellClass(this, cells[i]);
60814 for(; i < 42; i++) {
60815 //textEls[i].innerHTML = (++extraDays);
60817 d.setDate(d.getDate()+1);
60818 cells[i].dayName = (++extraDays);
60819 cells[i].className = "fc-future fc-other-month";
60820 setCellClass(this, cells[i]);
60823 //this.el.select('.fc-header-title h2',true).update(Date.monthNames[date.getMonth()] + " " + date.getFullYear());
60825 var totalRows = Math.ceil((date.getDaysInMonth() + date.getFirstDateOfMonth().getDay()) / 7);
60827 // this will cause all the cells to mis
60830 for (var r = 0;r < 6;r++) {
60831 for (var c =0;c < 7;c++) {
60832 this.ds.getAt(r).set('weekday' + c ,cells[i++].dayName );
60836 this.cells = this.view.el.select('.x-grid-row .x-grid-col',true);
60837 for(i=0;i<cells.length;i++) {
60839 this.cells.elements[i].dayName = cells[i].dayName ;
60840 this.cells.elements[i].className = cells[i].className;
60841 this.cells.elements[i].initialClassName = cells[i].initialClassName ;
60842 this.cells.elements[i].title = cells[i].title ;
60843 this.cells.elements[i].dateValue = cells[i].dateValue ;
60849 //this.el.select('tr.fc-week.fc-prev-last',true).removeClass('fc-last');
60850 //this.el.select('tr.fc-week.fc-next-last',true).addClass('fc-last').show();
60852 ////if(totalRows != 6){
60853 //this.el.select('tr.fc-week.fc-last',true).removeClass('fc-last').addClass('fc-next-last').hide();
60854 // this.el.select('tr.fc-week.fc-prev-last',true).addClass('fc-last');
60857 this.fireEvent('monthchange', this, date);
60862 * Returns the grid's SelectionModel.
60863 * @return {SelectionModel}
60865 getSelectionModel : function(){
60866 if(!this.selModel){
60867 this.selModel = new Roo.grid.CellSelectionModel();
60869 return this.selModel;
60873 this.eventStore.load()
60879 findCell : function(dt) {
60880 dt = dt.clearTime().getTime();
60882 this.cells.each(function(c){
60883 //Roo.log("check " +c.dateValue + '?=' + dt);
60884 if(c.dateValue == dt){
60894 findCells : function(rec) {
60895 var s = rec.data.start_dt.clone().clearTime().getTime();
60897 var e= rec.data.end_dt.clone().clearTime().getTime();
60900 this.cells.each(function(c){
60901 ////Roo.log("check " +c.dateValue + '<' + e + ' > ' + s);
60903 if(c.dateValue > e){
60906 if(c.dateValue < s){
60915 findBestRow: function(cells)
60919 for (var i =0 ; i < cells.length;i++) {
60920 ret = Math.max(cells[i].rows || 0,ret);
60927 addItem : function(rec)
60929 // look for vertical location slot in
60930 var cells = this.findCells(rec);
60932 rec.row = this.findBestRow(cells);
60934 // work out the location.
60938 for(var i =0; i < cells.length; i++) {
60946 if (crow.start.getY() == cells[i].getY()) {
60948 crow.end = cells[i];
60964 for (var i = 0; i < cells.length;i++) {
60965 cells[i].rows = Math.max(cells[i].rows || 0 , rec.row + 1 );
60972 clearEvents: function() {
60974 if (!this.eventStore.getCount()) {
60977 // reset number of rows in cells.
60978 Roo.each(this.cells.elements, function(c){
60982 this.eventStore.each(function(e) {
60983 this.clearEvent(e);
60988 clearEvent : function(ev)
60991 Roo.each(ev.els, function(el) {
60992 el.un('mouseenter' ,this.onEventEnter, this);
60993 el.un('mouseleave' ,this.onEventLeave, this);
61001 renderEvent : function(ev,ctr) {
61003 ctr = this.view.el.select('.fc-event-container',true).first();
61007 this.clearEvent(ev);
61013 var cells = ev.cells;
61014 var rows = ev.rows;
61015 this.fireEvent('eventrender', this, ev);
61017 for(var i =0; i < rows.length; i++) {
61021 cls += ' fc-event-start';
61023 if ((i+1) == rows.length) {
61024 cls += ' fc-event-end';
61027 //Roo.log(ev.data);
61028 // how many rows should it span..
61029 var cg = this.eventTmpl.append(ctr,Roo.apply({
61032 }, ev.data) , true);
61035 cg.on('mouseenter' ,this.onEventEnter, this, ev);
61036 cg.on('mouseleave' ,this.onEventLeave, this, ev);
61037 cg.on('click', this.onEventClick, this, ev);
61041 var sbox = rows[i].start.select('.fc-day-content',true).first().getBox();
61042 var ebox = rows[i].end.select('.fc-day-content',true).first().getBox();
61045 cg.setXY([sbox.x +2, sbox.y +(ev.row * 20)]);
61046 cg.setWidth(ebox.right - sbox.x -2);
61050 renderEvents: function()
61052 // first make sure there is enough space..
61054 if (!this.eventTmpl) {
61055 this.eventTmpl = new Roo.Template(
61056 '<div class="roo-dynamic fc-event fc-event-hori fc-event-draggable ui-draggable {fccls} {cls}" style="position: absolute" unselectable="on">' +
61057 '<div class="fc-event-inner">' +
61058 '<span class="fc-event-time">{time}</span>' +
61059 '<span class="fc-event-title" qtip="{qtip}">{title}</span>' +
61061 '<div class="ui-resizable-heandle ui-resizable-e"> </div>' +
61069 this.cells.each(function(c) {
61070 //Roo.log(c.select('.fc-day-content div',true).first());
61071 c.select('.fc-day-content div',true).first().setHeight(Math.max(34, (c.rows || 1) * 20));
61074 var ctr = this.view.el.select('.fc-event-container',true).first();
61077 this.eventStore.each(function(ev){
61079 this.renderEvent(ev);
61083 this.view.layout();
61087 onEventEnter: function (e, el,event,d) {
61088 this.fireEvent('evententer', this, el, event);
61091 onEventLeave: function (e, el,event,d) {
61092 this.fireEvent('eventleave', this, el, event);
61095 onEventClick: function (e, el,event,d) {
61096 this.fireEvent('eventclick', this, el, event);
61099 onMonthChange: function () {
61103 onLoad: function () {
61105 //Roo.log('calendar onload');
61107 if(this.eventStore.getCount() > 0){
61111 this.eventStore.each(function(d){
61116 if (typeof(add.end_dt) == 'undefined') {
61117 Roo.log("Missing End time in calendar data: ");
61121 if (typeof(add.start_dt) == 'undefined') {
61122 Roo.log("Missing Start time in calendar data: ");
61126 add.start_dt = typeof(add.start_dt) == 'string' ? Date.parseDate(add.start_dt,'Y-m-d H:i:s') : add.start_dt,
61127 add.end_dt = typeof(add.end_dt) == 'string' ? Date.parseDate(add.end_dt,'Y-m-d H:i:s') : add.end_dt,
61128 add.id = add.id || d.id;
61129 add.title = add.title || '??';
61137 this.renderEvents();
61147 render : function ()
61151 if (!this.view.el.hasClass('course-timesheet')) {
61152 this.view.el.addClass('course-timesheet');
61154 if (this.tsStyle) {
61159 Roo.log(_this.grid.view.el.getWidth());
61162 this.tsStyle = Roo.util.CSS.createStyleSheet({
61163 '.course-timesheet .x-grid-row' : {
61166 '.x-grid-row td' : {
61167 'vertical-align' : 0
61169 '.course-edit-link' : {
61171 'text-overflow' : 'ellipsis',
61172 'overflow' : 'hidden',
61173 'white-space' : 'nowrap',
61174 'cursor' : 'pointer'
61179 '.de-act-sup-link' : {
61180 'color' : 'purple',
61181 'text-decoration' : 'line-through'
61185 'text-decoration' : 'line-through'
61187 '.course-timesheet .course-highlight' : {
61188 'border-top-style': 'dashed !important',
61189 'border-bottom-bottom': 'dashed !important'
61191 '.course-timesheet .course-item' : {
61192 'font-family' : 'tahoma, arial, helvetica',
61193 'font-size' : '11px',
61194 'overflow' : 'hidden',
61195 'padding-left' : '10px',
61196 'padding-right' : '10px',
61197 'padding-top' : '10px'
61205 monitorWindowResize : false,
61206 cellrenderer : function(v,x,r)
61211 xtype: 'CellSelectionModel',
61218 beforeload : function (_self, options)
61220 options.params = options.params || {};
61221 options.params._month = _this.monthField.getValue();
61222 options.params.limit = 9999;
61223 options.params['sort'] = 'when_dt';
61224 options.params['dir'] = 'ASC';
61225 this.proxy.loadResponse = this.loadResponse;
61227 //this.addColumns();
61229 load : function (_self, records, options)
61231 _this.grid.view.el.select('.course-edit-link', true).on('click', function() {
61232 // if you click on the translation.. you can edit it...
61233 var el = Roo.get(this);
61234 var id = el.dom.getAttribute('data-id');
61235 var d = el.dom.getAttribute('data-date');
61236 var t = el.dom.getAttribute('data-time');
61237 //var id = this.child('span').dom.textContent;
61240 Pman.Dialog.CourseCalendar.show({
61244 productitem_active : id ? 1 : 0
61246 _this.grid.ds.load({});
61251 _this.panel.fireEvent('resize', [ '', '' ]);
61254 loadResponse : function(o, success, response){
61255 // this is overridden on before load..
61257 Roo.log("our code?");
61258 //Roo.log(success);
61259 //Roo.log(response)
61260 delete this.activeRequest;
61262 this.fireEvent("loadexception", this, o, response);
61263 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61268 result = o.reader.read(response);
61270 Roo.log("load exception?");
61271 this.fireEvent("loadexception", this, o, response, e);
61272 o.request.callback.call(o.request.scope, null, o.request.arg, false);
61275 Roo.log("ready...");
61276 // loop through result.records;
61277 // and set this.tdate[date] = [] << array of records..
61279 Roo.each(result.records, function(r){
61281 if(typeof(_this.tdata[r.data.when_dt.format('j')]) == 'undefined'){
61282 _this.tdata[r.data.when_dt.format('j')] = [];
61284 _this.tdata[r.data.when_dt.format('j')].push(r.data);
61287 //Roo.log(_this.tdata);
61289 result.records = [];
61290 result.totalRecords = 6;
61292 // let's generate some duumy records for the rows.
61293 //var st = _this.dateField.getValue();
61295 // work out monday..
61296 //st = st.add(Date.DAY, -1 * st.format('w'));
61298 var date = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61300 var firstOfMonth = date.getFirstDayOfMonth();
61301 var days = date.getDaysInMonth();
61303 var firstAdded = false;
61304 for (var i = 0; i < result.totalRecords ; i++) {
61305 //var d= st.add(Date.DAY, i);
61308 for(var w = 0 ; w < 7 ; w++){
61309 if(!firstAdded && firstOfMonth != w){
61316 var dd = (d > 0 && d < 10) ? "0"+d : d;
61317 row['weekday'+w] = String.format(
61318 '<span style="font-size: 16px;"><b>{0}</b></span>'+
61319 '<span class="course-edit-link" style="color:blue;" data-id="0" data-date="{1}"> Add New</span>',
61321 date.format('Y-m-')+dd
61324 if(typeof(_this.tdata[d]) != 'undefined'){
61325 Roo.each(_this.tdata[d], function(r){
61329 var desc = (r.productitem_id_descrip) ? r.productitem_id_descrip : '';
61330 if(r.parent_id*1>0){
61331 is_sub = (r.productitem_id_visible*1 < 1) ? 'de-act-sup-link' :'sub-link';
61334 if(r.productitem_id_visible*1 < 1 && r.parent_id*1 < 1){
61335 deactive = 'de-act-link';
61338 row['weekday'+w] += String.format(
61339 '<br /><span class="course-edit-link {3} {4}" qtip="{5}" data-id="{0}">{2} - {1}</span>',
61341 r.product_id_name, //1
61342 r.when_dt.format('h:ia'), //2
61352 // only do this if something added..
61354 result.records.push(_this.grid.dataSource.reader.newRow(row));
61358 // push it twice. (second one with an hour..
61362 this.fireEvent("load", this, o, o.request.arg);
61363 o.request.callback.call(o.request.scope, result, o.request.arg, true);
61365 sortInfo : {field: 'when_dt', direction : 'ASC' },
61367 xtype: 'HttpProxy',
61370 url : baseURL + '/Roo/Shop_course.php'
61373 xtype: 'JsonReader',
61390 'name': 'parent_id',
61394 'name': 'product_id',
61398 'name': 'productitem_id',
61416 click : function (_self, e)
61418 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61419 sd.setMonth(sd.getMonth()-1);
61420 _this.monthField.setValue(sd.format('Y-m-d'));
61421 _this.grid.ds.load({});
61427 xtype: 'Separator',
61431 xtype: 'MonthField',
61434 render : function (_self)
61436 _this.monthField = _self;
61437 // _this.monthField.set today
61439 select : function (combo, date)
61441 _this.grid.ds.load({});
61444 value : (function() { return new Date(); })()
61447 xtype: 'Separator',
61453 text : "Blue: in-active, green: in-active sup-event, red: de-active, purple: de-active sup-event"
61463 click : function (_self, e)
61465 var sd = Date.parseDate(_this.monthField.getValue(), "Y-m-d");
61466 sd.setMonth(sd.getMonth()+1);
61467 _this.monthField.setValue(sd.format('Y-m-d'));
61468 _this.grid.ds.load({});
61481 * Ext JS Library 1.1.1
61482 * Copyright(c) 2006-2007, Ext JS, LLC.
61484 * Originally Released Under LGPL - original licence link has changed is not relivant.
61487 * <script type="text/javascript">
61491 * @class Roo.LoadMask
61492 * A simple utility class for generically masking elements while loading data. If the element being masked has
61493 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
61494 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
61495 * element's UpdateManager load indicator and will be destroyed after the initial load.
61497 * Create a new LoadMask
61498 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
61499 * @param {Object} config The config object
61501 Roo.LoadMask = function(el, config){
61502 this.el = Roo.get(el);
61503 Roo.apply(this, config);
61505 this.store.on('beforeload', this.onBeforeLoad, this);
61506 this.store.on('load', this.onLoad, this);
61507 this.store.on('loadexception', this.onLoadException, this);
61508 this.removeMask = false;
61510 var um = this.el.getUpdateManager();
61511 um.showLoadIndicator = false; // disable the default indicator
61512 um.on('beforeupdate', this.onBeforeLoad, this);
61513 um.on('update', this.onLoad, this);
61514 um.on('failure', this.onLoad, this);
61515 this.removeMask = true;
61519 Roo.LoadMask.prototype = {
61521 * @cfg {Boolean} removeMask
61522 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
61523 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
61526 * @cfg {String} msg
61527 * The text to display in a centered loading message box (defaults to 'Loading...')
61529 msg : 'Loading...',
61531 * @cfg {String} msgCls
61532 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
61534 msgCls : 'x-mask-loading',
61537 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
61543 * Disables the mask to prevent it from being displayed
61545 disable : function(){
61546 this.disabled = true;
61550 * Enables the mask so that it can be displayed
61552 enable : function(){
61553 this.disabled = false;
61556 onLoadException : function()
61558 Roo.log(arguments);
61560 if (typeof(arguments[3]) != 'undefined') {
61561 Roo.MessageBox.alert("Error loading",arguments[3]);
61565 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
61566 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
61573 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61576 onLoad : function()
61578 (function() { this.el.unmask(this.removeMask); }).defer(50, this);
61582 onBeforeLoad : function(){
61583 if(!this.disabled){
61584 (function() { this.el.mask(this.msg, this.msgCls); }).defer(50, this);
61589 destroy : function(){
61591 this.store.un('beforeload', this.onBeforeLoad, this);
61592 this.store.un('load', this.onLoad, this);
61593 this.store.un('loadexception', this.onLoadException, this);
61595 var um = this.el.getUpdateManager();
61596 um.un('beforeupdate', this.onBeforeLoad, this);
61597 um.un('update', this.onLoad, this);
61598 um.un('failure', this.onLoad, this);
61603 * Ext JS Library 1.1.1
61604 * Copyright(c) 2006-2007, Ext JS, LLC.
61606 * Originally Released Under LGPL - original licence link has changed is not relivant.
61609 * <script type="text/javascript">
61614 * @class Roo.XTemplate
61615 * @extends Roo.Template
61616 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
61618 var t = new Roo.XTemplate(
61619 '<select name="{name}">',
61620 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
61624 // then append, applying the master template values
61627 * Supported features:
61632 {a_variable} - output encoded.
61633 {a_variable.format:("Y-m-d")} - call a method on the variable
61634 {a_variable:raw} - unencoded output
61635 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
61636 {a_variable:this.method_on_template(...)} - call a method on the template object.
61641 <tpl for="a_variable or condition.."></tpl>
61642 <tpl if="a_variable or condition"></tpl>
61643 <tpl exec="some javascript"></tpl>
61644 <tpl name="named_template"></tpl> (experimental)
61646 <tpl for="."></tpl> - just iterate the property..
61647 <tpl for=".."></tpl> - iterates with the parent (probably the template)
61651 Roo.XTemplate = function()
61653 Roo.XTemplate.superclass.constructor.apply(this, arguments);
61660 Roo.extend(Roo.XTemplate, Roo.Template, {
61663 * The various sub templates
61668 * basic tag replacing syntax
61671 * // you can fake an object call by doing this
61675 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
61678 * compile the template
61680 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
61683 compile: function()
61687 s = ['<tpl>', s, '</tpl>'].join('');
61689 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
61690 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
61691 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
61692 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
61693 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
61698 while(true == !!(m = s.match(re))){
61699 var forMatch = m[0].match(nameRe),
61700 ifMatch = m[0].match(ifRe),
61701 execMatch = m[0].match(execRe),
61702 namedMatch = m[0].match(namedRe),
61707 name = forMatch && forMatch[1] ? forMatch[1] : '';
61710 // if - puts fn into test..
61711 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
61713 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
61718 // exec - calls a function... returns empty if true is returned.
61719 exp = execMatch && execMatch[1] ? execMatch[1] : null;
61721 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
61729 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
61730 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
61731 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
61734 var uid = namedMatch ? namedMatch[1] : id;
61738 id: namedMatch ? namedMatch[1] : id,
61745 s = s.replace(m[0], '');
61747 s = s.replace(m[0], '{xtpl'+ id + '}');
61752 for(var i = tpls.length-1; i >= 0; --i){
61753 this.compileTpl(tpls[i]);
61754 this.tpls[tpls[i].id] = tpls[i];
61756 this.master = tpls[tpls.length-1];
61760 * same as applyTemplate, except it's done to one of the subTemplates
61761 * when using named templates, you can do:
61763 * var str = pl.applySubTemplate('your-name', values);
61766 * @param {Number} id of the template
61767 * @param {Object} values to apply to template
61768 * @param {Object} parent (normaly the instance of this object)
61770 applySubTemplate : function(id, values, parent)
61774 var t = this.tpls[id];
61778 if(t.test && !t.test.call(this, values, parent)){
61782 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
61783 Roo.log(e.toString());
61789 if(t.exec && t.exec.call(this, values, parent)){
61793 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
61794 Roo.log(e.toString());
61799 var vs = t.target ? t.target.call(this, values, parent) : values;
61800 parent = t.target ? values : parent;
61801 if(t.target && vs instanceof Array){
61803 for(var i = 0, len = vs.length; i < len; i++){
61804 buf[buf.length] = t.compiled.call(this, vs[i], parent);
61806 return buf.join('');
61808 return t.compiled.call(this, vs, parent);
61810 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
61811 Roo.log(e.toString());
61812 Roo.log(t.compiled);
61817 compileTpl : function(tpl)
61819 var fm = Roo.util.Format;
61820 var useF = this.disableFormats !== true;
61821 var sep = Roo.isGecko ? "+" : ",";
61822 var undef = function(str) {
61823 Roo.log("Property not found :" + str);
61827 var fn = function(m, name, format, args)
61829 //Roo.log(arguments);
61830 args = args ? args.replace(/\\'/g,"'") : args;
61831 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
61832 if (typeof(format) == 'undefined') {
61833 format= 'htmlEncode';
61835 if (format == 'raw' ) {
61839 if(name.substr(0, 4) == 'xtpl'){
61840 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
61843 // build an array of options to determine if value is undefined..
61845 // basically get 'xxxx.yyyy' then do
61846 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
61847 // (function () { Roo.log("Property not found"); return ''; })() :
61852 Roo.each(name.split('.'), function(st) {
61853 lookfor += (lookfor.length ? '.': '') + st;
61854 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
61857 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
61860 if(format && useF){
61862 args = args ? ',' + args : "";
61864 if(format.substr(0, 5) != "this."){
61865 format = "fm." + format + '(';
61867 format = 'this.call("'+ format.substr(5) + '", ';
61871 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
61875 // called with xxyx.yuu:(test,test)
61877 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
61879 // raw.. - :raw modifier..
61880 return "'"+ sep + udef_st + name + ")"+sep+"'";
61884 // branched to use + in gecko and [].join() in others
61886 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
61887 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
61890 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
61891 body.push(tpl.body.replace(/(\r\n|\n)/g,
61892 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
61893 body.push("'].join('');};};");
61894 body = body.join('');
61897 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
61899 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
61905 applyTemplate : function(values){
61906 return this.master.compiled.call(this, values, {});
61907 //var s = this.subs;
61910 apply : function(){
61911 return this.applyTemplate.apply(this, arguments);
61916 Roo.XTemplate.from = function(el){
61917 el = Roo.getDom(el);
61918 return new Roo.XTemplate(el.value || el.innerHTML);